202 lines
6.7 KiB
JavaScript
202 lines
6.7 KiB
JavaScript
add_task(async function () {
|
|
await pushPrefs(["ui.key.contentAccess", 5], ["ui.key.chromeAccess", 5]);
|
|
|
|
const gPageURL1 =
|
|
"data:text/html,<body><p>" +
|
|
"<button id='button' accesskey='y'>Button</button>" +
|
|
"<input id='checkbox' type='checkbox' accesskey='z'>Checkbox" +
|
|
"</p></body>";
|
|
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, gPageURL1);
|
|
|
|
Services.focus.clearFocus(window);
|
|
|
|
// Press an accesskey in the child document while the chrome is focused.
|
|
let focusedId = await performAccessKey(tab1.linkedBrowser, "y");
|
|
is(focusedId, "button", "button accesskey");
|
|
|
|
// Press an accesskey in the child document while the content document is focused.
|
|
focusedId = await performAccessKey(tab1.linkedBrowser, "z");
|
|
is(focusedId, "checkbox", "checkbox accesskey");
|
|
|
|
// Add an element with an accesskey to the chrome and press its accesskey while the chrome is focused.
|
|
let newButton = document.createXULElement("button");
|
|
newButton.id = "chromebutton";
|
|
newButton.setAttribute("aria-label", "chromebutton");
|
|
newButton.setAttribute("accesskey", "z");
|
|
document.documentElement.appendChild(newButton);
|
|
Services.focus.clearFocus(window);
|
|
|
|
newButton.getBoundingClientRect(); // Accesskey registration happens during frame construction.
|
|
|
|
focusedId = await performAccessKeyForChrome("z");
|
|
is(focusedId, "chromebutton", "chromebutton accesskey");
|
|
|
|
// Add a second tab and ensure that accesskey from the first tab is not used.
|
|
const gPageURL2 =
|
|
"data:text/html,<body>" +
|
|
"<button id='tab2button' accesskey='y'>Button in Tab 2</button>" +
|
|
"</body>";
|
|
let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, gPageURL2);
|
|
|
|
Services.focus.clearFocus(window);
|
|
|
|
focusedId = await performAccessKey(tab2.linkedBrowser, "y");
|
|
is(focusedId, "tab2button", "button accesskey in tab2");
|
|
|
|
// Press the accesskey for the chrome element while the content document is focused.
|
|
focusedId = await performAccessKeyForChrome("z");
|
|
is(focusedId, "chromebutton", "chromebutton accesskey");
|
|
|
|
gBrowser.removeTab(tab1);
|
|
gBrowser.removeTab(tab2);
|
|
|
|
// Test whether access key for the newButton isn't available when content
|
|
// consumes the key event.
|
|
|
|
// When content in the tab3 consumes all keydown events.
|
|
const gPageURL3 =
|
|
"data:text/html,<body id='tab3body'>" +
|
|
"<button id='tab3button' accesskey='y'>Button in Tab 3</button>" +
|
|
"<script>" +
|
|
"document.body.addEventListener('keydown', (event)=>{ event.preventDefault(); });" +
|
|
"</script></body>";
|
|
let tab3 = await BrowserTestUtils.openNewForegroundTab(gBrowser, gPageURL3);
|
|
|
|
Services.focus.clearFocus(window);
|
|
|
|
focusedId = await performAccessKey(tab3.linkedBrowser, "y");
|
|
is(focusedId, "tab3button", "button accesskey in tab3 should be focused");
|
|
|
|
newButton.onfocus = () => {
|
|
ok(false, "chromebutton shouldn't get focus during testing with tab3");
|
|
};
|
|
|
|
// Press the accesskey for the chrome element while the content document is focused.
|
|
focusedId = await performAccessKey(tab3.linkedBrowser, "z");
|
|
is(
|
|
focusedId,
|
|
"tab3body",
|
|
"button accesskey in tab3 should keep having focus"
|
|
);
|
|
|
|
newButton.onfocus = null;
|
|
|
|
gBrowser.removeTab(tab3);
|
|
|
|
// When content in the tab4 consumes all keypress events.
|
|
const gPageURL4 =
|
|
"data:text/html,<body id='tab4body'>" +
|
|
"<button id='tab4button' accesskey='y'>Button in Tab 4</button>" +
|
|
"<script>" +
|
|
"document.body.addEventListener('keypress', (event)=>{ event.preventDefault(); });" +
|
|
"</script></body>";
|
|
let tab4 = await BrowserTestUtils.openNewForegroundTab(gBrowser, gPageURL4);
|
|
|
|
Services.focus.clearFocus(window);
|
|
|
|
focusedId = await performAccessKey(tab4.linkedBrowser, "y");
|
|
is(focusedId, "tab4button", "button accesskey in tab4 should be focused");
|
|
|
|
newButton.onfocus = () => {
|
|
// EventStateManager handles accesskey before dispatching keypress event
|
|
// into the DOM tree, therefore, chrome accesskey always wins focus from
|
|
// content. However, this is different from shortcut keys.
|
|
todo(false, "chromebutton shouldn't get focus during testing with tab4");
|
|
};
|
|
|
|
// Press the accesskey for the chrome element while the content document is focused.
|
|
focusedId = await performAccessKey(tab4.linkedBrowser, "z");
|
|
is(
|
|
focusedId,
|
|
"tab4body",
|
|
"button accesskey in tab4 should keep having focus"
|
|
);
|
|
|
|
newButton.onfocus = null;
|
|
|
|
gBrowser.removeTab(tab4);
|
|
|
|
newButton.remove();
|
|
});
|
|
|
|
function performAccessKey(browser, key) {
|
|
return new Promise(resolve => {
|
|
let removeFocus, removeKeyDown, removeKeyUp;
|
|
function callback() {
|
|
removeFocus();
|
|
removeKeyUp();
|
|
removeKeyDown();
|
|
|
|
SpecialPowers.spawn(browser, [], () => {
|
|
let oldFocusedElement = content._oldFocusedElement;
|
|
delete content._oldFocusedElement;
|
|
return oldFocusedElement.id;
|
|
}).then(oldFocus => resolve(oldFocus));
|
|
}
|
|
|
|
removeFocus = BrowserTestUtils.addContentEventListener(
|
|
browser,
|
|
"focus",
|
|
callback,
|
|
{ capture: true },
|
|
event => {
|
|
if (!HTMLElement.isInstance(event.target)) {
|
|
return false; // ignore window and document focus events
|
|
}
|
|
|
|
event.target.ownerGlobal._sent = true;
|
|
let focusedElement = event.target.ownerGlobal.document.activeElement;
|
|
event.target.ownerGlobal._oldFocusedElement = focusedElement;
|
|
focusedElement.blur();
|
|
return true;
|
|
}
|
|
);
|
|
|
|
removeKeyDown = BrowserTestUtils.addContentEventListener(
|
|
browser,
|
|
"keydown",
|
|
() => {},
|
|
{ capture: true },
|
|
event => {
|
|
event.target.ownerGlobal._sent = false;
|
|
return true;
|
|
}
|
|
);
|
|
|
|
removeKeyUp = BrowserTestUtils.addContentEventListener(
|
|
browser,
|
|
"keyup",
|
|
callback,
|
|
{},
|
|
event => {
|
|
if (!event.target.ownerGlobal._sent) {
|
|
event.target.ownerGlobal._sent = true;
|
|
let focusedElement = event.target.ownerGlobal.document.activeElement;
|
|
event.target.ownerGlobal._oldFocusedElement = focusedElement;
|
|
focusedElement.blur();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
);
|
|
|
|
// Spawn an no-op content task to better ensure that the messages
|
|
// for adding the event listeners above get handled.
|
|
SpecialPowers.spawn(browser, [], () => {}).then(() => {
|
|
EventUtils.synthesizeKey(key, { altKey: true, shiftKey: true });
|
|
});
|
|
});
|
|
}
|
|
|
|
// This version is used when a chrome element is expected to be found for an accesskey.
|
|
async function performAccessKeyForChrome(key) {
|
|
let waitFocusChangePromise = BrowserTestUtils.waitForEvent(
|
|
document,
|
|
"focus",
|
|
true
|
|
);
|
|
EventUtils.synthesizeKey(key, { altKey: true, shiftKey: true });
|
|
await waitFocusChangePromise;
|
|
return document.activeElement.id;
|
|
}
|