ladybird/Libraries/LibWeb/DOM/Attr.cpp
Andreas Kling b6bef6b688 Libraries: Use UTF-16 for JS-visible runtime strings
Produce JS-visible string results as UTF-16 at their source, including
numeric formatting, BigInt and BigFraction formatting, URI encoding,
console formatting, parser errors, regular expression errors, Intl and
Temporal records, LibUnicode locale boundaries, and LibWeb bindings.

Handle fractional radix formatting through the UTF-16 builder view.
2026-06-22 19:51:25 +02:00

142 lines
5.3 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
* Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2025, Miguel Sacristán Izcue <miguel_tete17@hotmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/Attr.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/DOM/Attr.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/Element.h>
#include <LibWeb/DOM/MutationType.h>
#include <LibWeb/DOM/StaticNodeList.h>
#include <LibWeb/HTML/CustomElements/CustomElementReactionNames.h>
#include <LibWeb/TrustedTypes/TrustedTypePolicy.h>
namespace Web::DOM {
GC_DEFINE_ALLOCATOR(Attr);
GC::Ref<Attr> Attr::create(Document& document, FlyString local_name, String value, Element* owner_element)
{
return document.realm().create<Attr>(document, QualifiedName(move(local_name), Optional<FlyString> {}, Optional<FlyString> {}), move(value), owner_element);
}
GC::Ref<Attr> Attr::create(Document& document, QualifiedName qualified_name, String value, Element* owner_element)
{
return document.realm().create<Attr>(document, move(qualified_name), move(value), owner_element);
}
GC::Ref<Attr> Attr::clone(Document& document) const
{
return realm().create<Attr>(document, m_qualified_name, m_value, nullptr);
}
Attr::Attr(Document& document, QualifiedName qualified_name, String value, Element* owner_element)
: Node(document, NodeType::ATTRIBUTE_NODE)
, m_qualified_name(move(qualified_name))
, m_value(move(value))
, m_owner_element(owner_element)
{
}
void Attr::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(Attr);
Base::initialize(realm);
}
void Attr::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_owner_element);
}
Element* Attr::owner_element()
{
return m_owner_element.ptr();
}
Element const* Attr::owner_element() const
{
return m_owner_element.ptr();
}
void Attr::set_owner_element(Element* owner_element)
{
m_owner_element = owner_element;
}
// https://dom.spec.whatwg.org/#set-an-existing-attribute-value
WebIDL::ExceptionOr<void> Attr::set_value(String value)
{
// 1. If attributes element is null, then set attributes value to value and return.
if (!owner_element()) {
m_value = move(value);
return {};
}
// 2. Let element be attributes element.
auto const& element = *owner_element();
// 3. Let verifiedValue be the result of calling get Trusted Types-compliant attribute value with
// attributes local name, attributes namespace, element, and value.
auto const verified_value = TRY(TrustedTypes::get_trusted_types_compliant_attribute_value(
local_name(),
namespace_uri().has_value() ? Utf16String::from_utf8(namespace_uri().value()) : Optional<Utf16String>(),
element,
Utf16String::from_utf8(value)));
// 4. If attributes element is null, then set attributes value to verifiedValue, and return.
if (!owner_element()) {
m_value = verified_value.to_utf8_but_should_be_ported_to_utf16();
return {};
}
// 5. Change attribute to verifiedValue.
change_attribute(verified_value.to_utf8_but_should_be_ported_to_utf16());
return {};
}
// https://dom.spec.whatwg.org/#concept-element-attributes-change
void Attr::change_attribute(String value)
{
// 1. Let oldValue be attributes value.
auto old_value = move(m_value);
// 2. Set attributes value to value.
m_value = move(value);
// 3. Handle attribute changes for attribute with attributes element, oldValue, and value.
handle_attribute_changes(*owner_element(), old_value, m_value);
}
// https://dom.spec.whatwg.org/#handle-attribute-changes
void Attr::handle_attribute_changes(Element& element, Optional<String> const& old_value, Optional<String> const& new_value)
{
// 1. Queue a mutation record of "attributes" for element with attributes local name, attributes namespace, oldValue, « », « », null, and null.
element.queue_mutation_record(MutationType::attributes, local_name(), namespace_uri(), old_value, {}, {}, nullptr, nullptr);
// 2. If element is custom, then enqueue a custom element callback reaction with element, callback name "attributeChangedCallback",
// and « attributes local name, oldValue, newValue, attributes namespace ».
if (element.is_custom()) {
auto& vm = this->vm();
GC::RootVector<JS::Value> arguments;
arguments.append(JS::PrimitiveString::create(vm, Utf16FlyString::from_utf8(local_name())));
arguments.append(!old_value.has_value() ? JS::js_null() : JS::PrimitiveString::create(vm, Utf16String::from_utf8(old_value.value())));
arguments.append(!new_value.has_value() ? JS::js_null() : JS::PrimitiveString::create(vm, Utf16String::from_utf8(new_value.value())));
arguments.append(!namespace_uri().has_value() ? JS::js_null() : JS::PrimitiveString::create(vm, Utf16FlyString::from_utf8(namespace_uri().value())));
element.enqueue_a_custom_element_callback_reaction(HTML::CustomElementReactionNames::attributeChangedCallback, move(arguments));
}
// 3. Run the attribute change steps with element, attributes local name, oldValue, newValue, and attributes namespace.
element.run_attribute_change_steps(local_name(), old_value, new_value, namespace_uri());
}
}