mirror of
https://github.com/fergalmoran/ladybird.git
synced 2025-12-22 09:19:03 +00:00
LibWeb: Implement stub for ElementInternals
This implements a stub ElementInternals object which implements the shadowRoot getter only. Also implement attachInternals function.
This commit is contained in:
committed by
Andreas Kling
parent
ce8d3d17c4
commit
a65f1ecc37
@@ -48,6 +48,7 @@ static bool is_platform_object(Type const& type)
|
|||||||
"DocumentType"sv,
|
"DocumentType"sv,
|
||||||
"DOMRectReadOnly"sv,
|
"DOMRectReadOnly"sv,
|
||||||
"DynamicsCompressorNode"sv,
|
"DynamicsCompressorNode"sv,
|
||||||
|
"ElementInternals"sv,
|
||||||
"EventTarget"sv,
|
"EventTarget"sv,
|
||||||
"FileList"sv,
|
"FileList"sv,
|
||||||
"FontFace"sv,
|
"FontFace"sv,
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ source_set("HTML") {
|
|||||||
"Dates.cpp",
|
"Dates.cpp",
|
||||||
"DecodedImageData.cpp",
|
"DecodedImageData.cpp",
|
||||||
"DocumentState.cpp",
|
"DocumentState.cpp",
|
||||||
|
"ElementInternals.cpp",
|
||||||
"ErrorEvent.cpp",
|
"ErrorEvent.cpp",
|
||||||
"EventHandler.cpp",
|
"EventHandler.cpp",
|
||||||
"EventNames.cpp",
|
"EventNames.cpp",
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ standard_idl_files = [
|
|||||||
"//Userland/Libraries/LibWeb/HTML/DataTransfer.idl",
|
"//Userland/Libraries/LibWeb/HTML/DataTransfer.idl",
|
||||||
"//Userland/Libraries/LibWeb/HTML/DOMParser.idl",
|
"//Userland/Libraries/LibWeb/HTML/DOMParser.idl",
|
||||||
"//Userland/Libraries/LibWeb/HTML/DOMStringMap.idl",
|
"//Userland/Libraries/LibWeb/HTML/DOMStringMap.idl",
|
||||||
|
"//Userland/Libraries/LibWeb/HTML/ElementInternals.idl",
|
||||||
"//Userland/Libraries/LibWeb/HTML/ErrorEvent.idl",
|
"//Userland/Libraries/LibWeb/HTML/ErrorEvent.idl",
|
||||||
"//Userland/Libraries/LibWeb/HTML/EventSource.idl",
|
"//Userland/Libraries/LibWeb/HTML/EventSource.idl",
|
||||||
"//Userland/Libraries/LibWeb/HTML/FormDataEvent.idl",
|
"//Userland/Libraries/LibWeb/HTML/FormDataEvent.idl",
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ set(SOURCES
|
|||||||
HTML/DOMParser.cpp
|
HTML/DOMParser.cpp
|
||||||
HTML/DOMStringMap.cpp
|
HTML/DOMStringMap.cpp
|
||||||
HTML/DataTransfer.cpp
|
HTML/DataTransfer.cpp
|
||||||
|
HTML/ElementInternals.cpp
|
||||||
HTML/ErrorEvent.cpp
|
HTML/ErrorEvent.cpp
|
||||||
HTML/EventHandler.cpp
|
HTML/EventHandler.cpp
|
||||||
HTML/EventSource.cpp
|
HTML/EventSource.cpp
|
||||||
|
|||||||
@@ -405,6 +405,8 @@ protected:
|
|||||||
|
|
||||||
virtual bool id_reference_exists(String const&) const override;
|
virtual bool id_reference_exists(String const&) const override;
|
||||||
|
|
||||||
|
CustomElementState custom_element_state() const { return m_custom_element_state; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void make_html_uppercased_qualified_name();
|
void make_html_uppercased_qualified_name();
|
||||||
|
|
||||||
|
|||||||
@@ -352,6 +352,7 @@ class DecodedImageData;
|
|||||||
class DocumentState;
|
class DocumentState;
|
||||||
class DOMParser;
|
class DOMParser;
|
||||||
class DOMStringMap;
|
class DOMStringMap;
|
||||||
|
class ElementInternals;
|
||||||
class ErrorEvent;
|
class ErrorEvent;
|
||||||
class EventHandler;
|
class EventHandler;
|
||||||
class EventLoop;
|
class EventLoop;
|
||||||
|
|||||||
61
Userland/Libraries/LibWeb/HTML/ElementInternals.cpp
Normal file
61
Userland/Libraries/LibWeb/HTML/ElementInternals.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, the Ladybird developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibWeb/Bindings/ElementInternalsPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/Intrinsics.h>
|
||||||
|
#include <LibWeb/DOM/ShadowRoot.h>
|
||||||
|
#include <LibWeb/HTML/ElementInternals.h>
|
||||||
|
#include <LibWeb/HTML/HTMLElement.h>
|
||||||
|
|
||||||
|
namespace Web::HTML {
|
||||||
|
|
||||||
|
JS_DEFINE_ALLOCATOR(ElementInternals);
|
||||||
|
|
||||||
|
JS::NonnullGCPtr<ElementInternals> ElementInternals::create(JS::Realm& realm, HTMLElement& target_element)
|
||||||
|
{
|
||||||
|
return realm.heap().allocate<ElementInternals>(realm, realm, target_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementInternals::ElementInternals(JS::Realm& realm, HTMLElement& target_element)
|
||||||
|
: Bindings::PlatformObject(realm)
|
||||||
|
, m_target_element(target_element)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/#dom-elementinternals-shadowroot
|
||||||
|
JS::GCPtr<DOM::ShadowRoot> ElementInternals::shadow_root() const
|
||||||
|
{
|
||||||
|
// 1. Let target be this's target element.
|
||||||
|
auto target = m_target_element;
|
||||||
|
|
||||||
|
// 2. If target is not a shadow host, then return null.
|
||||||
|
if (!target->is_shadow_host())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// 3. Let shadow be target's shadow root.
|
||||||
|
auto shadow = target->shadow_root();
|
||||||
|
|
||||||
|
// 4. If shadow's available to element internals is false, then return null.
|
||||||
|
if (!shadow->available_to_element_internals())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// 5. Return shadow.
|
||||||
|
return shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElementInternals::initialize(JS::Realm& realm)
|
||||||
|
{
|
||||||
|
Base::initialize(realm);
|
||||||
|
WEB_SET_PROTOTYPE_FOR_INTERFACE(ElementInternals);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElementInternals::visit_edges(JS::Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_target_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
36
Userland/Libraries/LibWeb/HTML/ElementInternals.h
Normal file
36
Userland/Libraries/LibWeb/HTML/ElementInternals.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, the Ladybird developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/WeakPtr.h>
|
||||||
|
#include <LibJS/Heap/GCPtr.h>
|
||||||
|
#include <LibWeb/Bindings/PlatformObject.h>
|
||||||
|
#include <LibWeb/Forward.h>
|
||||||
|
|
||||||
|
namespace Web::HTML {
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/custom-elements.html#elementinternals
|
||||||
|
class ElementInternals final : public Bindings::PlatformObject {
|
||||||
|
WEB_PLATFORM_OBJECT(ElementInternals, Bindings::PlatformObject);
|
||||||
|
JS_DECLARE_ALLOCATOR(ElementInternals);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static JS::NonnullGCPtr<ElementInternals> create(JS::Realm&, HTMLElement& target_element);
|
||||||
|
|
||||||
|
JS::GCPtr<DOM::ShadowRoot> shadow_root() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit ElementInternals(JS::Realm&, HTMLElement& target_element);
|
||||||
|
|
||||||
|
virtual void initialize(JS::Realm&) override;
|
||||||
|
virtual void visit_edges(JS::Cell::Visitor& visitor) override;
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/custom-elements.html#internals-target
|
||||||
|
JS::NonnullGCPtr<HTMLElement> m_target_element;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
44
Userland/Libraries/LibWeb/HTML/ElementInternals.idl
Normal file
44
Userland/Libraries/LibWeb/HTML/ElementInternals.idl
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#import <DOM/ShadowRoot.idl>
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/custom-elements.html#elementinternals
|
||||||
|
[Exposed=Window]
|
||||||
|
interface ElementInternals {
|
||||||
|
// Shadow root access
|
||||||
|
readonly attribute ShadowRoot? shadowRoot;
|
||||||
|
|
||||||
|
// Form-associated custom elements
|
||||||
|
[FIXME] undefined setFormValue((File or USVString or FormData)? value,
|
||||||
|
optional (File or USVString or FormData)? state);
|
||||||
|
|
||||||
|
[FIXME] readonly attribute HTMLFormElement? form;
|
||||||
|
|
||||||
|
[FIXME] undefined setValidity(optional ValidityStateFlags flags = {},
|
||||||
|
optional DOMString message,
|
||||||
|
optional HTMLElement anchor);
|
||||||
|
[FIXME] readonly attribute boolean willValidate;
|
||||||
|
[FIXME] readonly attribute ValidityState validity;
|
||||||
|
[FIXME] readonly attribute DOMString validationMessage;
|
||||||
|
[FIXME] boolean checkValidity();
|
||||||
|
[FIXME] boolean reportValidity();
|
||||||
|
|
||||||
|
[FIXME] readonly attribute NodeList labels;
|
||||||
|
|
||||||
|
// Custom state pseudo-class
|
||||||
|
[FIXME, SameObject] readonly attribute CustomStateSet states;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Accessibility semantics
|
||||||
|
// ElementInternals includes ARIAMixin;
|
||||||
|
|
||||||
|
dictionary ValidityStateFlags {
|
||||||
|
boolean valueMissing = false;
|
||||||
|
boolean typeMismatch = false;
|
||||||
|
boolean patternMismatch = false;
|
||||||
|
boolean tooLong = false;
|
||||||
|
boolean tooShort = false;
|
||||||
|
boolean rangeUnderflow = false;
|
||||||
|
boolean rangeOverflow = false;
|
||||||
|
boolean stepMismatch = false;
|
||||||
|
boolean badInput = false;
|
||||||
|
boolean customError = false;
|
||||||
|
};
|
||||||
@@ -13,7 +13,9 @@
|
|||||||
#include <LibWeb/DOM/LiveNodeList.h>
|
#include <LibWeb/DOM/LiveNodeList.h>
|
||||||
#include <LibWeb/DOM/ShadowRoot.h>
|
#include <LibWeb/DOM/ShadowRoot.h>
|
||||||
#include <LibWeb/HTML/BrowsingContext.h>
|
#include <LibWeb/HTML/BrowsingContext.h>
|
||||||
|
#include <LibWeb/HTML/CustomElements/CustomElementDefinition.h>
|
||||||
#include <LibWeb/HTML/DOMStringMap.h>
|
#include <LibWeb/HTML/DOMStringMap.h>
|
||||||
|
#include <LibWeb/HTML/ElementInternals.h>
|
||||||
#include <LibWeb/HTML/EventHandler.h>
|
#include <LibWeb/HTML/EventHandler.h>
|
||||||
#include <LibWeb/HTML/Focus.h>
|
#include <LibWeb/HTML/Focus.h>
|
||||||
#include <LibWeb/HTML/HTMLAnchorElement.h>
|
#include <LibWeb/HTML/HTMLAnchorElement.h>
|
||||||
@@ -60,6 +62,7 @@ void HTMLElement::visit_edges(Cell::Visitor& visitor)
|
|||||||
Base::visit_edges(visitor);
|
Base::visit_edges(visitor);
|
||||||
visitor.visit(m_dataset);
|
visitor.visit(m_dataset);
|
||||||
visitor.visit(m_labels);
|
visitor.visit(m_labels);
|
||||||
|
visitor.visit(m_attached_internals);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::NonnullGCPtr<DOMStringMap> HTMLElement::dataset()
|
JS::NonnullGCPtr<DOMStringMap> HTMLElement::dataset()
|
||||||
@@ -608,6 +611,40 @@ TokenizedFeature::NoOpener HTMLElement::get_an_elements_noopener(StringView targ
|
|||||||
return TokenizedFeature::NoOpener::No;
|
return TokenizedFeature::NoOpener::No;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WebIDL::ExceptionOr<JS::NonnullGCPtr<ElementInternals>> HTMLElement::attach_internals()
|
||||||
|
{
|
||||||
|
// 1. If this's is value is not null, then throw a "NotSupportedError" DOMException.
|
||||||
|
if (is_value().has_value())
|
||||||
|
return WebIDL::NotSupportedError::create(realm(), "ElementInternals cannot be attached to a customized build-in element"_fly_string);
|
||||||
|
|
||||||
|
// 2. Let definition be the result of looking up a custom element definition given this's node document, its namespace, its local name, and null as the is value.
|
||||||
|
auto definition = document().lookup_custom_element_definition(namespace_uri(), local_name(), is_value());
|
||||||
|
|
||||||
|
// 3. If definition is null, then throw an "NotSupportedError" DOMException.
|
||||||
|
if (!definition)
|
||||||
|
return WebIDL::NotSupportedError::create(realm(), "ElementInternals cannot be attached to an element that is not a custom element"_fly_string);
|
||||||
|
|
||||||
|
// 4. If definition's disable internals is true, then throw a "NotSupportedError" DOMException.
|
||||||
|
if (definition->disable_internals())
|
||||||
|
return WebIDL::NotSupportedError::create(realm(), "ElementInternals are disabled for this custom element"_fly_string);
|
||||||
|
|
||||||
|
// 5. If this's attached internals is non-null, then throw an "NotSupportedError" DOMException.
|
||||||
|
if (m_attached_internals)
|
||||||
|
return WebIDL::NotSupportedError::create(realm(), "ElementInternals already attached"_fly_string);
|
||||||
|
|
||||||
|
// 6. If this's custom element state is not "precustomized" or "custom", then throw a "NotSupportedError" DOMException.
|
||||||
|
if (!first_is_one_of(custom_element_state(), DOM::CustomElementState::Precustomized, DOM::CustomElementState::Custom))
|
||||||
|
return WebIDL::NotSupportedError::create(realm(), "Custom element is in an invalid state to attach ElementInternals"_fly_string);
|
||||||
|
|
||||||
|
// 7. Set this's attached internals to a new ElementInternals instance whose target element is this.
|
||||||
|
auto internals = ElementInternals::create(realm(), *this);
|
||||||
|
|
||||||
|
m_attached_internals = internals;
|
||||||
|
|
||||||
|
// 8. Return this's attached internals.
|
||||||
|
return { internals };
|
||||||
|
}
|
||||||
|
|
||||||
void HTMLElement::did_receive_focus()
|
void HTMLElement::did_receive_focus()
|
||||||
{
|
{
|
||||||
if (m_content_editable_state != ContentEditableState::True)
|
if (m_content_editable_state != ContentEditableState::True)
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ public:
|
|||||||
String get_an_elements_target() const;
|
String get_an_elements_target() const;
|
||||||
TokenizedFeature::NoOpener get_an_elements_noopener(StringView target) const;
|
TokenizedFeature::NoOpener get_an_elements_noopener(StringView target) const;
|
||||||
|
|
||||||
|
WebIDL::ExceptionOr<JS::NonnullGCPtr<ElementInternals>> attach_internals();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HTMLElement(DOM::Document&, DOM::QualifiedName);
|
HTMLElement(DOM::Document&, DOM::QualifiedName);
|
||||||
|
|
||||||
@@ -97,6 +99,9 @@ private:
|
|||||||
|
|
||||||
JS::GCPtr<DOM::NodeList> m_labels;
|
JS::GCPtr<DOM::NodeList> m_labels;
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/custom-elements.html#attached-internals
|
||||||
|
JS::GCPtr<ElementInternals> m_attached_internals;
|
||||||
|
|
||||||
enum class ContentEditableState {
|
enum class ContentEditableState {
|
||||||
True,
|
True,
|
||||||
False,
|
False,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#import <CSS/ElementCSSInlineStyle.idl>
|
#import <CSS/ElementCSSInlineStyle.idl>
|
||||||
#import <HTML/DOMStringMap.idl>
|
#import <HTML/DOMStringMap.idl>
|
||||||
|
#import <HTML/ElementInternals.idl>
|
||||||
#import <DOM/Element.idl>
|
#import <DOM/Element.idl>
|
||||||
#import <DOM/EventHandler.idl>
|
#import <DOM/EventHandler.idl>
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ interface HTMLElement : Element {
|
|||||||
[LegacyNullToEmptyString, CEReactions] attribute DOMString innerText;
|
[LegacyNullToEmptyString, CEReactions] attribute DOMString innerText;
|
||||||
[LegacyNullToEmptyString, CEReactions] attribute DOMString outerText;
|
[LegacyNullToEmptyString, CEReactions] attribute DOMString outerText;
|
||||||
|
|
||||||
[FIXME] ElementInternals attachInternals();
|
ElementInternals attachInternals();
|
||||||
|
|
||||||
// The popover API
|
// The popover API
|
||||||
[FIXME] undefined showPopover();
|
[FIXME] undefined showPopover();
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ libweb_js_bindings(HTML/CustomElements/CustomElementRegistry)
|
|||||||
libweb_js_bindings(HTML/DOMParser)
|
libweb_js_bindings(HTML/DOMParser)
|
||||||
libweb_js_bindings(HTML/DOMStringMap)
|
libweb_js_bindings(HTML/DOMStringMap)
|
||||||
libweb_js_bindings(HTML/DataTransfer)
|
libweb_js_bindings(HTML/DataTransfer)
|
||||||
|
libweb_js_bindings(HTML/ElementInternals)
|
||||||
libweb_js_bindings(HTML/ErrorEvent)
|
libweb_js_bindings(HTML/ErrorEvent)
|
||||||
libweb_js_bindings(HTML/EventSource)
|
libweb_js_bindings(HTML/EventSource)
|
||||||
libweb_js_bindings(HTML/FormDataEvent)
|
libweb_js_bindings(HTML/FormDataEvent)
|
||||||
|
|||||||
Reference in New Issue
Block a user