Skip to content

Commit

Permalink
Move the focus to the previously focused element when <dialog> is closed
Browse files Browse the repository at this point in the history
This change is based on the latest changes for the <dialog> element in
whatwg/html#6531, such that closing
<dialog> should move the focus to the previously focused element.

Differential Revision: https://phabricator.services.mozilla.com/D109726

bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1660271
gecko-commit: 130bfa5327532a2b188e4cc06f5e1de7183327e8
gecko-reviewers: smaug
  • Loading branch information
sefeng211 authored and moz-wptsync-bot committed Apr 29, 2021
1 parent 765450f commit fc5814c
Showing 1 changed file with 156 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<!DOCTYPE html>
<meta charset=urf-8>
<meta name=viewport content="width=device-width,initial-scale=1">
<title>Test focus is moved to the previously focused element when dialog is closed</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>

<body>
<input />
<dialog>
<button id="button1">This is a button1</button>
<button id="button2">This is a button2</button>
<button id="button3">This is a button3</button>
</dialog>
<script>

// Test focus is moved to the previously focused element
function test_move_to_previously_focused(showModal) {
const input = document.querySelector("input");
input.focus();
const dialog = document.querySelector('dialog');
if (showModal) {
dialog.showModal();
} else {
dialog.show();
}
dialog.close();

assert_equals(document.activeElement, input);
}

// Test focus is moved to the previously focused element with some complex dialog usage
async function test_move_to_previously_focused_with_complex_dialog_usage(showModal) {
const input = document.querySelector("input");
input.focus();
const dialog = document.querySelector('dialog');
if (showModal) {
dialog.showModal();
} else {
dialog.show();
}

const button1 = document.getElementById("button1");
const button2 = document.getElementById("button2");
const button3 = document.getElementById("button3");

await test_driver.click(button1);
await test_driver.click(button2);
await test_driver.click(button3);

dialog.close();

assert_equals(document.activeElement, input);
}

// Test focus is moved to <body> if the previously focused
// element can't be focused
function test_move_to_body_if_fails(showModal) {
const input = document.querySelector("input");
input.focus();
const dialog = document.querySelector('dialog');
if (showModal) {
dialog.showModal();
} else {
dialog.show();
}
dialog.close();
input.remove();
assert_equals(document.activeElement, document.body);
document.body.appendChild(input);
}

// Test focus is moved to shadow host if the previously
// focused element is a shadow node.
function test_move_to_shadow_host(showModal) {
const shadowHost = document.createElement("div");

const shadowRoot = shadowHost.attachShadow({mode: 'open'});
shadowRoot.appendChild(document.createElement("input"));

document.body.appendChild(shadowHost);
const inputElement = shadowRoot.querySelector("input");
inputElement.focus();

assert_equals(document.activeElement, shadowHost);
assert_equals(shadowRoot.activeElement, inputElement);

const dialog = document.querySelector('dialog');
if (showModal) {
dialog.showModal();
} else {
dialog.show();
}
dialog.close();

assert_equals(document.activeElement, shadowHost);
assert_equals(shadowRoot.activeElement, inputElement);
}

// Test moving the focus doesn't scroll the viewport
function test_move_focus_dont_scroll_viewport(showModal) {
const outViewPortButton = document.createElement("button");
outViewPortButton.style.top = (window.innerHeight + 10).toString() + "px";
outViewPortButton.style.position = "absolute";
document.body.appendChild(outViewPortButton);

outViewPortButton.focus();
// Since the outViewPortButton is focused, so the viewport should be
// scrolled to it
assert_true(document.documentElement.scrollTop > 0 );

const dialog = document.querySelector('dialog');
if (showModal) {
dialog.showModal();
} else {
dialog.show();
}

window.scrollTo(0, 0);
assert_equals(document.documentElement.scrollTop, 0);

dialog.close();
assert_equals(document.documentElement.scrollTop, 0);

assert_equals(document.activeElement, outViewPortButton);
}

test(() => {
test_move_to_previously_focused(true);
test_move_to_previously_focused(false);
}, 'Focus should be moved to the previously focused element(Simple dialog usage)');

promise_test(async () => {
await test_move_to_previously_focused_with_complex_dialog_usage(true);
await test_move_to_previously_focused_with_complex_dialog_usage(false);
}, 'Focus should be moved to the previously focused element(Complex dialog usage)');

test(() => {
test_move_to_body_if_fails(true);
test_move_to_body_if_fails(false);
}, 'Focus should be moved to the body if the previously focused element is removed');

test(() => {
test_move_to_shadow_host(true);
test_move_to_shadow_host(false);
}, 'Focus should be moved to the shadow DOM host if the previouly focused element is a shadow DOM node');

test(() => {
test_move_focus_dont_scroll_viewport(true);
test_move_focus_dont_scroll_viewport(false);
}, 'Focus should not scroll if the previously focused element is outside the viewport');
</script>
</body>

0 comments on commit fc5814c

Please sign in to comment.