зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1629761 - Should not invoke attributeChangedCallback for the attribute that is changed during upgrading; r=smaug
In https://dom.spec.whatwg.org/#handle-attribute-changes, the attributeChangedCallback reaction is enqueued only if the custom-element-state is customized. And the assumption of "custom-element-definition is only available on the element whose custom-element-state is customized" is no longer true after bug 1610054 along with the spec changings in https://github.com/whatwg/html/pull/5126. Differential Revision: https://phabricator.services.mozilla.com/D71027 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
1e4fcf5b1a
Коммит
444a911d92
|
@ -182,7 +182,7 @@ void CustomElementData::AttachedInternals() {
|
|||
mIsAttachedInternals = true;
|
||||
}
|
||||
|
||||
CustomElementDefinition* CustomElementData::GetCustomElementDefinition() {
|
||||
CustomElementDefinition* CustomElementData::GetCustomElementDefinition() const {
|
||||
// Per spec, if there is a definition, the custom element state should be
|
||||
// either "failed" (during upgrade) or "customized".
|
||||
MOZ_ASSERT_IF(mCustomElementDefinition, mState != State::eUndefined);
|
||||
|
@ -492,6 +492,7 @@ CustomElementRegistry::CreateCustomElementCallback(
|
|||
return callback;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/commit-snapshots/65f39c6fc0efa92b0b2b23b93197016af6ac0de6/#enqueue-a-custom-element-callback-reaction
|
||||
/* static */
|
||||
void CustomElementRegistry::EnqueueLifecycleCallback(
|
||||
Document::ElementCallbackType aType, Element* aCustomElement,
|
||||
|
|
|
@ -103,7 +103,7 @@ struct CustomElementData {
|
|||
AutoTArray<UniquePtr<CustomElementReaction>, 3> mReactionQueue;
|
||||
|
||||
void SetCustomElementDefinition(CustomElementDefinition* aDefinition);
|
||||
CustomElementDefinition* GetCustomElementDefinition();
|
||||
CustomElementDefinition* GetCustomElementDefinition() const;
|
||||
nsAtom* GetCustomElementType() const { return mType; }
|
||||
void AttachedInternals();
|
||||
bool HasAttachedInternals() const { return mIsAttachedInternals; }
|
||||
|
|
|
@ -375,8 +375,7 @@ void Element::Focus(const FocusOptions& aOptions, CallerType aCallerType,
|
|||
fm->NeedsFlushBeforeEventHandling(this);
|
||||
return;
|
||||
}
|
||||
uint32_t fmFlags =
|
||||
nsFocusManager::FocusOptionsToFocusManagerFlags(aOptions);
|
||||
uint32_t fmFlags = nsFocusManager::FocusOptionsToFocusManagerFlags(aOptions);
|
||||
if (aCallerType == CallerType::NonSystem) {
|
||||
fmFlags |= nsIFocusManager::FLAG_NONSYSTEMCALLER;
|
||||
}
|
||||
|
@ -2331,31 +2330,34 @@ nsresult Element::SetAttrAndNotify(
|
|||
}
|
||||
}
|
||||
|
||||
CustomElementDefinition* definition = GetCustomElementDefinition();
|
||||
// Only custom element which is in `custom` state could get the
|
||||
// CustomElementDefinition.
|
||||
if (definition && definition->IsInObservedAttributeList(aName)) {
|
||||
RefPtr<nsAtom> oldValueAtom;
|
||||
if (oldValue) {
|
||||
oldValueAtom = oldValue->GetAsAtom();
|
||||
} else {
|
||||
// If there is no old value, get the value of the uninitialized
|
||||
// attribute that was swapped with aParsedValue.
|
||||
oldValueAtom = aParsedValue.GetAsAtom();
|
||||
const CustomElementData* data = GetCustomElementData();
|
||||
if (data && data->mState == CustomElementData::State::eCustom) {
|
||||
CustomElementDefinition* definition = data->GetCustomElementDefinition();
|
||||
MOZ_ASSERT(definition, "Should have a valid CustomElementDefinition");
|
||||
|
||||
if (definition->IsInObservedAttributeList(aName)) {
|
||||
RefPtr<nsAtom> oldValueAtom;
|
||||
if (oldValue) {
|
||||
oldValueAtom = oldValue->GetAsAtom();
|
||||
} else {
|
||||
// If there is no old value, get the value of the uninitialized
|
||||
// attribute that was swapped with aParsedValue.
|
||||
oldValueAtom = aParsedValue.GetAsAtom();
|
||||
}
|
||||
RefPtr<nsAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
|
||||
nsAutoString ns;
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
|
||||
|
||||
LifecycleCallbackArgs args = {nsDependentAtomString(aName),
|
||||
aModType == MutationEvent_Binding::ADDITION
|
||||
? VoidString()
|
||||
: nsDependentAtomString(oldValueAtom),
|
||||
nsDependentAtomString(newValueAtom),
|
||||
(ns.IsEmpty() ? VoidString() : ns)};
|
||||
|
||||
nsContentUtils::EnqueueLifecycleCallback(
|
||||
Document::eAttributeChanged, this, &args, nullptr, definition);
|
||||
}
|
||||
RefPtr<nsAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
|
||||
nsAutoString ns;
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
|
||||
|
||||
LifecycleCallbackArgs args = {nsDependentAtomString(aName),
|
||||
aModType == MutationEvent_Binding::ADDITION
|
||||
? VoidString()
|
||||
: nsDependentAtomString(oldValueAtom),
|
||||
nsDependentAtomString(newValueAtom),
|
||||
(ns.IsEmpty() ? VoidString() : ns)};
|
||||
|
||||
nsContentUtils::EnqueueLifecycleCallback(Document::eAttributeChanged, this,
|
||||
&args, nullptr, definition);
|
||||
}
|
||||
|
||||
if (aCallAfterSetAttr) {
|
||||
|
@ -2523,19 +2525,22 @@ void Element::PostIdMaybeChange(int32_t aNamespaceID, nsAtom* aName,
|
|||
nsresult Element::OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify) {
|
||||
// Only custom element which is in `custom` state could get the
|
||||
// CustomElementDefinition.
|
||||
CustomElementDefinition* definition = GetCustomElementDefinition();
|
||||
if (definition && definition->IsInObservedAttributeList(aName)) {
|
||||
nsAutoString ns;
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
|
||||
const CustomElementData* data = GetCustomElementData();
|
||||
if (data && data->mState == CustomElementData::State::eCustom) {
|
||||
CustomElementDefinition* definition = data->GetCustomElementDefinition();
|
||||
MOZ_ASSERT(definition, "Should have a valid CustomElementDefinition");
|
||||
|
||||
nsAutoString value(aValue.String());
|
||||
LifecycleCallbackArgs args = {nsDependentAtomString(aName), value, value,
|
||||
(ns.IsEmpty() ? VoidString() : ns)};
|
||||
if (definition->IsInObservedAttributeList(aName)) {
|
||||
nsAutoString ns;
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
|
||||
|
||||
nsContentUtils::EnqueueLifecycleCallback(Document::eAttributeChanged, this,
|
||||
&args, nullptr, definition);
|
||||
nsAutoString value(aValue.String());
|
||||
LifecycleCallbackArgs args = {nsDependentAtomString(aName), value, value,
|
||||
(ns.IsEmpty() ? VoidString() : ns)};
|
||||
|
||||
nsContentUtils::EnqueueLifecycleCallback(
|
||||
Document::eAttributeChanged, this, &args, nullptr, definition);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -2631,20 +2636,23 @@ nsresult Element::UnsetAttr(int32_t aNameSpaceID, nsAtom* aName, bool aNotify) {
|
|||
|
||||
PostIdMaybeChange(aNameSpaceID, aName, nullptr);
|
||||
|
||||
CustomElementDefinition* definition = GetCustomElementDefinition();
|
||||
// Only custom element which is in `custom` state could get the
|
||||
// CustomElementDefinition.
|
||||
if (definition && definition->IsInObservedAttributeList(aName)) {
|
||||
nsAutoString ns;
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
|
||||
const CustomElementData* data = GetCustomElementData();
|
||||
if (data && data->mState == CustomElementData::State::eCustom) {
|
||||
CustomElementDefinition* definition = data->GetCustomElementDefinition();
|
||||
MOZ_ASSERT(definition, "Should have a valid CustomElementDefinition");
|
||||
|
||||
RefPtr<nsAtom> oldValueAtom = oldValue.GetAsAtom();
|
||||
LifecycleCallbackArgs args = {
|
||||
nsDependentAtomString(aName), nsDependentAtomString(oldValueAtom),
|
||||
VoidString(), (ns.IsEmpty() ? VoidString() : ns)};
|
||||
if (definition->IsInObservedAttributeList(aName)) {
|
||||
nsAutoString ns;
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
|
||||
|
||||
nsContentUtils::EnqueueLifecycleCallback(Document::eAttributeChanged, this,
|
||||
&args, nullptr, definition);
|
||||
RefPtr<nsAtom> oldValueAtom = oldValue.GetAsAtom();
|
||||
LifecycleCallbackArgs args = {
|
||||
nsDependentAtomString(aName), nsDependentAtomString(oldValueAtom),
|
||||
VoidString(), (ns.IsEmpty() ? VoidString() : ns)};
|
||||
|
||||
nsContentUtils::EnqueueLifecycleCallback(
|
||||
Document::eAttributeChanged, this, &args, nullptr, definition);
|
||||
}
|
||||
}
|
||||
|
||||
rv = AfterSetAttr(aNameSpaceID, aName, nullptr, &oldValue, nullptr, aNotify);
|
||||
|
|
|
@ -50,6 +50,39 @@ test_with_window(function (contentWindow) {
|
|||
assert_connected_log_entry(log[5], element2);
|
||||
}, 'Upgrading a custom element must invoke attributeChangedCallback and connectedCallback before start upgrading another element');
|
||||
|
||||
test_with_window(function (contentWindow) {
|
||||
const contentDocument = contentWindow.document;
|
||||
contentDocument.write('<test-element>');
|
||||
|
||||
const element = contentDocument.querySelector('test-element');
|
||||
assert_equals(Object.getPrototypeOf(element), contentWindow.HTMLElement.prototype);
|
||||
|
||||
let log = [];
|
||||
class TestElement extends contentWindow.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.id = "foo";
|
||||
this.setAttribute('id', 'foo');
|
||||
this.removeAttribute('id');
|
||||
this.style.fontSize = '10px';
|
||||
log.push(create_constructor_log(this));
|
||||
}
|
||||
connectedCallback(...args) {
|
||||
log.push(create_connected_callback_log(this, ...args));
|
||||
}
|
||||
attributeChangedCallback(...args) {
|
||||
log.push(create_attribute_changed_callback_log(this, ...args));
|
||||
}
|
||||
static get observedAttributes() { return ['id', 'style']; }
|
||||
}
|
||||
contentWindow.customElements.define('test-element', TestElement);
|
||||
assert_equals(Object.getPrototypeOf(element), TestElement.prototype);
|
||||
|
||||
assert_equals(log.length, 2);
|
||||
assert_constructor_log_entry(log[0], element);
|
||||
assert_connected_log_entry(log[1], element);
|
||||
}, 'Upgrading a custom element must not invoke attributeChangedCallback for the attribute that is changed during upgrading');
|
||||
|
||||
test_with_window(function (contentWindow) {
|
||||
const contentDocument = contentWindow.document;
|
||||
contentDocument.write('<test-element id="first-element">');
|
||||
|
|
Загрузка…
Ссылка в новой задаче