Class: Dommy::Attr

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

Overview

‘Attr` — wraps an HTML attribute as a Node-like object. In real DOM each attribute on an element is an Attr; `el.getAttributeNode` returns the instance, `attr.value = “x”` mutates the element’s attribute, ‘attr.ownerElement` points back to the element.

We represent two states:

- "owned" — the Attr is attached to an Element. value reads/writes
  go through the element's Nokogiri attribute slot.
- "detached" — created via `document.createAttribute(name)` but
  not yet attached. Value is stored locally; `setAttributeNode`
  transfers it to an element.

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

Methods included from Bridge::Methods

included

Methods included from EventTarget

#__internal_deliver_event__, #add_event_listener, capture_flag, #deliver_at, #dispatch_event, js_truthy?, #remove_event_listener

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, owner: nil, value: "", namespace_uri: nil, prefix: nil, local_name: nil) ⇒ Attr

Returns a new instance of Attr.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/dommy/attr.rb', line 25

def initialize(name, owner: nil, value: "", namespace_uri: nil, prefix: nil, local_name: nil)
  qname = name.to_s
  @owner = owner
  @detached_value = value.to_s
  if namespace_uri && !namespace_uri.to_s.empty?
    # Namespaced attributes preserve case and carry prefix / localName.
    @name = qname
    @namespace_uri = namespace_uri.to_s
    @prefix = prefix
    @local_name = (local_name || qname.split(":", 2).last).to_s
  else
    # Null-namespace (HTML) attributes are lower-cased, as before.
    @name = qname.downcase
    @namespace_uri = nil
    @prefix = nil
    @local_name = @name
  end
end

Instance Attribute Details

#local_nameObject (readonly)

Returns the value of attribute local_name.



19
20
21
# File 'lib/dommy/attr.rb', line 19

def local_name
  @local_name
end

#nameObject (readonly)

Returns the value of attribute name.



19
20
21
# File 'lib/dommy/attr.rb', line 19

def name
  @name
end

#namespace_uriObject (readonly)

Returns the value of attribute namespace_uri.



19
20
21
# File 'lib/dommy/attr.rb', line 19

def namespace_uri
  @namespace_uri
end

#prefixObject (readonly)

Returns the value of attribute prefix.



19
20
21
# File 'lib/dommy/attr.rb', line 19

def prefix
  @prefix
end

Instance Method Details

#__internal_attach__(element) ⇒ Object

Internal: called by Element when the attr is being transferred to (or detached from) an Element.



147
148
149
150
151
# File 'lib/dommy/attr.rb', line 147

def __internal_attach__(element)
  @owner = element
  @detached_value = ""
  nil
end

#__internal_detach__Object



153
154
155
156
157
158
# File 'lib/dommy/attr.rb', line 153

def __internal_detach__
  cached = value
  @owner = nil
  @detached_value = cached
  nil
end

#__internal_event_parent__Object



21
22
23
# File 'lib/dommy/attr.rb', line 21

def __internal_event_parent__
  nil
end

#__js_call__(method, args) ⇒ 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
# File 'lib/dommy/attr.rb', line 117

def __js_call__(method, args)
  case method
  when "cloneNode"
    Attr.new(@name, owner: nil, value: value,
                    namespace_uri: @namespace_uri, prefix: @prefix, local_name: @local_name)
  when "isSameNode"
    is_same_node(args[0])
  when "getRootNode"
    get_root_node(args[0])
  when "compareDocumentPosition"
    compare_document_position(args[0])
  when "appendChild", "insertBefore"
    raise DOMException::HierarchyRequestError, "an Attr may not have children"
  when "removeChild", "replaceChild"
    raise DOMException::NotFoundError, "the node to be removed is not a child of this node"
  when "hasChildNodes"
    false
  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



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/dommy/attr.rb', line 73

def __js_get__(key)
  case key
  when "name"
    @name
  when "value"
    value
  when "nodeName"
    @name
  when "nodeValue"
    value
  when "textContent"
    # Node.textContent for an Attr returns its value (WHATWG DOM).
    value
  when "ownerElement"
    @owner
  when "localName"
    @local_name
  when "namespaceURI"
    @namespace_uri
  when "prefix"
    @prefix
  when "nodeType"
    2
  when "specified"
    # Legacy/useless attribute — always true (WHATWG DOM).
    true
  end
end

#__js_set__(key, val) ⇒ Object



102
103
104
105
106
107
108
109
110
111
# File 'lib/dommy/attr.rb', line 102

def __js_set__(key, val)
  case key
  when "value", "nodeValue", "textContent"
    self.value = val
  else
    return Bridge::UNHANDLED
  end

  nil
end

#owner_elementObject

The Element this attr is on, or nil if detached.



45
46
47
# File 'lib/dommy/attr.rb', line 45

def owner_element
  @owner
end

#valueObject



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/dommy/attr.rb', line 49

def value
  if @owner
    if @namespace_uri
      Backend.get_attribute_ns(@owner.__dommy_backend_node__, @namespace_uri, @local_name).to_s
    else
      @owner.__dommy_backend_node__[@name].to_s
    end
  else
    @detached_value
  end
end

#value=(new_value) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
# File 'lib/dommy/attr.rb', line 61

def value=(new_value)
  if @owner
    if @namespace_uri
      @owner.set_attribute_ns(@namespace_uri, @name, new_value.to_s)
    else
      @owner.set_attribute(@name, new_value.to_s)
    end
  else
    @detached_value = new_value.to_s
  end
end