Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Make custom elements's default ARIA id-ref work with shadow DOM
https://bugs.webkit.org/show_bug.cgi?id=245467 Reviewed by Manuel Rego Casasnovas. Make ElementInternals's id-ref ARIA attributes work with shadow DOM by recursively updating relations between AX objects in AXObjectCache::updateRelationsIfNeeded. * LayoutTests/accessibility/custom-elements/controls-shadow-expected.txt: Added. * LayoutTests/accessibility/custom-elements/controls-shadow.html: Added. * LayoutTests/accessibility/custom-elements/describedby-shadow-expected.txt: Added. * LayoutTests/accessibility/custom-elements/describedby-shadow.html: Added. * LayoutTests/accessibility/custom-elements/flowto-shadow-expected.txt: Added. * LayoutTests/accessibility/custom-elements/flowto-shadow.html: Added. * LayoutTests/accessibility/custom-elements/menuitem-shadow-expected.txt: Added. * LayoutTests/accessibility/custom-elements/menuitem-shadow.html: Added. * Source/WebCore/accessibility/AXObjectCache.cpp: (WebCore::AXObjectCache::updateRelationsIfNeeded): (WebCore::AXObjectCache::updateRelationsForTree): Extracted from updateRelationsIfNeeded. * Source/WebCore/accessibility/AXObjectCache.h: * Source/WebCore/dom/CustomElementDefaultARIA.cpp: (WebCore::isElementVisible): Fixed a bug that this function returns false when "thisElement" is disconnected but element is in the document tree. Canonical link: https://commits.webkit.org/254762@main
- Loading branch information
Showing
11 changed files
with
304 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
This tests that ElementInternals.ariaControlsElements can reference nodes outside the shadow tree. | ||
|
||
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". | ||
|
||
|
||
PASS internals.ariaControlsElements.length is 2 | ||
PASS internals.ariaControlsElements[0] is document.querySelectorAll(".control")[0] | ||
PASS internals.ariaControlsElements[1] is document.querySelectorAll(".control")[1] | ||
PASS labelForControl(customTab.ariaControlsElementAtIndex(0)) is "AXValue: Panel 1" | ||
PASS labelForControl(customTab.ariaControlsElementAtIndex(1)) is "AXValue: Panel 2" | ||
PASS successfullyParsed is true | ||
|
||
TEST COMPLETE | ||
Panel 1 | ||
Panel 2 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<body> | ||
<script src="../../resources/js-test.js"></script> | ||
<script src="../../resources/accessibility-helper.js"></script> | ||
<div class="control">Panel 1</div> | ||
<div class="control">Panel 2</div> | ||
<div id="host"></div> | ||
<script> | ||
|
||
class CustomTabElement extends HTMLElement { | ||
constructor() | ||
{ | ||
super(); | ||
window.internals = this.attachInternals(); | ||
internals.role = 'tab'; | ||
internals.ariaControlsElements = Array.from(document.querySelectorAll('.control')); | ||
shouldBe('internals.ariaControlsElements.length', '2'); | ||
shouldBe('internals.ariaControlsElements[0]', 'document.querySelectorAll(".control")[0]'); | ||
shouldBe('internals.ariaControlsElements[1]', 'document.querySelectorAll(".control")[1]'); | ||
} | ||
}; | ||
customElements.define('custom-tab', CustomTabElement); | ||
|
||
const customElement = new CustomTabElement; | ||
customElement.id = 'custom-tab'; | ||
const shadowRoot = host.attachShadow({'mode': 'closed'}); | ||
shadowRoot.appendChild(customElement); | ||
|
||
description("This tests that ElementInternals.ariaControlsElements can reference nodes outside the shadow tree."); | ||
if (!window.accessibilityController) | ||
debug('This test requires accessibilityController'); | ||
else { | ||
function labelForControl(control) { | ||
if (accessibilityController.platformName == "mac") | ||
return control.childAtIndex(0).stringValue; | ||
return control.stringValue; | ||
} | ||
window.customTab = accessibilityController.accessibleElementById('custom-tab'); | ||
shouldBeEqualToString('labelForControl(customTab.ariaControlsElementAtIndex(0))', 'AXValue: Panel 1'); | ||
shouldBeEqualToString('labelForControl(customTab.ariaControlsElementAtIndex(1))', 'AXValue: Panel 2'); | ||
} | ||
|
||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
This tests that aria fallback roles work correctly. | ||
|
||
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". | ||
|
||
|
||
PASS internals.ariaDescribedByElements.length is 2 | ||
PASS internals.ariaDescribedByElements[0] is document.querySelectorAll(".note")[0] | ||
PASS internals.ariaDescribedByElements[1] is document.querySelectorAll(".note")[1] | ||
PASS internals.ariaDetailsElements.length is 2 | ||
PASS internals.ariaDetailsElements[0] is document.querySelectorAll(".details")[0] | ||
PASS internals.ariaDetailsElements[1] is document.querySelectorAll(".details")[1] | ||
PASS internals.ariaErrorMessageElements.length is 2 | ||
PASS internals.ariaErrorMessageElements[0] is document.querySelectorAll(".error")[0] | ||
PASS internals.ariaErrorMessageElements[1] is document.querySelectorAll(".error")[1] | ||
PASS accessibilityController.accessibleElementById("custom-1").role is "AXRole: AXCheckBox" | ||
PASS accessibilityController.accessibleElementById("custom-1").helpText is "AXHelp: some description other description" | ||
PASS accessibilityController.accessibleElementById("custom-1").detailsElements().length is 2 | ||
PASS accessibilityController.accessibleElementById("custom-1").detailsElements()[0].domIdentifier is "details1" | ||
PASS accessibilityController.accessibleElementById("custom-1").detailsElements()[1].domIdentifier is "details2" | ||
PASS accessibilityController.accessibleElementById("custom-1").errorMessageElements().length is 2 | ||
PASS accessibilityController.accessibleElementById("custom-1").errorMessageElements()[0].domIdentifier is "error1" | ||
PASS accessibilityController.accessibleElementById("custom-1").errorMessageElements()[1].domIdentifier is "error2" | ||
PASS successfullyParsed is true | ||
|
||
TEST COMPLETE | ||
some description | ||
other description | ||
some details | ||
other details | ||
some error | ||
other error |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<body id="body"> | ||
<script src="../../resources/js-test.js"></script> | ||
<script src="../../resources/accessibility-helper.js"></script> | ||
<div id="host"></div> | ||
<div id="some" class="note">some description</div> | ||
<div class="note">other description</div> | ||
<div id="details1" class="details">some details</div> | ||
<div id="details2" class="details">other details</div> | ||
<div id="error1" class="error">some error</div> | ||
<div id="error2" class="error">other error</div> | ||
<script> | ||
|
||
class CustomElement extends HTMLElement { | ||
constructor() | ||
{ | ||
super(); | ||
window.internals = this.attachInternals(); | ||
internals.role = 'checkbox'; | ||
internals.ariaDescribedByElements = Array.from(document.querySelectorAll('.note')); | ||
internals.ariaDetailsElements = Array.from(document.querySelectorAll('.details')); | ||
internals.ariaErrorMessageElements = Array.from(document.querySelectorAll('.error')); | ||
shouldBe('internals.ariaDescribedByElements.length', '2'); | ||
shouldBe('internals.ariaDescribedByElements[0]', 'document.querySelectorAll(".note")[0]'); | ||
shouldBe('internals.ariaDescribedByElements[1]', 'document.querySelectorAll(".note")[1]'); | ||
shouldBe('internals.ariaDetailsElements.length', '2'); | ||
shouldBe('internals.ariaDetailsElements[0]', 'document.querySelectorAll(".details")[0]'); | ||
shouldBe('internals.ariaDetailsElements[1]', 'document.querySelectorAll(".details")[1]'); | ||
shouldBe('internals.ariaErrorMessageElements.length', '2'); | ||
shouldBe('internals.ariaErrorMessageElements[0]', 'document.querySelectorAll(".error")[0]'); | ||
shouldBe('internals.ariaErrorMessageElements[1]', 'document.querySelectorAll(".error")[1]'); | ||
} | ||
} | ||
customElements.define('custom-element', CustomElement); | ||
|
||
const shadowRoot = host.attachShadow({mode: 'closed'}); | ||
const customElement = new CustomElement; | ||
customElement.id = 'custom-1'; | ||
shadowRoot.appendChild(customElement); | ||
|
||
description("This tests that aria fallback roles work correctly."); | ||
if (!window.accessibilityController) | ||
debug('This test requires accessibilityController'); | ||
else { | ||
shouldBeEqualToString('accessibilityController.accessibleElementById("custom-1").role', 'AXRole: AXCheckBox'); | ||
shouldBeEqualToString('accessibilityController.accessibleElementById("custom-1").helpText', 'AXHelp: some description other description'); | ||
shouldBe('accessibilityController.accessibleElementById("custom-1").detailsElements().length', '2'); | ||
shouldBeEqualToString('accessibilityController.accessibleElementById("custom-1").detailsElements()[0].domIdentifier', 'details1'); | ||
shouldBeEqualToString('accessibilityController.accessibleElementById("custom-1").detailsElements()[1].domIdentifier', 'details2'); | ||
shouldBe('accessibilityController.accessibleElementById("custom-1").errorMessageElements().length', '2'); | ||
shouldBeEqualToString('accessibilityController.accessibleElementById("custom-1").errorMessageElements()[0].domIdentifier', 'error1'); | ||
shouldBeEqualToString('accessibilityController.accessibleElementById("custom-1").errorMessageElements()[1].domIdentifier', 'error2'); | ||
} | ||
|
||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
This tests that aria fallback roles work correctly. | ||
|
||
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". | ||
|
||
|
||
PASS internals.ariaFlowToElements.length is 2 | ||
PASS internals.ariaFlowToElements[0] is document.querySelectorAll(".flowto")[0] | ||
PASS internals.ariaFlowToElements[1] is document.querySelectorAll(".flowto")[1] | ||
PASS internals.ariaLabelledByElements.length is 2 | ||
PASS internals.ariaLabelledByElements[0] is document.querySelectorAll(".label")[0] | ||
PASS internals.ariaLabelledByElements[1] is document.querySelectorAll(".label")[1] | ||
PASS accessibilityController.accessibleElementById("custom-1").role is "AXRole: AXCheckBox" | ||
PASS platformValueForW3CName(accessibilityController.accessibleElementById("custom-1")) is "label 1 label 2" | ||
PASS accessibilityController.accessibleElementById("custom-1").ariaFlowToElementAtIndex(0).role is "AXRole: AXButton" | ||
PASS accessibilityController.accessibleElementById("custom-1").ariaFlowToElementAtIndex(0).title is "AXTitle: FlowTo1" | ||
PASS accessibilityController.accessibleElementById("custom-1").ariaFlowToElementAtIndex(1).role is "AXRole: AXButton" | ||
PASS accessibilityController.accessibleElementById("custom-1").ariaFlowToElementAtIndex(1).title is "AXTitle: FlowTo2" | ||
PASS accessibilityController.accessibleElementById("custom-1").ariaFlowToElementAtIndex(2) is null | ||
PASS successfullyParsed is true | ||
|
||
TEST COMPLETE | ||
FlowTo1 | ||
FlowTo2 | ||
label 1 | ||
label 2 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<body id="body"> | ||
<script src="../../resources/js-test.js"></script> | ||
<script src="../../resources/accessibility-helper.js"></script> | ||
<div role="button" class="flowto">FlowTo1</div> | ||
<div id="flowto2" role="button" class="flowto">FlowTo2</div> | ||
<div class="label">label 1</div> | ||
<div id="label2" class="label">label 2</div> | ||
<div id="host"></div> | ||
<script> | ||
|
||
class CustomElement extends HTMLElement { | ||
constructor() | ||
{ | ||
super(); | ||
window.internals = this.attachInternals(); | ||
internals.role = 'checkbox'; | ||
internals.ariaFlowToElements = Array.from(document.querySelectorAll('.flowto')); | ||
internals.ariaLabelledByElements = Array.from(document.querySelectorAll('.label')); | ||
shouldBe('internals.ariaFlowToElements.length', '2'); | ||
shouldBe('internals.ariaFlowToElements[0]', 'document.querySelectorAll(".flowto")[0]'); | ||
shouldBe('internals.ariaFlowToElements[1]', 'document.querySelectorAll(".flowto")[1]'); | ||
shouldBe('internals.ariaLabelledByElements.length', '2'); | ||
shouldBe('internals.ariaLabelledByElements[0]', 'document.querySelectorAll(".label")[0]'); | ||
shouldBe('internals.ariaLabelledByElements[1]', 'document.querySelectorAll(".label")[1]'); | ||
} | ||
}; | ||
customElements.define('custom-element', CustomElement); | ||
|
||
const shadowRoot = host.attachShadow({'mode': 'closed'}); | ||
const customElement = new CustomElement; | ||
customElement.id = 'custom-1'; | ||
shadowRoot.appendChild(customElement); | ||
|
||
description("This tests that aria fallback roles work correctly."); | ||
if (!window.accessibilityController) | ||
debug('This test requires accessibilityController'); | ||
else { | ||
shouldBeEqualToString('accessibilityController.accessibleElementById("custom-1").role', 'AXRole: AXCheckBox'); | ||
shouldBeEqualToString('platformValueForW3CName(accessibilityController.accessibleElementById("custom-1"))', 'label 1 label 2'); | ||
shouldBeEqualToString('accessibilityController.accessibleElementById("custom-1").ariaFlowToElementAtIndex(0).role', 'AXRole: AXButton'); | ||
shouldBeEqualToString('accessibilityController.accessibleElementById("custom-1").ariaFlowToElementAtIndex(0).title', 'AXTitle: FlowTo1'); | ||
shouldBeEqualToString('accessibilityController.accessibleElementById("custom-1").ariaFlowToElementAtIndex(1).role', 'AXRole: AXButton'); | ||
shouldBeEqualToString('accessibilityController.accessibleElementById("custom-1").ariaFlowToElementAtIndex(1).title', 'AXTitle: FlowTo2'); | ||
shouldBe('accessibilityController.accessibleElementById("custom-1").ariaFlowToElementAtIndex(2)', 'null'); | ||
} | ||
|
||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
This tests that aria fallback roles work correctly. | ||
|
||
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". | ||
|
||
|
||
PASS customMenuInternals.ariaActiveDescendantElement is document.getElementById("item-2") | ||
PASS customMenuInternals.ariaActiveDescendantElement is document.getElementById("item-2") | ||
PASS accessibilityController.accessibleElementById("menu-1").selectedChildrenCount is 1 | ||
PASS platformValueForW3CName(accessibilityController.accessibleElementById("menu-1").selectedChildAtIndex(0)) is "item 2" | ||
PASS accessibilityController.accessibleElementById("menu-1").selectedChildAtIndex(0).isSelected is true | ||
PASS successfullyParsed is true | ||
|
||
TEST COMPLETE | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<body> | ||
<script src="../../resources/js-test.js"></script> | ||
<script src="../../resources/accessibility-helper.js"></script> | ||
<custom-menu id="menu-1"> | ||
<div id="host"> | ||
<custom-menuitem id="item-1" aria-label="item 1"></custom-menuitem> | ||
<custom-menuitem id="item-2" aria-label="item 2"></custom-menuitem> | ||
</div> | ||
<script> | ||
|
||
class CustomMenuElement extends HTMLElement { | ||
constructor() | ||
{ | ||
super(); | ||
const internals = this.attachInternals(); | ||
internals.role = 'menubar'; | ||
internals.ariaActiveDescendantElement = document.getElementById('item-2'); | ||
window.customMenuInternals = internals; | ||
shouldBe('customMenuInternals.ariaActiveDescendantElement', 'document.getElementById("item-2")'); | ||
} | ||
}; | ||
customElements.define('custom-menu', CustomMenuElement); | ||
|
||
class CustomMenuItemElement extends HTMLElement { | ||
constructor() | ||
{ | ||
super(); | ||
const internals = this.attachInternals(); | ||
internals.role = 'menuitem'; | ||
} | ||
} | ||
customElements.define('custom-menuitem', CustomMenuItemElement); | ||
|
||
const shadowRoot = host.attachShadow({mode: 'closed'}); | ||
shadowRoot.innerHTML = '<custom-menu id="menu-1"><slot></slot></custom-menu>'; | ||
|
||
description("This tests that aria fallback roles work correctly."); | ||
if (!window.accessibilityController) | ||
debug('This test requires accessibilityController'); | ||
else { | ||
shouldBe('accessibilityController.accessibleElementById("menu-1").selectedChildrenCount', '1'); | ||
shouldBeEqualToString('platformValueForW3CName(accessibilityController.accessibleElementById("menu-1").selectedChildAtIndex(0))', 'item 2'); | ||
shouldBeTrue('accessibilityController.accessibleElementById("menu-1").selectedChildAtIndex(0).isSelected'); | ||
} | ||
|
||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters