Class: Dommy::Document
Overview
‘document` — the entry point for DOM construction and querying. Wrapper caching keeps DOM identity stable across repeated traversals (`body.children.parentElement`).
Constant Summary
collapse
- NAME_RE =
Spec-permitted name pattern (XML “Name” production restricted to ASCII for practicality). Used by ‘createElement` and `createAttribute` to validate the argument.
/\A[A-Za-z_][\w\-.:]*\z/.freeze
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::PROCESSING_INSTRUCTION_NODE, Node::TEXT_NODE
Instance Attribute Summary collapse
Instance Method Summary
collapse
-
#[](key) ⇒ Object
-
#[]=(key, value) ⇒ Object
-
#__event_parent__ ⇒ Object
-
#__js_call__(method, args) ⇒ Object
-
#__js_get__(key) ⇒ Object
-
#__js_set__(key, value) ⇒ Object
-
#__notify_attribute_changed__(element, name, old_value, new_value) ⇒ Object
-
#__notify_connected__(element) ⇒ Object
Lifecycle callback dispatchers.
-
#__notify_connected_subtree__(nk) ⇒ Object
-
#__notify_disconnected__(element) ⇒ Object
-
#__notify_disconnected_subtree__(nk) ⇒ Object
-
#__register_shadow_fragment__(fragment_node, shadow_root) ⇒ Object
ShadowRoot identity registry: map a Nokogiri DocumentFragment (the shadow tree’s backing node) to the wrapping ShadowRoot so slot assignment and event composition can walk from any inner node back to its shadow boundary.
-
#__reset_wrapper__(nokogiri_node) ⇒ Object
Clear the cached wrapper so the next ‘wrap_node` creates a new one.
-
#__set_active_element__(el) ⇒ Object
-
#__set_fullscreen_element__(element) ⇒ Object
-
#__shadow_root_containing__(node) ⇒ Object
-
#__shadow_root_for_fragment__(fragment_node) ⇒ Object
-
#active_element ⇒ Object
Currently-focused element (or body if none).
-
#adopt_node(node) ⇒ Object
Move a node from another document into this one.
-
#attach_template_content(template_element, html) ⇒ Object
—– template content helpers (called from Element) —–.
-
#base_uri ⇒ Object
‘document.baseURI` — resolves the first `<base href>` (if any) relative to the document URL; otherwise just the document URL.
-
#child_element_count ⇒ Object
-
#children ⇒ Object
ParentNode mixin (operates on the document’s element children — in practice the ‘<html>` root).
-
#close ⇒ Object
-
#cookie ⇒ Object
-
#cookie=(value) ⇒ Object
-
#create_attribute(name) ⇒ Object
-
#create_attribute_ns(namespace_uri, qualified_name) ⇒ Object
-
#create_comment(text) ⇒ Object
-
#create_document_fragment ⇒ Object
-
#create_element(name) ⇒ Object
Delegate factory methods to NodeWrapperCache.
-
#create_element_ns(namespace_uri, qualified_name) ⇒ Object
-
#create_event(type_name) ⇒ Object
Legacy ‘document.createEvent(“EventName”)` factory.
-
#create_node_iterator(root, what_to_show = NodeFilter::SHOW_ALL, filter = nil) ⇒ Object
‘document.createNodeIterator(root, whatToShow?, filter?)` — flat depth-first iteration.
-
#create_range ⇒ Object
-
#create_text_node(text) ⇒ Object
-
#create_tree_walker(root, what_to_show = NodeFilter::SHOW_ALL, filter = nil) ⇒ Object
‘document.createTreeWalker(root, whatToShow?, filter?)` — stateful tree traversal with sibling/parent navigation.
-
#doctype ⇒ Object
Minimal DocumentType — represents the ‘<!doctype html>` line.
-
#document_element ⇒ Object
-
#domain ⇒ Object
‘document.domain` — host portion of the URL.
-
#element_from_point(_x, _y) ⇒ Object
-
#exit_fullscreen ⇒ Object
(also: #exitFullscreen)
-
#first_element_child ⇒ Object
-
#forms ⇒ Object
-
#get_element_by_id(id) ⇒ Object
-
#get_elements_by_class_name(name) ⇒ Object
-
#get_elements_by_name(name) ⇒ Object
-
#get_elements_by_tag_name(name) ⇒ Object
-
#get_selection ⇒ Object
-
#has_focus? ⇒ Boolean
(also: #has_focus)
Stubs for layout / focus / selection / execCommand APIs that don’t apply to a layout-less DOM.
-
#has_template_content?(nokogiri_node) ⇒ Boolean
-
#head ⇒ Object
-
#images ⇒ Object
-
#import_node(node, deep = false) ⇒ Object
Copy a node from another document into this one.
-
#initialize(host = nil, nokogiri_doc: nil, default_view: nil) ⇒ Document
constructor
A new instance of Document.
-
#last_element_child ⇒ Object
-
#links ⇒ Object
Live HTMLCollection helpers — each call re-queries the document so post-mutation reads reflect the current state.
-
#migrate_template_descendants(root) ⇒ Object
-
#notify_attribute_mutation(target_node:, attribute_name:, old_value:) ⇒ Object
-
#notify_character_data_mutation(target_node:, old_value:) ⇒ Object
-
#notify_child_list_mutation(target_node:, added_nodes:, removed_nodes:, previous_sibling: nil, next_sibling: nil) ⇒ Object
-
#open ⇒ Object
No-ops — real browsers reset the DOM on ‘open()` and flush pending writes on `close()`.
-
#query_command_supported(_command) ⇒ Object
-
#query_selector(selector) ⇒ Object
-
#query_selector_all(selector) ⇒ Object
-
#referrer ⇒ Object
‘document.referrer` — Dommy never has a referring page, so this is always empty.
-
#register_observer(observer) ⇒ Object
-
#scripts ⇒ Object
-
#template_content_fragment(template_element) ⇒ Object
-
#template_content_inner_html(template_element) ⇒ Object
-
#title ⇒ Object
—– Public Ruby API (snake_case) —–.
-
#title=(value) ⇒ Object
-
#unregister_observer(observer) ⇒ Object
-
#url ⇒ Object
(also: #document_uri)
‘document.URL` / `documentURI` — both return location.href in real browsers (legacy aliases of the same field).
-
#wrap_node(node) ⇒ Object
Delegate node wrapping to NodeWrapperCache.
-
#write(*args) ⇒ Object
‘document.write(html)` — legacy API.
#__deliver_event__, #add_event_listener, #dispatch_event, #invoke_listener, #remove_event_listener
Constructor Details
#initialize(host = nil, nokogiri_doc: nil, default_view: nil) ⇒ Document
Returns a new instance of Document.
Instance Attribute Details
#body ⇒ Object
Returns the value of attribute body.
47
48
49
|
# File 'lib/dommy/document.rb', line 47
def body
@body
end
|
#default_view ⇒ Object
Returns the value of attribute default_view.
48
49
50
|
# File 'lib/dommy/document.rb', line 48
def default_view
@default_view
end
|
#fullscreen_element ⇒ Object
Fullscreen API — no actual fullscreen mode, just track which element claimed it. ‘element.requestFullscreen()` sets it; this is the read side.
269
270
271
|
# File 'lib/dommy/document.rb', line 269
def fullscreen_element
@fullscreen_element
end
|
#nokogiri_doc ⇒ Object
Returns the value of attribute nokogiri_doc.
47
48
49
|
# File 'lib/dommy/document.rb', line 47
def nokogiri_doc
@nokogiri_doc
end
|
Instance Method Details
#[](key) ⇒ Object
357
358
359
|
# File 'lib/dommy/document.rb', line 357
def [](key)
__js_get__(key.to_s)
end
|
#[]=(key, value) ⇒ Object
361
362
363
|
# File 'lib/dommy/document.rb', line 361
def []=(key, value)
__js_set__(key.to_s, value)
end
|
#__event_parent__ ⇒ Object
524
525
526
|
# File 'lib/dommy/document.rb', line 524
def __event_parent__
@default_view
end
|
#__js_call__(method, args) ⇒ Object
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
|
# File 'lib/dommy/document.rb', line 447
def __js_call__(method, args)
case method
when "exitFullscreen"
exit_fullscreen
when "startViewTransition"
callback = args[0]
if callback.respond_to?(:__js_call__)
callback.__js_call__("call", [])
elsif callback.respond_to?(:call)
callback.call
end
ViewTransition.new(@default_view)
when "createElement"
create_element(args[0])
when "createElementNS"
create_element_ns(args[0], args[1])
when "createTextNode"
create_text_node(args[0])
when "createComment"
(args[0])
when "createDocumentFragment"
create_document_fragment
when "querySelector"
query_selector(args[0])
when "querySelectorAll"
query_selector_all(args[0])
when "getElementById"
get_element_by_id(args[0])
when "getElementsByClassName"
get_elements_by_class_name(args[0])
when "getElementsByTagName"
get_elements_by_tag_name(args[0])
when "getElementsByName"
get_elements_by_name(args[0])
when "createAttribute"
create_attribute(args[0])
when "createAttributeNS"
create_attribute_ns(args[0], args[1])
when "createTreeWalker"
create_tree_walker(args[0], args[1] || NodeFilter::SHOW_ALL, args[2])
when "createNodeIterator"
create_node_iterator(args[0], args[1] || NodeFilter::SHOW_ALL, args[2])
when "createEvent"
create_event(args[0])
when "importNode"
import_node(args[0], args[1])
when "adoptNode"
adopt_node(args[0])
when "hasFocus"
has_focus?
when "getSelection"
get_selection
when "elementFromPoint"
element_from_point(args[0], args[1])
when "queryCommandSupported"
query_command_supported(args[0])
when "addEventListener"
add_event_listener(args[0], args[1], args[2])
when "removeEventListener"
remove_event_listener(args[0], args[1])
when "dispatchEvent"
dispatch_event(args[0])
when "write"
write(*args)
when "open"
open
when "close"
close
else
nil
end
end
|
#__js_get__(key) ⇒ Object
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
|
# File 'lib/dommy/document.rb', line 379
def __js_get__(key)
case key
when "body"
@body
when "head"
head
when "doctype"
doctype
when "defaultView"
@default_view
when "fullscreenElement"
@fullscreen_element
when "fullscreenEnabled"
true
when "scrollingElement"
wrap_node(@nokogiri_doc.at_css("html"))
when "documentElement"
wrap_node(@nokogiri_doc.at_css("html"))
when "title"
read_title
when "cookie"
cookie
when "nodeType"
9
when "activeElement"
active_element
when "URL", "documentURI"
url
when "baseURI"
base_uri
when "domain"
domain
when "referrer"
referrer
when "links"
links
when "forms"
forms
when "scripts"
scripts
when "images"
images
when "children"
children
when "childElementCount"
child_element_count
when "firstElementChild"
first_element_child
when "lastElementChild"
last_element_child
when "nodeName"
"#document"
else
nil
end
end
|
#__js_set__(key, value) ⇒ Object
436
437
438
439
440
441
442
443
444
445
|
# File 'lib/dommy/document.rb', line 436
def __js_set__(key, value)
case key
when "title"
write_title(value.to_s)
when "cookie"
self.cookie = value.to_s
end
nil
end
|
#__notify_attribute_changed__(element, name, old_value, new_value) ⇒ Object
579
580
581
|
# File 'lib/dommy/document.rb', line 579
def __notify_attribute_changed__(element, name, old_value, new_value)
@mutation_coordinator.notify_attribute_changed(element, name, old_value, new_value)
end
|
#__notify_connected__(element) ⇒ Object
Lifecycle callback dispatchers. Errors raised inside user callbacks are swallowed so a single buggy custom element can’t break the whole mutation pipeline. Delegate to MutationCoordinator
563
564
565
|
# File 'lib/dommy/document.rb', line 563
def __notify_connected__(element)
@mutation_coordinator.notify_connected(element)
end
|
#__notify_connected_subtree__(nk) ⇒ Object
571
572
573
|
# File 'lib/dommy/document.rb', line 571
def __notify_connected_subtree__(nk)
@mutation_coordinator.notify_connected_subtree(nk)
end
|
#__notify_disconnected__(element) ⇒ Object
567
568
569
|
# File 'lib/dommy/document.rb', line 567
def __notify_disconnected__(element)
@mutation_coordinator.notify_disconnected(element)
end
|
#__notify_disconnected_subtree__(nk) ⇒ Object
575
576
577
|
# File 'lib/dommy/document.rb', line 575
def __notify_disconnected_subtree__(nk)
@mutation_coordinator.notify_disconnected_subtree(nk)
end
|
#__register_shadow_fragment__(fragment_node, shadow_root) ⇒ Object
ShadowRoot identity registry: map a Nokogiri DocumentFragment (the shadow tree’s backing node) to the wrapping ShadowRoot so slot assignment and event composition can walk from any inner node back to its shadow boundary. Delegate to ShadowRootRegistry
546
547
548
|
# File 'lib/dommy/document.rb', line 546
def __register_shadow_fragment__(fragment_node, shadow_root)
@shadow_registry.register(fragment_node, shadow_root)
end
|
#__reset_wrapper__(nokogiri_node) ⇒ Object
Clear the cached wrapper so the next ‘wrap_node` creates a new one. Used by `customElements.define` to upgrade nodes that were constructed before the registration landed.
536
537
538
|
# File 'lib/dommy/document.rb', line 536
def __reset_wrapper__(nokogiri_node)
@node_wrapper_cache.reset_wrapper(nokogiri_node)
end
|
#__set_active_element__(el) ⇒ Object
178
179
180
|
# File 'lib/dommy/document.rb', line 178
def __set_active_element__(el)
@active_element = el
end
|
#__set_fullscreen_element__(element) ⇒ Object
271
272
273
274
275
276
277
|
# File 'lib/dommy/document.rb', line 271
def __set_fullscreen_element__(element)
previous = @fullscreen_element
@fullscreen_element = element
return if previous == element
dispatch_event(Event.new("fullscreenchange"))
end
|
#__shadow_root_containing__(node) ⇒ Object
554
555
556
|
# File 'lib/dommy/document.rb', line 554
def __shadow_root_containing__(node)
@shadow_registry.find_enclosing(node)
end
|
#__shadow_root_for_fragment__(fragment_node) ⇒ Object
550
551
552
|
# File 'lib/dommy/document.rb', line 550
def __shadow_root_for_fragment__(fragment_node)
@shadow_registry.find_for_fragment(fragment_node)
end
|
#active_element ⇒ Object
Currently-focused element (or body if none). Updated via ‘el.focus()` / `el.blur()`.
174
175
176
|
# File 'lib/dommy/document.rb', line 174
def active_element
@active_element || @body
end
|
#adopt_node(node) ⇒ Object
Move a node from another document into this one. The source node is detached from its previous owner and its ownerDocument becomes this. Returns the (possibly re-wrapped) node.
214
215
216
217
218
219
220
221
222
223
224
225
226
|
# File 'lib/dommy/document.rb', line 214
def adopt_node(node)
return nil unless node.respond_to?(:__node__)
src = node.__node__
src.unlink if src.parent
moved = if src.document == @nokogiri_doc
src
else
clone_into_doc(src, true)
end
wrap_node(moved)
end
|
#attach_template_content(template_element, html) ⇒ Object
—– template content helpers (called from Element) —–
651
652
653
|
# File 'lib/dommy/document.rb', line 651
def attach_template_content(template_element, html)
@template_content_registry.attach(template_element, html)
end
|
#base_uri ⇒ Object
‘document.baseURI` — resolves the first `<base href>` (if any) relative to the document URL; otherwise just the document URL. When `<base href>` is itself absolute, that wins. Browsers also ignore subsequent <base> elements; we mirror that.
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
# File 'lib/dommy/document.rb', line 95
def base_uri
doc_url = url
base_el = @nokogiri_doc.at_css("base[href]")
return doc_url unless base_el
href = base_el["href"].to_s
return doc_url if href.empty?
begin
URI.join(doc_url.to_s.empty? ? "about:blank" : doc_url, href).to_s
rescue URI::InvalidURIError
doc_url
end
end
|
#child_element_count ⇒ Object
160
161
162
|
# File 'lib/dommy/document.rb', line 160
def child_element_count
children.size
end
|
#children ⇒ Object
ParentNode mixin (operates on the document’s element children —in practice the ‘<html>` root).
153
154
155
156
157
158
|
# File 'lib/dommy/document.rb', line 153
def children
HTMLCollection.new do
root = @nokogiri_doc.root
root ? [wrap_node(root)].compact : []
end
end
|
#close ⇒ Object
353
354
355
|
# File 'lib/dommy/document.rb', line 353
def close
nil
end
|
#cookie ⇒ Object
313
314
315
|
# File 'lib/dommy/document.rb', line 313
def cookie
@cookie_jar.to_cookie_string
end
|
#cookie=(value) ⇒ Object
317
318
319
320
|
# File 'lib/dommy/document.rb', line 317
def cookie=(value)
@cookie_jar.set_cookie(value)
nil
end
|
#create_attribute(name) ⇒ Object
Create a detached Attr. ‘setAttributeNode` attaches it to an element. Per spec, name must match the XML Name production —invalid names throw InvalidCharacterError.
185
186
187
|
# File 'lib/dommy/document.rb', line 185
def create_attribute(name)
@node_wrapper_cache.create_attribute(name)
end
|
#create_attribute_ns(namespace_uri, qualified_name) ⇒ Object
189
190
191
|
# File 'lib/dommy/document.rb', line 189
def create_attribute_ns(namespace_uri, qualified_name)
@node_wrapper_cache.create_attribute_ns(namespace_uri, qualified_name)
end
|
Create a Comment node. Wraps the Nokogiri comment so it flows through the same wrap_node identity machinery as Element / TextNode.
367
368
369
|
# File 'lib/dommy/document.rb', line 367
def (text)
@node_wrapper_cache.(text)
end
|
#create_document_fragment ⇒ Object
371
372
373
|
# File 'lib/dommy/document.rb', line 371
def create_document_fragment
@node_wrapper_cache.create_document_fragment
end
|
#create_element(name) ⇒ Object
Delegate factory methods to NodeWrapperCache
629
630
631
|
# File 'lib/dommy/document.rb', line 629
def create_element(name)
@node_wrapper_cache.create_element(name)
end
|
#create_element_ns(namespace_uri, qualified_name) ⇒ Object
322
323
324
|
# File 'lib/dommy/document.rb', line 322
def create_element_ns(namespace_uri, qualified_name)
@node_wrapper_cache.create_element_ns(namespace_uri, qualified_name)
end
|
#create_event(type_name) ⇒ Object
Legacy ‘document.createEvent(“EventName”)` factory. Returns an Event subclass instance whose init still has to be called (`event.initEvent(type, bubbles, cancelable)`). Matches the mapping happy-dom and linkedom use.
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
|
# File 'lib/dommy/document.rb', line 232
def create_event(type_name)
name = type_name.to_s
case name
when "Event", "Events", "HTMLEvents"
Event.new("")
when "CustomEvent"
CustomEvent.new("")
when "MouseEvent", "MouseEvents"
MouseEvent.new("")
when "KeyboardEvent", "KeyboardEvents"
KeyboardEvent.new("")
else
Event.new("")
end
end
|
#create_node_iterator(root, what_to_show = NodeFilter::SHOW_ALL, filter = nil) ⇒ Object
‘document.createNodeIterator(root, whatToShow?, filter?)` —flat depth-first iteration.
#create_range ⇒ Object
262
263
264
|
# File 'lib/dommy/document.rb', line 262
def create_range
Range.new(self)
end
|
#create_text_node(text) ⇒ Object
633
634
635
|
# File 'lib/dommy/document.rb', line 633
def create_text_node(text)
@node_wrapper_cache.create_text_node(text)
end
|
#create_tree_walker(root, what_to_show = NodeFilter::SHOW_ALL, filter = nil) ⇒ Object
‘document.createTreeWalker(root, whatToShow?, filter?)` — stateful tree traversal with sibling/parent navigation. `filter` may be a Ruby Proc, a JS-bridge callable, or an object with `accept_node` / `acceptNode`.
#doctype ⇒ Object
Minimal DocumentType — represents the ‘<!doctype html>` line. Always present in HTML5 documents we parse, so we synthesize a stub object whose only useful field is `name`. Tests just need `nodeType == 10`.
307
308
309
|
# File 'lib/dommy/document.rb', line 307
def doctype
@doctype ||= DocumentType.new("html")
end
|
#document_element ⇒ Object
74
75
76
|
# File 'lib/dommy/document.rb', line 74
def document_element
wrap_node(@nokogiri_doc.at_css("html"))
end
|
#domain ⇒ Object
‘document.domain` — host portion of the URL. Real browsers restrict cross-origin reads of this; we just return the bare host.
112
113
114
115
116
117
|
# File 'lib/dommy/document.rb', line 112
def domain
view = @default_view
return "" unless view&.location
view.location.__js_get__("hostname").to_s
end
|
#element_from_point(_x, _y) ⇒ Object
289
290
291
|
# File 'lib/dommy/document.rb', line 289
def element_from_point(_x, _y)
nil
end
|
#exit_fullscreen ⇒ Object
Also known as:
exitFullscreen
279
280
281
282
283
284
285
|
# File 'lib/dommy/document.rb', line 279
def exit_fullscreen
return PromiseValue.resolve(@default_view, nil) if @fullscreen_element.nil?
@fullscreen_element = nil
dispatch_event(Event.new("fullscreenchange"))
PromiseValue.resolve(@default_view, nil)
end
|
#first_element_child ⇒ Object
164
165
166
|
# File 'lib/dommy/document.rb', line 164
def first_element_child
wrap_node(@nokogiri_doc.root)
end
|
133
134
135
136
137
|
# File 'lib/dommy/document.rb', line 133
def forms
HTMLCollection.new do
@nokogiri_doc.css("form").map { |n| wrap_node(n) }.compact
end
end
|
#get_element_by_id(id) ⇒ Object
645
646
647
|
# File 'lib/dommy/document.rb', line 645
def get_element_by_id(id)
@node_wrapper_cache.get_element_by_id(id)
end
|
#get_elements_by_class_name(name) ⇒ Object
375
376
377
|
# File 'lib/dommy/document.rb', line 375
def get_elements_by_class_name(name)
@node_wrapper_cache.get_elements_by_class_name(name)
end
|
#get_elements_by_name(name) ⇒ Object
330
331
332
|
# File 'lib/dommy/document.rb', line 330
def get_elements_by_name(name)
@node_wrapper_cache.get_elements_by_name(name)
end
|
#get_elements_by_tag_name(name) ⇒ Object
326
327
328
|
# File 'lib/dommy/document.rb', line 326
def get_elements_by_tag_name(name)
@node_wrapper_cache.get_elements_by_tag_name(name)
end
|
#get_selection ⇒ Object
258
259
260
|
# File 'lib/dommy/document.rb', line 258
def get_selection
@__selection ||= Selection.new(self)
end
|
#has_focus? ⇒ Boolean
Also known as:
has_focus
Stubs for layout / focus / selection / execCommand APIs that don’t apply to a layout-less DOM. They exist so callers don’t hit NoMethodError; semantics are documented as no-op.
252
253
254
|
# File 'lib/dommy/document.rb', line 252
def has_focus?
true
end
|
#has_template_content?(nokogiri_node) ⇒ Boolean
667
668
669
|
# File 'lib/dommy/document.rb', line 667
def has_template_content?(nokogiri_node)
@template_content_registry.has_content?(nokogiri_node)
end
|
#head ⇒ Object
78
79
80
|
# File 'lib/dommy/document.rb', line 78
def head
wrap_node(@nokogiri_doc.at_css("head"))
end
|
#images ⇒ Object
145
146
147
148
149
|
# File 'lib/dommy/document.rb', line 145
def images
HTMLCollection.new do
@nokogiri_doc.css("img").map { |n| wrap_node(n) }.compact
end
end
|
#import_node(node, deep = false) ⇒ Object
Copy a node from another document into this one. The returned wrapper is owned by ‘this`. Per spec, the source node is left in place. `deep: true` copies the entire subtree.
204
205
206
207
208
209
|
# File 'lib/dommy/document.rb', line 204
def import_node(node, deep = false)
return nil unless node.respond_to?(:__node__)
copy = clone_into_doc(node.__node__, deep)
wrap_node(copy)
end
|
#last_element_child ⇒ Object
168
169
170
|
# File 'lib/dommy/document.rb', line 168
def last_element_child
wrap_node(@nokogiri_doc.root)
end
|
#links ⇒ Object
Live HTMLCollection helpers — each call re-queries the document so post-mutation reads reflect the current state.
127
128
129
130
131
|
# File 'lib/dommy/document.rb', line 127
def links
HTMLCollection.new do
@nokogiri_doc.css("a[href], area[href]").map { |n| wrap_node(n) }.compact
end
end
|
#migrate_template_descendants(root) ⇒ Object
663
664
665
|
# File 'lib/dommy/document.rb', line 663
def migrate_template_descendants(root)
@template_content_registry.migrate_descendants(root)
end
|
#notify_attribute_mutation(target_node:, attribute_name:, old_value:) ⇒ Object
607
608
609
610
611
612
613
|
# File 'lib/dommy/document.rb', line 607
def notify_attribute_mutation(target_node:, attribute_name:, old_value:)
@mutation_coordinator.notify_attribute_mutation(
target_node: target_node,
attribute_name: attribute_name,
old_value: old_value
)
end
|
#notify_character_data_mutation(target_node:, old_value:) ⇒ Object
615
616
617
618
619
620
|
# File 'lib/dommy/document.rb', line 615
def notify_character_data_mutation(target_node:, old_value:)
@mutation_coordinator.notify_character_data_mutation(
target_node: target_node,
old_value: old_value
)
end
|
#notify_child_list_mutation(target_node:, added_nodes:, removed_nodes:, previous_sibling: nil, next_sibling: nil) ⇒ Object
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
|
# File 'lib/dommy/document.rb', line 591
def notify_child_list_mutation(
target_node:,
added_nodes:,
removed_nodes:,
previous_sibling: nil,
next_sibling: nil
)
@mutation_coordinator.notify_child_list_mutation(
target_node: target_node,
added_nodes: added_nodes,
removed_nodes: removed_nodes,
previous_sibling: previous_sibling,
next_sibling: next_sibling
)
end
|
#open ⇒ Object
No-ops — real browsers reset the DOM on ‘open()` and flush pending writes on `close()`. We don’t model the parse pipeline.
349
350
351
|
# File 'lib/dommy/document.rb', line 349
def open
nil
end
|
#query_command_supported(_command) ⇒ Object
293
294
295
|
# File 'lib/dommy/document.rb', line 293
def query_command_supported(_command)
false
end
|
#query_selector(selector) ⇒ Object
637
638
639
|
# File 'lib/dommy/document.rb', line 637
def query_selector(selector)
@node_wrapper_cache.query_selector(selector)
end
|
#query_selector_all(selector) ⇒ Object
641
642
643
|
# File 'lib/dommy/document.rb', line 641
def query_selector_all(selector)
@node_wrapper_cache.query_selector_all(selector)
end
|
#referrer ⇒ Object
‘document.referrer` — Dommy never has a referring page, so this is always empty.
121
122
123
|
# File 'lib/dommy/document.rb', line 121
def referrer
""
end
|
#register_observer(observer) ⇒ Object
583
584
585
|
# File 'lib/dommy/document.rb', line 583
def register_observer(observer)
@mutation_coordinator.register_observer(observer)
end
|
#scripts ⇒ Object
139
140
141
142
143
|
# File 'lib/dommy/document.rb', line 139
def scripts
HTMLCollection.new do
@nokogiri_doc.css("script").map { |n| wrap_node(n) }.compact
end
end
|
#template_content_fragment(template_element) ⇒ Object
655
656
657
|
# File 'lib/dommy/document.rb', line 655
def template_content_fragment(template_element)
@template_content_registry.fragment_for(template_element)
end
|
#template_content_inner_html(template_element) ⇒ Object
659
660
661
|
# File 'lib/dommy/document.rb', line 659
def template_content_inner_html(template_element)
@template_content_registry.inner_html_of(template_element)
end
|
#title ⇒ Object
—– Public Ruby API (snake_case) —–
66
67
68
|
# File 'lib/dommy/document.rb', line 66
def title
read_title
end
|
#title=(value) ⇒ Object
70
71
72
|
# File 'lib/dommy/document.rb', line 70
def title=(value)
write_title(value.to_s)
end
|
#unregister_observer(observer) ⇒ Object
587
588
589
|
# File 'lib/dommy/document.rb', line 587
def unregister_observer(observer)
@mutation_coordinator.unregister_observer(observer)
end
|
#url ⇒ Object
Also known as:
document_uri
‘document.URL` / `documentURI` — both return location.href in real browsers (legacy aliases of the same field).
84
85
86
87
|
# File 'lib/dommy/document.rb', line 84
def url
view = @default_view
view&.location ? view.location.href : ""
end
|
#wrap_node(node) ⇒ Object
Delegate node wrapping to NodeWrapperCache
529
530
531
|
# File 'lib/dommy/document.rb', line 529
def wrap_node(node)
@node_wrapper_cache.wrap(node)
end
|
#write(*args) ⇒ Object
‘document.write(html)` — legacy API. Appends parsed nodes to the body. Real browsers only re-stream the DOM during initial parse; this stub is enough for tests that fire write() during teardown.
337
338
339
340
341
342
343
344
345
|
# File 'lib/dommy/document.rb', line 337
def write(*args)
html = args.join
fragment = Parser.fragment(html, owner_doc: @nokogiri_doc)
removed = []
added = fragment.children.to_a
added.each { |node| @body.__node__.add_child(node) }
notify_child_list_mutation(target_node: @body.__node__, added_nodes: added, removed_nodes: removed)
nil
end
|