From fb8dfc98b9633234b3e9d25fb9ea4518efbc4048 Mon Sep 17 00:00:00 2001 From: Marco Castelluccio Date: Sun, 16 Jul 2023 00:52:02 +0000 Subject: [PATCH] Bug 1811129 - Implement the new dialog initial focus algorithm r=emilio The main changes of the new algorithm are * Make the dialog focusing steps look at sequentially focusable elements instead of any focusable element. * Make the dialog element itself get focus if it has the autofocus attribute set. * Make the dialog element itself get focus as a fallback instead of focus being "reset" to the body element. Spec PR (merged): https://github.com/whatwg/html/pull/8199 Differential Revision: https://phabricator.services.mozilla.com/D181263 UltraBlame original commit: cbf5ea1b17d2b0fbea7c1849ab2a1902396ad291 --- dom/base/FragmentOrElement.cpp | 27 ++++++++++++++----- dom/html/HTMLDialogElement.cpp | 6 ++++- dom/html/HTMLDialogElement.h | 2 ++ .../child-sequential-focus.html.ini | 12 --------- .../dialog-focus-shadow.html.ini | 20 -------------- .../dialog-showModal.html.ini | 5 ---- .../show-modal-focusing-steps.html.ini | 5 ---- 7 files changed, 28 insertions(+), 49 deletions(-) delete mode 100644 testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/child-sequential-focus.html.ini delete mode 100644 testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow.html.ini delete mode 100644 testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html.ini delete mode 100644 testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/show-modal-focusing-steps.html.ini diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 9305b6b09cb5..71ed6b9522c5 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -1036,9 +1036,14 @@ Element* nsIContent::GetFocusDelegate(bool aWithMouse, whereToLook = root; } - auto IsFocusable = [&](Element* aElement) { + auto IsFocusable = [&](Element* aElement) -> nsIFrame::Focusable { nsIFrame* frame = aElement->GetPrimaryFrame(); - return frame && frame->IsFocusable(aWithMouse); + + if (!frame) { + return {}; + } + + return frame->IsFocusable(aWithMouse); }; Element* potentialFocus = nullptr; @@ -1059,10 +1064,20 @@ Element* nsIContent::GetFocusDelegate(bool aWithMouse, return el; } - } else if (!potentialFocus && IsFocusable(el)) { - - - potentialFocus = el; + } else if (!potentialFocus) { + if (nsIFrame::Focusable focusable = IsFocusable(el)) { + if (IsHTMLElement(nsGkAtoms::dialog)) { + if (focusable.mTabIndex >= 0) { + + + potentialFocus = el; + } + } else { + + + potentialFocus = el; + } + } } if (!autofocus && potentialFocus) { diff --git a/dom/html/HTMLDialogElement.cpp b/dom/html/HTMLDialogElement.cpp index 4f8670a41a75..f75d83483f6e 100644 --- a/dom/html/HTMLDialogElement.cpp +++ b/dom/html/HTMLDialogElement.cpp @@ -159,7 +159,9 @@ void HTMLDialogElement::FocusDialog() { doc->FlushPendingNotifications(FlushType::Frames); } - RefPtr control = GetFocusDelegate(false ); + RefPtr control = HasAttr(nsGkAtoms::autofocus) + ? this + : GetFocusDelegate(false ); if (!control) { @@ -169,6 +171,8 @@ void HTMLDialogElement::FocusDialog() { FocusCandidate(*control, IsInTopLayer()); } +int32_t HTMLDialogElement::TabIndexDefault() { return 0; } + void HTMLDialogElement::QueueCancelDialog() { OwnerDoc() diff --git a/dom/html/HTMLDialogElement.h b/dom/html/HTMLDialogElement.h index fec166857a62..fa133aa8bc5a 100644 --- a/dom/html/HTMLDialogElement.h +++ b/dom/html/HTMLDialogElement.h @@ -49,6 +49,8 @@ class HTMLDialogElement final : public nsGenericHTMLElement { MOZ_CAN_RUN_SCRIPT_BOUNDARY void FocusDialog(); + int32_t TabIndexDefault() override; + nsString mReturnValue; protected: diff --git a/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/child-sequential-focus.html.ini b/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/child-sequential-focus.html.ini deleted file mode 100644 index 6f8c4561a74d..000000000000 --- a/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/child-sequential-focus.html.ini +++ /dev/null @@ -1,12 +0,0 @@ -[child-sequential-focus.html] - [dialog element with autofocus should get initial focus.] - expected: FAIL - - [Only keyboard-focusable elements should get dialog initial focus.] - expected: FAIL - - [Only keyboard-focusable elements should get dialog initial focus including in subtrees.] - expected: FAIL - - [Only keyboard-focusable elements should get dialog initial focus including in nested buttons.] - expected: FAIL diff --git a/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow.html.ini b/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow.html.ini deleted file mode 100644 index 863e564527a6..000000000000 --- a/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow.html.ini +++ /dev/null @@ -1,20 +0,0 @@ -[dialog-focus-shadow.html] - expected: - if (os == "android") and fission: [OK, TIMEOUT] - [show: No autofocus, no delegatesFocus, no siblings] - expected: FAIL - - [showModal: No autofocus, no delegatesFocus, no siblings] - expected: FAIL - - [show: Autofocus on shadow host, no delegatesFocus, no siblings] - expected: FAIL - - [showModal: Autofocus on shadow host, no delegatesFocus, no siblings] - expected: FAIL - - [show: Autofocus inside shadow tree, no delegatesFocus, no siblings] - expected: FAIL - - [showModal: Autofocus inside shadow tree, no delegatesFocus, no siblings] - expected: FAIL diff --git a/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html.ini b/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html.ini deleted file mode 100644 index c7357edd2498..000000000000 --- a/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[dialog-showModal.html] - expected: - if (os == "android") and fission: [OK, TIMEOUT] - [opening dialog without focusable children] - expected: FAIL diff --git a/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/show-modal-focusing-steps.html.ini b/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/show-modal-focusing-steps.html.ini deleted file mode 100644 index f0d673d2c214..000000000000 --- a/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/show-modal-focusing-steps.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[show-modal-focusing-steps.html] - expected: - if (os == "android") and fission: [OK, TIMEOUT] - [focus when a modal dialog is opened] - expected: FAIL