mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Backed out 8 changesets (bug 1413836) for delegatesFocus related wpt failures. CLOSED TREE
Backed out changeset 53c86681259e (bug 1413836) Backed out changeset dc6a694146fd (bug 1413836) Backed out changeset ae89d15d28eb (bug 1413836) Backed out changeset 979fef259e32 (bug 1413836) Backed out changeset d829be6f2813 (bug 1413836) Backed out changeset c1d1d4b5ab74 (bug 1413836) Backed out changeset 19e3256ea07c (bug 1413836) Backed out changeset dc8d5d9533e4 (bug 1413836)
This commit is contained in:
parent
71a718fbc8
commit
efbb4a2760
@ -1183,13 +1183,11 @@ already_AddRefed<ShadowRoot> Element::AttachShadow(const ShadowRootInit& aInit,
|
||||
OwnerDoc()->ReportShadowDOMUsage();
|
||||
}
|
||||
|
||||
return AttachShadowWithoutNameChecks(aInit.mMode, aInit.mDelegatesFocus,
|
||||
aInit.mSlotAssignment);
|
||||
return AttachShadowWithoutNameChecks(aInit.mMode, aInit.mSlotAssignment);
|
||||
}
|
||||
|
||||
already_AddRefed<ShadowRoot> Element::AttachShadowWithoutNameChecks(
|
||||
ShadowRootMode aMode, bool aDelegatesFocus,
|
||||
SlotAssignmentMode aSlotAssignment) {
|
||||
ShadowRootMode aMode, SlotAssignmentMode aSlotAssignment) {
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
|
||||
RefPtr<mozilla::dom::NodeInfo> nodeInfo =
|
||||
@ -1217,8 +1215,8 @@ already_AddRefed<ShadowRoot> Element::AttachShadowWithoutNameChecks(
|
||||
* and mode is init's mode.
|
||||
*/
|
||||
auto* nim = nodeInfo->NodeInfoManager();
|
||||
RefPtr<ShadowRoot> shadowRoot = new (nim) ShadowRoot(
|
||||
this, aMode, aDelegatesFocus, aSlotAssignment, nodeInfo.forget());
|
||||
RefPtr<ShadowRoot> shadowRoot =
|
||||
new (nim) ShadowRoot(this, aMode, aSlotAssignment, nodeInfo.forget());
|
||||
|
||||
if (NodeOrAncestorHasDirAuto()) {
|
||||
shadowRoot->SetAncestorHasDirAuto();
|
||||
|
@ -1269,7 +1269,7 @@ class Element : public FragmentOrElement {
|
||||
bool CanAttachShadowDOM() const;
|
||||
|
||||
already_AddRefed<ShadowRoot> AttachShadowWithoutNameChecks(
|
||||
ShadowRootMode aMode, bool aDelegatesFocus = false,
|
||||
ShadowRootMode aMode,
|
||||
SlotAssignmentMode aSlotAssignmentMode = SlotAssignmentMode::Named);
|
||||
|
||||
// Attach UA Shadow Root if it is not attached.
|
||||
|
@ -48,12 +48,11 @@ NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
|
||||
NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
|
||||
|
||||
ShadowRoot::ShadowRoot(Element* aElement, ShadowRootMode aMode,
|
||||
bool aDelegatesFocus, SlotAssignmentMode aSlotAssignment,
|
||||
SlotAssignmentMode aSlotAssignment,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
|
||||
: DocumentFragment(std::move(aNodeInfo)),
|
||||
DocumentOrShadowRoot(this),
|
||||
mMode(aMode),
|
||||
mDelegatesFocus(aDelegatesFocus),
|
||||
mSlotAssignment(aSlotAssignment),
|
||||
mIsUAWidget(false),
|
||||
mIsAvailableToElementInternals(false) {
|
||||
@ -752,41 +751,6 @@ void ShadowRoot::MaybeUnslotHostChild(nsIContent& aChild) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
|
||||
Element* ShadowRoot::GetFirstFocusable(bool aWithMouse) const {
|
||||
for (nsIContent* child = GetFirstChild(); child;
|
||||
child = child->GetNextNode()) {
|
||||
if (auto* slot = HTMLSlotElement::FromNode(child)) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
||||
for (const auto& node : assignedNodes) {
|
||||
if (node->IsElement()) {
|
||||
Element* assignedElement = node->AsElement();
|
||||
if (nsIFrame* frame = assignedElement->GetPrimaryFrame()) {
|
||||
if (frame->IsFocusable(aWithMouse)) {
|
||||
return assignedElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (child->IsElement()) {
|
||||
if (nsIFrame* frame = child->GetPrimaryFrame()) {
|
||||
if (frame->IsFocusable(aWithMouse)) {
|
||||
return child->AsElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ShadowRoot* root = child->GetShadowRoot()) {
|
||||
if (Element* firstFocusable = root->GetFirstFocusable(aWithMouse)) {
|
||||
return firstFocusable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ShadowRoot::MaybeSlotHostChild(nsIContent& aChild) {
|
||||
MOZ_ASSERT(aChild.GetParent() == GetHost());
|
||||
// Check to ensure that the child not an anonymous subtree root because even
|
||||
|
@ -52,7 +52,7 @@ class ShadowRoot final : public DocumentFragment,
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot, DocumentFragment)
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
ShadowRoot(Element* aElement, ShadowRootMode aMode, bool aDelegatesFocus,
|
||||
ShadowRoot(Element* aElement, ShadowRootMode aMode,
|
||||
SlotAssignmentMode aSlotAssignment,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
|
||||
|
||||
@ -67,10 +67,6 @@ class ShadowRoot final : public DocumentFragment,
|
||||
// child from the currently-assigned slot, if any.
|
||||
void MaybeUnslotHostChild(nsIContent&);
|
||||
|
||||
// Loop through this tree (including slot assigned elements, nested shadow
|
||||
// trees) to find the first focusable element.
|
||||
Element* GetFirstFocusable(bool aWithMouse) const;
|
||||
|
||||
// Shadow DOM v1
|
||||
Element* Host() const {
|
||||
MOZ_ASSERT(GetHost(),
|
||||
@ -80,7 +76,6 @@ class ShadowRoot final : public DocumentFragment,
|
||||
}
|
||||
|
||||
ShadowRootMode Mode() const { return mMode; }
|
||||
bool DelegatesFocus() const { return mDelegatesFocus; }
|
||||
SlotAssignmentMode SlotAssignment() const { return mSlotAssignment; }
|
||||
bool IsClosed() const { return mMode == ShadowRootMode::Closed; }
|
||||
|
||||
@ -278,8 +273,6 @@ class ShadowRoot final : public DocumentFragment,
|
||||
|
||||
const ShadowRootMode mMode;
|
||||
|
||||
bool mDelegatesFocus;
|
||||
|
||||
const SlotAssignmentMode mSlotAssignment;
|
||||
|
||||
// The computed data from the style sheets.
|
||||
|
@ -1311,20 +1311,10 @@ void nsFocusManager::NotifyFocusStateChange(Element* aElement,
|
||||
eventStateToAdd |= NS_EVENT_STATE_FOCUSRING;
|
||||
}
|
||||
aElement->AddStates(eventStateToAdd);
|
||||
|
||||
for (nsIContent* host = aElement->GetContainingShadowHost(); host;
|
||||
host = host->GetContainingShadowHost()) {
|
||||
host->AsElement()->AddStates(NS_EVENT_STATE_FOCUS);
|
||||
}
|
||||
} else {
|
||||
EventStates eventStateToRemove =
|
||||
NS_EVENT_STATE_FOCUS | NS_EVENT_STATE_FOCUSRING;
|
||||
aElement->RemoveStates(eventStateToRemove);
|
||||
|
||||
for (nsIContent* host = aElement->GetContainingShadowHost(); host;
|
||||
host = host->GetContainingShadowHost()) {
|
||||
host->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUS);
|
||||
}
|
||||
}
|
||||
|
||||
for (nsIContent* content = aElement; content && content != commonAncestor;
|
||||
@ -2116,36 +2106,7 @@ Element* nsFocusManager::FlushAndCheckIfFocusable(Element* aElement,
|
||||
}
|
||||
}
|
||||
|
||||
if (frame->IsFocusable(aFlags & FLAG_BYMOUSE)) {
|
||||
return aElement;
|
||||
}
|
||||
|
||||
if (ShadowRoot* root = aElement->GetShadowRoot()) {
|
||||
if (root->DelegatesFocus()) {
|
||||
// If focus target is a shadow-including inclusive ancestor of the
|
||||
// currently focused area of a top-level browsing context's DOM anchor,
|
||||
// then return null.
|
||||
if (nsPIDOMWindowInner* innerWindow =
|
||||
aElement->OwnerDoc()->GetInnerWindow()) {
|
||||
BrowsingContext* bc = innerWindow->GetBrowsingContext();
|
||||
if (bc && bc->IsTop()) {
|
||||
if (Element* focusedElement = innerWindow->GetFocusedElement()) {
|
||||
if (focusedElement->IsShadowIncludingInclusiveDescendantOf(
|
||||
aElement)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Element* firstFocusable =
|
||||
root->GetFirstFocusable(aFlags & FLAG_BYMOUSE)) {
|
||||
return firstFocusable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return frame->IsFocusable(aFlags & FLAG_BYMOUSE) ? aElement : nullptr;
|
||||
}
|
||||
|
||||
bool nsFocusManager::Blur(BrowsingContext* aBrowsingContextToClear,
|
||||
|
@ -3438,16 +3438,6 @@ nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
if (frame->IsFocusable(/* aWithMouse = */ true)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ShadowRoot* root = newFocus->GetShadowRoot()) {
|
||||
if (root->DelegatesFocus()) {
|
||||
if (Element* firstFocusable =
|
||||
root->GetFirstFocusable(/* aWithMouse */ true)) {
|
||||
newFocus = firstFocusable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(newFocus, newFocus->IsElement());
|
||||
|
@ -2381,13 +2381,6 @@ void nsGenericHTMLElement::Click(CallerType aCallerType) {
|
||||
|
||||
bool nsGenericHTMLElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
||||
int32_t* aTabIndex) {
|
||||
if (ShadowRoot* root = GetShadowRoot()) {
|
||||
if (root->DelegatesFocus()) {
|
||||
*aIsFocusable = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Document* doc = GetComposedDoc();
|
||||
if (!doc || doc->HasFlag(NODE_IS_EDITABLE)) {
|
||||
// In designMode documents we only allow focusing the document.
|
||||
|
@ -260,8 +260,6 @@ partial interface Element {
|
||||
// https://dom.spec.whatwg.org/#dictdef-shadowrootinit
|
||||
dictionary ShadowRootInit {
|
||||
required ShadowRootMode mode;
|
||||
[Pref="dom.shadowdom.delegatesFocus.enabled"]
|
||||
boolean delegatesFocus = false;
|
||||
[Pref="dom.shadowdom.slot.assign.enabled"]
|
||||
SlotAssignmentMode slotAssignment = "named";
|
||||
};
|
||||
|
@ -24,8 +24,6 @@ interface ShadowRoot : DocumentFragment
|
||||
{
|
||||
// Shadow DOM v1
|
||||
readonly attribute ShadowRootMode mode;
|
||||
[Pref="dom.shadowdom.delegatesFocus.enabled"]
|
||||
readonly attribute boolean delegatesFocus;
|
||||
[Pref="dom.shadowdom.slot.assign.enabled"]
|
||||
readonly attribute SlotAssignmentMode slotAssignment;
|
||||
readonly attribute Element host;
|
||||
|
@ -3765,12 +3765,6 @@
|
||||
value: @IS_NOT_ANDROID@
|
||||
mirror: always
|
||||
|
||||
# Is the 'delegatesFocus' attribute for shadow dom
|
||||
- name: dom.shadowdom.delegatesFocus.enabled
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# Is the 'assign' API for slot element enabled?
|
||||
- name: dom.shadowdom.slot.assign.enabled
|
||||
type: bool
|
||||
|
@ -0,0 +1,10 @@
|
||||
[ShadowRoot-delegatesFocus.html]
|
||||
[default delegatesFocus value]
|
||||
expected: FAIL
|
||||
|
||||
[delegatesFocus set to false in init dict]
|
||||
expected: FAIL
|
||||
|
||||
[delegatesFocus set to true in init dict]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,4 @@
|
||||
[click-focus-delegatesFocus-tabindex-varies.html]
|
||||
[click on host with delegatesFocus, #aboveSlot tabindex = 2, #slot and #slotted tabindex = 1]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,4 @@
|
||||
[click-focus-delegatesFocus-tabindex-zero.html]
|
||||
[click on host with delegatesFocus, all tabindex=0 except spacer]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,37 @@
|
||||
[focus-method-delegatesFocus.html]
|
||||
[focus() on host with delegatesFocus & tabindex=0, #outside with tabindex=0]
|
||||
expected: FAIL
|
||||
|
||||
[focus() on host with delegatesFocus & tabindex=0, #aboveSlots and #belowSlots with tabindex=0]
|
||||
expected: FAIL
|
||||
|
||||
[focus() on host with delegatesFocus & tabindex = 0, all other tabindex=-1]
|
||||
expected: FAIL
|
||||
|
||||
[focus() on host with delegatesFocus, all tabindex=-1]
|
||||
expected: FAIL
|
||||
|
||||
[focus() on host with delegatesFocus, all tabindex=0]
|
||||
expected: FAIL
|
||||
|
||||
[focus() on host with delegatesFocus & tabindex=0, #belowSlots with tabindex=0]
|
||||
expected: FAIL
|
||||
|
||||
[focus() on host with delegatesFocus & tabindex =-1, all other tabindex=0]
|
||||
expected: FAIL
|
||||
|
||||
[focus() on host with delegatesFocus & no tabindex, all other tabindex=0]
|
||||
expected: FAIL
|
||||
|
||||
[focus() on host with delegatesFocus & tabindex=0, #aboveSlots with tabindex=0 and #belowSlots with tabindex=1]
|
||||
expected: FAIL
|
||||
|
||||
[focus() on host with delegatesFocus & tabindex=0, #slottedToFirstSlot, #slottedToSecondSlot, #belowSlots with tabindex=0]
|
||||
expected: FAIL
|
||||
|
||||
[focus() on host with delegatesFocus with another host with no delegatesFocus and a focusable child]
|
||||
expected: FAIL
|
||||
|
||||
[focus() on host with delegatesFocus with another host with delegatesFocus and a focusable child]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,10 @@
|
||||
[focus-pseudo-matches-on-shadow-host.html]
|
||||
[:focus must match a shadow host with open mode shadow root that contains the focused element]
|
||||
expected: FAIL
|
||||
|
||||
[:focus must not match a shadow host with closed mode shadow root that does not contain the focused element]
|
||||
expected: FAIL
|
||||
|
||||
[:focus must match a shadow host with closed mode shadow root that contains the focused element]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,2 @@
|
||||
[focus-pseudo-on-shadow-host-1.html]
|
||||
expected: FAIL
|
@ -0,0 +1,2 @@
|
||||
[focus-pseudo-on-shadow-host-2.html]
|
||||
expected: FAIL
|
@ -0,0 +1,19 @@
|
||||
[focus-selector-delegatesFocus.html]
|
||||
[:focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=false is focused]
|
||||
expected: FAIL
|
||||
|
||||
[:focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=true is focused]
|
||||
expected: FAIL
|
||||
|
||||
[:focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=false is focused]
|
||||
expected: FAIL
|
||||
|
||||
[:focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=true is focused]
|
||||
expected: FAIL
|
||||
|
||||
[:focus applies to host with delegatesFocus=true when the shadow root's descendant has focus]
|
||||
expected: FAIL
|
||||
|
||||
[:focus applies to host with delegatesFocus=false when the shadow root's descendant has focus]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,4 @@
|
||||
[focus-tabindex-order-shadow-negative-delegatesFocus.html]
|
||||
[Order when all tabindex=-1 is and delegatesFocus = true]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,4 @@
|
||||
[focus-tabindex-order-shadow-varying-delegatesFocus.html]
|
||||
[Order when tabindex varies and delegatesFocus = true]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,4 @@
|
||||
[focus-tabindex-order-shadow-zero-delegatesFocus.html]
|
||||
[Order when all tabindex=0 is and delegatesFocus = true]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>HTML Test: click on shadow host with delegatesFocus</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/testdriver.js"></script>
|
||||
<script src="/resources/testdriver-vendor.js"></script>
|
||||
<script src="resources/shadow-utils.js"></script>
|
||||
|
||||
<body>
|
||||
<div id="host">
|
||||
<div id="slotted">slotted</div>
|
||||
</div>
|
||||
<div id="outside">outside</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
const host = document.getElementById("host");
|
||||
const slotted = document.getElementById("slotted");
|
||||
|
||||
const shadowRoot = host.attachShadow({ mode: "open", delegatesFocus: true });
|
||||
const aboveSlot = document.createElement("div");
|
||||
aboveSlot.innerText = "aboveSlot";
|
||||
const slot = document.createElement("slot");
|
||||
shadowRoot.appendChild(aboveSlot);
|
||||
shadowRoot.appendChild(slot);
|
||||
|
||||
const elementsInFlatTreeOrder = [host, aboveSlot, slot, slotted, outside];
|
||||
|
||||
// Final structure:
|
||||
// <div #host> (delegatesFocus=true)
|
||||
// #shadowRoot
|
||||
// <div #aboveSlot>
|
||||
// <slot #slot>
|
||||
// (slotted) <div #slotted>
|
||||
// <div #outside>
|
||||
|
||||
function setAllTabIndex(value) {
|
||||
setTabIndex(elementsInFlatTreeOrder, value);
|
||||
}
|
||||
|
||||
function removeAllTabIndex() {
|
||||
removeTabIndex(elementsInFlatTreeOrder);
|
||||
}
|
||||
|
||||
function resetTabIndexAndFocus() {
|
||||
removeAllTabIndex();
|
||||
resetFocus(document);
|
||||
resetFocus(shadowRoot);
|
||||
}
|
||||
|
||||
test(() => {
|
||||
resetTabIndexAndFocus();
|
||||
setAllTabIndex(0);
|
||||
host.click();
|
||||
assert_equals(shadowRoot.activeElement, null);
|
||||
assert_equals(document.activeElement, document.body);
|
||||
}, "call click() on host with delegatesFocus, all tabindex=0");
|
||||
|
||||
test(() => {
|
||||
resetTabIndexAndFocus();
|
||||
setAllTabIndex(0);
|
||||
slotted.click();
|
||||
assert_equals(shadowRoot.activeElement, null);
|
||||
assert_equals(document.activeElement, document.body);
|
||||
}, "call click() on slotted element in delegatesFocus shadow tree, all tabindex=0");
|
||||
</script>
|
@ -1,138 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>HTML Test: click on shadow host with delegatesFocus</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/testdriver.js"></script>
|
||||
<script src="/resources/testdriver-vendor.js"></script>
|
||||
<script src="resources/shadow-utils.js"></script>
|
||||
|
||||
<body>
|
||||
<div id="host">
|
||||
<div id="slotted">slotted</div>
|
||||
</div>
|
||||
<div id="outside">outside</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
const host = document.getElementById("host");
|
||||
const slotted = document.getElementById("slotted");
|
||||
|
||||
const shadowRoot = host.attachShadow({ mode: "open", delegatesFocus: true });
|
||||
const aboveSlot = document.createElement("div");
|
||||
aboveSlot.innerText = "aboveSlot";
|
||||
const slot = document.createElement("slot");
|
||||
shadowRoot.appendChild(aboveSlot);
|
||||
shadowRoot.appendChild(slot);
|
||||
|
||||
const elementsInFlatTreeOrder = [host, aboveSlot, slot, slotted, outside];
|
||||
|
||||
// Final structure:
|
||||
// <div #host> (delegatesFocus=true)
|
||||
// #shadowRoot
|
||||
// <div #aboveSlot>
|
||||
// <slot #slot>
|
||||
// (slotted) <div #slotted>
|
||||
// <div #outside>
|
||||
|
||||
function setAllTabIndex(value) {
|
||||
setTabIndex(elementsInFlatTreeOrder, value);
|
||||
}
|
||||
|
||||
function removeAllTabIndex() {
|
||||
removeTabIndex(elementsInFlatTreeOrder);
|
||||
}
|
||||
|
||||
function resetTabIndexAndFocus() {
|
||||
removeAllTabIndex();
|
||||
resetFocus(document);
|
||||
resetFocus(shadowRoot);
|
||||
}
|
||||
|
||||
test(() => {
|
||||
resetTabIndexAndFocus();
|
||||
setAllTabIndex(0);
|
||||
host.click();
|
||||
assert_equals(shadowRoot.activeElement, null);
|
||||
assert_equals(document.activeElement, document.body);
|
||||
}, "call click() on host with delegatesFocus, all tabindex=0");
|
||||
|
||||
test(() => {
|
||||
resetTabIndexAndFocus();
|
||||
setAllTabIndex(0);
|
||||
slotted.click();
|
||||
assert_equals(shadowRoot.activeElement, null);
|
||||
assert_equals(document.activeElement, document.body);
|
||||
}, "call click() on slotted element in delegatesFocus shadow tree, all tabindex=0");
|
||||
|
||||
function createNestedHosts(outerDelegatesFocus, innerDelegatesFocus) {
|
||||
// Structure:
|
||||
// <div> outerHost
|
||||
// <input> outerLightChild
|
||||
// #shadowRoot outerShadow delegatesFocus=true
|
||||
// <div> spacer
|
||||
// <span> innerHost
|
||||
// #shadowRoot innerShadow delegatesFocus=true/false
|
||||
// <input> innerShadowChild
|
||||
// <input> outerShadowChild
|
||||
const outerHost = document.createElement('div');
|
||||
const outerLightChild = document.createElement('input');
|
||||
outerHost.appendChild(outerLightChild);
|
||||
const innerHost = document.createElement('span');
|
||||
const outerShadow = outerHost.attachShadow({mode: 'closed', delegatesFocus:outerDelegatesFocus});
|
||||
|
||||
const spacer = document.createElement("div");
|
||||
spacer.style = "height: 1000px;";
|
||||
outerShadow.appendChild(spacer);
|
||||
|
||||
outerShadow.appendChild(innerHost);
|
||||
const outerShadowChild = document.createElement('input');
|
||||
outerShadow.appendChild(outerShadowChild);
|
||||
|
||||
const innerShadow = innerHost.attachShadow({mode: 'closed', delegatesFocus:innerDelegatesFocus});
|
||||
const innerShadowChild = document.createElement('input');
|
||||
innerShadow.appendChild(innerShadowChild);
|
||||
|
||||
document.body.insertBefore(outerHost, document.body.firstChild);
|
||||
return {outerHost: outerHost,
|
||||
outerLightChild: outerLightChild,
|
||||
outerShadow: outerShadow,
|
||||
outerShadowChild: outerShadowChild,
|
||||
innerHost: innerHost,
|
||||
innerShadow: innerShadow,
|
||||
innerShadowChild: innerShadowChild};
|
||||
}
|
||||
|
||||
promise_test(async function() {
|
||||
const dom = createNestedHosts(true, true);
|
||||
await test_driver.click(dom.outerHost);
|
||||
assert_equals(document.activeElement, dom.outerHost);
|
||||
assert_equals(dom.outerShadow.activeElement, dom.innerHost);
|
||||
assert_equals(dom.innerShadow.activeElement, dom.innerShadowChild);
|
||||
}, "click on the host with delegatesFocus with another host with delegatesFocus and a focusable child");
|
||||
|
||||
promise_test(async function() {
|
||||
const dom = createNestedHosts(true, false);
|
||||
await test_driver.click(dom.outerHost);
|
||||
assert_equals(document.activeElement, dom.outerHost);
|
||||
assert_equals(dom.outerShadow.activeElement, dom.innerHost);
|
||||
assert_equals(dom.innerShadow.activeElement, dom.innerShadowChild);
|
||||
}, "click on the host with delegatesFocus with another host with no delegatesFocus and a focusable child");
|
||||
|
||||
promise_test(async function() {
|
||||
const dom = createNestedHosts(false, true);
|
||||
await test_driver.click(dom.outerHost);
|
||||
assert_equals(document.activeElement, document.body);
|
||||
assert_equals(dom.outerShadow.activeElement, null);
|
||||
assert_equals(dom.innerShadow.activeElement, null);
|
||||
}, "click on the host with no delegatesFocus with another host with delegatesFocus and a focusable child");
|
||||
|
||||
promise_test(async function() {
|
||||
const dom = createNestedHosts(false, false);
|
||||
await test_driver.click(dom.outerHost);
|
||||
assert_equals(document.activeElement, document.body);
|
||||
assert_equals(dom.outerShadow.activeElement, null);
|
||||
assert_equals(dom.innerShadow.activeElement, null);
|
||||
}, "click on the host with no delegatesFocus with another host with no delegatesFocus and a focusable child");
|
||||
|
||||
</script>
|
@ -16,21 +16,11 @@
|
||||
|
||||
let focusedDefault = false;
|
||||
function didFocusDefault() { }
|
||||
function handleFocus() {
|
||||
if (!focusedDefault) {
|
||||
// Use step_timeout here to avoid nested focusing steps.
|
||||
// For example, <input id="defaultFocus" autofocus> could run scripts
|
||||
// while it's autofocusing which may run the tests, so that the
|
||||
// focus() usage in the tests becomes nested focusing steps.
|
||||
step_timeout(function() {
|
||||
testInMode('open');
|
||||
testInMode('closed');
|
||||
}, 0);
|
||||
}
|
||||
function checkFocusMatch() {
|
||||
focusedDefault = true;
|
||||
didFocusDefault();
|
||||
}
|
||||
defaultFocus.addEventListener('focus', handleFocus);
|
||||
defaultFocus.addEventListener('focus', checkFocusMatch);
|
||||
|
||||
function prepare(test)
|
||||
{
|
||||
@ -85,6 +75,9 @@ function testInMode(mode) {
|
||||
|
||||
}
|
||||
|
||||
testInMode('open');
|
||||
testInMode('closed');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -6,14 +6,13 @@
|
||||
<link rel="help" href="https://html.spec.whatwg.org/#element-has-the-focus">
|
||||
<link rel="help=" href="https://bugs.webkit.org/show_bug.cgi?id=202432">
|
||||
<link rel="match" href="/css/reference/ref-filled-green-100px-square.xht">
|
||||
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" >
|
||||
</head>
|
||||
<body>
|
||||
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
|
||||
<div id="host"><span>FAIL</span></div>
|
||||
<style>
|
||||
#host { background: green; width: 100px; height: 100px; }
|
||||
#host span { background: red; font: 10px/1 Ahem; }
|
||||
#host span { background: red; }
|
||||
#host:focus span { background: green; color: green; }
|
||||
</style>
|
||||
<script>
|
||||
|
@ -11,8 +11,6 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<input>
|
||||
|
||||
<script>
|
||||
function createFocusableDiv() {
|
||||
const div = document.createElement("div");
|
||||
@ -65,27 +63,7 @@ for (const delegatesFocus of delegatesFocusValues) {
|
||||
assert_true(nestedShadowChild.matches(":focus"), "element in nested shadow tree matches :focus");
|
||||
assert_true(nestedHost.matches(":focus"), "host of nested shadow tree matches focus");
|
||||
assert_true(host.matches(":focus"), "topmost host matches focus");
|
||||
}, `:focus applies to host with delegatesFocus=${delegatesFocus} when an element in a nested shadow tree with delegatesFocus=${nestedDelegatesFocus} is focused`);
|
||||
|
||||
test(() => {
|
||||
resetFocus();
|
||||
const host = createShadowHost(delegatesFocus, document.body);
|
||||
const nestedHost = createShadowHost(nestedDelegatesFocus, host.shadowRoot);
|
||||
const nestedShadowChild = createFocusableDiv();
|
||||
nestedHost.shadowRoot.appendChild(nestedShadowChild);
|
||||
// All nested shadow hosts should has :focus applied
|
||||
nestedShadowChild.focus();
|
||||
|
||||
const elementOutsideOfShadowDOM = document.querySelector("input");
|
||||
// Move the focus to an element which is outside of the nested
|
||||
// shadow DOM trees
|
||||
elementOutsideOfShadowDOM.focus();
|
||||
|
||||
assert_false(nestedShadowChild.matches(":focus"), "element in nested shadow tree doesn't matche :focus");
|
||||
assert_false(nestedHost.matches(":focus"), "host of nested shadow tree doesn't match focus");
|
||||
assert_false(host.matches(":focus"), "topmost host matches focus");
|
||||
assert_true(elementOutsideOfShadowDOM.matches(":focus"), "The element outside of shadow dom matches :focus");
|
||||
}, `:focus should be removed from hosts with delegatesFocus=${delegatesFocus} when none of the elements in a nested shadow tree with delegatesFocus=${nestedDelegatesFocus} is focused`);
|
||||
}, `:focus applies to host with delegatesFocus=${delegatesFocus} when an element in a nested shadow tree with delegatesFocus=${nestedDelegatesFocus} is focused`);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -1,29 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>HTML Test: Use tab to navigate the focus to an element inside shadow host with delegatesFocus</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/testdriver.js"></script>
|
||||
<script src="/resources/testdriver-vendor.js"></script>
|
||||
<script src="resources/shadow-utils.js"></script>
|
||||
|
||||
<body>
|
||||
<div id="host"></div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
const host = document.getElementById("host");
|
||||
|
||||
const shadowRoot = host.attachShadow({ mode: "open", delegatesFocus: true });
|
||||
const input = document.createElement("input");
|
||||
shadowRoot.appendChild(input);
|
||||
|
||||
promise_test(async function() {
|
||||
assert_equals(document.activeElement, document.body);
|
||||
// Press <tab>
|
||||
await navigateFocusForward();
|
||||
assert_equals(document.activeElement, host);
|
||||
assert_equals(shadowRoot.activeElement, input);
|
||||
assert_true(host.matches(':focus'));
|
||||
}, ":focus should be applied to the host when the focus is moved by <tab>");
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user