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
--- 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);
});