1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 02:07:35 +00:00

LibWeb: Reimplement Element attribute related methods with NamedNodeMap

This commit is contained in:
Timothy Flynn 2021-10-16 16:16:57 -04:00 committed by Linus Groh
parent 2a3ac02ef1
commit c62b70d88f
2 changed files with 44 additions and 36 deletions

View file

@ -38,6 +38,7 @@ namespace Web::DOM {
Element::Element(Document& document, QualifiedName qualified_name) Element::Element(Document& document, QualifiedName qualified_name)
: ParentNode(document, NodeType::ELEMENT_NODE) : ParentNode(document, NodeType::ELEMENT_NODE)
, m_qualified_name(move(qualified_name)) , m_qualified_name(move(qualified_name))
, m_attributes(NamedNodeMap::create(*this))
{ {
make_html_uppercased_qualified_name(); make_html_uppercased_qualified_name();
} }
@ -46,53 +47,60 @@ Element::~Element()
{ {
} }
Attribute* Element::find_attribute(const FlyString& name) // https://dom.spec.whatwg.org/#dom-element-getattribute
String Element::get_attribute(const FlyString& name) const
{ {
for (auto& attribute : m_attributes) { // 1. Let attr be the result of getting an attribute given qualifiedName and this.
if (attribute->name() == name) auto const* attribute = m_attributes->get_attribute(name);
return attribute;
} // 2. If attr is null, return null.
return nullptr; if (!attribute)
} return {};
const Attribute* Element::find_attribute(const FlyString& name) const // 3. Return attrs value.
{ return attribute->value();
for (auto& attribute : m_attributes) {
if (attribute->name() == name)
return attribute;
}
return nullptr;
}
String Element::attribute(const FlyString& name) const
{
if (auto* attribute = find_attribute(name))
return attribute->value();
return {};
} }
// https://dom.spec.whatwg.org/#dom-element-setattribute
ExceptionOr<void> Element::set_attribute(const FlyString& name, const String& value) ExceptionOr<void> Element::set_attribute(const FlyString& name, const String& value)
{ {
// 1. If qualifiedName does not match the Name production in XML, then throw an "InvalidCharacterError" DOMException.
// FIXME: Proper name validation // FIXME: Proper name validation
if (name.is_empty()) if (name.is_empty())
return InvalidCharacterError::create("Attribute name must not be empty"); return InvalidCharacterError::create("Attribute name must not be empty");
CSS::StyleInvalidator style_invalidator(document()); CSS::StyleInvalidator style_invalidator(document());
if (auto* attribute = find_attribute(name)) // 2. If this is in the HTML namespace and its node document is an HTML document, then set qualifiedName to qualifiedName in ASCII lowercase.
// 3. Let attribute be the first attribute in thiss attribute list whose qualified name is qualifiedName, and null otherwise.
auto* attribute = m_attributes->get_attribute(name);
// 4. If attribute is null, create an attribute whose local name is qualifiedName, value is value, and node document is thiss node document, then append this attribute to this, and then return.
if (!attribute) {
auto new_attribute = Attribute::create(document(), name, value);
m_attributes->append_attribute(new_attribute);
}
// 5. Change attribute to value.
else {
attribute->set_value(value); attribute->set_value(value);
else }
m_attributes.append(Attribute::create(document(), name, value, this));
parse_attribute(name, value); parse_attribute(name, value);
return {}; return {};
} }
// https://dom.spec.whatwg.org/#dom-element-removeattribute
void Element::remove_attribute(const FlyString& name) void Element::remove_attribute(const FlyString& name)
{ {
CSS::StyleInvalidator style_invalidator(document()); CSS::StyleInvalidator style_invalidator(document());
m_attributes->remove_attribute(name);
}
m_attributes.remove_first_matching([&](auto& attribute) { return attribute->name() == name; }); // https://dom.spec.whatwg.org/#dom-element-hasattribute
bool Element::has_attribute(const FlyString& name) const
{
return m_attributes->get_attribute(name) != nullptr;
} }
bool Element::has_class(const FlyString& class_name, CaseSensitivity case_sensitivity) const bool Element::has_class(const FlyString& class_name, CaseSensitivity case_sensitivity) const

View file

@ -13,6 +13,7 @@
#include <LibWeb/DOM/Attribute.h> #include <LibWeb/DOM/Attribute.h>
#include <LibWeb/DOM/ChildNode.h> #include <LibWeb/DOM/ChildNode.h>
#include <LibWeb/DOM/ExceptionOr.h> #include <LibWeb/DOM/ExceptionOr.h>
#include <LibWeb/DOM/NamedNodeMap.h>
#include <LibWeb/DOM/NonDocumentTypeChildNode.h> #include <LibWeb/DOM/NonDocumentTypeChildNode.h>
#include <LibWeb/DOM/ParentNode.h> #include <LibWeb/DOM/ParentNode.h>
#include <LibWeb/HTML/AttributeNames.h> #include <LibWeb/HTML/AttributeNames.h>
@ -48,13 +49,13 @@ public:
// NOTE: This is for the JS bindings // NOTE: This is for the JS bindings
const FlyString& namespace_uri() const { return namespace_(); } const FlyString& namespace_uri() const { return namespace_(); }
bool has_attribute(const FlyString& name) const { return find_attribute(name) != nullptr; } bool has_attribute(const FlyString& name) const;
bool has_attributes() const { return !m_attributes.is_empty(); } bool has_attributes() const { return !m_attributes->is_empty(); }
String attribute(const FlyString& name) const; String attribute(const FlyString& name) const { return get_attribute(name); }
String get_attribute(const FlyString& name) const { return attribute(name); } String get_attribute(const FlyString& name) const;
ExceptionOr<void> set_attribute(const FlyString& name, const String& value); ExceptionOr<void> set_attribute(const FlyString& name, const String& value);
void remove_attribute(const FlyString& name); void remove_attribute(const FlyString& name);
size_t attribute_list_size() const { return m_attributes.size(); } size_t attribute_list_size() const { return m_attributes->length(); }
DOM::ExceptionOr<bool> matches(StringView selectors) const; DOM::ExceptionOr<bool> matches(StringView selectors) const;
@ -66,8 +67,10 @@ public:
template<typename Callback> template<typename Callback>
void for_each_attribute(Callback callback) const void for_each_attribute(Callback callback) const
{ {
for (auto& attribute : m_attributes) for (size_t i = 0; i < m_attributes->length(); ++i) {
auto const* attribute = m_attributes->item(i);
callback(attribute->name(), attribute->value()); callback(attribute->name(), attribute->value());
}
} }
bool has_class(const FlyString&, CaseSensitivity = CaseSensitivity::CaseSensitive) const; bool has_class(const FlyString&, CaseSensitivity = CaseSensitivity::CaseSensitive) const;
@ -125,14 +128,11 @@ protected:
virtual void children_changed() override; virtual void children_changed() override;
private: private:
Attribute* find_attribute(const FlyString& name);
const Attribute* find_attribute(const FlyString& name) const;
void make_html_uppercased_qualified_name(); void make_html_uppercased_qualified_name();
QualifiedName m_qualified_name; QualifiedName m_qualified_name;
String m_html_uppercased_qualified_name; String m_html_uppercased_qualified_name;
Vector<NonnullRefPtr<Attribute>> m_attributes; NonnullRefPtr<NamedNodeMap> m_attributes;
RefPtr<CSS::CSSStyleDeclaration> m_inline_style; RefPtr<CSS::CSSStyleDeclaration> m_inline_style;