Bug 1335905 - In the process of fixing jareds bugs draft
authormanotejmeka <manotejmeka@gmail.com>
Fri, 03 Mar 2017 01:15:32 -0500
changeset 493038 a656bde4ce69e6ace8d53dbfaf603f9f50e94bda
parent 493037 8772114d5dcc4ff783fd2381b2eaa712c18d6a89
child 547749 852cae8ff0ecc9a58f2782e4fdd31b233a5ab5ab
push id47636
push userbmo:manotejmeka@gmail.com
push dateFri, 03 Mar 2017 06:26:49 +0000
bugs1335905
milestone54.0a1
Bug 1335905 - In the process of fixing jareds bugs MozReview-Commit-ID: 3zqbK5nQOfG
browser/components/preferences/in-content/findInPage.js
browser/components/preferences/in-content/preferences.js
browser/components/preferences/in-content/preferences.xul
browser/components/preferences/in-content/searchResults.xul
browser/components/preferences/in-content/tests/browser_search_within_preferences.js
browser/locales/en-US/chrome/browser/preferences/preferences.dtd
--- a/browser/components/preferences/in-content/findInPage.js
+++ b/browser/components/preferences/in-content/findInPage.js
@@ -1,34 +1,39 @@
-// paneSearchResults needs init function to initialize the object
-var gSearchResults = {
-  init() {}
-}
-
-// Obtaining the search field
-let mainSearchElement = document.getElementById("searchInput");
-
-document.getElementById("searchInput").addEventListener("command", searchFunc);
-
-const searchResultsCategory = document.getElementById("category-search-results");
+var gFindSelection = null;
+// Search Results Pane
+var gSearchResultsCategory = null;
+// Search input 
+var gMainSearchElement = null;
 
 /**
  * Toggling Seachbar on and off according to browser.preferences.search
  */
 function showSearchIfEnabled() {
   let mainSearchEnable = Services.prefs.getBoolPref("browser.preferences.search");
   if (mainSearchEnable) {
-    mainSearchElement.hidden = false;
+    gMainSearchElement.hidden = false;
   } 
   else {
-    mainSearchElement.hidden = true;
+    gMainSearchElement.hidden = true;
   }
 }
