зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1625864 - Fire state change event on LINKED change. r=Jamie,morgan
Also stop recreating any accessible that has href modified. Differential Revision: https://phabricator.services.mozilla.com/D71258
This commit is contained in:
Родитель
3d7faad085
Коммит
7fac737410
|
@ -50,6 +50,7 @@ enum AccType {
|
|||
* Other accessible types.
|
||||
*/
|
||||
eApplicationType,
|
||||
eHTMLLinkType,
|
||||
eHTMLOptGroupType,
|
||||
eImageMapType,
|
||||
eMenuPopupType,
|
||||
|
|
|
@ -285,16 +285,23 @@ nsAccessibilityService::ListenersChanged(nsIArray* aEventChanges) {
|
|||
change->GetCountOfEventListenerChangesAffectingAccessibility(&changeCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
for (uint32_t i = 0; i < changeCount; i++) {
|
||||
if (changeCount) {
|
||||
Document* ownerDoc = node->OwnerDoc();
|
||||
DocAccessible* document = GetExistingDocAccessible(ownerDoc);
|
||||
|
||||
// Create an accessible for a inaccessible element having click event
|
||||
// handler.
|
||||
if (document && !document->HasAccessible(node) &&
|
||||
nsCoreUtils::HasClickListener(node)) {
|
||||
document->ContentInserted(node, node->GetNextSibling());
|
||||
break;
|
||||
if (document) {
|
||||
Accessible* acc = document->GetAccessible(node);
|
||||
if (!acc && nsCoreUtils::HasClickListener(node)) {
|
||||
// Create an accessible for a inaccessible element having click event
|
||||
// handler.
|
||||
document->ContentInserted(node, node->GetNextSibling());
|
||||
} else if (acc && acc->IsHTMLLink() && !acc->AsHTMLLink()->IsLinked()) {
|
||||
// Notify of a LINKED state change if an HTML link gets a click
|
||||
// listener but does not have an href attribute.
|
||||
RefPtr<AccEvent> linkedChangeEvent =
|
||||
new AccStateChangeEvent(acc, states::LINKED);
|
||||
document->FireDelayedEvent(linkedChangeEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ class EmbeddedObjCollector;
|
|||
class EventTree;
|
||||
class HTMLImageMapAccessible;
|
||||
class HTMLLIAccessible;
|
||||
class HTMLLinkAccessible;
|
||||
class HyperTextAccessible;
|
||||
class ImageAccessible;
|
||||
class KeyBinding;
|
||||
|
@ -576,6 +577,9 @@ class Accessible : public nsISupports {
|
|||
bool IsHTMLListItem() const { return mType == eHTMLLiType; }
|
||||
HTMLLIAccessible* AsHTMLListItem();
|
||||
|
||||
bool IsHTMLLink() const { return mType == eHTMLLinkType; }
|
||||
HTMLLinkAccessible* AsHTMLLink();
|
||||
|
||||
bool IsHTMLOptGroup() const { return mType == eHTMLOptGroupType; }
|
||||
|
||||
bool IsHTMLTable() const { return mType == eHTMLTableType; }
|
||||
|
|
|
@ -671,7 +671,7 @@ void DocAccessible::AttributeWillChange(dom::Element* aElement,
|
|||
return;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::aria_disabled ||
|
||||
if (aAttribute == nsGkAtoms::aria_disabled || aAttribute == nsGkAtoms::href ||
|
||||
aAttribute == nsGkAtoms::disabled || aAttribute == nsGkAtoms::tabindex ||
|
||||
aAttribute == nsGkAtoms::contenteditable) {
|
||||
mPrevStateBits = accessible->State();
|
||||
|
@ -732,7 +732,7 @@ void DocAccessible::AttributeChanged(dom::Element* aElement,
|
|||
|
||||
// Fire accessible events iff there's an accessible, otherwise we consider
|
||||
// the accessible state wasn't changed, i.e. its state is initial state.
|
||||
AttributeChangedImpl(accessible, aNameSpaceID, aAttribute);
|
||||
AttributeChangedImpl(accessible, aNameSpaceID, aAttribute, aModType);
|
||||
|
||||
// Update dependent IDs cache. Take care of accessible elements because no
|
||||
// accessible element means either the element is not accessible at all or
|
||||
|
@ -748,7 +748,7 @@ void DocAccessible::AttributeChanged(dom::Element* aElement,
|
|||
// DocAccessible protected member
|
||||
void DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute) {
|
||||
nsAtom* aAttribute, int32_t aModType) {
|
||||
// Fire accessible event after short timer, because we need to wait for
|
||||
// DOM attribute & resulting layout to actually change. Otherwise,
|
||||
// assistive technology will retrieve the wrong state/value/selection info.
|
||||
|
@ -921,6 +921,23 @@ void DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
|
|||
if (aAttribute == nsGkAtoms::value) {
|
||||
if (aAccessible->IsProgress())
|
||||
FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aModType == dom::MutationEvent_Binding::REMOVAL ||
|
||||
aModType == dom::MutationEvent_Binding::ADDITION) {
|
||||
if (aAttribute == nsGkAtoms::href) {
|
||||
if (aAccessible->IsHTMLLink() &&
|
||||
!nsCoreUtils::HasClickListener(aAccessible->GetContent())) {
|
||||
RefPtr<AccEvent> linkedChangeEvent =
|
||||
new AccStateChangeEvent(aAccessible, states::LINKED);
|
||||
FireDelayedEvent(linkedChangeEvent);
|
||||
// Fire a focusable state change event if the previous state was
|
||||
// different. It may be the same if there is tabindex on this link.
|
||||
aAccessible->MaybeFireFocusableStateChange(
|
||||
(mPrevStateBits & states::FOCUSABLE));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1789,17 +1806,6 @@ bool DocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::href) {
|
||||
// Not worth the expense to ensure which namespace these are in. It doesn't
|
||||
// kill use to recreate the accessible even if the attribute was used in
|
||||
// the wrong namespace or an element that doesn't support it.
|
||||
|
||||
// Make sure the accessible is recreated asynchronously to allow the content
|
||||
// to handle the attribute change.
|
||||
RecreateAccessible(aElement);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::aria_multiselectable &&
|
||||
aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::role)) {
|
||||
// This affects whether the accessible supports SelectAccessible.
|
||||
|
|
|
@ -472,9 +472,10 @@ class DocAccessible : public HyperTextAccessibleWrap,
|
|||
* @param aAccessible [in] accessible the DOM attribute is changed for
|
||||
* @param aNameSpaceID [in] namespace of changed attribute
|
||||
* @param aAttribute [in] changed attribute
|
||||
* @param aModType [in] modification type (changed/added/removed)
|
||||
*/
|
||||
void AttributeChangedImpl(Accessible* aAccessible, int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute);
|
||||
nsAtom* aAttribute, int32_t aModType);
|
||||
|
||||
/**
|
||||
* Fire accessible events when ARIA attribute is changed.
|
||||
|
|
|
@ -23,7 +23,9 @@ using namespace mozilla::a11y;
|
|||
|
||||
HTMLLinkAccessible::HTMLLinkAccessible(nsIContent* aContent,
|
||||
DocAccessible* aDoc)
|
||||
: HyperTextAccessibleWrap(aContent, aDoc) {}
|
||||
: HyperTextAccessibleWrap(aContent, aDoc) {
|
||||
mType = eHTMLLinkType;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIAccessible
|
||||
|
@ -107,7 +109,7 @@ already_AddRefed<nsIURI> HTMLLinkAccessible::AnchorURIAt(
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected members
|
||||
// HTMLLinkAccessible
|
||||
|
||||
bool HTMLLinkAccessible::IsLinked() const {
|
||||
EventStates state = mContent->AsElement()->State();
|
||||
|
|
|
@ -35,17 +35,21 @@ class HTMLLinkAccessible : public HyperTextAccessibleWrap {
|
|||
virtual already_AddRefed<nsIURI> AnchorURIAt(
|
||||
uint32_t aAnchorIndex) const override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLLinkAccessible() {}
|
||||
|
||||
enum { eAction_Jump = 0 };
|
||||
|
||||
/**
|
||||
* Returns true if the link has href attribute.
|
||||
*/
|
||||
bool IsLinked() const;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLLinkAccessible() {}
|
||||
|
||||
enum { eAction_Jump = 0 };
|
||||
};
|
||||
|
||||
inline HTMLLinkAccessible* Accessible::AsHTMLLink() {
|
||||
return IsHTMLLink() ? static_cast<HTMLLinkAccessible*>(this) : nullptr;
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -122,6 +122,10 @@
|
|||
getNode("scrollable2").setAttribute("disabled", "true");
|
||||
await p;
|
||||
|
||||
p = waitForEvent(...focusableStateChange("link", false));
|
||||
getNode("link").removeAttribute("href");
|
||||
await p;
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -152,5 +156,7 @@
|
|||
|
||||
<textarea id="textarea" rows="3" cols="30"></textarea>
|
||||
|
||||
<a id="link" href="#">A link</a>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -117,6 +117,20 @@
|
|||
await p;
|
||||
}
|
||||
|
||||
async function testLinked() {
|
||||
let p = waitForEvent(...stateChange(STATE_LINKED, false, false, "link1"));
|
||||
getNode("link1").removeAttribute("href");
|
||||
await p;
|
||||
|
||||
p = waitForEvent(...stateChange(STATE_LINKED, false, false, "link2"));
|
||||
getNode("link2").removeAttribute("onclick");
|
||||
await p;
|
||||
|
||||
p = waitForEvent(...stateChange(STATE_LINKED, false, true, "link3"));
|
||||
getNode("link3").setAttribute("href", "http://example.com");
|
||||
await p;
|
||||
}
|
||||
|
||||
async function doTests() {
|
||||
// Test opening details objects
|
||||
await openNode("detailsOpen", "summaryOpen", true);
|
||||
|
@ -159,6 +173,8 @@
|
|||
await echoingStateChange("text1", "aria-disabled", "disabled", null,
|
||||
EXT_STATE_ENABLED, true, true);
|
||||
|
||||
await testLinked();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -245,6 +261,10 @@
|
|||
|
||||
<input id="text1">
|
||||
|
||||
<a id="link1" href="#">I am a link link</a>
|
||||
<a id="link2" onclick="console.log('hi')">I am a link-ish link</a>
|
||||
<a id="link3">I am a non-link link</a>
|
||||
|
||||
<div id="eventdump"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Загрузка…
Ссылка в новой задаче