Serenity Operating System
1/*
2 * Copyright (c) 2020, the SerenityOS developers.
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <LibWeb/Bindings/ShadowRootPrototype.h>
10#include <LibWeb/DOM/DocumentFragment.h>
11
12namespace Web::DOM {
13
14class ShadowRoot final : public DocumentFragment {
15 WEB_PLATFORM_OBJECT(ShadowRoot, DocumentFragment);
16
17public:
18 Bindings::ShadowRootMode mode() const { return m_mode; }
19
20 bool delegates_focus() const { return m_delegates_focus; }
21 void set_delegates_focus(bool delegates_focus) { m_delegates_focus = delegates_focus; }
22
23 bool available_to_element_internals() const { return m_available_to_element_internals; }
24 void set_available_to_element_internals(bool available_to_element_internals) { m_available_to_element_internals = available_to_element_internals; }
25
26 // ^EventTarget
27 virtual EventTarget* get_parent(Event const&) override;
28
29 WebIDL::ExceptionOr<DeprecatedString> inner_html() const;
30 WebIDL::ExceptionOr<void> set_inner_html(DeprecatedString const&);
31
32private:
33 ShadowRoot(Document&, Element& host, Bindings::ShadowRootMode);
34 virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
35
36 // ^Node
37 virtual DeprecatedFlyString node_name() const override { return "#shadow-root"; }
38 virtual bool is_shadow_root() const final { return true; }
39
40 // NOTE: The specification doesn't seem to specify a default value for closed. Assuming closed for now.
41 Bindings::ShadowRootMode m_mode { Bindings::ShadowRootMode::Closed };
42 bool m_delegates_focus { false };
43 bool m_available_to_element_internals { false };
44};
45
46template<>
47inline bool Node::fast_is<ShadowRoot>() const { return is_shadow_root(); }
48
49template<typename Callback>
50inline IterationDecision Node::for_each_shadow_including_descendant(Callback callback)
51{
52 if (callback(*this) == IterationDecision::Break)
53 return IterationDecision::Break;
54 for (auto* child = first_child(); child; child = child->next_sibling()) {
55 if (child->is_element()) {
56 if (JS::GCPtr<ShadowRoot> shadow_root = static_cast<Element*>(child)->shadow_root_internal()) {
57 if (shadow_root->for_each_shadow_including_descendant(callback) == IterationDecision::Break)
58 return IterationDecision::Break;
59 }
60 }
61 if (child->for_each_shadow_including_descendant(callback) == IterationDecision::Break)
62 return IterationDecision::Break;
63 }
64 return IterationDecision::Continue;
65}
66
67}