Class: Dommy::DocumentType

Inherits:
Object
  • Object
show all
Includes:
Bridge::Methods, EventTarget, Node
Defined in:
lib/dommy/document.rb

Overview

DocumentType (<!doctype html>) — exposes name / publicId / systemId and nodeType=10. HTML5 doctypes carry empty public/system IDs, but implementation.createDocumentType can set them.

Two modes:

  • node-backed — wraps the Makiri DocumentType node of a parsed document (document.doctype). Participates in the tree machinery (compareDocumentPosition / getRootNode / sibling links) like any other backend-backed node, via the shared Node mixin.
  • synthetic — a standalone doctype (implementation.createDocumentType) carrying just name/public/system id and an owner document. No backend node, so it stays tree-DISCONNECTED per its detached nature.

Defined Under Namespace

Modules: NodeBacked

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, Node::XMLNS_NAMESPACE, Node::XML_NAMESPACE

Instance Method Summary collapse

Methods included from Bridge::Methods

included

Methods included from EventTarget

#__dommy_dump_event_failure__, #__internal_deliver_event__, #__internal_process_event_handler_return__, #add_event_listener, capture_flag, #deliver_at, #dispatch_event, #event_name_from_on, #invoke_listener_isolated, js_truthy?, #on_handler, #remove_event_listener, #set_on_handler

Methods included from Node

#compare_document_position, #get_root_node, #is_default_namespace, #is_equal_node, #is_same_node, #lookup_namespace_uri, #lookup_prefix

Constructor Details

#initialize(name = "", public_id = "", system_id = "", owner_document: nil, backend_node: nil, document: nil) ⇒ DocumentType

owner_document: links a synthetic doctype to its document so the ChildNode methods can act on the tree; a standalone one has none, so those methods are no-ops per spec. backend_node: + document: build the node-backed variant (a parsed-tree doctype or the createDocumentType factory node), which reads name/publicId/systemId straight off the node (the factory preserves case).



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/dommy/document.rb', line 41

def initialize(name = "", public_id = "", system_id = "", owner_document: nil, backend_node: nil, document: nil)
  @__node__ = backend_node
  if backend_node
    @document = document
    @owner_document = document
    extend(NodeBacked)
  else
    @name = name.to_s
    @public_id = public_id.to_s
    @system_id = system_id.to_s
    @owner_document = owner_document
  end
end

Instance Method Details

#__internal_event_parent__Object



149
150
151
# File 'lib/dommy/document.rb', line 149

def __internal_event_parent__
  parent_node
end

#__js_call__(method, args) ⇒ Object



174
175
176
177
178
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
217
218
219
220
221
222
223
224
225
# File 'lib/dommy/document.rb', line 174

def __js_call__(method, args)
  case method
  when "lookupNamespaceURI"
    lookup_namespace_uri(args[0])
  when "lookupPrefix"
    lookup_prefix(args[0])
  when "isDefaultNamespace"
    is_default_namespace(args[0])
  when "cloneNode"
    clone_node(args[0])
  when "hasChildNodes"
    false
  when "contains"
    # A DocumentType is a leaf node: it contains only itself.
    !args[0].nil? && is_same_node(args[0])
  when "isEqualNode"
    is_equal_node(args[0])
  when "isSameNode"
    is_same_node(args[0])
  when "getRootNode"
    get_root_node(args[0])
  when "compareDocumentPosition"
    compare_document_position(args[0])
  when "appendChild", "insertBefore", "replaceChild"
    # Pre-insert / replace step 1 rejects a non-parent context node with
    # HierarchyRequestError before the reference-child check.
    raise Bridge::TypeError, "Argument is not a Node." unless args[0].is_a?(Dommy::Node)

    raise DOMException::HierarchyRequestError, "a DocumentType may not have children"
  when "removeChild"
    raise Bridge::TypeError, "Argument is not a Node." unless args[0].is_a?(Dommy::Node)

    raise DOMException::NotFoundError, "the node to be removed is not a child of this node"
  when "before"
    before(*args)
  when "after"
    after(*args)
  when "replaceWith"
    replace_with(*args)
  when "remove"
    remove
    Bridge::UNDEFINED # DocumentType (ChildNode)#remove is void -> JS undefined
  when "normalize"
    nil
  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



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/dommy/document.rb', line 117

