Bug 1358645 - Close the preference dialog when the user clicks the overlay background. r=jaws
authorChris Peterson <cpeterson@mozilla.com>
Sat, 29 Apr 2017 19:43:50 -0700
changeset 357672 b8e7b44f3050
parent 357671 d661115e6032
child 357673 5fb3ab3d4ce8
push id42443
push usercpeterson@mozilla.com
push dateThu, 11 May 2017 01:48:16 +0000
treeherderautoland@b8e7b44f3050 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1358645
milestone55.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 1358645 - Close the preference dialog when the user clicks the overlay background. r=jaws We close the dialog using the same code path as when the user presses the ESC key. MozReview-Commit-ID: LNMDTgMl2L
browser/components/preferences/in-content-old/subdialogs.js
browser/components/preferences/in-content-old/tests/browser_subdialogs.js
browser/components/preferences/in-content/subdialogs.js
browser/components/preferences/in-content/tests/browser_subdialogs.js
--- a/browser/components/preferences/in-content-old/subdialogs.js
+++ b/browser/components/preferences/in-content-old/subdialogs.js
@@ -123,16 +123,23 @@ var gSubDialog = {
       };
       this._frame.addEventListener("load", onBlankLoad);
       this._frame.loadURI("about:blank");
     }, 0);
   },
 
   handleEvent(aEvent) {
     switch (aEvent.type) {
+      case "click":
+        // Close the dialog if the user clicked the overlay background, just
+        // like when the user presses the ESC key (case "command" below).
+        if (aEvent.target === this._overlay) {
+          this._frame.contentWindow.close();
+        }
+        break;
       case "command":
         this._frame.contentWindow.close();
         break;
       case "dialogclosing":
         this._onDialogClosing(aEvent);
         break;
       case "DOMTitleChanged":
         this.updateTitle(aEvent);
@@ -385,33 +392,39 @@ var gSubDialog = {
     // Similarly DOMFrameContentLoaded only fires on the top window
     window.addEventListener("DOMFrameContentLoaded", this, true);
 
     // Wait for the stylesheets injected during DOMContentLoaded to load before showing the dialog
     // otherwise there is a flicker of the stylesheet applying.
     this._frame.addEventListener("load", this);
 
     chromeBrowser.addEventListener("unload", this, true);
+
     // Ensure we get <esc> keypresses even if nothing in the subdialog is focusable
     // (happens on OS X when only text inputs and lists are focusable, and
     //  the subdialog only has checkboxes/radiobuttons/buttons)
     window.addEventListener("keydown", this, true);
+
+    this._overlay.addEventListener("click", this, true);
   },
 
   _removeDialogEventListeners() {
     let chromeBrowser = this._getBrowser();
     chromeBrowser.removeEventListener("DOMTitleChanged", this, true);
     chromeBrowser.removeEventListener("unload", this, true);
 
     this._closeButton.removeEventListener("command", this);
 
     window.removeEventListener("DOMFrameContentLoaded", this, true);
     this._frame.removeEventListener("load", this);
     this._frame.contentWindow.removeEventListener("dialogclosing", this);
     window.removeEventListener("keydown", this, true);
+
+    this._overlay.removeEventListener("click", this, true);
+
     if (this._resizeObserver) {
       this._resizeObserver.disconnect();
       this._resizeObserver = null;
     }
     this._untrapFocus();
   },
 
   _trapFocus() {
--- a/browser/components/preferences/in-content-old/tests/browser_subdialogs.js
+++ b/browser/components/preferences/in-content-old/tests/browser_subdialogs.js
@@ -165,16 +165,34 @@ add_task(function* click_close_button_on
   yield open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
 
   info("canceling the dialog");
   yield close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
     function() { return BrowserTestUtils.synthesizeMouseAtCenter("#dialogClose", {}, tab.linkedBrowser); },
     null, 0, {runClosingFnOutsideOfContentTask: true});
 });
 
+add_task(function* background_click_should_close_dialog() {
+  yield open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
+
+  // Clicking on an inactive part of dialog itself should not close the dialog.
+  // Click the dialog title bar here to make sure nothing happens.
+  info("clicking the dialog title bar");
+  BrowserTestUtils.synthesizeMouseAtCenter("#dialogTitle", {}, tab.linkedBrowser);
+
+  // Close the dialog by clicking on the overlay background. Simulate a click
+  // at point (2,2) instead of (0,0) so we are sure we're clicking on the
+  // overlay background instead of some boundary condition that a real user
+  // would never click.
+  info("clicking the overlay background");
+  yield close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
+    function() { return BrowserTestUtils.synthesizeMouseAtPoint(2, 2, {}, tab.linkedBrowser); },
+    null, 0, {runClosingFnOutsideOfContentTask: true});
+});
+
 add_task(function* back_navigation_on_subdialog_should_close_dialog() {
   yield open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
 
   info("canceling the dialog");
   yield close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
     function() { content.window.gSubDialog._frame.goBack(); },
     null, undefined);
 });
