Bug 1365847 - Do not search for unselected <xul:deck> items. draft
authorEvan Tseng <evan@tseng.io>
Fri, 26 May 2017 16:28:43 +0800
changeset 594078 bd6bc25bf72ada53b23f63678ceac62123d70ccb
parent 594071 45fde181a497a187d01d5412f5b72897c7520517
child 633326 26d6de82a9db10f721cca8a8c997ca1221fc0036
push id63926
push userbmo:evan@tseng.io
push dateWed, 14 Jun 2017 14:07:37 +0000
bugs1365847
milestone56.0a1
Bug 1365847 - Do not search for unselected <xul:deck> items. MozReview-Commit-ID: BBeg2RdUtHV
browser/components/preferences/in-content-new/findInPage.js
browser/components/preferences/in-content-new/tests/browser.ini
browser/components/preferences/in-content-new/tests/browser_search_within_preferences.js
browser/components/preferences/in-content-new/tests/browser_search_within_preferences_1.js
browser/components/preferences/in-content-new/tests/browser_search_within_preferences_2.js
--- a/browser/components/preferences/in-content-new/findInPage.js
+++ b/browser/components/preferences/in-content-new/findInPage.js
@@ -295,46 +295,72 @@ var gSearchResultsPane = {
       // Searching some elements, such as xul:label, store their user-visible text in a "value" attribute.
       // Value will be skipped for menuitem since value in menuitem could represent index number to distinct each item.
       let valueResult = nodeObject.tagName !== "menuitem" ?
        this.stringMatchesFilters(nodeObject.getAttribute("value"), searchPhrase) : false;
 
       // Searching some elements, such as xul:button, buttons to open subdialogs.
       let keywordsResult = this.stringMatchesFilters(nodeObject.getAttribute("searchkeywords"), searchPhrase);
 
-      // Creating tooltips for buttons
-      if (keywordsResult && nodeObject.tagName === "button") {
+      // Creating tooltips for buttons and menulists.
+      if (keywordsResult && (nodeObject.tagName === "button" || nodeObject.tagName == "menulist")) {
         this.listSearchTooltips.push(nodeObject);
       }
 
       if ((nodeObject.tagName == "button" ||
            nodeObject.tagName == "menulist" ||
            nodeObject.tagName == "menuitem") &&
            (labelResult || valueResult || keywordsResult)) {
         nodeObject.setAttribute("highlightable", "true");
       }
 
       matchesFound = matchesFound || complexTextNodesResult || labelResult || valueResult || keywordsResult;
     }
 
-    for (let i = 0; i < nodeObject.childNodes.length; i++) {
-      // Search only if child node is not hidden
-      if (!nodeObject.childNodes[i].hidden && nodeObject.getAttribute("data-hidden-from-search") !== "true") {
-        let result = this.searchWithinNode(nodeObject.childNodes[i], searchPhrase);
-        // Creating tooltips for menulist element
-        if (result && nodeObject.tagName === "menulist") {
-          this.listSearchTooltips.push(nodeObject);
-        }
+    // Should not search unselected child nodes of a <xul:deck> element
+    // except the "historyPane" <xul:deck> element.
+    if (nodeObject.tagName == "deck" && nodeObject.id != "historyPane") {
+      let index = nodeObject.selectedIndex;
+      if (index != -1) {
+        let result = this.searchChildNodeIfVisible(nodeObject, index, searchPhrase);
+        matchesFound = matchesFound || result;
+      }
+    } else {
+      for (let i = 0; i < nodeObject.childNodes.length; i++) {
+        let result = this.searchChildNodeIfVisible(nodeObject, i, searchPhrase);
         matchesFound = matchesFound || result;
       }
     }
     return matchesFound;
   },
 
   /**
+   * Search for a phrase within a child node if it is visible.
+   *
+   * @param Node nodeObject
+   *    The parent DOM Element
+   * @param Number index
+   *    The index for the childNode
+   * @param String searchPhrase
+   * @returns boolean
+   *    Returns true when found the specific childNode, false otherwise
+   */
+  searchChildNodeIfVisible(nodeObject, index, searchPhrase) {
+    let result = false;
+    if (!nodeObject.childNodes[index].hidden && nodeObject.getAttribute("data-hidden-from-search") !== "true") {
+      result = this.searchWithinNode(nodeObject.childNodes[index], searchPhrase);
+      // Creating tooltips for menulist element
+      if (result && nodeObject.tagName === "menulist") {
+        this.listSearchTooltips.push(nodeObject);
+      }
+    }
+    return result;
+  },
+
+  /**
    * Inserting a div structure infront of the DOM element matched textContent.
    * Then calculation the offsets to position the tooltip in the correct place.
    *
    * @param Node currentNode
    *    DOM Element
    * @param String query
    *    Word or words that are being searched for
    */
--- a/browser/components/preferences/in-content-new/tests/browser.ini
+++ b/browser/components/preferences/in-content-new/tests/browser.ini
@@ -8,17 +8,18 @@ support-files =
 
 [browser_applications_selection.js]
 [browser_advanced_update.js]
 skip-if = !updater
 [browser_basic_rebuild_fonts_test.js]
 [browser_bug410900.js]
 [browser_bug705422.js]
 [browser_bug731866.js]
-[browser_search_within_preferences.js]
+[browser_search_within_preferences_1.js]
+[browser_search_within_preferences_2.js]
 [browser_search_subdialogs_within_preferences_1.js]
 [browser_search_subdialogs_within_preferences_2.js]
 [browser_search_subdialogs_within_preferences_3.js]
 [browser_search_subdialogs_within_preferences_4.js]
 [browser_bug795764_cachedisabled.js]
 [browser_bug1018066_resetScrollPosition.js]
 [browser_bug1020245_openPreferences_to_paneContent.js]
 [browser_bug1184989_prevent_scrolling_when_preferences_flipped.js]
rename from browser/components/preferences/in-content-new/tests/browser_search_within_preferences.js
rename to browser/components/preferences/in-content-new/tests/browser_search_within_preferences_1.js
--- a/browser/components/preferences/in-content-new/tests/browser_search_within_preferences.js
+++ b/browser/components/preferences/in-content-new/tests/browser_search_within_preferences_1.js
@@ -1,28 +1,31 @@
-/*
-* This file contains tests for the Preferences search bar.
-*/
+"use strict";
+/**
+ * This file contains tests for the Preferences search bar.
+ */
 
 requestLongerTimeout(2);
 
 /**
  * Tests to see if search bar is being hidden when pref is turned off
  */
 add_task(async function() {
   await SpecialPowers.pushPrefEnv({"set": [["browser.preferences.search", false]]});
   await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   let searchInput = gBrowser.contentDocument.querySelectorAll("#searchInput");
   is(searchInput.length, 1, "There should only be one element name searchInput querySelectorAll");
   is_element_hidden(searchInput[0], "Search box should be hidden");
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
   await SpecialPowers.popPrefEnv();
 });
 
-// Enabling Searching functionatily. Will display search bar form this testcase forward.
+/**
+ * Enabling searching functionality. Will display search bar from this testcase forward.
+ */
 add_task(async function() {
   await SpecialPowers.pushPrefEnv({"set": [["browser.preferences.search", true]]});
 });
 
 /**
  * Tests to see if search bar is being shown when pref is turned on
  */
 add_task(async function() {
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content-new/tests/browser_search_within_preferences_2.js
@@ -0,0 +1,58 @@
+"use strict";
+/**
+ * This file contains tests for the Preferences search bar.
+ */
+
+/**
+ * Enabling searching functionality. Will display search bar from this testcase forward.
+ */
+add_task(async function() {
+  await SpecialPowers.pushPrefEnv({"set": [["browser.preferences.search", true]]});
+});
+
+/**
+ * Test that we only search the selected child of a XUL deck.
+ * When we search "Forget this Email",
+ * it should not show the "Forget this Email" button if the Firefox account is not logged in yet.
+ */
+add_task(async function() {
+  await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+
+  // Ensure the "Create Account" button in the hidden child of the <xul:deck>
+  // is selected and displayed on the screen.
+  let weavePrefsDeck = gBrowser.contentDocument.getElementById("weavePrefsDeck");
+  is(weavePrefsDeck.selectedIndex, 0, "Should select the #noFxaAccount child node");
+  let noFxaSignUp = weavePrefsDeck.childNodes[0].querySelector("#noFxaSignUp");
+  is(noFxaSignUp.label, "Create Account", "The Create Account button should exist");
+
+  // Performs search.
+  let searchInput = gBrowser.contentDocument.getElementById("searchInput");
+  searchInput.focus();
+  searchInput.value = "Create Account";
+  searchInput.doCommand();
+
+  let mainPrefTag = gBrowser.contentDocument.getElementById("mainPrefPane");
+  for (let i = 0; i < mainPrefTag.childElementCount; i++) {
+    let child = mainPrefTag.children[i];
+    if (child.id == "header-searchResults" ||
+        child.id == "weavePrefsDeck") {
+      is_element_visible(child, "Should be in search results");
+    } else if (child.id) {
+      is_element_hidden(child, "Should not be in search results");
+    }
+  }
+
+  // Ensure the "Forget this Email" button exists in the hidden child of the <xul:deck>.
+  let unlinkFxaAccount = weavePrefsDeck.childNodes[1].querySelector("#unverifiedUnlinkFxaAccount");
+  is(unlinkFxaAccount.label, "Forget this Email", "The Forget this Email button should exist");
+
+  // Performs search.
+  searchInput.focus();
+  searchInput.value = "Forget this Email";
+  searchInput.doCommand();
+
+  let noResultsEl = gBrowser.contentDocument.querySelector(".no-results-message");
+  is_element_visible(noResultsEl, "Should be reporting no results");
+
+  await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});