LibWeb: Implement Element.attachShadow and Element.shadowRoot :^)

This commit is contained in:
Karol Kosek 2023-01-28 20:37:46 +01:00 committed by Andreas Kling
parent 9ed4fe7049
commit 4311fd2774
3 changed files with 71 additions and 0 deletions

View file

@ -459,6 +459,58 @@ DOMTokenList* Element::class_list()
return m_class_list;
}
// https://dom.spec.whatwg.org/#dom-element-attachshadow
WebIDL::ExceptionOr<JS::NonnullGCPtr<ShadowRoot>> Element::attach_shadow(ShadowRootInit init)
{
// 1. If thiss namespace is not the HTML namespace, then throw a "NotSupportedError" DOMException.
if (namespace_() != Namespace::HTML)
return WebIDL::NotSupportedError::create(realm(), "Element's namespace is not the HTML namespace"sv);
// 2. If thiss local name is not one of the following:
// FIXME: - a valid custom element name
// - "article", "aside", "blockquote", "body", "div", "footer", "h1", "h2", "h3", "h4", "h5", "h6", "header", "main", "nav", "p", "section", or "span"
if (!local_name().is_one_of("article", "aside", "blockquote", "body", "div", "footer", "h1", "h2", "h3", "h4", "h5", "h6", "header", "main", "nav", "p", "section", "span")) {
// then throw a "NotSupportedError" DOMException.
return WebIDL::NotSupportedError::create(realm(), DeprecatedString::formatted("Element '{}' cannot be a shadow host", local_name()));
}
// FIXME: 3. If thiss local name is a valid custom element name, or thiss is value is not null, then: ...
// 4. If this is a shadow host, then throw an "NotSupportedError" DOMException.
if (is_shadow_host())
return WebIDL::NotSupportedError::create(realm(), "Element already is a shadow host");
// 5. Let shadow be a new shadow root whose node document is thiss node document, host is this, and mode is init["mode"].
auto shadow = MUST_OR_THROW_OOM(heap().allocate<ShadowRoot>(realm(), document(), *this, init.mode));
// 6. Set shadows delegates focus to init["delegatesFocus"].
shadow->set_delegates_focus(init.delegates_focus);
// FIXME: 7. If thiss custom element state is "precustomized" or "custom", then set shadows available to element internals to true.
// FIXME: 8. Set shadows slot assignment to init["slotAssignment"].
// 9. Set thiss shadow root to shadow.
set_shadow_root(shadow);
// 10. Return shadow.
return shadow;
}
// https://dom.spec.whatwg.org/#dom-element-shadowroot
JS::GCPtr<ShadowRoot> Element::shadow_root() const
{
// 1. Let shadow be thiss shadow root.
auto shadow = m_shadow_root;
// 2. If shadow is null or its mode is "closed", then return null.
if (shadow == nullptr || shadow->mode() == Bindings::ShadowRootMode::Closed)
return nullptr;
// 3. Return shadow.
return shadow;
}
// https://dom.spec.whatwg.org/#dom-element-matches
WebIDL::ExceptionOr<bool> Element::matches(StringView selectors) const
{

View file

@ -10,6 +10,7 @@
#include <AK/DeprecatedString.h>
#include <LibWeb/ARIA/ARIAMixin.h>
#include <LibWeb/Bindings/ElementPrototype.h>
#include <LibWeb/Bindings/ShadowRootPrototype.h>
#include <LibWeb/CSS/CSSStyleDeclaration.h>
#include <LibWeb/CSS/StyleComputer.h>
#include <LibWeb/DOM/Attr.h>
@ -27,6 +28,11 @@
namespace Web::DOM {
struct ShadowRootInit {
Bindings::ShadowRootMode mode;
bool delegates_focus = false;
};
// https://w3c.github.io/csswg-drafts/cssom-view-1/#dictdef-scrolloptions
struct ScrollOptions {
Bindings::ScrollBehavior behavior { Bindings::ScrollBehavior::Auto };
@ -78,6 +84,9 @@ public:
DOMTokenList* class_list();
WebIDL::ExceptionOr<JS::NonnullGCPtr<ShadowRoot>> attach_shadow(ShadowRootInit init);
JS::GCPtr<ShadowRoot> shadow_root() const;
WebIDL::ExceptionOr<bool> matches(StringView selectors) const;
WebIDL::ExceptionOr<DOM::Element const*> closest(StringView selectors) const;

View file

@ -8,6 +8,7 @@
#import <DOM/Node.idl>
#import <DOM/NodeList.idl>
#import <DOM/ParentNode.idl>
#import <DOM/ShadowRoot.idl>
#import <Geometry/DOMRect.idl>
#import <Geometry/DOMRectList.idl>
@ -50,6 +51,9 @@ interface Element : Node {
[Reflect=class] attribute DOMString className;
[SameObject, PutForwards=value] readonly attribute DOMTokenList classList;
ShadowRoot attachShadow(ShadowRootInit init);
readonly attribute ShadowRoot? shadowRoot;
boolean matches(DOMString selectors);
Element? closest(DOMString selectors);
@ -81,6 +85,12 @@ interface Element : Node {
};
dictionary ShadowRootInit {
required ShadowRootMode mode;
boolean delegatesFocus = false;
// FIXME: SlotAssignmentMode slotAssignment = "named";
};
Element includes ParentNode;
Element includes ChildNode;
Element includes InnerHTML;