Class: Dommy::ShadowRoot
Overview
‘ShadowRoot` — a DocumentFragment-shaped subtree attached to a host Element via `attachShadow`. Lives in its own Nokogiri fragment that’s invisible to the outer document’s tree walks (querySelector, getElementById, children, etc.), which is the core “encapsulation” the spec promises.
Tree manipulation works the same as a normal Element/Fragment; the boundary is enforced only on outer queries and event composition. CSS scoping (‘:host`, `::slotted`) is out of scope.
Constant Summary
Constants included
from Node
Node::ATTRIBUTE_NODE, Node::CDATA_SECTION_NODE, Node::COMMENT_NODE, Node::DOCUMENT_FRAGMENT_NODE, Node::DOCUMENT_NODE, Node::DOCUMENT_POSITION_CONTAINED_BY, Node::DOCUMENT_POSITION_CONTAINS, Node::DOCUMENT_POSITION_DISCONNECTED, Node::DOCUMENT_POSITION_FOLLOWING, Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC, Node::DOCUMENT_POSITION_PRECEDING, Node::DOCUMENT_TYPE_NODE, Node::ELEMENT_NODE, Node::HTML_NAMESPACE, Node::PROCESSING_INSTRUCTION_NODE, Node::TEXT_NODE
Instance Attribute Summary collapse
Instance Method Summary
collapse
included
#append, #append_child, #prepend, #replace_children
Methods included from Node
#compare_document_position, #is_default_namespace, #is_equal_node, #is_same_node, #lookup_namespace_uri, #lookup_prefix
#__internal_deliver_event__, #add_event_listener, capture_flag, #deliver_at, #dispatch_event, js_truthy?, #remove_event_listener
Constructor Details
#initialize(host, mode:, delegates_focus: false, slot_assignment: "named") ⇒ ShadowRoot
Returns a new instance of ShadowRoot.
22
23
24
25
26
27
28
29
30
|
# File 'lib/dommy/shadow_root.rb', line 22
def initialize(host, mode:, delegates_focus: false, slot_assignment: "named")
@host = host
@mode = mode.to_s
@delegates_focus = !!delegates_focus
@slot_assignment = slot_assignment.to_s
@document = host.document
@__node__ = @document.nokogiri_doc.fragment("")
@document.__internal_register_shadow_fragment__(@__node__, self)
end
|
Instance Attribute Details
#delegates_focus ⇒ Object
Returns the value of attribute delegates_focus.
18
19
20
|
# File 'lib/dommy/shadow_root.rb', line 18
def delegates_focus
@delegates_focus
end
|
#document ⇒ Object
Returns the value of attribute document.
18
19
20
|
# File 'lib/dommy/shadow_root.rb', line 18
def document
@document
end
|
#host ⇒ Object
Returns the value of attribute host.
18
19
20
|
# File 'lib/dommy/shadow_root.rb', line 18
def host
@host
end
|
#mode ⇒ Object
Returns the value of attribute mode.
18
19
20
|
# File 'lib/dommy/shadow_root.rb', line 18
def mode
@mode
end
|
#slot_assignment ⇒ Object
Returns the value of attribute slot_assignment.
18
19
20
|
# File 'lib/dommy/shadow_root.rb', line 18
def slot_assignment
@slot_assignment
end
|
Instance Method Details
#[](key) ⇒ Object
‘[]` accessor mirrors the bracket convention used elsewhere.
119
120
121
|
# File 'lib/dommy/shadow_root.rb', line 119
def [](key)
__js_get__(key.to_s)
end
|
#[]=(k, v) ⇒ Object
123
124
125
|
# File 'lib/dommy/shadow_root.rb', line 123
def []=(k, v)
__js_set__(k.to_s, v)
end
|
#__dommy_backend_node__ ⇒ Object
20
|
# File 'lib/dommy/shadow_root.rb', line 20
def __dommy_backend_node__ = @__node__
|
#__internal_event_parent__ ⇒ Object
Event bubbling stops at the ShadowRoot unless event has ‘composed: true`. The host is the bubble-path successor when composition crosses the boundary (handled in Event dispatch).
221
222
223
|
# File 'lib/dommy/shadow_root.rb', line 221
def __internal_event_parent__
nil
end
|
#__js_call__(method, args) ⇒ Object
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
# File 'lib/dommy/shadow_root.rb', line 179
def __js_call__(method, args)
case method
when "querySelector"
query_selector(Internal.css_query_arg!(args))
when "querySelectorAll"
query_selector_all(Internal.css_query_arg!(args))
when "getElementById"
get_element_by_id(args[0])
when "isEqualNode"
is_equal_node(args[0])
when "isSameNode"
is_same_node(args[0])
when "compareDocumentPosition"
compare_document_position(args[0])
when "hasChildNodes"
@__node__.children.any?
when "normalize"
nil
when "append"
append(*args)
when "prepend"
prepend(*args)
when "replaceChildren"
replace_children(*args)
when "appendChild"
append_child(args[0])
when "getRootNode"
get_root_node(args[0])
when "contains"
contains?(args[0])
when "addEventListener"
add_event_listener(args[0], args[1], args[2])
when "removeEventListener"
remove_event_listener(args[0], args[1], args[2])
when "dispatchEvent"
dispatch_event(args[0])
end
end
|
#__js_get__(key) ⇒ Object
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
# File 'lib/dommy/shadow_root.rb', line 127
def __js_get__(key)
case key
when "host"
@host
when "mode"
@mode
when "delegatesFocus"
@delegates_focus
when "slotAssignment"
@slot_assignment
when "innerHTML"
inner_html
when "textContent"
text_content
when "children"
children
when "childNodes"
child_nodes
when "childElementCount"
child_element_count
when "firstChild"
first_child
when "lastChild"
last_child
when "firstElementChild"
first_element_child
when "lastElementChild"
last_element_child
when "nodeType"
11
end
end
|
#__js_set__(key, value) ⇒ Object
160
161
162
163
164
165
166
167
168
169
170
171
|
# File 'lib/dommy/shadow_root.rb', line 160
def __js_set__(key, value)
case key
when "innerHTML"
self.inner_html = value
when "textContent"
self.text_content = value
else
return Bridge::UNHANDLED
end
nil
end
|
#child_element_count ⇒ Object
65
66
67
|
# File 'lib/dommy/shadow_root.rb', line 65
def child_element_count
@__node__.element_children.size
end
|
#child_nodes ⇒ Object
61
62
63
|
# File 'lib/dommy/shadow_root.rb', line 61
def child_nodes
@__node__.children.map { |n| @document.wrap_node(n) }.compact
end
|
#children ⇒ Object
57
58
59
|
# File 'lib/dommy/shadow_root.rb', line 57
def children
@__node__.element_children.map { |n| @document.wrap_node(n) }.compact
end
|
#contains?(other) ⇒ Boolean
109
110
111
112
113
114
115
116
|
# File 'lib/dommy/shadow_root.rb', line 109
def contains?(other)
return false unless other.respond_to?(:__dommy_backend_node__)
other_node = other.__dommy_backend_node__
return true if other_node == @__node__
Internal::NodeTraversal.ancestor_of?(@__node__, other_node)
end
|
#first_child ⇒ Object
69
70
71
|
# File 'lib/dommy/shadow_root.rb', line 69
def first_child
@document.wrap_node(@__node__.children.first)
end
|
#first_element_child ⇒ Object
77
78
79
|
# File 'lib/dommy/shadow_root.rb', line 77
def first_element_child
@document.wrap_node(@__node__.element_children.first)
end
|
#get_element_by_id(id) ⇒ Object
97
98
99
100
101
|
# File 'lib/dommy/shadow_root.rb', line 97
def get_element_by_id(id)
return nil if id.nil?
@document.wrap_node(@__node__.at_css("##{id}"))
end
|
#get_root_node(_options = nil) ⇒ Object
‘getRootNode()` returns the ShadowRoot itself (closed-shadow semantics; `composed: true` callers go through the Event path).
105
106
107
|
# File 'lib/dommy/shadow_root.rb', line 105
def get_root_node(_options = nil)
self
end
|
#inner_html ⇒ Object
—- Public Ruby API (ParentNode + DocumentFragment mixin) —-
34
35
36
|
# File 'lib/dommy/shadow_root.rb', line 34
def inner_html
@__node__.children.map(&:to_html).join
end
|
#inner_html=(html) ⇒ Object
38
39
40
41
42
43
44
45
46
|
# File 'lib/dommy/shadow_root.rb', line 38
def inner_html=(html)
removed = @__node__.children.to_a
removed.each(&:unlink)
fragment = Parser.fragment(html.to_s, owner_doc: @document.nokogiri_doc)
added = fragment.children.to_a
added.each { |n| @__node__.add_child(n) }
notify_child_list(added: added, removed: removed)
nil
end
|
#last_child ⇒ Object
73
74
75
|
# File 'lib/dommy/shadow_root.rb', line 73
def last_child
@document.wrap_node(@__node__.children.last)
end
|
#last_element_child ⇒ Object
81
82
83
|
# File 'lib/dommy/shadow_root.rb', line 81
def last_element_child
@document.wrap_node(@__node__.element_children.last)
end
|
#query_selector(selector) ⇒ Object
85
86
87
88
89
|
# File 'lib/dommy/shadow_root.rb', line 85
def query_selector(selector)
return nil if selector.nil? || selector.to_s.empty?
@document.wrap_node(@__node__.at_css(selector.to_s))
end
|
#query_selector_all(selector) ⇒ Object
91
92
93
94
95
|
# File 'lib/dommy/shadow_root.rb', line 91
def query_selector_all(selector)
return NodeList.new if selector.nil? || selector.to_s.empty?
NodeList.new(@__node__.css(selector.to_s).map { |n| @document.wrap_node(n) }.compact)
end
|
#text_content ⇒ Object
48
49
50
|
# File 'lib/dommy/shadow_root.rb', line 48
def text_content
@__node__.text
end
|
#text_content=(value) ⇒ Object
52
53
54
55
|
# File 'lib/dommy/shadow_root.rb', line 52
def text_content=(value)
@__node__.children.each(&:unlink)
@__node__.add_child(Backend.create_text(value.to_s, @document.nokogiri_doc))
end
|