+// paneSearchResults needs init function to initialize the object
+var gSearchResultsPane = {
+  init() {
+    let controller = getSelectionController();
+    gFindSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
 
-showSearchIfEnabled();
+    document.getElementById("searchInput").addEventListener("command", searchFunction);
+    gSearchResultsCategory = document.getElementById("category-search-results");
+    // Obtaining the search Input
+    gMainSearchElement = document.getElementById("searchInput");
+    showSearchIfEnabled();
+  }
+}
 
 /**
  * Check that the passed string matches the filter arguments.
  *
  * @param String str
  *    to search for filter words in.
  * @param String filter
  *    is a string containing all of the words to filter on.
@@ -53,21 +58,22 @@ let categoriesInitialized = false;
  * When search bar is clicked initializes all the JS bindings
  *
  * @returns null
  */
 function initializeCategories() {
   //  Initializing all the JS for all the tabs
   if (!categoriesInitialized) {
     categoriesInitialized = true;
-    gCategoryInits.forEach( function(eachTab) {
-      if (!eachTab.inited) {
-        eachTab.init();
+    for (let eachTab of gCategoryInits) {
+      // eachTab [name, Object]
+      if (!eachTab[1].inited) {
+        eachTab[1].init();
       }
-    });
+    }
   }
 }
 
 /**
  * Finding text nodes from the nodes
  * Source - http://stackoverflow.com/questions/10730309/find-all-text-nodes-in-html-page
  *
  * @param Node nodeObject
@@ -87,34 +93,32 @@ function textNodeDescendants(node) {
  * Finding words in the text nodes
  * Cases where the word is split up due to access keys
  * @param Array textNodes
  *    List of Html elements
  * @param Array nodeSizes
  *    Running size of text nodes
  * @param String textSearch
  *    Concatination of textNodes's text content
- * @param String word
- *    Word to search for
- * @param Object findSelection
- *    SelectionController
+ * @param String searchPhrase
+ *    word or words to search for
  * @returns boolean
- *      Returns true when atleast one instance of word is found, otherwise false
+ *      Returns true when atleast one instance of search phrase is found, otherwise false
  */
-function multiSearch(textNodes, nodeSizes, textSearch, word, findSelection) {
-  let regExp = new RegExp(word, "gi");
+function multiSearch(textNodes, nodeSizes, textSearch, searchPhrase) {
+  let regExp = new RegExp(searchPhrase, "gi");
   let result, indices = [];
 
   while ((result = regExp.exec(textSearch))) {
     indices.push(result.index);
   }
 
-  // Looping through each spot the word is found in the concatinated string
-  indices.forEach(function(startValue, startIndex) {
-    let endValue = startValue + word.length;
+  // Looping through each spot the searchPhrase is found in the concatinated string
+  for (let startValue of indices) {
+    let endValue = startValue + searchPhrase.length;
     let startNode = null;
     let endNode = null;
     let nodeStartIndex = null;
 
     // Determining the start and end node to highlight from
     nodeSizes.forEach(function(lengthNodes, index) {
       // Determining the start node
       if (!startNode && lengthNodes >= startValue) {
@@ -127,40 +131,38 @@ function multiSearch(textNodes, nodeSize
       // Determining the end node
       if (!endNode && lengthNodes >= endValue) {
         endNode = textNodes[index];
         if (index != nodeStartIndex || index > 0 ) {
           endValue -= nodeSizes[index - 1];
         }
       }
     });
-    // Selection the section to higlight
     let range = document.createRange();
     range.setStart(startNode, startValue);
     range.setEnd(endNode, endValue);
-    findSelection.addRange(range);
-  });
+    gFindSelection.addRange(range);
+  }
 
   return indices.length > 0;
 }
 
 /**
  * Finding if search phrase in defined node property (textContet, value, label)
  *
  * @param Node nodePropertyObject
  *    specific html element property
  * @param String searchPhrase
  *    word or words to search for
  * @returns boolean
  *      Returns true when found in textContent, false otherwise
  */
 function searchNodeProperty(nodePropertyObject, searchPhrase) {
-  if (typeof nodePropertyObject == "string" && nodePropertyObject != ""
-  && stringMatchesFilters(nodePropertyObject, searchPhrase)) {
-    return true;
+  if (typeof nodePropertyObject == "string" && nodePropertyObject != "") {
+    return stringMatchesFilters(nodePropertyObject, searchPhrase);
   }
   return false;
 }
 
 /**
  * Getter for Selection Controller
  *
  * @returns controller
@@ -174,164 +176,127 @@ function getSelectionController() {
   let controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsISelectionDisplay)
                .QueryInterface(Ci.nsISelectionController);
 
   return controller;
 }
 
 /**
- * SHows or hides content according to search input
+ * Shows or hides content according to search input
  *
  * @param String event
- *    to search for filter words in
+ *    to search for filted query in
  */
-function searchFunc(event) {
-  let words = event.target.value.trim();
+function searchFunction(event) {
+  let query = event.target.value.trim();
 
-  // Controller
-  let controller = getSelectionController();
-  let findSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
-  findSelection.removeAllRanges();
+  gFindSelection.removeAllRanges();
 
-  // Init for Search Results tab
   let srHeader = document.getElementById("header-searchResults");
-  let noResults = document.getElementById("noResultsFound");
-  let strings = document.getElementById("searchResultBundle");
 
-  if (words) {
-    console.time("SearchTime");
-
+  if (query) {
     // Showing the Search Results Tag
     gotoPref("paneSearchResults");
-    srHeader.hidden = false;
-    // setAttribute("hidden", "false");
-    searchResultsCategory.hidden = false;
-    // setAttribute("hidden", "false");
+    // srHeader.hidden = false;
+    gSearchResultsCategory.hidden = false;
 
-    let searchFound = false;
+    let resultsFound = false;
 
     // Building the range for highlighted areas
     let rootPreferences = document.getElementById("mainPrefPane")
     let rootPreferencesChildren = rootPreferences.childNodes;
 
     // Showing all the children to bind JS, Access Keys, etc
     for (let i = 0; i < rootPreferences.childElementCount; i++) {
       rootPreferencesChildren[i].hidden = false;
-      // setAttribute("hidden", "false");
     }
 
-    // Showing or Hiding specific section depending on if words are found
+    // Showing or Hiding specific section depending on if words in query are found
     for (let i = 0; i < rootPreferences.childElementCount; i++) {
-      if (nodeRecursion(rootPreferencesChildren[i], words, findSelection)) {
+      if (rootPreferencesChildren[i].className != "header" &&
+      rootPreferencesChildren[i].className != "no-results-message" &&
+      searchWithinNode(rootPreferencesChildren[i], query)) {
         rootPreferencesChildren[i].hidden = false;
-        // setAttribute("hidden", "false");
-        searchFound = true;
+        resultsFound = true;
       } 
       else {
         rootPreferencesChildren[i].hidden = true;
-        // setAttribute("hidden", "true");
-      }
-    }
-    srHeader.hidden = false;
-    // setAttribute("hidden", "false");
-
-    if (!searchFound) {
-      noResults.hidden = false;
-      // setAttribute("hidden", "false");
-      for (let i = 0; i < noResults.childNodes.length; i++) {
-        if (i == 0) {
-            noResults.childNodes[0].textContent = strings.getFormattedString("sorryMessage", [words]);
-        }
-        noResults.childNodes[i].hidden = false;
-        // setAttribute("hidden", "false");
       }
     }
-    console.timeEnd("SearchTime");
+    // It hides Search Results header so turning it on
+    srHeader.hidden = false;
+
+    if (!resultsFound) {
+      for (let element of document.querySelectorAll(".no-results-message")) {
+        element.hidden = false;
+      }
+      let strings = document.getElementById("searchResultBundle");
+      document.getElementById("sorry-message").textContent = strings.getFormattedString("sorryMessage", [query]);
+    }
   } 
   else {
-    searchResultsCategory.hidden = true;
-    // setAttribute("hidden", "true");
-
-    srHeader.hidden = true;
-    // setAttribute("hidden", "true");
-    noResults.hidden = true;
-    // setAttribute("hidden", "true");
-    // Hiding the child nodes so they will not be searched
-    for (let i = 0; i < noResults.childNodes.length; i++) {
-      noResults.childNodes[i].hidden = true;
-      // setAttribute("hidden", "true");
-    }
-
+    gSearchResultsCategory.hidden = true;
+    document.getElementById("sorry-message").textContent = "";
     // Going back to General when cleared
     gotoPref("paneGeneral");
   }
 
 }
 
 /**
  * Finding leaf nodes and checking their content for words to search
  *
  * @param Node nodeObject
  *    Html element
  * @param String searchPhrase
- *    The list of words to search for
- * @param Object findSelection
- *    SelectionController
  * @returns boolean
  *      Returns true when found in atleast one childNode, false otherwise
  */
-function nodeRecursion(nodeObject, searchPhrase, findSelection) {
+function searchWithinNode(nodeObject, searchPhrase) {
   let foundIn = false;
   if (nodeObject.childElementCount == 0) {
     let leafTextNodes, otherTextNodes = [];
-    //  List of words to search on
-    let listOfWords = searchPhrase.trim().split();
 
     if (nodeObject) {
       leafTextNodes = textNodeDescendants(nodeObject);
     }
     if (nodeObject.boxObject) {
       otherTextNodes = textNodeDescendants(nodeObject.boxObject);
     }
-
-     //  Searching in the Text Nodes
-    leafTextNodes.forEach(function(node) {
-      listOfWords.forEach(function(word) {
-        let boolAns = multiSearch([node],[node.length],node.textContent, word, findSelection);
-        foundIn = foundIn || boolAns;
-      });
-    });
+    //  Searching in the Text Nodes
+    for (let node of leafTextNodes) {
+      let boolAns = multiSearch([node],[node.length],node.textContent, searchPhrase);
+      foundIn = foundIn || boolAns; 
+    }
 
     //  Collecting data from boxObject
     let nodeSizes = [];
     let allNodeText = "";
     let runningSize = 0;
 
-    otherTextNodes.forEach(function(node) {
+    for (let node of otherTextNodes){
       runningSize += node.textContent.length;
       allNodeText += node.textContent;
       nodeSizes.push(runningSize);
-    });
+    }
 
-    listOfWords.forEach(function(word) {
-      // Access key are presented
-      let splitAns = multiSearch(otherTextNodes, nodeSizes, allNodeText, word, findSelection);
+    // Access key are presented
+    let splitAns = multiSearch(otherTextNodes, nodeSizes, allNodeText, searchPhrase);
 
-      //  Searching in the buttons label property
-      let buttonAns = searchNodeProperty(nodeObject["label"], word);
+    //  Searching in the buttons label property
+    let buttonAns = searchNodeProperty(nodeObject.getAttribute("label"), searchPhrase);
 
-      //  Label tag that does not have textContent but text is in Value attr
-      let labelAns = searchNodeProperty(nodeObject["value"], word);
+    //  Label tag that does not have textContent but text is in Value attr
+    let labelAns = searchNodeProperty(nodeObject.value, searchPhrase);
 
-      foundIn = foundIn || splitAns || buttonAns || labelAns;
-    });
+    foundIn = foundIn || splitAns || buttonAns || labelAns;
   }
 
   for (let i = 0; i < nodeObject.childNodes.length; i++) {
     // Search only if child node is not hidden
     if (!nodeObject.childNodes[i].hidden) {
-      let boolAns = nodeRecursion(nodeObject.childNodes[i], searchPhrase, findSelection);
+      let boolAns = searchWithinNode(nodeObject.childNodes[i], searchPhrase);
       foundIn = foundIn || boolAns;
     }
   }
   return foundIn;
 }
--- a/browser/components/preferences/in-content/preferences.js
+++ b/browser/components/preferences/in-content/preferences.js
@@ -54,25 +54,26 @@ addEventListener("DOMContentLoaded", fun
   init_all();
 });
 
 function init_all() {
   document.documentElement.instantApply = true;
 
   gSubDialog.init();
   register_module("paneGeneral", gMainPane);
-  register_module("paneSearchResults", gSearchResults);
+  register_module("paneSearchResults", gSearchResultsPane);
   register_module("paneSearch", gSearchPane);
   register_module("panePrivacy", gPrivacyPane);
   register_module("paneContainers", gContainersPane);
   register_module("paneAdvanced", gAdvancedPane);
   register_module("paneApplications", gApplicationsPane);
   register_module("paneContent", gContentPane);
   register_module("paneSync", gSyncPane);
   register_module("paneSecurity", gSecurityPane);
+  gSearchResultsPane.init();
 
   let categories = document.getElementById("categories");
   categories.addEventListener("select", event => gotoPref(event.target.value));
 
   document.documentElement.addEventListener("keydown", function(event) {
     if (event.keyCode == KeyEvent.DOM_VK_TAB) {
       categories.setAttribute("keyboard-navigation", "true");
     }
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -70,19 +70,19 @@
       title="&prefWindow.title;">
 #endif
 
   <html:link rel="shortcut icon"
               href="chrome://browser/skin/preferences/in-content/favicon.ico"/>
 
   <script type="application/javascript"
           src="chrome://browser/content/utilityOverlay.js"/>
+  <script src="chrome://browser/content/preferences/in-content/findInPage.js"/>
   <script type="application/javascript"
           src="chrome://browser/content/preferences/in-content/preferences.js"/>
-
   <script src="chrome://browser/content/preferences/in-content/subdialogs.js"/>
 
   <stringbundle id="bundleBrand"
                 src="chrome://branding/locale/brand.properties"/>
   <stringbundle id="bundlePreferences"
                 src="chrome://browser/locale/preferences/preferences.properties"/>
 
   <stringbundleset id="appManagerBundleset">
@@ -197,18 +197,18 @@
       <!-- Disable the findbar because it doesn't work properly.
            Remove this keyset once bug 1094240 ("disablefastfind" attribute
            broken in e10s mode) is fixed. -->
       <key key="&focusSearch1.key;" modifiers="accel" id="focusSearch1" oncommand=";"/>
     </keyset>
 
 
     <vbox class="main-content" flex="1">
-      <div align="right">  
-        <textbox type="search" name="q" value="" id="searchInput" placeholder="Search" oncommand=";" hidden="true" onclick="initializeCategories()"/>
+      <div align="right">
+        <textbox type="search" id="searchInput" placeholder="&searchInput.label;" oncommand=";" hidden="true" onfocus="initializeCategories()"/>
       </div>
       <prefpane id="mainPrefPane">
 #include searchResults.xul
 #include main.xul
 #include search.xul
 #include privacy.xul
 #include containers.xul
 #include advanced.xul
@@ -234,13 +234,9 @@
         </caption>
         <browser id="dialogFrame"
                  name="dialogFrame"
                  autoscroll="false"
                  disablehistory="true"/>
       </groupbox>
     </vbox>
   </stack>
-
-    <script src="chrome://browser/content/preferences/in-content/findInPage.js"/>
-
 </page>
-
--- a/browser/components/preferences/in-content/searchResults.xul
+++ b/browser/components/preferences/in-content/searchResults.xul
@@ -4,12 +4,12 @@
 <hbox id="header-searchResults"
       class="header"
       hidden="true"
       data-category="paneSearchResults">
   <label class="header-name" flex="1">&paneSearchResults.title;</label>
   <html:a class="help-button" target="_blank" aria-label="&helpButton.label;"></html:a>
 </hbox>
 
-<groupbox id="noResultsFound" align="start" data-category="paneSearchResults" hidden="true">
-  <label hidden="true"></label>
-  <label hidden="true">&needHelp.label;<a href="https://support.mozilla.org/t5/Mozilla-Support-English/ct-p/Mozilla-EN" class="text-link">&supportPage.label;</a></label>
+<groupbox class="no-results-message" align="start" data-category="paneSearchResults" hidden="true">
+  <label class="no-results-message" id="sorry-message" hidden="true"></label>
+  <label class="no-results-message" hidden="true">&needHelp.label;<a href="https://support.mozilla.org/t5/Mozilla-Support-English/ct-p/Mozilla-EN" class="text-link">&supportPage.label;</a></label>
 </groupbox>
--- a/browser/components/preferences/in-content/tests/browser_search_within_preferences.js
+++ b/browser/components/preferences/in-content/tests/browser_search_within_preferences.js
@@ -98,46 +98,54 @@ add_task(function*() {
 
 /**
  * Test for if nothing is found
  */
 add_task(function*() {
   Services.prefs.setBoolPref("browser.preferences.search", true);
   yield openPreferencesViaOpenPreferencesAPI("paneGeneral", undefined, {leaveOpen: true});
 
-  let searchResults = gBrowser.contentDocument.getElementById("noResultsFound");
+  let allSearchResults = gBrowser.contentDocument.getElementsByClassName("no-results-message");
 
-  is_element_hidden(searchResults, "Should not be in search results yet");
+  for (let result of allSearchResults){
+    is_element_hidden(result, "Should not be in search results yet");
+  }
 
   // Performs search
   let searchInput = gBrowser.contentDocument.getElementById("searchInput");
   searchInput.click();
   yield new Promise(resolve => setTimeout(resolve, 1000));
   searchInput.value = "coach";
   searchInput.click();
 
-  // Checks we are in no results found
-  is_element_visible(searchResults, "Should be in search results");
+  for (let result of allSearchResults){
+    // Checks we are in no results found
+    // All elements should be shown because word is not found
+    is_element_visible(result, "Should be in search results");
+  }
+  
 
   // Takes search off
   searchInput.value = "";
   searchInput.click();
-
-  // Checks if back to normal
-  is_element_hidden(searchResults, "Should not be in search results");
+  for (let result of allSearchResults){
+    // Checks if back to normal
+    is_element_hidden(result, "Should not be in search results");
+  }
+  
 
   yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
   Services.prefs.setBoolPref("browser.preferences.search", false);
 });
 
 /**
  * Test for if we go back to general tab after search case
  */
 add_task(function*() {
-  //Services.prefs.setBoolPref("browser.preferences.search", true);
+  Services.prefs.setBoolPref("browser.preferences.search", true);
   yield openPreferencesViaOpenPreferencesAPI("privacy", undefined, {leaveOpen: true});
   
   let generalPane = gBrowser.contentDocument.getElementById("header-general");
 
   is_element_hidden(generalPane, "Should not be in general");
 
   // Performs search
   let searchInput = gBrowser.contentDocument.getElementById("searchInput");
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.dtd
@@ -24,8 +24,10 @@
 <!ENTITY  paneContainers.title    "Container Tabs">
 <!ENTITY  paneSecurity.title      "Security">
 <!ENTITY  paneAdvanced.title      "Advanced">
 
 <!-- LOCALIZATION NOTE (paneSync.title): This should match syncBrand.shortName.label in ../syncBrand.dtd -->
 <!ENTITY  paneSync.title          "Sync">
 
 <!ENTITY  helpButton.label        "Help">
+
+<!ENTITY searchInput.label        "Search">