def __js_get__(key)
  case key
  when "name"
    name
  when "nodeName"
    # WHATWG: a DocumentType's nodeName is its name.
    name
  when "nodeType"
    10
  when "publicId"
    public_id
  when "systemId"
    system_id
  when "ownerDocument"
    @owner_document
  when "parentNode"
    parent_node
  when "parentElement"
    nil
  when "nextSibling"
    next_sibling
  when "previousSibling"
    previous_sibling
  when "childNodes"
    NodeList.new
  when "firstChild", "lastChild"
    nil
  end
end

#after(*nodes) ⇒ Object



102
103
104
105
106
107
# File 'lib/dommy/document.rb', line 102

def after(*nodes)
  return nil unless @owner_document

  @owner_document.__internal_insert_at_doctype__(nodes, after: true)
  nil
end

#before(*nodes) ⇒ Object



95
96
97
98
99
100
# File 'lib/dommy/document.rb', line 95

def before(*nodes)
  return nil unless @owner_document

  @owner_document.__internal_insert_at_doctype__(nodes, after: false)
  nil
end

#clone_node(_deep = false) ⇒ Object

Node.cloneNode on a doctype: a detached copy with the same name/publicId/ systemId (a doctype is a leaf, so deep is irrelevant). Node-backed when a backend factory is available, else synthetic — either reports the same values and isEqualNode-matches the original.



157
158
159
160
161
162
163
164
165
166
167
# File 'lib/dommy/document.rb', line 157

def clone_node(_deep = false)
  if @__node__ && @document
    node = begin
      Backend.create_document_type(name, public_id, system_id, @document.backend_doc)
    rescue StandardError
      nil
    end
    return DocumentType.new(backend_node: node, document: @document) if node
  end
  DocumentType.new(name, public_id, system_id, owner_document: @owner_document)
end

#documentObject

The document this doctype currently belongs to (nil for a detached synthetic doctype). Lets a cross-document appendChild/insert detect that the node must be adopted (re-created) into the destination backend.



58
59
60
# File 'lib/dommy/document.rb', line 58

def document
  @document || @owner_document
end

#nameObject



62
63
64
# File 'lib/dommy/document.rb', line 62

def name
  @__node__ ? @__node__.name : @name
end

#next_siblingObject



81
82
83
# File 'lib/dommy/document.rb', line 81

def next_sibling
  @__node__ && @__node__.next && @document.wrap_node(@__node__.next)
end

#parent_nodeObject



75
76
77
78
79
# File 'lib/dommy/document.rb', line 75

def parent_node
  # wrap_node maps the backend document node (the doctype's parent) to the
  # Dommy Document.
  @__node__ && @__node__.parent && @document.wrap_node(@__node__.parent)
end

#previous_siblingObject



85
86
87
# File 'lib/dommy/document.rb', line 85

def previous_sibling
  @__node__ && @__node__.previous && @document.wrap_node(@__node__.previous)
end

#public_idObject

Makiri reports nil for an absent public/system id; DOM exposes "".



67
68
69
# File 'lib/dommy/document.rb', line 67

def public_id
  @__node__ ? @__node__.public_id.to_s : @public_id
end

#removeObject

ChildNode mixin — the doctype's parent is the document.



90
91
92
93
# File 'lib/dommy/document.rb', line 90

def remove
  @owner_document&.__internal_remove_doctype__(self)
  nil
end

#replace_with(*nodes) ⇒ Object



109
110
111
112
113
114
115
# File 'lib/dommy/document.rb', line 109

def replace_with(*nodes)
  return nil unless @owner_document

  @owner_document.__internal_insert_at_doctype__(nodes, after: false)
  remove
  nil
end

#system_idObject



71
72
73
# File 'lib/dommy/document.rb', line 71

def system_id
  @__node__ ? @__node__.system_id.to_s : @system_id
end