Bug 1358645 - Close the preference dialog when the user clicks the overlay background. r?jaws draft
authorChris Peterson <cpeterson@mozilla.com>
Sat, 29 Apr 2017 19:43:50 -0700
changeset 572919 c0ba1c188d7f062cd3b6eb5eda0f52f511f6a164
parent 572730 0b255199db9d6a6f189b89b7906f99155bde3726
child 627160 ba7d713fb1c1c2ea34a07c9b8afff8051d689f5b
push id57226
push usercpeterson@mozilla.com
push dateThu, 04 May 2017 23:55:48 +0000
reviewersjaws
bugs1358645
milestone55.0a1
Bug 1358645 - Close the preference dialog when the user clicks the overlay background. r?jaws 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,22 @@ 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.
+        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 +391,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
@@ -164,16 +164,33 @@ 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.
+  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,22 @@ 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.
+        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 +391,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
@@ -164,16 +164,33 @@ 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.
+  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);
 });