Module: Dommy::Internal::ChildNode
- Included in:
- CharacterDataNode, ParentNode
- Defined in:
- lib/dommy/internal/child_node.rb
Overview
Shared ChildNode surface (WHATWG DOM before / after / replaceWith)
plus the argument-coercion + childList-notification primitives those and
ParentNode's own mutators build on. Included by both ParentNode (Element /
Fragment / ShadowRoot) and the leaf CharacterData nodes (Text / Comment /
ProcessingInstruction) — a leaf can be moved with before/after but must
NOT gain appendChild/insertBefore, so those stay in ParentNode.
Includers must expose @__node__ (the backing node) and @document.
Instance Method Summary collapse
-
#child_node_after(args) ⇒ Object
ChildNode#after — insert nodes as following siblings of
@__node__. -
#child_node_before(args) ⇒ Object
ChildNode#before — insert nodes as preceding siblings of
@__node__. -
#child_node_replace_with(args) ⇒ Object
ChildNode#replaceWith — replace
@__node__with the given nodes. -
#nullable_dom_string(value) ⇒ Object
WebIDL nullable DOMString coercion (
DOMString?): JS null and undefined both become the null value, which callers treat as the empty string. -
#validate_insert_before_ref!(args) ⇒ Object
WebIDL check for
insertBefore(node, child):childis a required but nullable Node, so a missing argument or a value that is neither a Node nor null/undefined is a TypeError before any DOM step runs.
Instance Method Details
#child_node_after(args) ⇒ Object
ChildNode#after — insert nodes as following siblings of @__node__.
36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/dommy/internal/child_node.rb', line 36 def child_node_after(args) parent = @__node__.parent return nil unless parent arg_nodes = backend_nodes_in(args) viable_next = @__node__.next_sibling viable_next = viable_next.next_sibling while viable_next && arg_nodes.any? { |n| n == viable_next } nodes = args.flat_map { |arg| detach_dom_nodes(arg) } insert_child_nodes(nodes, viable_next, parent) notify_child_list(added: nodes, target: parent) nil end |
#child_node_before(args) ⇒ Object
ChildNode#before — insert nodes as preceding siblings of @__node__.
Follows the spec's "viable previous sibling" dance: the reference child
is the first preceding sibling NOT among the argument nodes, resolved
AFTER the arguments are detached (converting them into a node removes
them from their old parents). Nodes are then inserted forward before the
(fixed) reference — reversing would emit them backwards.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/dommy/internal/child_node.rb', line 20 def child_node_before(args) parent = @__node__.parent return nil unless parent arg_nodes = backend_nodes_in(args) viable_prev = @__node__.previous_sibling viable_prev = viable_prev.previous_sibling while viable_prev && arg_nodes.any? { |n| n == viable_prev } nodes = args.flat_map { |arg| detach_dom_nodes(arg) } ref = viable_prev.nil? ? parent.children.first : viable_prev.next_sibling insert_child_nodes(nodes, ref, parent) notify_child_list(added: nodes, target: parent) nil end |
#child_node_replace_with(args) ⇒ Object
ChildNode#replaceWith — replace @__node__ with the given nodes.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/dommy/internal/child_node.rb', line 51 def child_node_replace_with(args) parent = @__node__.parent return nil unless parent arg_nodes = backend_nodes_in(args) viable_next = @__node__.next_sibling viable_next = viable_next.next_sibling while viable_next && arg_nodes.any? { |n| n == viable_next } removed = @__node__ nodes = args.flat_map { |arg| detach_dom_nodes(arg) } if @__node__.parent == parent # `@__node__` survived the conversion (it wasn't among the arguments): # insert the new nodes before it, then unlink it — a true replace. nodes.each { |n| @__node__.add_previous_sibling(n) } @__node__.unlink notify_child_list(added: nodes, removed: [removed], target: parent) else # `@__node__` was itself an argument, so the conversion already moved # it into `nodes`; pre-insert the set before the viable next sibling. insert_child_nodes(nodes, viable_next, parent) notify_child_list(added: nodes, target: parent) end nil end |
#nullable_dom_string(value) ⇒ Object
WebIDL nullable DOMString coercion (DOMString?): JS null and undefined
both become the null value, which callers treat as the empty string.
78 79 80 81 82 |
# File 'lib/dommy/internal/child_node.rb', line 78 def nullable_dom_string(value) return "" if value.nil? || (defined?(Bridge::UNDEFINED) && value.equal?(Bridge::UNDEFINED)) value.to_s end |
#validate_insert_before_ref!(args) ⇒ Object
WebIDL check for insertBefore(node, child): child is a required but
nullable Node, so a missing argument or a value that is neither a Node
nor null/undefined is a TypeError before any DOM step runs. Now safe
since the seeded stubs report the correct arity (2), so .length-based
WPT helpers always pass the reference argument.
89 90 91 92 93 94 95 96 97 |
# File 'lib/dommy/internal/child_node.rb', line 89 def validate_insert_before_ref!(args) raise Bridge::TypeError, "insertBefore requires 2 arguments." if args.length < 2 ref = args[1] return if ref.nil? || (defined?(Bridge::UNDEFINED) && ref.equal?(Bridge::UNDEFINED)) return if ref.is_a?(Dommy::Node) raise Bridge::TypeError, "The reference child is not a Node." end |