diff --git a/Userland/Libraries/LibWeb/DOM/Attribute.cpp b/Userland/Libraries/LibWeb/DOM/Attribute.cpp index 77b5ebb1e7..da29d7cdc0 100644 --- a/Userland/Libraries/LibWeb/DOM/Attribute.cpp +++ b/Userland/Libraries/LibWeb/DOM/Attribute.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include namespace Web::DOM { @@ -23,6 +25,11 @@ Attribute::Attribute(Document& document, FlyString local_name, String value, Ele { } +Element* Attribute::owner_element() +{ + return m_owner_element; +} + Element const* Attribute::owner_element() const { return m_owner_element; @@ -33,4 +40,33 @@ void Attribute::set_owner_element(Element const* owner_element) m_owner_element = owner_element; } +// https://dom.spec.whatwg.org/#set-an-existing-attribute-value +void Attribute::set_value(String value) +{ + // 1. If attribute’s element is null, then set attribute’s value to value. + if (!owner_element()) { + m_value = move(value); + return; + } + + // 2. Otherwise, change attribute to value. + // https://dom.spec.whatwg.org/#concept-element-attributes-change + // 1. Handle attribute changes for attribute with attribute’s element, attribute’s value, and value. + handle_attribute_changes(*owner_element(), m_value, value); + + // 2. Set attribute’s value to value. + m_value = move(value); +} + +// https://dom.spec.whatwg.org/#handle-attribute-changes +void Attribute::handle_attribute_changes(Element& element, String const& old_value, [[maybe_unused]] String const& new_value) +{ + // 1. Queue a mutation record of "attributes" for element with attribute’s local name, attribute’s namespace, oldValue, « », « », null, and null. + element.queue_mutation_record(MutationType::attributes, local_name(), namespace_uri(), old_value, StaticNodeList::create({}), StaticNodeList::create({}), nullptr, nullptr); + + // FIXME: 2. If element is custom, then enqueue a custom element callback reaction with element, callback name "attributeChangedCallback", and an argument list containing attribute’s local name, oldValue, newValue, and attribute’s namespace. + + // FIXME: 3. Run the attribute change steps with element, attribute’s local name, oldValue, newValue, and attribute’s namespace. +} + } diff --git a/Userland/Libraries/LibWeb/DOM/Attribute.h b/Userland/Libraries/LibWeb/DOM/Attribute.h index 5019a25926..1431d3083b 100644 --- a/Userland/Libraries/LibWeb/DOM/Attribute.h +++ b/Userland/Libraries/LibWeb/DOM/Attribute.h @@ -30,14 +30,17 @@ public: String const& name() const { return m_qualified_name.as_string(); } String const& value() const { return m_value; } - void set_value(String value) { m_value = move(value); } + void set_value(String value); + Element* owner_element(); Element const* owner_element() const; void set_owner_element(Element const* owner_element); // Always returns true: https://dom.spec.whatwg.org/#dom-attr-specified constexpr bool specified() const { return true; } + void handle_attribute_changes(Element&, String const& old_value, String const& new_value); + private: Attribute(Document&, FlyString local_name, String value, Element const*); diff --git a/Userland/Libraries/LibWeb/DOM/NamedNodeMap.cpp b/Userland/Libraries/LibWeb/DOM/NamedNodeMap.cpp index fe049c55c4..30f4d21574 100644 --- a/Userland/Libraries/LibWeb/DOM/NamedNodeMap.cpp +++ b/Userland/Libraries/LibWeb/DOM/NamedNodeMap.cpp @@ -154,8 +154,8 @@ ExceptionOr NamedNodeMap::set_attribute(Attribute& attribute) void NamedNodeMap::replace_attribute(Attribute& old_attribute, Attribute& new_attribute, size_t old_attribute_index) { // 1. Handle attribute changes for oldAttr with oldAttr’s element, oldAttr’s value, and newAttr’s value. - // FIXME: The steps to handle an attribute change deal with mutation records and custom element states. - // Once those are supported, implement these steps: https://dom.spec.whatwg.org/#handle-attribute-changes + VERIFY(old_attribute.owner_element()); + old_attribute.handle_attribute_changes(*old_attribute.owner_element(), old_attribute.value(), new_attribute.value()); // 2. Replace oldAttr by newAttr in oldAttr’s element’s attribute list. m_attributes.remove(old_attribute_index); @@ -172,8 +172,7 @@ void NamedNodeMap::replace_attribute(Attribute& old_attribute, Attribute& new_at void NamedNodeMap::append_attribute(Attribute& attribute) { // 1. Handle attribute changes for attribute with element, null, and attribute’s value. - // FIXME: The steps to handle an attribute change deal with mutation records and custom element states. - // Once those are supported, implement these steps: https://dom.spec.whatwg.org/#handle-attribute-changes + attribute.handle_attribute_changes(associated_element(), {}, attribute.value()); // 2. Append attribute to element’s attribute list. m_attributes.append(attribute); @@ -182,6 +181,22 @@ void NamedNodeMap::append_attribute(Attribute& attribute) attribute.set_owner_element(&associated_element()); } +// https://dom.spec.whatwg.org/#concept-element-attributes-remove +void NamedNodeMap::remove_attribute_at_index(size_t attribute_index) +{ + NonnullRefPtr attribute = m_attributes.at(attribute_index); + + // 1. Handle attribute changes for attribute with attribute’s element, attribute’s value, and null. + VERIFY(attribute->owner_element()); + attribute->handle_attribute_changes(*attribute->owner_element(), attribute->value(), {}); + + // 2. Remove attribute from attribute’s element’s attribute list. + m_attributes.remove(attribute_index); + + // 3. Set attribute’s element to null. + attribute->set_owner_element(nullptr); +} + // https://dom.spec.whatwg.org/#concept-element-attributes-remove-by-name Attribute const* NamedNodeMap::remove_attribute(StringView qualified_name) { @@ -192,7 +207,7 @@ Attribute const* NamedNodeMap::remove_attribute(StringView qualified_name) // 2. If attr is non-null, then remove attr. if (attribute) - m_attributes.remove(item_index); + remove_attribute_at_index(item_index); // 3. Return attr. return attribute; diff --git a/Userland/Libraries/LibWeb/DOM/NamedNodeMap.h b/Userland/Libraries/LibWeb/DOM/NamedNodeMap.h index 510475bcc1..c13be70230 100644 --- a/Userland/Libraries/LibWeb/DOM/NamedNodeMap.h +++ b/Userland/Libraries/LibWeb/DOM/NamedNodeMap.h @@ -55,6 +55,8 @@ private: Element& associated_element() { return ref_count_target(); } Element const& associated_element() const { return ref_count_target(); } + void remove_attribute_at_index(size_t attribute_index); + NonnullRefPtrVector m_attributes; };