--- a/browser/components/preferences/in-content/subdialogs.js
+++ b/browser/components/preferences/in-content/subdialogs.js
@@ -123,16 +123,23 @@ var gSubDialog = {
       };
       this._frame.addEventListener("load", onBlankLoad);
       this._frame.loadURI("about:blank");
     }, 0);
   },
 
   handleEvent(aEvent) {
     switch (aEvent.type) {
+      case "click":
+        // Close the dialog if the user clicked the overlay background, just
+        // like when the user presses the ESC key (case "command" below).
+        if (aEvent.target === this._overlay) {
+          this._frame.contentWindow.close();
+        }
+        break;
       case "command":
         this._frame.contentWindow.close();
         break;
       case "dialogclosing":
         this._onDialogClosing(aEvent);
         break;
       case "DOMTitleChanged":
         this.updateTitle(aEvent);
@@ -385,33 +392,39 @@ var gSubDialog = {
     // Similarly DOMFrameContentLoaded only fires on the top window
     window.addEventListener("DOMFrameContentLoaded", this, true);
 
     // Wait for the stylesheets injected during DOMContentLoaded to load before showing the dialog
     // otherwise there is a flicker of the stylesheet applying.
     this._frame.addEventListener("load", this);
 
     chromeBrowser.addEventListener("unload", this, true);
+
     // Ensure we get <esc> keypresses even if nothing in the subdialog is focusable
     // (happens on OS X when only text inputs and lists are focusable, and
     //  the subdialog only has checkboxes/radiobuttons/buttons)
     window.addEventListener("keydown", this, true);
+
+    this._overlay.addEventListener("click", this, true);
   },
 
   _removeDialogEventListeners() {
     let chromeBrowser = this._getBrowser();
     chromeBrowser.removeEventListener("DOMTitleChanged", this, true);
     chromeBrowser.removeEventListener("unload", this, true);
 
     this._closeButton.removeEventListener("command", this);
 
     window.removeEventListener("DOMFrameContentLoaded", this, true);
     this._frame.removeEventListener("load", this);
     this._frame.contentWindow.removeEventListener("dialogclosing", this);
     window.removeEventListener("keydown", this, true);
+
+    this._overlay.removeEventListener("click", this, true);
+
     if (this._resizeObserver) {
       this._resizeObserver.disconnect();
       this._resizeObserver = null;
     }
     this._untrapFocus();
   },
 
   _trapFocus() {
--- a/browser/components/preferences/in-content/tests/browser_subdialogs.js
+++ b/browser/components/preferences/in-content/tests/browser_subdialogs.js
@@ -165,16 +165,34 @@ add_task(function* click_close_button_on
   yield open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
 
   info("canceling the dialog");
   yield close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
     function() { return BrowserTestUtils.synthesizeMouseAtCenter("#dialogClose", {}, tab.linkedBrowser); },
     null, 0, {runClosingFnOutsideOfContentTask: true});
 });
 
+add_task(function* background_click_should_close_dialog() {
+  yield open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
+
+  // Clicking on an inactive part of dialog itself should not close the dialog.
+  // Click the dialog title bar here to make sure nothing happens.
+  info("clicking the dialog title bar");
+  BrowserTestUtils.synthesizeMouseAtCenter("#dialogTitle", {}, tab.linkedBrowser);
+
+  // Close the dialog by clicking on the overlay background. Simulate a click
+  // at point (2,2) instead of (0,0) so we are sure we're clicking on the
+  // overlay background instead of some boundary condition that a real user
+  // would never click.
+  info("clicking the overlay background");
+  yield close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
+    function() { return BrowserTestUtils.synthesizeMouseAtPoint(2, 2, {}, tab.linkedBrowser); },
+    null, 0, {runClosingFnOutsideOfContentTask: true});
+});
+
 add_task(function* back_navigation_on_subdialog_should_close_dialog() {
   yield open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
 
   info("canceling the dialog");
   yield close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
     function() { content.window.gSubDialog._frame.goBack(); },
     null, undefined);
 });