Bug 1395181 part 2: Support click handlers added to the root element. r=eeejay

Normally, we treat the body as the DOM node for a DocAccessible.
However, a click listener can be added to the root element; e.g. the html element.
We now treat a click listener added to the root element the same as if one were added to the body.

This required a change to nsAccessibilityService to use the DocAccessible when click listeners change for the root element so a cache update is pushed.
This change was made for the body also, since we weren't pushing a cache update for click listener changes on the body either.

Differential Revision: https://phabricator.services.mozilla.com/D144278
This commit is contained in:
James Teh 2022-04-22 23:13:36 +00:00
parent ddd6d00a57
commit a3b482acc2
4 changed files with 56 additions and 4 deletions

View file

@ -304,6 +304,10 @@ nsAccessibilityService::ListenersChanged(nsIArray* aEventChanges) {
if (document) {
LocalAccessible* acc = document->GetAccessible(content);
if (!acc && (content == document->GetContent() ||
content == document->DocumentNode()->GetRootElement())) {
acc = document;
}
if (!acc && nsCoreUtils::HasClickListener(content)) {
// Create an accessible for a inaccessible element having click event
// handler.

View file

@ -2616,3 +2616,26 @@ LocalAccessible* DocAccessible::GetAccessible(nsINode* aNode) const {
return aNode == mDocumentNode ? const_cast<DocAccessible*>(this)
: mNodeToAccessibleMap.Get(aNode);
}
bool DocAccessible::HasPrimaryAction() const {
if (HyperTextAccessible::HasPrimaryAction()) {
return true;
}
// mContent is normally the body, but there might be a click listener on the
// root.
dom::Element* root = mDocumentNode->GetRootElement();
if (mContent != root) {
return nsCoreUtils::HasClickListener(root);
}
return false;
}
void DocAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
aName.Truncate();
if (aIndex != 0) {
return;
}
if (HasPrimaryAction()) {
aName.AssignLiteral("click");
}
}

View file

@ -84,6 +84,10 @@ class DocAccessible : public HyperTextAccessibleWrap,
virtual nsRect RelativeBounds(nsIFrame** aRelativeFrame) const override;
// ActionAccessible
virtual bool HasPrimaryAction() const override;
virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override;
// HyperTextAccessible
virtual already_AddRefed<EditorBase> GetEditor() const override;

View file

@ -170,9 +170,9 @@ addAccessibleTask(
await _testActions("onclick_img", ["showlongdesc"]);
// Remove 'href' from link and test linkable child
acc = findAccessibleChildByID(docAcc, "link1");
const link1Acc = findAccessibleChildByID(docAcc, "link1");
is(
acc.firstChild.getActionName(0),
link1Acc.firstChild.getActionName(0),
"click ancestor",
"linkable child has click ancestor action"
);
@ -180,8 +180,29 @@ addAccessibleTask(
let link1 = content.document.getElementById("link1");
link1.removeAttribute("href");
});
await untilCacheIs(() => acc.actionCount, 0, "link has no actions");
is(acc.firstChild.actionCount, 0, "linkable child's actions removed");
await untilCacheIs(() => link1Acc.actionCount, 0, "link has no actions");
is(link1Acc.firstChild.actionCount, 0, "linkable child's actions removed");
// Add a click handler to the body. Ensure it propagates to descendants.
await invokeContentTask(browser, [], () => {
content.document.body.onclick = () => {};
});
await untilCacheIs(() => docAcc.actionCount, 1, "Doc has 1 action");
await _testActions("link1", ["click ancestor"]);
await invokeContentTask(browser, [], () => {
content.document.body.onclick = null;
});
await untilCacheIs(() => docAcc.actionCount, 0, "Doc has no actions");
is(link1Acc.actionCount, 0, "link has no actions");
// Add a click handler to the root element. Ensure it propagates to
// descendants.
await invokeContentTask(browser, [], () => {
content.document.documentElement.onclick = () => {};
});
await untilCacheIs(() => docAcc.actionCount, 1, "Doc has 1 action");
await _testActions("link1", ["click ancestor"]);
},
{
chrome: true,