mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-26 01:35:08 +02:00
Previously, the LibWeb bindings generator would output multiple per interface files like Prototype/Constructor/Namespace/GlobalMixin depending on the contents of that IDL file. This complicates the build system as it means that it does not know what files will be generated without knowledge of the contents of that IDL file. Instead, for each IDL file only generate a single Bindings/<IDLFile>.h and Bindings/<IDLFile>.cpp.
143 lines
5.2 KiB
C++
143 lines
5.2 KiB
C++
/*
|
||
* 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 attribute’s element is null, then set attribute’s value to value and return.
|
||
if (!owner_element()) {
|
||
m_value = move(value);
|
||
return {};
|
||
}
|
||
|
||
// 2. Let element be attribute’s element.
|
||
auto const& element = *owner_element();
|
||
|
||
// 3. Let verifiedValue be the result of calling get Trusted Types-compliant attribute value with
|
||
// attribute’s local name, attribute’s 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 attribute’s element is null, then set attribute’s 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 attribute’s value.
|
||
auto old_value = move(m_value);
|
||
|
||
// 2. Set attribute’s value to value.
|
||
m_value = move(value);
|
||
|
||
// 3. Handle attribute changes for attribute with attribute’s 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 attribute’s local name, attribute’s 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 « attribute’s local name, oldValue, newValue, attribute’s namespace ».
|
||
if (element.is_custom()) {
|
||
auto& vm = this->vm();
|
||
|
||
GC::RootVector<JS::Value> arguments { vm.heap() };
|
||
arguments.append(JS::PrimitiveString::create(vm, local_name()));
|
||
arguments.append(!old_value.has_value() ? JS::js_null() : JS::PrimitiveString::create(vm, old_value.value()));
|
||
arguments.append(!new_value.has_value() ? JS::js_null() : JS::PrimitiveString::create(vm, new_value.value()));
|
||
arguments.append(!namespace_uri().has_value() ? JS::js_null() : JS::PrimitiveString::create(vm, namespace_uri().value()));
|
||
|
||
element.enqueue_a_custom_element_callback_reaction(HTML::CustomElementReactionNames::attributeChangedCallback, move(arguments));
|
||
}
|
||
|
||
// 3. Run the attribute change steps with element, attribute’s local name, oldValue, newValue, and attribute’s namespace.
|
||
element.run_attribute_change_steps(local_name(), old_value, new_value, namespace_uri());
|
||
}
|
||
|
||
}
|