1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-28 11:37:45 +00:00

LibWeb: Port Element interface from DeprecatedString

This is the last IDL interface which was using DeprecatedString! :^)
This commit is contained in:
Shannon Booth 2023-10-06 07:43:52 +13:00 committed by Andreas Kling
parent 274e0f4988
commit 4321606bba
12 changed files with 295 additions and 251 deletions

View file

@ -170,7 +170,7 @@ DeprecatedString Element::get_attribute_value(StringView local_name, DeprecatedF
}
// https://dom.spec.whatwg.org/#dom-element-getattributenode
JS::GCPtr<Attr> Element::get_attribute_node(DeprecatedFlyString const& name) const
JS::GCPtr<Attr> Element::get_attribute_node(FlyString const& name) const
{
// The getAttributeNode(qualifiedName) method steps are to return the result of getting an attribute given qualifiedName and this.
return m_attributes->get_attribute(name);
@ -258,13 +258,17 @@ WebIDL::ExceptionOr<QualifiedName> validate_and_extract(JS::Realm& realm, Deprec
}
// https://dom.spec.whatwg.org/#dom-element-setattributens
WebIDL::ExceptionOr<void> Element::set_attribute_ns(DeprecatedFlyString const& namespace_, DeprecatedFlyString const& qualified_name, DeprecatedString const& value)
WebIDL::ExceptionOr<void> Element::set_attribute_ns(Optional<String> const& namespace_, FlyString const& qualified_name, FlyString const& value)
{
DeprecatedFlyString deprecated_namespace;
if (namespace_.has_value())
deprecated_namespace = namespace_->to_deprecated_string();
// 1. Let namespace, prefix, and localName be the result of passing namespace and qualifiedName to validate and extract.
auto extracted_qualified_name = TRY(validate_and_extract(realm(), namespace_, qualified_name));
auto extracted_qualified_name = TRY(validate_and_extract(realm(), deprecated_namespace, qualified_name.to_deprecated_fly_string()));
// 2. Set an attribute value for this using localName, value, and also prefix and namespace.
set_attribute_value(extracted_qualified_name.local_name().to_deprecated_fly_string(), value, extracted_qualified_name.deprecated_prefix(), extracted_qualified_name.deprecated_namespace_());
set_attribute_value(extracted_qualified_name.local_name().to_deprecated_fly_string(), value.to_deprecated_fly_string(), extracted_qualified_name.deprecated_prefix(), extracted_qualified_name.deprecated_namespace_());
return {};
}
@ -319,18 +323,22 @@ bool Element::has_attribute(StringView name) const
}
// https://dom.spec.whatwg.org/#dom-element-hasattributens
bool Element::has_attribute_ns(StringView namespace_, StringView name) const
bool Element::has_attribute_ns(Optional<String> const& namespace_, StringView name) const
{
StringView namespace_view;
if (namespace_.has_value())
namespace_view = namespace_->bytes_as_string_view();
// 1. If namespace is the empty string, then set it to null.
if (namespace_.is_empty())
namespace_ = {};
if (namespace_view.is_empty())
namespace_view = {};
// 2. Return true if this has an attribute whose namespace is namespace and local name is localName; otherwise false.
return m_attributes->get_attribute_ns(namespace_, name) != nullptr;
return m_attributes->get_attribute_ns(namespace_view, name) != nullptr;
}
// https://dom.spec.whatwg.org/#dom-element-toggleattribute
WebIDL::ExceptionOr<bool> Element::toggle_attribute(DeprecatedFlyString const& name, Optional<bool> force)
WebIDL::ExceptionOr<bool> Element::toggle_attribute(FlyString const& name, Optional<bool> force)
{
// 1. If qualifiedName does not match the Name production in XML, then throw an "InvalidCharacterError" DOMException.
// FIXME: Proper name validation
@ -349,7 +357,7 @@ WebIDL::ExceptionOr<bool> Element::toggle_attribute(DeprecatedFlyString const& n
// 1. If force is not given or is true, create an attribute whose local name is qualifiedName, value is the empty
// string, and node document is thiss node document, then append this attribute to this, and then return true.
if (!force.has_value() || force.value()) {
auto new_attribute = Attr::create(document(), MUST(String::from_deprecated_string(insert_as_lowercase ? name.to_lowercase() : name)), String {});
auto new_attribute = Attr::create(document(), insert_as_lowercase ? MUST(Infra::to_ascii_lowercase(name)) : name.to_string(), String {});
m_attributes->append_attribute(new_attribute);
return true;
@ -370,13 +378,13 @@ WebIDL::ExceptionOr<bool> Element::toggle_attribute(DeprecatedFlyString const& n
}
// https://dom.spec.whatwg.org/#dom-element-getattributenames
Vector<DeprecatedString> Element::get_attribute_names() const
Vector<String> Element::get_attribute_names() const
{
// The getAttributeNames() method steps are to return the qualified names of the attributes in thiss attribute list, in order; otherwise a new list.
Vector<DeprecatedString> names;
Vector<String> names;
for (size_t i = 0; i < m_attributes->length(); ++i) {
auto const* attribute = m_attributes->item(i);
names.append(attribute->name().to_deprecated_fly_string());
names.append(attribute->name().to_string());
}
return names;
}
@ -733,9 +741,10 @@ WebIDL::ExceptionOr<void> Element::set_inner_html(StringView markup)
}
// https://w3c.github.io/DOM-Parsing/#dom-innerhtml-innerhtml
WebIDL::ExceptionOr<DeprecatedString> Element::inner_html() const
WebIDL::ExceptionOr<String> Element::inner_html() const
{
return serialize_fragment(DOMParsing::RequireWellFormed::Yes);
auto inner_html = TRY(serialize_fragment(DOMParsing::RequireWellFormed::Yes));
return MUST(String::from_deprecated_string(inner_html));
}
bool Element::is_focused() const
@ -805,7 +814,7 @@ void Element::make_html_uppercased_qualified_name()
{
// This is allowed by the spec: "User agents could optimize qualified name and HTML-uppercased qualified name by storing them in internal slots."
if (namespace_() == Namespace::HTML && document().document_type() == Document::Type::HTML)
m_html_uppercased_qualified_name = DeprecatedString(qualified_name()).to_uppercase();
m_html_uppercased_qualified_name = MUST(Infra::to_ascii_uppercase(qualified_name()));
else
m_html_uppercased_qualified_name = qualified_name();
}
@ -1359,7 +1368,7 @@ bool Element::is_actually_disabled() const
}
// https://w3c.github.io/DOM-Parsing/#dom-element-insertadjacenthtml
WebIDL::ExceptionOr<void> Element::insert_adjacent_html(DeprecatedString position, DeprecatedString text)
WebIDL::ExceptionOr<void> Element::insert_adjacent_html(String const& position, String const& text)
{
JS::GCPtr<Node> context;
// 1. Use the first matching item from this list:
@ -1475,24 +1484,24 @@ WebIDL::ExceptionOr<JS::GCPtr<Node>> Element::insert_adjacent(DeprecatedString c
}
// https://dom.spec.whatwg.org/#dom-element-insertadjacentelement
WebIDL::ExceptionOr<JS::GCPtr<Element>> Element::insert_adjacent_element(DeprecatedString const& where, JS::NonnullGCPtr<Element> element)
WebIDL::ExceptionOr<JS::GCPtr<Element>> Element::insert_adjacent_element(String const& where, JS::NonnullGCPtr<Element> element)
{
// The insertAdjacentElement(where, element) method steps are to return the result of running insert adjacent, give this, where, and element.
auto returned_node = TRY(insert_adjacent(where, move(element)));
auto returned_node = TRY(insert_adjacent(where.to_deprecated_string(), move(element)));
if (!returned_node)
return JS::GCPtr<Element> { nullptr };
return JS::GCPtr<Element> { verify_cast<Element>(*returned_node) };
}
// https://dom.spec.whatwg.org/#dom-element-insertadjacenttext
WebIDL::ExceptionOr<void> Element::insert_adjacent_text(DeprecatedString const& where, DeprecatedString const& data)
WebIDL::ExceptionOr<void> Element::insert_adjacent_text(String const& where, String const& data)
{
// 1. Let text be a new Text node whose data is data and node document is thiss node document.
auto text = heap().allocate<DOM::Text>(realm(), document(), MUST(String::from_deprecated_string(data)));
auto text = heap().allocate<DOM::Text>(realm(), document(), data);
// 2. Run insert adjacent, given this, where, and text.
// Spec Note: This method returns nothing because it existed before we had a chance to design it.
(void)TRY(insert_adjacent(where, text));
(void)TRY(insert_adjacent(where.to_deprecated_string(), text));
return {};
}
@ -1859,9 +1868,9 @@ void Element::setup_custom_element_from_constructor(HTML::CustomElementDefinitio
m_is_value = is_value;
}
void Element::set_prefix(DeprecatedFlyString const& value)
void Element::set_prefix(Optional<FlyString> value)
{
m_qualified_name.set_prefix(MUST(FlyString::from_deprecated_fly_string(value)));
m_qualified_name.set_prefix(move(value));
}
void Element::for_each_attribute(Function<void(DeprecatedFlyString const&, DeprecatedString const&)> callback) const

View file

@ -74,30 +74,30 @@ class Element
public:
virtual ~Element() override;
DeprecatedFlyString qualified_name() const { return m_qualified_name.as_string().to_deprecated_fly_string(); }
DeprecatedString const& html_uppercased_qualified_name() const { return m_html_uppercased_qualified_name; }
FlyString const& qualified_name() const { return m_qualified_name.as_string(); }
FlyString const& html_uppercased_qualified_name() const { return m_html_uppercased_qualified_name; }
virtual FlyString node_name() const final { return MUST(FlyString::from_deprecated_fly_string(html_uppercased_qualified_name())); }
virtual FlyString node_name() const final { return html_uppercased_qualified_name(); }
DeprecatedFlyString deprecated_local_name() const { return m_qualified_name.local_name().to_deprecated_fly_string(); }
FlyString const& local_name() const { return m_qualified_name.local_name(); }
// NOTE: This is for the JS bindings
FlyString tag_name() const { return MUST(FlyString::from_deprecated_fly_string(html_uppercased_qualified_name())); }
DeprecatedString const& deprecated_tag_name() const { return html_uppercased_qualified_name(); }
FlyString const& tag_name() const { return html_uppercased_qualified_name(); }
DeprecatedString deprecated_tag_name() const { return html_uppercased_qualified_name().to_deprecated_fly_string(); }
Optional<FlyString> const& prefix() const { return m_qualified_name.prefix(); }
DeprecatedFlyString deprecated_prefix() const { return m_qualified_name.deprecated_prefix(); }
void set_prefix(DeprecatedFlyString const& value);
void set_prefix(Optional<FlyString> value);
DeprecatedFlyString namespace_() const { return m_qualified_name.deprecated_namespace_(); }
// NOTE: This is for the JS bindings
DeprecatedFlyString namespace_uri() const { return namespace_(); }
Optional<FlyString> const& namespace_uri() const { return m_qualified_name.namespace_(); }
// FIXME: This should be taking a 'FlyString const&'
// FIXME: This should be taking a 'FlyString const&' / 'Optional<FlyString> const&'
bool has_attribute(StringView name) const;
bool has_attribute_ns(StringView namespace_, StringView name) const;
bool has_attribute_ns(Optional<String> const& namespace_, StringView name) const;
bool has_attributes() const;
// FIXME: This should be taking a 'FlyString const&'
@ -111,7 +111,13 @@ public:
WebIDL::ExceptionOr<void> set_attribute(DeprecatedFlyString const& name, DeprecatedString const& value);
WebIDL::ExceptionOr<void> set_attribute(DeprecatedFlyString const& name, Optional<String> const& value);
WebIDL::ExceptionOr<void> set_attribute_ns(DeprecatedFlyString const& namespace_, DeprecatedFlyString const& qualified_name, DeprecatedString const& value);
WebIDL::ExceptionOr<void> set_attribute(FlyString const& name, Optional<String> const& value)
{
return set_attribute(name.to_deprecated_fly_string(), value);
}
// FIXME: This should be taking an Optional<FlyString>
WebIDL::ExceptionOr<void> set_attribute_ns(Optional<String> const& namespace_, FlyString const& qualified_name, FlyString const& value);
void set_attribute_value(DeprecatedFlyString const& local_name, DeprecatedString const& value, DeprecatedFlyString const& prefix = {}, DeprecatedFlyString const& namespace_ = {});
WebIDL::ExceptionOr<JS::GCPtr<Attr>> set_attribute_node(Attr&);
WebIDL::ExceptionOr<JS::GCPtr<Attr>> set_attribute_node_ns(Attr&);
@ -119,12 +125,12 @@ public:
// FIXME: This should take a 'FlyString cosnt&'
void remove_attribute(StringView name);
WebIDL::ExceptionOr<bool> toggle_attribute(DeprecatedFlyString const& name, Optional<bool> force);
WebIDL::ExceptionOr<bool> toggle_attribute(FlyString const& name, Optional<bool> force);
size_t attribute_list_size() const;
NamedNodeMap const* attributes() const { return m_attributes.ptr(); }
Vector<DeprecatedString> get_attribute_names() const;
Vector<String> get_attribute_names() const;
JS::GCPtr<Attr> get_attribute_node(DeprecatedFlyString const& name) const;
JS::GCPtr<Attr> get_attribute_node(FlyString const& name) const;
DOMTokenList* class_list();
@ -189,10 +195,10 @@ public:
CSS::CSSStyleDeclaration* style_for_bindings();
WebIDL::ExceptionOr<DeprecatedString> inner_html() const;
WebIDL::ExceptionOr<String> inner_html() const;
WebIDL::ExceptionOr<void> set_inner_html(StringView);
WebIDL::ExceptionOr<void> insert_adjacent_html(DeprecatedString position, DeprecatedString text);
WebIDL::ExceptionOr<void> insert_adjacent_html(String const& position, String const& text);
bool is_focused() const;
bool is_active() const;
@ -244,20 +250,20 @@ public:
bool is_actually_disabled() const;
WebIDL::ExceptionOr<JS::GCPtr<Element>> insert_adjacent_element(DeprecatedString const& where, JS::NonnullGCPtr<Element> element);
WebIDL::ExceptionOr<void> insert_adjacent_text(DeprecatedString const& where, DeprecatedString const& data);
WebIDL::ExceptionOr<JS::GCPtr<Element>> insert_adjacent_element(String const& where, JS::NonnullGCPtr<Element> element);
WebIDL::ExceptionOr<void> insert_adjacent_text(String const& where, String const& data);
// https://w3c.github.io/csswg-drafts/cssom-view-1/#dom-element-scrollintoview
ErrorOr<void> scroll_into_view(Optional<Variant<bool, ScrollIntoViewOptions>> = {});
// https://www.w3.org/TR/wai-aria-1.2/#ARIAMixin
#define ARIA_IMPL(name, attribute) \
DeprecatedString name() const override \
Optional<String> name() const override \
{ \
return deprecated_get_attribute(attribute); \
return get_attribute(attribute); \
} \
\
WebIDL::ExceptionOr<void> set_##name(DeprecatedString const& value) override \
WebIDL::ExceptionOr<void> set_##name(Optional<String> const& value) override \
{ \
TRY(set_attribute(attribute, value)); \
return {}; \
@ -387,7 +393,7 @@ private:
void enqueue_an_element_on_the_appropriate_element_queue();
QualifiedName m_qualified_name;
DeprecatedString m_html_uppercased_qualified_name;
FlyString m_html_uppercased_qualified_name;
JS::GCPtr<NamedNodeMap> m_attributes;
Vector<AttributeChangeSteps> m_attribute_change_steps;

View file

@ -21,14 +21,14 @@ dictionary ScrollIntoViewOptions : ScrollOptions {
};
// https://dom.spec.whatwg.org/#element
[Exposed=Window, UseDeprecatedAKString]
[Exposed=Window]
interface Element : Node {
readonly attribute DOMString? namespaceURI;
[ImplementedAs=deprecated_prefix] readonly attribute DOMString? prefix;
[ImplementedAs=deprecated_local_name] readonly attribute DOMString localName;
[ImplementedAs=deprecated_tag_name] readonly attribute DOMString tagName;
readonly attribute DOMString? prefix;
readonly attribute DOMString localName;
readonly attribute DOMString tagName;
[ImplementedAs=deprecated_get_attribute] DOMString? getAttribute(DOMString qualifiedName);
DOMString? getAttribute(DOMString qualifiedName);
[CEReactions] undefined setAttribute(DOMString qualifiedName, DOMString value);
[CEReactions] undefined setAttributeNS(DOMString? namespace , DOMString qualifiedName , DOMString value);
[CEReactions] Attr? setAttributeNode(Attr attr);

View file

@ -581,7 +581,10 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Element>> create_element(Document& document
return JS::throw_completion(WebIDL::NotSupportedError::create(realm, "Synchronously created custom element must have the same local name that element creation was invoked with"_fly_string));
// 10. Set results namespace prefix to prefix.
element->set_prefix(prefix);
if (prefix.is_null())
element->set_prefix({});
else
element->set_prefix(MUST(FlyString::from_deprecated_fly_string(prefix)));
// 11. Set results is value to null.
element->set_is_value(Optional<String> {});

View file

@ -1786,17 +1786,19 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
// process its IDREFs in the order they occur:
// - or, if computing a description, and the current node has an aria-describedby attribute that contains at least one valid IDREF, and the current node is not already part of an aria-describedby traversal,
// process its IDREFs in the order they occur:
if ((target == NameOrDescription::Name && Node::first_valid_id(element->aria_labelled_by(), document).has_value())
|| (target == NameOrDescription::Description && Node::first_valid_id(element->aria_described_by(), document).has_value())) {
auto aria_labelled_by = element->aria_labelled_by();
auto aria_described_by = element->aria_described_by();
if ((target == NameOrDescription::Name && aria_labelled_by.has_value() && Node::first_valid_id(aria_labelled_by->to_deprecated_string(), document).has_value())
|| (target == NameOrDescription::Description && aria_described_by.has_value() && Node::first_valid_id(aria_described_by->to_deprecated_string(), document).has_value())) {
// i. Set the accumulated text to the empty string.
total_accumulated_text.clear();
Vector<StringView> id_list;
if (target == NameOrDescription::Name) {
id_list = element->aria_labelled_by().split_view(Infra::is_ascii_whitespace);
id_list = aria_labelled_by->bytes_as_string_view().split_view_if(Infra::is_ascii_whitespace);
} else {
id_list = element->aria_described_by().split_view(Infra::is_ascii_whitespace);
id_list = aria_described_by->bytes_as_string_view().split_view_if(Infra::is_ascii_whitespace);
}
// ii. For each IDREF:
for (auto const& id_ref : id_list) {
@ -1817,10 +1819,10 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
return total_accumulated_text.to_string();
}
// C. Otherwise, if computing a name, and if the current node has an aria-label attribute whose value is not the empty string, nor, when trimmed of white space, is not the empty string:
if (target == NameOrDescription::Name && !element->aria_label().is_empty() && !element->aria_label().trim_whitespace().is_empty()) {
if (target == NameOrDescription::Name && element->aria_label().has_value() && !element->aria_label()->is_empty() && !element->aria_label()->bytes_as_string_view().is_whitespace()) {
// TODO: - If traversal of the current node is due to recursion and the current node is an embedded control as defined in step 2E, ignore aria-label and skip to rule 2E.
// - Otherwise, return the value of aria-label.
return String::from_deprecated_string(element->aria_label());
return element->aria_label().value();
}
// TODO: D. Otherwise, if the current node's native markup provides an attribute (e.g. title) or element (e.g. HTML label) that defines a text alternative,
// return that alternative in the form of a flat string as defined by the host language, unless the element is marked as presentational (role="presentation" or role="none").
@ -1908,29 +1910,33 @@ ErrorOr<String> Node::accessible_description(Document const& document) const
{
// If aria-describedby is present, user agents MUST compute the accessible description by concatenating the text alternatives for elements referenced by an aria-describedby attribute on the current element.
// The text alternatives for the referenced elements are computed using a number of methods, outlined below in the section titled Accessible Name and Description Computation.
if (is_element()) {
HashTable<i32> visited_nodes;
StringBuilder builder;
auto const* element = static_cast<Element const*>(this);
auto id_list = element->aria_described_by().split_view(Infra::is_ascii_whitespace);
for (auto const& id : id_list) {
if (auto description_element = document.get_element_by_id(id)) {
auto description = TRY(
description_element->name_or_description(NameOrDescription::Description, document,
visited_nodes));
if (!description.is_empty()) {
if (builder.is_empty()) {
builder.append(description);
} else {
builder.append(" "sv);
builder.append(description);
}
if (!is_element())
return String {};
auto const* element = static_cast<Element const*>(this);
auto described_by = element->aria_described_by();
if (!described_by.has_value())
return String {};
HashTable<i32> visited_nodes;
StringBuilder builder;
auto id_list = described_by->bytes_as_string_view().split_view_if(Infra::is_ascii_whitespace);
for (auto const& id : id_list) {
if (auto description_element = document.get_element_by_id(id)) {
auto description = TRY(
description_element->name_or_description(NameOrDescription::Description, document,
visited_nodes));
if (!description.is_empty()) {
if (builder.is_empty()) {
builder.append(description);
} else {
builder.append(" "sv);
builder.append(description);
}
}
}
return builder.to_string();
}
return String {};
return builder.to_string();
}
Optional<StringView> Node::first_valid_id(DeprecatedString const& value, Document const& document)

View file

@ -146,20 +146,20 @@ JS::NonnullGCPtr<HTMLCollection> ParentNode::get_elements_by_tag_name(Deprecated
// 2. Otherwise, if roots node document is an HTML document, return a HTMLCollection rooted at root, whose filter matches the following descendant elements:
if (root().document().document_type() == Document::Type::HTML) {
auto qualified_name_in_ascii_lowercase = qualified_name.to_lowercase();
auto qualified_name_in_ascii_lowercase = MUST(FlyString::from_deprecated_fly_string(qualified_name.to_lowercase()));
return HTMLCollection::create(*this, HTMLCollection::Scope::Descendants, [qualified_name, qualified_name_in_ascii_lowercase](Element const& element) {
// - Whose namespace is the HTML namespace and whose qualified name is qualifiedName, in ASCII lowercase.
if (element.namespace_() == Namespace::HTML)
return element.qualified_name() == qualified_name_in_ascii_lowercase;
// - Whose namespace is not the HTML namespace and whose qualified name is qualifiedName.
return element.qualified_name() == qualified_name;
return element.qualified_name().to_deprecated_fly_string() == qualified_name;
});
}
// 3. Otherwise, return a HTMLCollection rooted at root, whose filter matches descendant elements whose qualified name is qualifiedName.
return HTMLCollection::create(*this, HTMLCollection::Scope::Descendants, [qualified_name](Element const& element) {
return element.qualified_name() == qualified_name;
return element.qualified_name().to_deprecated_fly_string() == qualified_name;
});
}