Bug 1769586 - P1: Implement ARIA element reflection in Element and ElementInternals. r=peterv
Differential Revision: https://phabricator.services.mozilla.com/D209767
This commit is contained in:
@@ -1835,18 +1835,12 @@ already_AddRefed<nsIHTMLCollection> Element::GetElementsByClassName(
|
|||||||
return nsContentUtils::GetElementsByClassName(this, aClassNames);
|
return nsContentUtils::GetElementsByClassName(this, aClassNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
Element* Element::GetAttrAssociatedElement(nsAtom* aAttr) const {
|
bool Element::HasSharedRoot(const Element* aElement) const {
|
||||||
if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) {
|
|
||||||
nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElements.Get(aAttr);
|
|
||||||
if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakAttrEl)) {
|
|
||||||
// If reflectedTarget's explicitly set attr-element |attrEl| is
|
|
||||||
// a descendant of any of element's shadow-including ancestors, then
|
|
||||||
// return |atrEl|.
|
|
||||||
nsINode* root = SubtreeRoot();
|
nsINode* root = SubtreeRoot();
|
||||||
nsINode* attrSubtreeRoot = attrEl->SubtreeRoot();
|
nsINode* attrSubtreeRoot = aElement->SubtreeRoot();
|
||||||
do {
|
do {
|
||||||
if (root == attrSubtreeRoot) {
|
if (root == attrSubtreeRoot) {
|
||||||
return attrEl;
|
return true;
|
||||||
}
|
}
|
||||||
auto* shadow = ShadowRoot::FromNode(root);
|
auto* shadow = ShadowRoot::FromNode(root);
|
||||||
if (!shadow || !shadow->GetHost()) {
|
if (!shadow || !shadow->GetHost()) {
|
||||||
@@ -1854,6 +1848,27 @@ Element* Element::GetAttrAssociatedElement(nsAtom* aAttr) const {
|
|||||||
}
|
}
|
||||||
root = shadow->GetHost()->SubtreeRoot();
|
root = shadow->GetHost()->SubtreeRoot();
|
||||||
} while (true);
|
} while (true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Element* Element::GetElementByIdInDocOrSubtree(nsAtom* aID) const {
|
||||||
|
if (auto* docOrShadowRoot = GetContainingDocumentOrShadowRoot()) {
|
||||||
|
return docOrShadowRoot->GetElementById(aID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsContentUtils::MatchElementId(SubtreeRoot()->AsContent(), aID);
|
||||||
|
}
|
||||||
|
|
||||||
|
Element* Element::GetAttrAssociatedElement(nsAtom* aAttr) const {
|
||||||
|
if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) {
|
||||||
|
nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElementMap.Get(aAttr);
|
||||||
|
if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakAttrEl)) {
|
||||||
|
// If reflectedTarget's explicitly set attr-element |attrEl| is
|
||||||
|
// a descendant of any of element's shadow-including ancestors, then
|
||||||
|
// return |atrEl|.
|
||||||
|
if (HasSharedRoot(attrEl)) {
|
||||||
|
return attrEl;
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1866,23 +1881,102 @@ Element* Element::GetAttrAssociatedElement(nsAtom* aAttr) const {
|
|||||||
MOZ_ASSERT(value->Type() == nsAttrValue::eAtom,
|
MOZ_ASSERT(value->Type() == nsAttrValue::eAtom,
|
||||||
"Attribute used for attr associated element must be parsed");
|
"Attribute used for attr associated element must be parsed");
|
||||||
|
|
||||||
nsAtom* valueAtom = value->GetAtomValue();
|
return GetElementByIdInDocOrSubtree(value->GetAtomValue());
|
||||||
if (auto* docOrShadowRoot = GetContainingDocumentOrShadowRoot()) {
|
|
||||||
return docOrShadowRoot->GetElementById(valueAtom);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsINode* root = SubtreeRoot();
|
void Element::GetAttrAssociatedElements(
|
||||||
for (auto* node = root; node; node = node->GetNextNode(root)) {
|
nsAtom* aAttr, bool* aUseCachedValue,
|
||||||
if (node->HasID() && node->AsContent()->GetID() == valueAtom) {
|
Nullable<nsTArray<RefPtr<Element>>>& aElements) {
|
||||||
return node->AsElement();
|
MOZ_ASSERT(aElements.IsNull());
|
||||||
|
|
||||||
|
auto& [explicitlySetAttrElements, cachedAttrElements] =
|
||||||
|
ExtendedDOMSlots()->mAttrElementsMap.LookupOrInsert(aAttr);
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#attr-associated-elements
|
||||||
|
auto getAttrAssociatedElements =
|
||||||
|
[&, &explicitlySetAttrElements =
|
||||||
|
explicitlySetAttrElements]() -> Maybe<nsTArray<RefPtr<Element>>> {
|
||||||
|
nsTArray<RefPtr<Element>> elements;
|
||||||
|
|
||||||
|
if (explicitlySetAttrElements) {
|
||||||
|
// 3. If reflectedTarget's explicitly set attr-elements is not null
|
||||||
|
for (const nsWeakPtr& weakEl : *explicitlySetAttrElements) {
|
||||||
|
// For each attrElement in reflectedTarget's explicitly set
|
||||||
|
// attr-elements:
|
||||||
|
if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakEl)) {
|
||||||
|
// If attrElement is not a descendant of any of element's
|
||||||
|
// shadow-including ancestors, then continue.
|
||||||
|
if (!HasSharedRoot(attrEl)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Append attrElement to elements.
|
||||||
|
elements.AppendElement(attrEl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
} else {
|
||||||
|
// 4. Otherwise
|
||||||
|
// 1. Let contentAttributeValue be the result of running
|
||||||
|
// reflectedTarget's get the content attribute.
|
||||||
|
const nsAttrValue* value = GetParsedAttr(aAttr);
|
||||||
|
// 2. If contentAttributeValue is null, then return null.
|
||||||
|
if (!value) {
|
||||||
|
return Nothing();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Let tokens be contentAttributeValue, split on ASCII whitespace.
|
||||||
|
MOZ_ASSERT(value->Type() == nsAttrValue::eAtomArray ||
|
||||||
|
value->Type() == nsAttrValue::eAtom,
|
||||||
|
"Attribute used for attr associated elements must be parsed");
|
||||||
|
for (uint32_t i = 0; i < value->GetAtomCount(); i++) {
|
||||||
|
// For each id of tokens:
|
||||||
|
if (auto* candidate = GetElementByIdInDocOrSubtree(
|
||||||
|
value->AtomAt(static_cast<int32_t>(i)))) {
|
||||||
|
// Append candidate to elements.
|
||||||
|
elements.AppendElement(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(std::move(elements));
|
||||||
|
};
|
||||||
|
|
||||||
|
// getter steps:
|
||||||
|
// 1. Let elements be the result of running this's get the attr-associated
|
||||||
|
// elements.
|
||||||
|
auto elements = getAttrAssociatedElements();
|
||||||
|
|
||||||
|
if (elements && elements == cachedAttrElements) {
|
||||||
|
// 2. If the contents of elements is equal to the contents of this's cached
|
||||||
|
// attr-associated elements, then return this's cached attr-associated
|
||||||
|
// elements object.
|
||||||
|
MOZ_ASSERT(!*aUseCachedValue);
|
||||||
|
*aUseCachedValue = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Let elementsAsFrozenArray be elements, converted to a FrozenArray<T>?.
|
||||||
|
// (the binding code takes aElements and returns it as a FrozenArray)
|
||||||
|
// 5. Set this's cached attr-associated elements object to
|
||||||
|
// elementsAsFrozenArray.
|
||||||
|
// (the binding code stores the attr-associated elements object in a slot)
|
||||||
|
// 6. Return elementsAsFrozenArray.
|
||||||
|
if (elements) {
|
||||||
|
aElements.SetValue(elements->Clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Set this's cached attr-associated elements to elements.
|
||||||
|
cachedAttrElements = std::move(elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Element::ClearExplicitlySetAttrElement(nsAtom* aAttr) {
|
void Element::ClearExplicitlySetAttrElement(nsAtom* aAttr) {
|
||||||
if (auto* slots = GetExistingExtendedDOMSlots()) {
|
if (auto* slots = GetExistingExtendedDOMSlots()) {
|
||||||
slots->mExplicitlySetAttrElements.Remove(aAttr);
|
slots->mExplicitlySetAttrElementMap.Remove(aAttr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Element::ClearExplicitlySetAttrElements(nsAtom* aAttr) {
|
||||||
|
if (auto* slots = GetExistingExtendedDOMSlots()) {
|
||||||
|
slots->mAttrElementsMap.Remove(aAttr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1905,7 +1999,7 @@ void Element::ExplicitlySetAttrElement(nsAtom* aAttr, Element* aElement) {
|
|||||||
#endif
|
#endif
|
||||||
SetAttr(aAttr, EmptyString(), IgnoreErrors());
|
SetAttr(aAttr, EmptyString(), IgnoreErrors());
|
||||||
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||||
slots->mExplicitlySetAttrElements.InsertOrUpdate(
|
slots->mExplicitlySetAttrElementMap.InsertOrUpdate(
|
||||||
aAttr, do_GetWeakReference(aElement));
|
aAttr, do_GetWeakReference(aElement));
|
||||||
#ifdef ACCESSIBILITY
|
#ifdef ACCESSIBILITY
|
||||||
if (accService) {
|
if (accService) {
|
||||||
@@ -1929,9 +2023,48 @@ void Element::ExplicitlySetAttrElement(nsAtom* aAttr, Element* aElement) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Element::ExplicitlySetAttrElements(
|
||||||
|
nsAtom* aAttr,
|
||||||
|
const Nullable<Sequence<OwningNonNull<Element>>>& aElements) {
|
||||||
|
#ifdef ACCESSIBILITY
|
||||||
|
nsAccessibilityService* accService = GetAccService();
|
||||||
|
#endif
|
||||||
|
// Accessibility requires that no other attribute changes occur between
|
||||||
|
// AttrElementWillChange and AttrElementChanged. Scripts could cause
|
||||||
|
// this, so don't let them run here. We do this even if accessibility isn't
|
||||||
|
// running so that the JS behavior is consistent regardless of accessibility.
|
||||||
|
// Otherwise, JS might be able to use this difference to determine whether
|
||||||
|
// accessibility is running, which would be a privacy concern.
|
||||||
|
nsAutoScriptBlocker scriptBlocker;
|
||||||
|
|
||||||
|
#ifdef ACCESSIBILITY
|
||||||
|
if (accService) {
|
||||||
|
accService->NotifyAttrElementWillChange(this, aAttr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (aElements.IsNull()) {
|
||||||
|
ClearExplicitlySetAttrElements(aAttr);
|
||||||
|
UnsetAttr(aAttr, IgnoreErrors());
|
||||||
|
} else {
|
||||||
|
SetAttr(aAttr, EmptyString(), IgnoreErrors());
|
||||||
|
auto& entry = ExtendedDOMSlots()->mAttrElementsMap.LookupOrInsert(aAttr);
|
||||||
|
entry.first.emplace(nsTArray<nsWeakPtr>());
|
||||||
|
for (Element* el : aElements.Value()) {
|
||||||
|
entry.first->AppendElement(do_GetWeakReference(el));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ACCESSIBILITY
|
||||||
|
if (accService) {
|
||||||
|
accService->NotifyAttrElementChanged(this, aAttr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Element* Element::GetExplicitlySetAttrElement(nsAtom* aAttr) const {
|
Element* Element::GetExplicitlySetAttrElement(nsAtom* aAttr) const {
|
||||||
if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) {
|
if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) {
|
||||||
nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElements.Get(aAttr);
|
nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElementMap.Get(aAttr);
|
||||||
if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakAttrEl)) {
|
if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakAttrEl)) {
|
||||||
return attrEl;
|
return attrEl;
|
||||||
}
|
}
|
||||||
@@ -2897,7 +3030,14 @@ bool Element::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (aNamespaceID == kNameSpaceID_None) {
|
if (aNamespaceID == kNameSpaceID_None) {
|
||||||
if (aAttribute == nsGkAtoms::_class || aAttribute == nsGkAtoms::part) {
|
if (aAttribute == nsGkAtoms::_class || aAttribute == nsGkAtoms::part ||
|
||||||
|
aAttribute == nsGkAtoms::aria_controls ||
|
||||||
|
aAttribute == nsGkAtoms::aria_describedby ||
|
||||||
|
aAttribute == nsGkAtoms::aria_details ||
|
||||||
|
aAttribute == nsGkAtoms::aria_errormessage ||
|
||||||
|
aAttribute == nsGkAtoms::aria_flowto ||
|
||||||
|
aAttribute == nsGkAtoms::aria_labelledby ||
|
||||||
|
aAttribute == nsGkAtoms::aria_owns) {
|
||||||
aResult.ParseAtomArray(aValue);
|
aResult.ParseAtomArray(aValue);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2969,6 +3109,14 @@ void Element::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
|||||||
}
|
}
|
||||||
} else if (aName == nsGkAtoms::aria_activedescendant) {
|
} else if (aName == nsGkAtoms::aria_activedescendant) {
|
||||||
ClearExplicitlySetAttrElement(aName);
|
ClearExplicitlySetAttrElement(aName);
|
||||||
|
} else if (aName == nsGkAtoms::aria_controls ||
|
||||||
|
aName == nsGkAtoms::aria_describedby ||
|
||||||
|
aName == nsGkAtoms::aria_details ||
|
||||||
|
aName == nsGkAtoms::aria_errormessage ||
|
||||||
|
aName == nsGkAtoms::aria_flowto ||
|
||||||
|
aName == nsGkAtoms::aria_labelledby ||
|
||||||
|
aName == nsGkAtoms::aria_owns) {
|
||||||
|
ClearExplicitlySetAttrElements(aName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3025,6 +3173,16 @@ void Element::OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
|
|||||||
aName == nsGkAtoms::aria_activedescendant) {
|
aName == nsGkAtoms::aria_activedescendant) {
|
||||||
ClearExplicitlySetAttrElement(aName);
|
ClearExplicitlySetAttrElement(aName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aNamespaceID == kNameSpaceID_None &&
|
||||||
|
(aName == nsGkAtoms::aria_controls ||
|
||||||
|
aName == nsGkAtoms::aria_describedby ||
|
||||||
|
aName == nsGkAtoms::aria_details ||
|
||||||
|
aName == nsGkAtoms::aria_errormessage ||
|
||||||
|
aName == nsGkAtoms::aria_flowto || aName == nsGkAtoms::aria_labelledby ||
|
||||||
|
aName == nsGkAtoms::aria_owns)) {
|
||||||
|
ClearExplicitlySetAttrElements(aName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EventListenerManager* Element::GetEventListenerManagerForAttr(nsAtom* aAttrName,
|
EventListenerManager* Element::GetEventListenerManagerForAttr(nsAtom* aAttrName,
|
||||||
|
|||||||
@@ -267,6 +267,17 @@ class TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString;
|
|||||||
ExplicitlySetAttrElement(nsGkAtoms::attr, aElement); \
|
ExplicitlySetAttrElement(nsGkAtoms::attr, aElement); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define REFLECT_NULLABLE_ELEMENTS_ATTR(method, attr) \
|
||||||
|
void Get##method(bool* aUseCachedValue, \
|
||||||
|
Nullable<nsTArray<RefPtr<Element>>>& aElements) { \
|
||||||
|
GetAttrAssociatedElements(nsGkAtoms::attr, aUseCachedValue, aElements); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void Set##method( \
|
||||||
|
const Nullable<Sequence<OwningNonNull<Element>>>& aElements) { \
|
||||||
|
ExplicitlySetAttrElements(nsGkAtoms::attr, aElements); \
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(keithamus): Reference the spec link once merged.
|
// TODO(keithamus): Reference the spec link once merged.
|
||||||
// https://github.com/whatwg/html/pull/9841/files#diff-41cf6794ba4200b839c53531555f0f3998df4cbb01a4d5cb0b94e3ca5e23947dR86024
|
// https://github.com/whatwg/html/pull/9841/files#diff-41cf6794ba4200b839c53531555f0f3998df4cbb01a4d5cb0b94e3ca5e23947dR86024
|
||||||
enum class InvokeAction : uint8_t {
|
enum class InvokeAction : uint8_t {
|
||||||
@@ -706,21 +717,28 @@ class Element : public FragmentOrElement {
|
|||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaColIndex, aria_colindex)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaColIndex, aria_colindex)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaColIndexText, aria_colindextext)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaColIndexText, aria_colindextext)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaColSpan, aria_colspan)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaColSpan, aria_colspan)
|
||||||
|
REFLECT_NULLABLE_ELEMENTS_ATTR(AriaControlsElements, aria_controls)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaCurrent, aria_current)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaCurrent, aria_current)
|
||||||
|
REFLECT_NULLABLE_ELEMENTS_ATTR(AriaDescribedByElements, aria_describedby)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaDescription, aria_description)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaDescription, aria_description)
|
||||||
|
REFLECT_NULLABLE_ELEMENTS_ATTR(AriaDetailsElements, aria_details)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaDisabled, aria_disabled)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaDisabled, aria_disabled)
|
||||||
|
REFLECT_NULLABLE_ELEMENTS_ATTR(AriaErrorMessageElements, aria_errormessage)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaExpanded, aria_expanded)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaExpanded, aria_expanded)
|
||||||
|
REFLECT_NULLABLE_ELEMENTS_ATTR(AriaFlowToElements, aria_flowto)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaHasPopup, aria_haspopup)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaHasPopup, aria_haspopup)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaHidden, aria_hidden)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaHidden, aria_hidden)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaInvalid, aria_invalid)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaInvalid, aria_invalid)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaKeyShortcuts, aria_keyshortcuts)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaKeyShortcuts, aria_keyshortcuts)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaLabel, aria_label)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaLabel, aria_label)
|
||||||
|
REFLECT_NULLABLE_ELEMENTS_ATTR(AriaLabelledByElements, aria_labelledby)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaLevel, aria_level)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaLevel, aria_level)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaLive, aria_live)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaLive, aria_live)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaModal, aria_modal)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaModal, aria_modal)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaMultiLine, aria_multiline)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaMultiLine, aria_multiline)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaMultiSelectable, aria_multiselectable)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaMultiSelectable, aria_multiselectable)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaOrientation, aria_orientation)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaOrientation, aria_orientation)
|
||||||
|
REFLECT_NULLABLE_ELEMENTS_ATTR(AriaOwnsElements, aria_owns)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaPlaceholder, aria_placeholder)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaPlaceholder, aria_placeholder)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaPosInSet, aria_posinset)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaPosInSet, aria_posinset)
|
||||||
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaPressed, aria_pressed)
|
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaPressed, aria_pressed)
|
||||||
@@ -1172,6 +1190,10 @@ class Element : public FragmentOrElement {
|
|||||||
const MappedAttributeEntry* const aMaps[],
|
const MappedAttributeEntry* const aMaps[],
|
||||||
uint32_t aMapCount);
|
uint32_t aMapCount);
|
||||||
|
|
||||||
|
bool HasSharedRoot(const Element* aElement) const;
|
||||||
|
|
||||||
|
Element* GetElementByIdInDocOrSubtree(nsAtom* aID) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline bool GetAttr(const nsAtom* aName, DOMString& aResult) const {
|
inline bool GetAttr(const nsAtom* aName, DOMString& aResult) const {
|
||||||
MOZ_ASSERT(aResult.IsEmpty(), "Should have empty string coming in");
|
MOZ_ASSERT(aResult.IsEmpty(), "Should have empty string coming in");
|
||||||
@@ -1308,14 +1330,21 @@ class Element : public FragmentOrElement {
|
|||||||
* https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#attr-associated-element
|
* https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#attr-associated-element
|
||||||
*/
|
*/
|
||||||
Element* GetAttrAssociatedElement(nsAtom* aAttr) const;
|
Element* GetAttrAssociatedElement(nsAtom* aAttr) const;
|
||||||
|
void GetAttrAssociatedElements(
|
||||||
|
nsAtom* aAttr, bool* aUseCachedValue,
|
||||||
|
Nullable<nsTArray<RefPtr<Element>>>& aElements);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an attribute element for the given attribute.
|
* Sets an attribute element for the given attribute.
|
||||||
* https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#explicitly-set-attr-element
|
* https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#explicitly-set-attr-element
|
||||||
*/
|
*/
|
||||||
void ExplicitlySetAttrElement(nsAtom* aAttr, Element* aElement);
|
void ExplicitlySetAttrElement(nsAtom* aAttr, Element* aElement);
|
||||||
|
void ExplicitlySetAttrElements(
|
||||||
|
nsAtom* aAttr,
|
||||||
|
const Nullable<Sequence<OwningNonNull<Element>>>& aElements);
|
||||||
|
|
||||||
void ClearExplicitlySetAttrElement(nsAtom*);
|
void ClearExplicitlySetAttrElement(nsAtom*);
|
||||||
|
void ClearExplicitlySetAttrElements(nsAtom*);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the attribute element for the given attribute.
|
* Gets the attribute element for the given attribute.
|
||||||
|
|||||||
@@ -637,7 +637,8 @@ void FragmentOrElement::nsExtendedDOMSlots::UnlinkExtendedSlots(
|
|||||||
mAnimations = nullptr;
|
mAnimations = nullptr;
|
||||||
aContent.ClearMayHaveAnimations();
|
aContent.ClearMayHaveAnimations();
|
||||||
}
|
}
|
||||||
mExplicitlySetAttrElements.Clear();
|
mExplicitlySetAttrElementMap.Clear();
|
||||||
|
mAttrElementsMap.Clear();
|
||||||
mRadioGroupContainer = nullptr;
|
mRadioGroupContainer = nullptr;
|
||||||
mPart = nullptr;
|
mPart = nullptr;
|
||||||
}
|
}
|
||||||
@@ -661,6 +662,15 @@ void FragmentOrElement::nsExtendedDOMSlots::TraverseExtendedSlots(
|
|||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mSlots->mPart");
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mSlots->mPart");
|
||||||
aCb.NoteXPCOMChild(mPart.get());
|
aCb.NoteXPCOMChild(mPart.get());
|
||||||
|
|
||||||
|
for (auto& tableEntry : mAttrElementsMap) {
|
||||||
|
auto& [explicitlySetElements, cachedAttrElements] =
|
||||||
|
*tableEntry.GetModifiableData();
|
||||||
|
if (cachedAttrElements) {
|
||||||
|
ImplCycleCollectionTraverse(aCb, *cachedAttrElements,
|
||||||
|
"cached attribute elements entry", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mCustomElementData) {
|
if (mCustomElementData) {
|
||||||
mCustomElementData->Traverse(aCb);
|
mCustomElementData->Traverse(aCb);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -268,10 +268,21 @@ class FragmentOrElement : public nsIContent {
|
|||||||
RefPtr<nsDOMTokenList> mPart;
|
RefPtr<nsDOMTokenList> mPart;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Explicitly set attr-elements, see
|
* Explicitly set attr-element, see
|
||||||
* https://html.spec.whatwg.org/#explicitly-set-attr-element
|
* https://html.spec.whatwg.org/#explicitly-set-attr-element
|
||||||
*/
|
*/
|
||||||
nsTHashMap<RefPtr<nsAtom>, nsWeakPtr> mExplicitlySetAttrElements;
|
nsTHashMap<RefPtr<nsAtom>, nsWeakPtr> mExplicitlySetAttrElementMap;
|
||||||
|
/**
|
||||||
|
* Explicitly set attr-elements, see
|
||||||
|
* https://html.spec.whatwg.org/#explicitly-set-attr-elements
|
||||||
|
*
|
||||||
|
* The first member of the pair are the explicitly set attr-elements. The
|
||||||
|
* second member is the cached attr-associated elements.
|
||||||
|
*/
|
||||||
|
|
||||||
|
nsTHashMap<RefPtr<nsAtom>, std::pair<Maybe<nsTArray<nsWeakPtr>>,
|
||||||
|
Maybe<nsTArray<RefPtr<Element>>>>>
|
||||||
|
mAttrElementsMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
class nsDOMSlots : public nsIContent::nsContentSlots {
|
class nsDOMSlots : public nsIContent::nsContentSlots {
|
||||||
|
|||||||
@@ -41,6 +41,13 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ElementInternals)
|
|||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTarget, mSubmissionValue, mState,
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTarget, mSubmissionValue, mState,
|
||||||
mValidity, mValidationAnchor,
|
mValidity, mValidationAnchor,
|
||||||
mCustomStateSet);
|
mCustomStateSet);
|
||||||
|
|
||||||
|
for (auto& tableEntry : tmp->mAttrElementsMap) {
|
||||||
|
auto& [explicitlySetElements, cachedAttrElements] =
|
||||||
|
*tableEntry.GetModifiableData();
|
||||||
|
ImplCycleCollectionTraverse(cb, cachedAttrElements,
|
||||||
|
"cached attribute elements entry", 0);
|
||||||
|
}
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ElementInternals)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(ElementInternals)
|
||||||
@@ -428,6 +435,7 @@ void ElementInternals::Unlink() {
|
|||||||
mFieldSet->RemoveElement(mTarget);
|
mFieldSet->RemoveElement(mTarget);
|
||||||
mFieldSet = nullptr;
|
mFieldSet = nullptr;
|
||||||
}
|
}
|
||||||
|
mAttrElementsMap.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElementInternals::GetAttr(const nsAtom* aName, nsAString& aResult) const {
|
void ElementInternals::GetAttr(const nsAtom* aName, nsAString& aResult) const {
|
||||||
@@ -469,6 +477,23 @@ nsresult ElementInternals::SetAttr(nsAtom* aName, const nsAString& aValue) {
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult ElementInternals::SetAttrInternal(nsAtom* aName,
|
||||||
|
const nsAString& aValue) {
|
||||||
|
bool attrHadValue;
|
||||||
|
nsAttrValue attrValue(aValue);
|
||||||
|
return mAttrs.SetAndSwapAttr(aName, attrValue, &attrHadValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult ElementInternals::UnsetAttrInternal(nsAtom* aName) {
|
||||||
|
nsAttrValue attrValue;
|
||||||
|
auto attrPos = mAttrs.IndexOfAttr(aName);
|
||||||
|
if (attrPos >= 0) {
|
||||||
|
return mAttrs.RemoveAttrAt(attrPos, attrValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
DocGroup* ElementInternals::GetDocGroup() {
|
DocGroup* ElementInternals::GetDocGroup() {
|
||||||
return mTarget->OwnerDoc()->GetDocGroup();
|
return mTarget->OwnerDoc()->GetDocGroup();
|
||||||
}
|
}
|
||||||
@@ -516,9 +541,11 @@ void ElementInternals::SetAttrElement(nsAtom* aAttr, Element* aElement) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (aElement) {
|
if (aElement) {
|
||||||
mAttrElements.InsertOrUpdate(aAttr, do_GetWeakReference(aElement));
|
mAttrElementMap.InsertOrUpdate(aAttr, do_GetWeakReference(aElement));
|
||||||
|
SetAttrInternal(aAttr, EmptyString());
|
||||||
} else {
|
} else {
|
||||||
mAttrElements.Remove(aAttr);
|
mAttrElementMap.Remove(aAttr);
|
||||||
|
UnsetAttrInternal(aAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ACCESSIBILITY
|
#ifdef ACCESSIBILITY
|
||||||
@@ -529,9 +556,103 @@ void ElementInternals::SetAttrElement(nsAtom* aAttr, Element* aElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Element* ElementInternals::GetAttrElement(nsAtom* aAttr) const {
|
Element* ElementInternals::GetAttrElement(nsAtom* aAttr) const {
|
||||||
nsWeakPtr weakAttrEl = mAttrElements.Get(aAttr);
|
nsWeakPtr weakAttrEl = mAttrElementMap.Get(aAttr);
|
||||||
nsCOMPtr<Element> attrEl = do_QueryReferent(weakAttrEl);
|
nsCOMPtr<Element> attrEl = do_QueryReferent(weakAttrEl);
|
||||||
return attrEl;
|
return attrEl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ElementInternals::SetAttrElements(
|
||||||
|
nsAtom* aAttr,
|
||||||
|
const Nullable<Sequence<OwningNonNull<Element>>>& aElements) {
|
||||||
|
#ifdef ACCESSIBILITY
|
||||||
|
nsAccessibilityService* accService = GetAccService();
|
||||||
|
#endif
|
||||||
|
// Accessibility requires that no other attribute changes occur between
|
||||||
|
// AttrElementWillChange and AttrElementChanged. Scripts could cause
|
||||||
|
// this, so don't let them run here. We do this even if accessibility isn't
|
||||||
|
// running so that the JS behavior is consistent regardless of accessibility.
|
||||||
|
// Otherwise, JS might be able to use this difference to determine whether
|
||||||
|
// accessibility is running, which would be a privacy concern.
|
||||||
|
nsAutoScriptBlocker scriptBlocker;
|
||||||
|
#ifdef ACCESSIBILITY
|
||||||
|
if (accService) {
|
||||||
|
accService->NotifyAttrElementWillChange(mTarget, aAttr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nsAttrValue emptyAttr;
|
||||||
|
if (aElements.IsNull()) {
|
||||||
|
mAttrElementsMap.Remove(aAttr);
|
||||||
|
UnsetAttrInternal(aAttr);
|
||||||
|
} else {
|
||||||
|
auto& [attrElements, cachedAttrElements] =
|
||||||
|
mAttrElementsMap.LookupOrInsert(aAttr);
|
||||||
|
attrElements.Clear();
|
||||||
|
for (Element* el : aElements.Value()) {
|
||||||
|
attrElements.AppendElement(do_GetWeakReference(el));
|
||||||
|
}
|
||||||
|
SetAttrInternal(aAttr, EmptyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ACCESSIBILITY
|
||||||
|
if (accService) {
|
||||||
|
accService->NotifyAttrElementChanged(mTarget, aAttr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElementInternals::GetAttrElements(
|
||||||
|
nsAtom* aAttr, bool* aUseCachedValue,
|
||||||
|
Nullable<nsTArray<RefPtr<Element>>>& aElements) {
|
||||||
|
MOZ_ASSERT(aElements.IsNull());
|
||||||
|
|
||||||
|
auto attrElementsMaybeEntry = mAttrElementsMap.Lookup(aAttr);
|
||||||
|
if (!attrElementsMaybeEntry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
aElements.SetValue(nsTArray<RefPtr<Element>>());
|
||||||
|
auto& [attrElements, cachedAttrElements] = attrElementsMaybeEntry.Data();
|
||||||
|
|
||||||
|
auto getAttrAssociatedElements = [&, &attrElements = attrElements]() {
|
||||||
|
CopyableTArray<RefPtr<Element>> elements;
|
||||||
|
|
||||||
|
for (const nsWeakPtr& weakEl : attrElements) {
|
||||||
|
// For each attrElement in reflectedTarget's explicitly set attr-elements:
|
||||||
|
if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakEl)) {
|
||||||
|
// Append attrElement to elements.
|
||||||
|
elements.AppendElement(attrEl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#attr-associated-elements
|
||||||
|
// Getter steps:
|
||||||
|
// 1. Let elements be the result of running this's get the attr-associated
|
||||||
|
// elements.
|
||||||
|
auto elements = getAttrAssociatedElements();
|
||||||
|
|
||||||
|
if (elements == cachedAttrElements) {
|
||||||
|
// 2. If the contents of elements is equal to the contents of this's cached
|
||||||
|
// attr-associated elements, then return this's cached attr-associated
|
||||||
|
// elements object.
|
||||||
|
MOZ_ASSERT(!*aUseCachedValue);
|
||||||
|
*aUseCachedValue = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Let elementsAsFrozenArray be elements, converted to a FrozenArray<T>?.
|
||||||
|
// (the binding code takes aElements and returns it as a FrozenArray)
|
||||||
|
// 5. Set this's cached attr-associated elements object to
|
||||||
|
// elementsAsFrozenArray.
|
||||||
|
// (the binding code stores the attr-associated elements object in a slot)
|
||||||
|
// 6. Return elementsAsFrozenArray.
|
||||||
|
aElements.SetValue(elements.Clone());
|
||||||
|
|
||||||
|
// 4. Set this's cached attr-associated elements to elements.
|
||||||
|
cachedAttrElements = std::move(elements);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
} // namespace mozilla::dom
|
||||||
|
|||||||
@@ -34,6 +34,17 @@
|
|||||||
SetAttrElement(nsGkAtoms::attr, aElement); \
|
SetAttrElement(nsGkAtoms::attr, aElement); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ARIA_REFLECT_ATTR_ELEMENTS(method, attr) \
|
||||||
|
void Get##method(bool* aUseCachedValue, \
|
||||||
|
Nullable<nsTArray<RefPtr<Element>>>& aElements) { \
|
||||||
|
GetAttrElements(nsGkAtoms::attr, aUseCachedValue, aElements); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void Set##method( \
|
||||||
|
const Nullable<Sequence<OwningNonNull<Element>>>& aElements) { \
|
||||||
|
SetAttrElements(nsGkAtoms::attr, aElements); \
|
||||||
|
}
|
||||||
|
|
||||||
class nsINodeList;
|
class nsINodeList;
|
||||||
class nsGenericHTMLElement;
|
class nsGenericHTMLElement;
|
||||||
|
|
||||||
@@ -137,21 +148,28 @@ class ElementInternals final : public nsIFormControl,
|
|||||||
ARIA_REFLECT_ATTR(AriaColIndex, aria_colindex)
|
ARIA_REFLECT_ATTR(AriaColIndex, aria_colindex)
|
||||||
ARIA_REFLECT_ATTR(AriaColIndexText, aria_colindextext)
|
ARIA_REFLECT_ATTR(AriaColIndexText, aria_colindextext)
|
||||||
ARIA_REFLECT_ATTR(AriaColSpan, aria_colspan)
|
ARIA_REFLECT_ATTR(AriaColSpan, aria_colspan)
|
||||||
|
ARIA_REFLECT_ATTR_ELEMENTS(AriaControlsElements, aria_controls)
|
||||||
ARIA_REFLECT_ATTR(AriaCurrent, aria_current)
|
ARIA_REFLECT_ATTR(AriaCurrent, aria_current)
|
||||||
|
ARIA_REFLECT_ATTR_ELEMENTS(AriaDescribedByElements, aria_describedby)
|
||||||
ARIA_REFLECT_ATTR(AriaDescription, aria_description)
|
ARIA_REFLECT_ATTR(AriaDescription, aria_description)
|
||||||
|
ARIA_REFLECT_ATTR_ELEMENTS(AriaDetailsElements, aria_details)
|
||||||
ARIA_REFLECT_ATTR(AriaDisabled, aria_disabled)
|
ARIA_REFLECT_ATTR(AriaDisabled, aria_disabled)
|
||||||
|
ARIA_REFLECT_ATTR_ELEMENTS(AriaErrorMessageElements, aria_errormessage)
|
||||||
ARIA_REFLECT_ATTR(AriaExpanded, aria_expanded)
|
ARIA_REFLECT_ATTR(AriaExpanded, aria_expanded)
|
||||||
|
ARIA_REFLECT_ATTR_ELEMENTS(AriaFlowToElements, aria_flowto)
|
||||||
ARIA_REFLECT_ATTR(AriaHasPopup, aria_haspopup)
|
ARIA_REFLECT_ATTR(AriaHasPopup, aria_haspopup)
|
||||||
ARIA_REFLECT_ATTR(AriaHidden, aria_hidden)
|
ARIA_REFLECT_ATTR(AriaHidden, aria_hidden)
|
||||||
ARIA_REFLECT_ATTR(AriaInvalid, aria_invalid)
|
ARIA_REFLECT_ATTR(AriaInvalid, aria_invalid)
|
||||||
ARIA_REFLECT_ATTR(AriaKeyShortcuts, aria_keyshortcuts)
|
ARIA_REFLECT_ATTR(AriaKeyShortcuts, aria_keyshortcuts)
|
||||||
ARIA_REFLECT_ATTR(AriaLabel, aria_label)
|
ARIA_REFLECT_ATTR(AriaLabel, aria_label)
|
||||||
|
ARIA_REFLECT_ATTR_ELEMENTS(AriaLabelledByElements, aria_labelledby)
|
||||||
ARIA_REFLECT_ATTR(AriaLevel, aria_level)
|
ARIA_REFLECT_ATTR(AriaLevel, aria_level)
|
||||||
ARIA_REFLECT_ATTR(AriaLive, aria_live)
|
ARIA_REFLECT_ATTR(AriaLive, aria_live)
|
||||||
ARIA_REFLECT_ATTR(AriaModal, aria_modal)
|
ARIA_REFLECT_ATTR(AriaModal, aria_modal)
|
||||||
ARIA_REFLECT_ATTR(AriaMultiLine, aria_multiline)
|
ARIA_REFLECT_ATTR(AriaMultiLine, aria_multiline)
|
||||||
ARIA_REFLECT_ATTR(AriaMultiSelectable, aria_multiselectable)
|
ARIA_REFLECT_ATTR(AriaMultiSelectable, aria_multiselectable)
|
||||||
ARIA_REFLECT_ATTR(AriaOrientation, aria_orientation)
|
ARIA_REFLECT_ATTR(AriaOrientation, aria_orientation)
|
||||||
|
ARIA_REFLECT_ATTR_ELEMENTS(AriaOwnsElements, aria_owns)
|
||||||
ARIA_REFLECT_ATTR(AriaPlaceholder, aria_placeholder)
|
ARIA_REFLECT_ATTR(AriaPlaceholder, aria_placeholder)
|
||||||
ARIA_REFLECT_ATTR(AriaPosInSet, aria_posinset)
|
ARIA_REFLECT_ATTR(AriaPosInSet, aria_posinset)
|
||||||
ARIA_REFLECT_ATTR(AriaPressed, aria_pressed)
|
ARIA_REFLECT_ATTR(AriaPressed, aria_pressed)
|
||||||
@@ -194,6 +212,17 @@ class ElementInternals final : public nsIFormControl,
|
|||||||
*/
|
*/
|
||||||
void SetAttrElement(nsAtom* aAttr, Element* aElement);
|
void SetAttrElement(nsAtom* aAttr, Element* aElement);
|
||||||
|
|
||||||
|
void SetAttrElements(
|
||||||
|
nsAtom* aAttr,
|
||||||
|
const Nullable<Sequence<OwningNonNull<Element>>>& aElements);
|
||||||
|
|
||||||
|
void GetAttrElements(nsAtom* aAttr, bool* aUseCachedValue,
|
||||||
|
Nullable<nsTArray<RefPtr<Element>>>& aElements);
|
||||||
|
|
||||||
|
nsresult SetAttrInternal(nsAtom* aName, const nsAString& aValue);
|
||||||
|
|
||||||
|
nsresult UnsetAttrInternal(nsAtom* aName);
|
||||||
|
|
||||||
// It's a target element which is a custom element.
|
// It's a target element which is a custom element.
|
||||||
RefPtr<HTMLElement> mTarget;
|
RefPtr<HTMLElement> mTarget;
|
||||||
|
|
||||||
@@ -238,7 +267,11 @@ class ElementInternals final : public nsIFormControl,
|
|||||||
* Explicitly set attr-elements, see
|
* Explicitly set attr-elements, see
|
||||||
* https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#explicitly-set-attr-element
|
* https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#explicitly-set-attr-element
|
||||||
*/
|
*/
|
||||||
nsTHashMap<RefPtr<nsAtom>, nsWeakPtr> mAttrElements;
|
nsTHashMap<RefPtr<nsAtom>, nsWeakPtr> mAttrElementMap;
|
||||||
|
|
||||||
|
nsTHashMap<RefPtr<nsAtom>,
|
||||||
|
std::pair<nsTArray<nsWeakPtr>, nsTArray<RefPtr<Element>>>>
|
||||||
|
mAttrElementsMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
} // namespace mozilla::dom
|
||||||
|
|||||||
@@ -47,18 +47,38 @@ interface mixin ARIAMixin {
|
|||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString? ariaColSpan;
|
attribute DOMString? ariaColSpan;
|
||||||
|
|
||||||
|
// TODO: Use FrozenArray once available. (Bug 1236777)
|
||||||
|
[Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray]
|
||||||
|
attribute sequence<Element>? ariaControlsElements;
|
||||||
|
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString? ariaCurrent;
|
attribute DOMString? ariaCurrent;
|
||||||
|
|
||||||
|
// TODO: Use FrozenArray once available. (Bug 1236777)
|
||||||
|
[Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray]
|
||||||
|
attribute sequence<Element>? ariaDescribedByElements;
|
||||||
|
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString? ariaDescription;
|
attribute DOMString? ariaDescription;
|
||||||
|
|
||||||
|
// TODO: Use FrozenArray once available. (Bug 1236777)
|
||||||
|
[Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray]
|
||||||
|
attribute sequence<Element>? ariaDetailsElements;
|
||||||
|
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString? ariaDisabled;
|
attribute DOMString? ariaDisabled;
|
||||||
|
|
||||||
|
// TODO: Use FrozenArray once available. (Bug 1236777)
|
||||||
|
[Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray]
|
||||||
|
attribute sequence<Element>? ariaErrorMessageElements;
|
||||||
|
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString? ariaExpanded;
|
attribute DOMString? ariaExpanded;
|
||||||
|
|
||||||
|
// TODO: Use FrozenArray once available. (Bug 1236777)
|
||||||
|
[Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray]
|
||||||
|
attribute sequence<Element>? ariaFlowToElements;
|
||||||
|
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString? ariaHasPopup;
|
attribute DOMString? ariaHasPopup;
|
||||||
|
|
||||||
@@ -74,6 +94,10 @@ interface mixin ARIAMixin {
|
|||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString? ariaLabel;
|
attribute DOMString? ariaLabel;
|
||||||
|
|
||||||
|
// TODO: Use FrozenArray once available. (Bug 1236777)
|
||||||
|
[Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray]
|
||||||
|
attribute sequence<Element>? ariaLabelledByElements;
|
||||||
|
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString? ariaLevel;
|
attribute DOMString? ariaLevel;
|
||||||
|
|
||||||
@@ -92,6 +116,10 @@ interface mixin ARIAMixin {
|
|||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString? ariaOrientation;
|
attribute DOMString? ariaOrientation;
|
||||||
|
|
||||||
|
// TODO: Use FrozenArray once available. (Bug 1236777)
|
||||||
|
[Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray]
|
||||||
|
attribute sequence<Element>? ariaOwnsElements;
|
||||||
|
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString? ariaPlaceholder;
|
attribute DOMString? ariaPlaceholder;
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,2 @@
|
|||||||
[ElementInternals-accessibility.html]
|
[ElementInternals-accessibility.html]
|
||||||
prefs: [accessibility.ARIAElementReflection.enabled:true]
|
prefs: [accessibility.ARIAElementReflection.enabled:true]
|
||||||
[ariaControlsElements is defined in ElementInternals]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ariaDescribedByElements is defined in ElementInternals]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ariaDetailsElements is defined in ElementInternals]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ariaFlowToElements is defined in ElementInternals]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ariaLabelledByElements is defined in ElementInternals]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ariaOwnsElements is defined in ElementInternals]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ariaErrorMessageElements is defined in ElementInternals]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
[element-internals-aria-element-reflection.html]
|
[element-internals-aria-element-reflection.html]
|
||||||
[Getting previously-unset ARIA element reflection properties on ElementInternals should return null.]
|
prefs: [accessibility.ARIAElementReflection.enabled:true]
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Setting ariaLabelledByElements should change the accessible name of the custom element]
|
[Setting ariaLabelledByElements should change the accessible name of the custom element]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
[aria-element-reflection-disconnected.html]
|
[aria-element-reflection-disconnected.html]
|
||||||
prefs: [accessibility.ARIAElementReflection.enabled:true]
|
prefs: [accessibility.ARIAElementReflection.enabled:true]
|
||||||
[Element references should stay valid when content is disconnected (element array)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
[aria-element-reflection-labelledby.html]
|
|
||||||
[Setting ariaLabelledByElements should determine the computed label for the labelled element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Setting ariaLabelledByElements before inserting the elements referred to in the document should cause the label to be updated once elements are inserted]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Setting ariaLabelledByElements on an element before inserting it in the document should cause the label to be updated once the element is inserted]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Moving the label from shadow DOM to light DOM causes the reference to become valid]
|
|
||||||
expected: FAIL
|
|
||||||
@@ -1,34 +1,2 @@
|
|||||||
[aria-element-reflection.html]
|
[aria-element-reflection.html]
|
||||||
prefs: [accessibility.ARIAElementReflection.enabled:true]
|
prefs: [accessibility.ARIAElementReflection.enabled:true]
|
||||||
[aria-errormessage]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[aria-details]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[aria-labelledby.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[aria-controls.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[aria-describedby.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[aria-flowto.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[aria-owns.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[shadow DOM behaviour for FrozenArray element reflection.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Moving explicitly set elements across shadow DOM boundaries.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Moving explicitly set elements around within the same scope, and removing from the DOM.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Passing values of the wrong type should throw a TypeError]
|
|
||||||
expected: FAIL
|
|
||||||
|
|||||||
@@ -1,43 +1,2 @@
|
|||||||
[idlharness.window.html]
|
[idlharness.window.html]
|
||||||
prefs: [accessibility.ARIAElementReflection.enabled:true]
|
prefs: [accessibility.ARIAElementReflection.enabled:true]
|
||||||
[Element interface: attribute ariaControlsElements]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: attribute ariaDescribedByElements]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: attribute ariaDetailsElements]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: attribute ariaFlowToElements]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: attribute ariaLabelledByElements]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: attribute ariaOwnsElements]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: element must inherit property "ariaControlsElements" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: element must inherit property "ariaDescribedByElements" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: element must inherit property "ariaDetailsElements" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: element must inherit property "ariaFlowToElements" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: element must inherit property "ariaLabelledByElements" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: element must inherit property "ariaOwnsElements" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: attribute ariaErrorMessageElements]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element interface: element must inherit property "ariaErrorMessageElements" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|||||||
Reference in New Issue
Block a user