Bug 1669990 - SubDialog: Use system event listener for escape key. r=Gijs

If a <select> in a SubDialog closes its popup when the user hits the esc key, it calls `preventDefault()` on the event. The SubDialog code didn't see this preventDefault, because it was using a normal event listener, while the select code uses a system event listener.

https://searchfox.org/mozilla-central/rev/c2e3ac11be4837718c2604e58085fbc8252b69dd/layout/forms/nsListControlFrame.cpp#925,2058,2068-2069,2075-2076

Differential Revision: https://phabricator.services.mozilla.com/D93253
This commit is contained in:
pbz 2020-11-19 18:20:36 +00:00
Родитель de79a8a3ce
Коммит 13ef0eb48a
3 изменённых файлов: 72 добавлений и 4 удалений

Просмотреть файл

@ -54,3 +54,65 @@ add_task(async function test_subdialog_esc_does_not_cancel_load() {
ok(true, "Load completed");
});
});
/**
* Tests that ESC on a SubDialog with an open dropdown doesn't close the dialog.
*/
add_task(async function test_subdialog_esc_on_dropdown_does_not_close_dialog() {
await BrowserTestUtils.withNewTab("http://example.com", async function(
browser
) {
// Open the test dialog
let dialogBox = gBrowser.getTabDialogBox(browser);
let dialogClose = dialogBox.open(TEST_DIALOG_PATH, {
keepOpenSameOriginNav: true,
});
let dialogs = dialogBox._dialogManager._dialogs;
is(dialogs.length, 1, "Dialog manager has a dialog.");
let dialog = dialogs[0];
info("Waiting for dialog to open.");
await dialog._dialogReady;
// Open dropdown
let select = dialog._frame.contentDocument.getElementById("select");
let shownPromise = BrowserTestUtils.waitForEvent(
select,
"popupshowing",
true
);
info("Opening dropdown");
select.focus();
EventUtils.synthesizeKey("VK_SPACE", {}, dialog._frame.contentWindow);
await shownPromise;
let hiddenPromise = BrowserTestUtils.waitForEvent(
select,
"popuphiding",
true
);
// Race dropdown closing vs SubDialog close
let race = Promise.race([
hiddenPromise.then(() => true),
dialogClose.then(() => false),
]);
// Close the dropdown with esc key
info("Hitting escape key.");
await EventUtils.synthesizeKey("KEY_Escape");
let result = await race;
ok(result, "Select closed first");
await new Promise(resolve => executeSoon(resolve));
ok(!dialog._isClosing, "Dialog is not closing");
ok(dialog._openedURL, "Dialog is open");
});
});

Просмотреть файл

@ -7,8 +7,7 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
title="Sample sub-dialog" style="width: 32em; height: 5em;"
onload="document.getElementById('textbox').focus();">
title="Sample sub-dialog">
<dialog id="subDialog">
<script>
document.addEventListener("dialogaccept", acceptSubdialog);
@ -21,6 +20,11 @@
<html:input id="textbox" value="Default text" />
<html:select id="select">
<html:option>Foo</html:option>
<html:option>Bar</html:option>
</html:select>
<separator class="thin"/>
<button oncommand="window.close();" label="Close" />

Просмотреть файл

@ -772,7 +772,9 @@ SubDialog.prototype = {
_trapFocus() {
this.focus();
this._box.addEventListener("keydown", this, true);
// Attach a system event listener so the dialog can cancel keydown events.
// See Bug 1669990.
this._box.addEventListener("keydown", this, { mozSystemGroup: true });
this._closeButton?.addEventListener("keydown", this);
if (!this._window.isChromeWindow) {
@ -781,7 +783,7 @@ SubDialog.prototype = {
},
_untrapFocus() {
this._box.removeEventListener("keydown", this, true);
this._box.removeEventListener("keydown", this, { mozSystemGroup: true });
this._closeButton?.removeEventListener("keydown", this);
this._window.removeEventListener("focus", this, true);
},