Bug 1052992: Add quick-search event listeners to system event group, so stopPropagation on keyboard events does not affect the findbar. r=MattN
authorIaroslav Sheptykin <yarik.sheptykin@googlemail.com>
Thu, 16 Oct 2014 00:38:58 -0700
changeset 210593 9794e8f22ac8566ed9342472388c20d5a940d9a5
parent 210592 f707c1692a77f4b1191f62eda85be8a424e5631c
child 210594 42a182f0431fb873eeba2bde9ec240db78680cbe
push id27656
push usercbook@mozilla.com
push dateThu, 16 Oct 2014 14:01:11 +0000
treeherdermozilla-central@757c194494a2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1052992
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1052992: Add quick-search event listeners to system event group, so stopPropagation on keyboard events does not affect the findbar. r=MattN
toolkit/content/tests/browser/browser.ini
toolkit/content/tests/browser/browser_findbar.js
toolkit/content/tests/browser/head.js
toolkit/content/widgets/findbar.xml
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-
+support-files = head.js
 [browser_autoscroll_disabled.js]
 skip-if = e10s # Bug ?????? - test touches content (getElementById on the content document)
 [browser_browserDrop.js]
 skip-if = buildapp == 'mulet'
 [browser_bug295977_autoscroll_overflow.js]
 skip-if = e10s # Bug 921935 - focusmanager issues with e10s
 [browser_bug594509.js]
 skip-if = e10s # Bug ?????? - intermittent crash of child process reported when run under e10s
--- a/toolkit/content/tests/browser/browser_findbar.js
+++ b/toolkit/content/tests/browser/browser_findbar.js
@@ -1,12 +1,58 @@
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
   "resource://gre/modules/Promise.jsm");
 Components.utils.import("resource://gre/modules/Timer.jsm", this);
 
+/**
+ * Makes sure that the findbar hotkeys (' and /) event listeners
+ * are added to the system event group and do not get blocked
+ * by calling stopPropagation on a keypress event on a page.
+ */
+add_task(function* test_hotkey_event_propagation() {
+  info("Ensure hotkeys are not affected by stopPropagation.");
+
+  // Opening new tab
+  let tab = yield promiseTestPageLoad();
+  let browser = gBrowser.getBrowserForTab(tab);
+  let findbar = gBrowser.getFindBar();
+
+  // Pressing these keys open the findbar.
+  const HOTKEYS = ["/", "'"];
+
+  // Checking if findbar appears when any hotkey is pressed.
+  for (let key of HOTKEYS) {
+    is(findbar.hidden, true, "Findbar is hidden now.");
+    gBrowser.selectedTab = tab;
+    yield promiseFocus();
+    EventUtils.sendChar(key, browser.contentWindow);
+    is(findbar.hidden, false, "Findbar should not be hidden.");
+    yield closeFindbarAndWait(findbar);
+  }
+
+  // Stop propagation for all keyboard events.
+  let window = browser.contentWindow;
+  let stopPropagation = function(e) { e.stopImmediatePropagation(); };
+  window.addEventListener("keydown", stopPropagation, true);
+  window.addEventListener("keypress", stopPropagation, true);
+  window.addEventListener("keyup", stopPropagation, true);
+
+  // Checking if findbar still appears when any hotkey is pressed.
+  for (let key of HOTKEYS) {
+    is(findbar.hidden, true, "Findbar is hidden now.");
+    gBrowser.selectedTab = tab;
+    yield promiseFocus();
+    EventUtils.sendChar(key, browser.contentWindow);
+    is(findbar.hidden, false, "Findbar should not be hidden.");
+    yield closeFindbarAndWait(findbar);
+  }
+
+  gBrowser.removeTab(tab);
+});
+
 add_task(function* test_not_found() {
   info("Check correct 'Phrase not found' on new tab");
 
   let tab = yield promiseTestPageLoad();
 
   // Search for the first word.
   yield promiseFindFinished("--- THIS SHOULD NEVER MATCH ---", false);
   let findbar = gBrowser.getFindBar();
@@ -98,8 +144,19 @@ function promiseFindFinished(searchText,
       onFindResult: foundOrTimedout
     };
     findbar.browser.finder.addResultListener(resultListener);
     findbar._find();
   });
 
   return deferred.promise;
 }
+
+/**
+ * A promise-like wrapper for the waitForFocus helper.
+ */
+function promiseFocus() {
+  return new Promise((resolve) => {
+    waitForFocus(function(){
+      resolve();
+    }, content);
+  });
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/head.js
@@ -0,0 +1,20 @@
+"use strict";
+
+/**
+ * A wrapper for the findbar's method "close", which is not synchronous
+ * because of animation.
+ */
+function closeFindbarAndWait(findbar) {
+  return new Promise((resolve) => {
+    if (findbar.hidden)
+      return resolve();
+    findbar.addEventListener("transitionend", function cont(aEvent) {
+      if (aEvent.propertyName != "visibility") {
+        return;
+      }
+      findbar.removeEventListener("transitionend", cont);
+      resolve();
+    });
+    findbar.close();
+  });
+}
--- a/toolkit/content/widgets/findbar.xml
+++ b/toolkit/content/widgets/findbar.xml
@@ -252,28 +252,34 @@
         <getter><![CDATA[
           if (!this._browser) {
             this._browser =
               document.getElementById(this.getAttribute("browserid"));
           }
           return this._browser;
         ]]></getter>
         <setter><![CDATA[
+          // A shortcut for the service.
+          let els = Components.classes["@mozilla.org/eventlistenerservice;1"].
+            getService(Components.interfaces.nsIEventListenerService);
+
           if (this._browser) {
-            this._browser.removeEventListener("keypress", this, false);
-            this._browser.removeEventListener("mouseup", this, false);
+            els.removeSystemEventListener(this._browser, "keypress", this,
+                                          false);
+            els.removeSystemEventListener(this._browser, "mouseup", this,
+                                          false);
             let finder = this._browser.finder;
             if (finder)
               finder.removeResultListener(this);
           }
 
           this._browser = val;
           if (this._browser) {
-            this._browser.addEventListener("keypress", this, false);
-            this._browser.addEventListener("mouseup", this, false);
+            els.addSystemEventListener(this._browser, "keypress", this, false);
+            els.addSystemEventListener(this._browser, "mouseup", this, false);
             this._browser.finder.addResultListener(this);
 
             this._findField.value = this._browser._lastSearchString;
             this.toggleHighlight(this.browser._lastSearchHighlight);
           }
           return val;
         ]]></setter>
       </property>