mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-08-17 01:10:28 +03: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:
parent
ce8d3d17c4
commit
a65f1ecc37
Notes:
sideshowbarker
2024-07-17 18:49:10 +09:00
Author: https://github.com/lukewarlow Commit: https://github.com/LadybirdBrowser/ladybird/commit/a65f1ecc37 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/272 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/tcl3
@ -48,6 +48,7 @@ static bool is_platform_object(Type const& type)
|
||||
"DocumentType"sv,
|
||||
"DOMRectReadOnly"sv,
|
||||
"DynamicsCompressorNode"sv,
|
||||
"ElementInternals"sv,
|
||||
"EventTarget"sv,
|
||||
"FileList"sv,
|
||||
"FontFace"sv,
|
||||
|
@ -30,6 +30,7 @@ source_set("HTML") {
|
||||
"Dates.cpp",
|
||||
"DecodedImageData.cpp",
|
||||
"DocumentState.cpp",
|
||||
"ElementInternals.cpp",
|
||||
"ErrorEvent.cpp",
|
||||
"EventHandler.cpp",
|
||||
"EventNames.cpp",
|
||||
|
@ -119,6 +119,7 @@ standard_idl_files = [
|
||||
"//Userland/Libraries/LibWeb/HTML/DataTransfer.idl",
|
||||
"//Userland/Libraries/LibWeb/HTML/DOMParser.idl",
|
||||
"//Userland/Libraries/LibWeb/HTML/DOMStringMap.idl",
|
||||
"//Userland/Libraries/LibWeb/HTML/ElementInternals.idl",
|
||||
"//Userland/Libraries/LibWeb/HTML/ErrorEvent.idl",
|
||||
"//Userland/Libraries/LibWeb/HTML/EventSource.idl",
|
||||
"//Userland/Libraries/LibWeb/HTML/FormDataEvent.idl",
|
||||
|
@ -273,6 +273,7 @@ set(SOURCES
|
||||
HTML/DOMParser.cpp
|
||||
HTML/DOMStringMap.cpp
|
||||
HTML/DataTransfer.cpp
|
||||
HTML/ElementInternals.cpp
|
||||
HTML/ErrorEvent.cpp
|
||||
HTML/EventHandler.cpp
|
||||
HTML/EventSource.cpp
|
||||
|
@ -405,6 +405,8 @@ protected:
|
||||
|
||||
virtual bool id_reference_exists(String const&) const override;
|
||||
|
||||
CustomElementState custom_element_state() const { return m_custom_element_state; }
|
||||
|
||||
private:
|
||||
void make_html_uppercased_qualified_name();
|
||||
|
||||
|
@ -352,6 +352,7 @@ class DecodedImageData;
|
||||
class DocumentState;
|
||||
class DOMParser;
|
||||
class DOMStringMap;
|
||||
class ElementInternals;
|
||||
class ErrorEvent;
|
||||
class EventHandler;
|
||||
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/ShadowRoot.h>
|
||||
#include <LibWeb/HTML/BrowsingContext.h>
|
||||
#include <LibWeb/HTML/CustomElements/CustomElementDefinition.h>
|
||||
#include <LibWeb/HTML/DOMStringMap.h>
|
||||
#include <LibWeb/HTML/ElementInternals.h>
|
||||
#include <LibWeb/HTML/EventHandler.h>
|
||||
#include <LibWeb/HTML/Focus.h>
|
||||
#include <LibWeb/HTML/HTMLAnchorElement.h>
|
||||
@ -60,6 +62,7 @@ void HTMLElement::visit_edges(Cell::Visitor& visitor)
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_dataset);
|
||||
visitor.visit(m_labels);
|
||||
visitor.visit(m_attached_internals);
|
||||
}
|
||||
|
||||
JS::NonnullGCPtr<DOMStringMap> HTMLElement::dataset()
|
||||
@ -608,6 +611,40 @@ TokenizedFeature::NoOpener HTMLElement::get_an_elements_noopener(StringView targ
|
||||
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()
|
||||
{
|
||||
if (m_content_editable_state != ContentEditableState::True)
|
||||
|
@ -75,6 +75,8 @@ public:
|
||||
String get_an_elements_target() const;
|
||||
TokenizedFeature::NoOpener get_an_elements_noopener(StringView target) const;
|
||||
|
||||
WebIDL::ExceptionOr<JS::NonnullGCPtr<ElementInternals>> attach_internals();
|
||||
|
||||
protected:
|
||||
HTMLElement(DOM::Document&, DOM::QualifiedName);
|
||||
|
||||
@ -97,6 +99,9 @@ private:
|
||||
|
||||
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 {
|
||||
True,
|
||||
False,
|
||||
|
@ -1,5 +1,6 @@
|
||||
#import <CSS/ElementCSSInlineStyle.idl>
|
||||
#import <HTML/DOMStringMap.idl>
|
||||
#import <HTML/ElementInternals.idl>
|
||||
#import <DOM/Element.idl>
|
||||
#import <DOM/EventHandler.idl>
|
||||
|
||||
@ -28,7 +29,7 @@ interface HTMLElement : Element {
|
||||
[LegacyNullToEmptyString, CEReactions] attribute DOMString innerText;
|
||||
[LegacyNullToEmptyString, CEReactions] attribute DOMString outerText;
|
||||
|
||||
[FIXME] ElementInternals attachInternals();
|
||||
ElementInternals attachInternals();
|
||||
|
||||
// The popover API
|
||||
[FIXME] undefined showPopover();
|
||||
|
@ -103,6 +103,7 @@ libweb_js_bindings(HTML/CustomElements/CustomElementRegistry)
|
||||
libweb_js_bindings(HTML/DOMParser)
|
||||
libweb_js_bindings(HTML/DOMStringMap)
|
||||
libweb_js_bindings(HTML/DataTransfer)
|
||||
libweb_js_bindings(HTML/ElementInternals)
|
||||
libweb_js_bindings(HTML/ErrorEvent)
|
||||
libweb_js_bindings(HTML/EventSource)
|
||||
libweb_js_bindings(HTML/FormDataEvent)
|
||||
|
Loading…
Reference in New Issue
Block a user