opal-browser 0.1.0.beta1 → 0.2.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +60 -0
  3. data/.yardopts +1 -1
  4. data/Gemfile +7 -2
  5. data/LICENSE +19 -0
  6. data/README.md +74 -10
  7. data/config.ru +2 -1
  8. data/index.html.erb +22 -0
  9. data/opal-browser.gemspec +9 -11
  10. data/opal/browser.rb +1 -1
  11. data/opal/browser/animation_frame.rb +66 -9
  12. data/opal/browser/canvas.rb +72 -18
  13. data/opal/browser/canvas/data.rb +1 -1
  14. data/opal/browser/console.rb +3 -37
  15. data/opal/browser/cookies.rb +80 -24
  16. data/opal/browser/css/declaration.rb +0 -5
  17. data/opal/browser/{timeout.rb → delay.rb} +13 -13
  18. data/opal/browser/dom.rb +0 -2
  19. data/opal/browser/dom/attribute.rb +6 -0
  20. data/opal/browser/dom/builder.rb +4 -8
  21. data/opal/browser/dom/character_data.rb +43 -7
  22. data/opal/browser/dom/document.rb +13 -11
  23. data/opal/browser/dom/element.rb +127 -29
  24. data/opal/browser/dom/element/image.rb +23 -0
  25. data/opal/browser/dom/element/offset.rb +27 -10
  26. data/opal/browser/dom/element/scroll.rb +32 -12
  27. data/opal/browser/dom/element/size.rb +29 -0
  28. data/opal/browser/dom/event.rb +88 -75
  29. data/opal/browser/dom/event/animation.rb +16 -4
  30. data/opal/browser/dom/event/audio_processing.rb +6 -4
  31. data/opal/browser/dom/event/base.rb +229 -64
  32. data/opal/browser/dom/event/before_unload.rb +6 -4
  33. data/opal/browser/dom/event/clipboard.rb +6 -4
  34. data/opal/browser/dom/event/close.rb +16 -4
  35. data/opal/browser/dom/event/composition.rb +16 -4
  36. data/opal/browser/dom/event/custom.rb +43 -8
  37. data/opal/browser/dom/event/device_light.rb +6 -4
  38. data/opal/browser/dom/event/device_motion.rb +17 -4
  39. data/opal/browser/dom/event/device_orientation.rb +16 -4
  40. data/opal/browser/dom/event/device_proximity.rb +6 -4
  41. data/opal/browser/dom/event/drag.rb +34 -28
  42. data/opal/browser/dom/event/focus.rb +21 -5
  43. data/opal/browser/dom/event/gamepad.rb +33 -20
  44. data/opal/browser/dom/event/hash_change.rb +6 -4
  45. data/opal/browser/dom/event/keyboard.rb +45 -23
  46. data/opal/browser/dom/event/message.rb +28 -8
  47. data/opal/browser/dom/event/mouse.rb +26 -25
  48. data/opal/browser/dom/event/page_transition.rb +6 -4
  49. data/opal/browser/dom/event/pop_state.rb +16 -4
  50. data/opal/browser/dom/event/progress.rb +16 -4
  51. data/opal/browser/dom/event/sensor.rb +6 -4
  52. data/opal/browser/dom/event/storage.rb +6 -4
  53. data/opal/browser/dom/event/touch.rb +10 -19
  54. data/opal/browser/dom/event/ui.rb +19 -3
  55. data/opal/browser/dom/event/wheel.rb +2 -2
  56. data/opal/browser/dom/mutation_observer.rb +65 -5
  57. data/opal/browser/dom/node.rb +164 -59
  58. data/opal/browser/dom/node_set.rb +4 -0
  59. data/opal/browser/dom/text.rb +16 -1
  60. data/opal/browser/event_source.rb +5 -2
  61. data/opal/browser/history.rb +51 -15
  62. data/opal/browser/http.rb +22 -7
  63. data/opal/browser/http/headers.rb +5 -0
  64. data/opal/browser/http/request.rb +40 -10
  65. data/opal/browser/immediate.rb +123 -9
  66. data/opal/browser/interval.rb +8 -13
  67. data/opal/browser/location.rb +13 -3
  68. data/opal/browser/navigator.rb +9 -6
  69. data/opal/browser/screen.rb +31 -5
  70. data/opal/browser/socket.rb +8 -4
  71. data/opal/browser/storage.rb +118 -33
  72. data/opal/browser/support.rb +232 -0
  73. data/opal/browser/utils.rb +24 -6
  74. data/opal/browser/version.rb +1 -1
  75. data/opal/browser/window.rb +1 -2
  76. data/opal/browser/window/scroll.rb +21 -11
  77. data/opal/browser/window/size.rb +16 -6
  78. data/opal/browser/window/view.rb +23 -5
  79. data/spec/dom/builder_spec.rb +19 -19
  80. data/spec/dom/document_spec.rb +6 -6
  81. data/spec/dom/element_spec.rb +5 -5
  82. data/spec/dom/event_spec.rb +20 -20
  83. data/spec/dom/mutation_observer_spec.rb +5 -5
  84. data/spec/dom/node_spec.rb +39 -27
  85. data/spec/dom_spec.rb +10 -8
  86. data/spec/event_source_spec.rb +12 -12
  87. data/spec/history_spec.rb +24 -15
  88. data/spec/http_spec.rb +18 -17
  89. data/spec/immediate_spec.rb +9 -7
  90. data/spec/runner.rb +114 -0
  91. data/spec/socket_spec.rb +8 -8
  92. data/spec/spec_helper.rb +1 -0
  93. data/spec/storage_spec.rb +6 -6
  94. data/spec/wgxpath.install.js +49 -0
  95. data/spec/window_spec.rb +2 -2
  96. metadata +21 -54
  97. data/opal/browser/compatibility.rb +0 -59
  98. data/opal/browser/compatibility/animation_frame.rb +0 -93
  99. data/opal/browser/compatibility/dom/document/window.rb +0 -15
  100. data/opal/browser/compatibility/dom/element/css.rb +0 -15
  101. data/opal/browser/compatibility/dom/element/matches.rb +0 -31
  102. data/opal/browser/compatibility/dom/element/offset.rb +0 -20
  103. data/opal/browser/compatibility/dom/element/scroll.rb +0 -25
  104. data/opal/browser/compatibility/dom/element/style.rb +0 -15
  105. data/opal/browser/compatibility/dom/mutation_observer.rb +0 -47
  106. data/opal/browser/compatibility/http/request.rb +0 -15
  107. data/opal/browser/compatibility/immediate.rb +0 -107
  108. data/opal/browser/compatibility/window/scroll.rb +0 -27
  109. data/opal/browser/compatibility/window/size.rb +0 -13
  110. data/opal/browser/compatibility/window/view.rb +0 -13
  111. data/opal/browser/dom/compatibility.rb +0 -8
  112. data/opal/browser/http/compatibility.rb +0 -1
  113. data/opal/browser/window/compatibility.rb +0 -3
@@ -1,23 +1,47 @@
1
1
  module Browser; module DOM
2
2
 
3
+ # A {MutationObserver} is a performant way to observe changes in the DOM,
4
+ # either on the tree, the attributes or data.
5
+ #
6
+ # @see https://developer.mozilla.org/en/docs/Web/API/MutationObserver
3
7
  class MutationObserver
8
+ def self.supported?
9
+ Browser.supports? :MutationObserver
10
+ end
11
+
4
12
  include Native
5
13
 
14
+ # Encapsulates a recorded change.
6
15
  class Record
7
16
  include Native
8
17
 
18
+ # @!attribute [r] type
19
+ # @return [:attributes, :tree, :cdata] the type of the recorded change
9
20
  def type
10
21
  case `#@native.type`
11
- when :attributes then :attributes
22
+ when :attributes then :attribute
12
23
  when :childList then :tree
13
24
  when :characterData then :cdata
14
25
  end
15
26
  end
16
27
 
17
- def attributes?; type == :attributes; end
18
- def tree?; type == :tree; end
19
- def cdata?; type == :cdata; end
28
+ # Returns true if the change happened on attributes.
29
+ def attribute?
30
+ type == :attribute
31
+ end
32
+
33
+ # Returns true if the change happened on the tree.
34
+ def tree?
35
+ type == :tree
36
+ end
20
37
 
38
+ # Returns true if the change happened in a CDATA section.
39
+ def cdata?
40
+ type == :cdata
41
+ end
42
+
43
+ # @!attribute [r] added
44
+ # @return [NodeSet] the added nodes
21
45
  def added
22
46
  array = if `#@native.addedNodes != null`
23
47
  Native::Array.new(`#@native.addedNodes`)
@@ -28,6 +52,8 @@ class MutationObserver
28
52
  NodeSet.new($document, array)
29
53
  end
30
54
 
55
+ # @!attribute [r] removed
56
+ # @return [NodeSet] the removed nodes
31
57
  def removed
32
58
  array = if `#@native.removedNodes != null`
33
59
  Native::Array.new(`#@native.removedNodes`)
@@ -38,14 +64,28 @@ class MutationObserver
38
64
  NodeSet.new($document, array)
39
65
  end
40
66
 
67
+ # @!attribute [r] target
68
+ # @return [Node] the node the mutation affected
41
69
  def target
42
70
  DOM(`#@native.target`)
43
71
  end
44
72
 
73
+ # @!attribute [r] old
74
+ # @return [String] the old value
45
75
  alias_native :old, :oldValue
46
- alias_native :attribute, :attributeName
76
+
77
+ # @!attribute [r] name
78
+ # @return [String] the name of the attribute
79
+ alias_native :name, :attributeName
80
+
81
+ # @!attribute [r] namespace
82
+ # @return [String] the namespace of the attribute
83
+ alias_native :namespace, :attributeNamespace
47
84
  end
48
85
 
86
+ # Create a new MutationObserver with the given block.
87
+ #
88
+ # @yieldparam records [Array<Record>] the recorded changes
49
89
  def initialize(&block)
50
90
  %x{
51
91
  var func = function(records) {
@@ -56,6 +96,22 @@ class MutationObserver
56
96
  super(`new window.MutationObserver(func)`)
57
97
  end
58
98
 
99
+ # Observe the given target with the given options.
100
+ #
101
+ # The supported options are:
102
+ #
103
+ # + **children** - whether to observe changes on the children
104
+ # of the target or not
105
+ # + **tree** - whether to observe changes on the whole subtree
106
+ # or not
107
+ # + **attributes** - whether to observe changes to attributes or not,
108
+ # if the value is `:old` the old value will be saved
109
+ # + **cdata** - whether to observe changes to CDATA sections or not,
110
+ # if the value is `:old` the old value will be saved
111
+ # + **filter** - array of attribute names to observe
112
+ #
113
+ # @param target [DOM::Node, native] the node to observe
114
+ # @param options [Hash?] the options
59
115
  def observe(target, options = nil)
60
116
  unless options
61
117
  options = {
@@ -71,10 +127,14 @@ class MutationObserver
71
127
  self
72
128
  end
73
129
 
130
+ # Empty the observer queue and return its contents.
131
+ #
132
+ # @return [Array<Record>]
74
133
  def take
75
134
  `#@native.takeRecords()`.map { |r| Record.new(r) }
76
135
  end
77
136
 
137
+ # Disconnect the observer, thus stopping observing any changes.
78
138
  def disconnect
79
139
  `#@native.disconnect()`
80
140
  end
@@ -1,5 +1,8 @@
1
1
  module Browser; module DOM
2
2
 
3
+ # Abstract class for all DOM node types.
4
+ #
5
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/Node
3
6
  class Node
4
7
  include Native
5
8
 
@@ -16,6 +19,11 @@ class Node
16
19
  DOCUMENT_FRAGMENT_NODE = 11
17
20
  NOTATION_NODE = 12
18
21
 
22
+ # Wrap a native DOM node.
23
+ #
24
+ # @param value [native] the native DOM node
25
+ #
26
+ # @return [Node]
19
27
  def self.new(value)
20
28
  if self == Node
21
29
  @classes ||= [nil, Element, Attribute, Text, CDATA, nil, nil, nil, Comment, Document, nil, DocumentFragment]
@@ -30,23 +38,33 @@ class Node
30
38
  end
31
39
  end
32
40
 
41
+ # Return true of the other element is the same underlying DOM node.
42
+ #
43
+ # @return [Boolean]
33
44
  def ==(other)
34
45
  `#@native === #{Native.try_convert(other)}`
35
46
  end
36
47
 
48
+ # Return true if the node name matches the given name case-insensitively.
49
+ #
50
+ # @param name [String] the name to match with
51
+ #
52
+ # @return [Boolean]
37
53
  def =~(name)
38
54
  self.name.downcase == name.downcase
39
55
  end
40
56
 
57
+ # Append a child to the node.
58
+ #
59
+ # When passing a {String} a text node will be created.
60
+ #
61
+ # When passing an Object that responds to #each, every yielded element
62
+ # will be added following the same logic.
63
+ #
64
+ # @param node [String, Node, #each, #to_n] the node to append
65
+ #
66
+ # @return [self]
41
67
  def <<(node)
42
- add_child(node)
43
- end
44
-
45
- def <=>(other)
46
- raise NotImplementedError
47
- end
48
-
49
- def add_child(node)
50
68
  if native?(node)
51
69
  `#@native.appendChild(node)`
52
70
  elsif node.respond_to? :each
@@ -60,26 +78,57 @@ class Node
60
78
  self
61
79
  end
62
80
 
63
- def add_next_sibling(node)
64
- `#@native.parentNode.insertBefore(node, #@native.nextSibling)`
81
+ alias add_child <<
65
82
 
66
- self
83
+ # Add the passed node after this one.
84
+ #
85
+ # When passing a {String} a text node will be created.
86
+ #
87
+ # @param node [String, Node, #to_n] the node to add
88
+ def add_next_sibling(node)
89
+ if native?(node)
90
+ `#@native.parentNode.insertBefore(node, #@native.nextSibling)`
91
+ elsif String === node
92
+ `#@native.parentNode.insertBefore(
93
+ #@native.ownerDocument.createTextNode(node), #@native.nextSibling)`
94
+ else
95
+ `#@native.parentNode.insertBefore(#{Native.convert(node)},
96
+ #@native.nextSibling)`
97
+ end
67
98
  end
68
99
 
100
+ # Add the passed node before this one.
101
+ #
102
+ # When passing a {String} a text node will be created.
103
+ #
104
+ # @param node [String, Node, #to_n] the node to add
69
105
  def add_previous_sibling(node)
70
- `#@native.parentNode.insertBefore(node, #@native)`
71
-
72
- self
106
+ if native?(node)
107
+ `#@native.parentNode.insertBefore(node, #@native)`
108
+ elsif String === node
109
+ `#@native.parentNode.insertBefore(
110
+ #@native.ownerDocument.createTextNode(node), #@native)`
111
+ else
112
+ `#@native.parentNode.insertBefore(#{Native.convert(node)}, #@native)`
113
+ end
73
114
  end
74
115
 
75
116
  alias after add_next_sibling
76
117
 
77
- def append_to(element)
78
- element.add_child(self)
79
-
80
- self
118
+ # Append the node to the passed one.
119
+ #
120
+ # @param node [Node] the node to append to
121
+ def append_to(node)
122
+ node.add_child(self)
81
123
  end
82
124
 
125
+ # Get an array of ancestors.
126
+ #
127
+ # Passing a selector will select the ancestors matching it.
128
+ #
129
+ # @param expression [String] the selector to use as filter
130
+ #
131
+ # @return [NodeSet]
83
132
  def ancestors(expression = nil)
84
133
  return NodeSet.new(document) unless parent
85
134
 
@@ -93,52 +142,72 @@ class Node
93
142
  parents.pop
94
143
  end
95
144
 
96
- return NodeSet.new(document, parents) unless expression
145
+ if expression
146
+ parents.select! {|p|
147
+ p.matches? expression
148
+ }
149
+ end
97
150
 
98
- NodeSet.new document, parents.select {|p|
99
- p.matches?(expression)
100
- }
151
+ NodeSet.new document, parents
101
152
  end
102
153
 
103
154
  alias before add_previous_sibling
104
155
 
156
+ # Remove the node from its parent.
105
157
  def remove
106
- detach
107
- clear
108
-
109
- self
110
- end
111
-
112
- def detach
113
158
  parent.remove_child(self) if parent
159
+ end
114
160
 
115
- self
161
+ # Remove all the children of the node.
162
+ def clear
163
+ children.each(&:remove)
116
164
  end
117
165
 
118
- def clear; end
166
+ # @!attribute content
167
+ # @return [String] the inner text content of the node
168
+ if Browser.supports? 'Element.textContent'
169
+ def content
170
+ `#@native.textContent`
171
+ end
119
172
 
120
- def remove_child(element)
121
- `#@native.removeChild(#{Native.try_convert(element)})`
173
+ def content=(value)
174
+ `#@native.textContent = #{value}`
175
+ end
176
+ elsif Browser.supports? 'Element.innerText'
177
+ def content
178
+ `#@native.innerText`
179
+ end
122
180
 
123
- self
124
- end
181
+ def content=(value)
182
+ `#@native.innerText = #{value}`
183
+ end
184
+ else
185
+ def content
186
+ raise NotImplementedError, 'node text content unsupported'
187
+ end
125
188
 
126
- def clear
127
- children.each(&:remove)
189
+ def content=(value)
190
+ raise NotImplementedError, 'node text content unsupported'
191
+ end
128
192
  end
129
193
 
130
194
  def blank?
131
195
  raise NotImplementedError
132
196
  end
133
197
 
198
+ # Return true if the node is a CDATA section.
134
199
  def cdata?
135
200
  node_type == CDATA_SECTION_NODE
136
201
  end
137
202
 
203
+ # @!attribute [r] child
204
+ # @return [Node?] the first child of the node
138
205
  def child
139
206
  children.first
140
207
  end
141
208
 
209
+ # @!attribute children
210
+ # @return [NodeSet] the children of the node
142
211
  def children
143
212
  NodeSet.new(document, Native::Array.new(`#@native.childNodes`))
144
213
  end
@@ -147,43 +216,51 @@ class Node
147
216
  raise NotImplementedError
148
217
  end
149
218
 
219
+ # Return true if the node is a comment.
150
220
  def comment?
151
221
  node_type == COMMENT_NODE
152
222
  end
153
223
 
224
+ # @!attribute [r] document
225
+ # @return [Document?] the document the node is attached to
154
226
  def document
155
- DOM(`#@native.ownerDocument`)
227
+ DOM(`#@native.ownerDocument`) if defined?(`#@native.ownerDocument`)
156
228
  end
157
229
 
230
+ # Return true if the node is a document.
158
231
  def document?
159
232
  node_type == DOCUMENT_NODE
160
233
  end
161
234
 
235
+ # Return true if the node is an element.
162
236
  def elem?
163
237
  node_type == ELEMENT_NODE
164
238
  end
165
239
 
166
240
  alias element? elem?
167
241
 
242
+ # @!attribute [r] element_children
243
+ # @return [NodeSet] all the children which are elements
168
244
  def element_children
169
245
  children.select(&:element?)
170
246
  end
171
247
 
172
248
  alias elements element_children
173
249
 
250
+ # @!attribute [r] first_element_child
251
+ # @return [Element?] the first element child
174
252
  def first_element_child
175
253
  element_children.first
176
254
  end
177
255
 
256
+ # Return true if the node is a document fragment.
178
257
  def fragment?
179
258
  node_type == DOCUMENT_FRAGMENT_NODE
180
259
  end
181
260
 
182
- def hash
183
- # TODO: implement this properly
184
- end
185
-
186
- def inner_html(*)
261
+ # @!attribute inner_html
262
+ # @return [String] the inner HTML of the node
263
+ def inner_html
187
264
  `#@native.innerHTML`
188
265
  end
189
266
 
@@ -191,26 +268,24 @@ class Node
191
268
  `#@native.innerHTML = #{value}`
192
269
  end
193
270
 
194
- def inner_text(*)
195
- `#@native.textContent`
196
- end
197
-
198
- alias content inner_text
199
-
200
- def inner_text=(value)
201
- `#@native.textContent = #{value}`
202
- end
203
-
204
- alias content= inner_text=
271
+ alias inner_text content
272
+ alias inner_text= content=
205
273
 
274
+ # @!attribute [r] last_element_child
275
+ # @return [Element?] the last element child
206
276
  def last_element_child
207
277
  element_children.last
208
278
  end
209
279
 
280
+ # Check if the node matches the given CSS selector.
281
+ #
282
+ # @param expression [String] the CSS selector
210
283
  def matches?(expression)
211
284
  false
212
285
  end
213
286
 
287
+ # @!attribute name
288
+ # @return [String] the name of the node
214
289
  def name
215
290
  `#@native.nodeName || nil`
216
291
  end
@@ -219,14 +294,22 @@ class Node
219
294
  `#@native.nodeName = #{value.to_s}`
220
295
  end
221
296
 
297
+ # @!attribute [r] namespace
298
+ # @return [String] the namespace of the node
222
299
  def namespace
223
300
  `#@native.namespaceURI || nil`
224
301
  end
225
302
 
303
+ # @!attribute next
304
+ # @return [Node?] the next sibling of the node
226
305
  def next
227
306
  DOM(`#@native.nextSibling`) if `#@native.nextSibling != null`
228
307
  end
229
308
 
309
+ alias next= add_next_sibling
310
+
311
+ # @!attribute [r] next_element
312
+ # @return [Element?] the next element sibling of the node
230
313
  def next_element
231
314
  current = self.next
232
315
 
@@ -243,19 +326,23 @@ class Node
243
326
 
244
327
  alias node_name= name=
245
328
 
329
+ # @!attribute [r] node_type
330
+ # @return [Symbol] the type of the node
246
331
  def node_type
247
332
  `#@native.nodeType`
248
333
  end
249
334
 
335
+ # @!attribute parent
336
+ # @return [Element?] the parent of the node
250
337
  def parent
251
338
  DOM(`#@native.parentNode`) if `#@native.parentNode != null`
252
339
  end
253
340
 
254
- def parent= (node)
341
+ def parent=(node)
255
342
  `#@native.parentNode = #{Native.try_convert(node)}`
256
343
  end
257
344
 
258
- def parse (text, options = {})
345
+ def parse(text, options = {})
259
346
  raise NotImplementedError
260
347
  end
261
348
 
@@ -263,12 +350,16 @@ class Node
263
350
  raise NotImplementedError
264
351
  end
265
352
 
353
+ # @!attribute previous
354
+ # @return [Node?] the previous sibling of the node
266
355
  def previous
267
356
  DOM(`#@native.previousSibling`) if `#@native.previousSibling != null`
268
357
  end
269
358
 
270
359
  alias previous= add_previous_sibling
271
360
 
361
+ # @!attribute [r] previous_element
362
+ # @return [Element?] the previous element sibling of the node
272
363
  def previous_element
273
364
  current = self.previous
274
365
 
@@ -281,16 +372,27 @@ class Node
281
372
 
282
373
  alias previous_sibling previous
283
374
 
284
- # TODO: implement for NodeSet
375
+ # Remove the given node from the children of this node.
376
+ def remove_child(node)
377
+ `#@native.removeChild(#{Native.try_convert(node)})`
378
+ end
379
+
380
+ # Replace the node with the given one.
381
+ #
382
+ # @todo implement for NodeSet
383
+ #
384
+ # @param node [Node] the node to replace with
385
+ # @return [Node] the passed node
285
386
  def replace(node)
286
387
  `#@native.parentNode.replaceChild(#@native, #{Native.try_convert(node)})`
287
388
 
288
389
  node
289
390
  end
290
391
 
291
- alias text inner_text
292
- alias text= inner_text=
392
+ alias text content
393
+ alias text= content=
293
394
 
395
+ # Return true if the node is a text node.
294
396
  def text?
295
397
  node_type == TEXT_NODE
296
398
  end
@@ -301,6 +403,8 @@ class Node
301
403
 
302
404
  alias type node_type
303
405
 
406
+ # @!attribute value
407
+ # @return [String] the value of the node
304
408
  def value
305
409
  `#@native.nodeValue || nil`
306
410
  end
@@ -309,6 +413,7 @@ class Node
309
413
  `#@native.nodeValue = value`
310
414
  end
311
415
 
416
+ # @private
312
417
  def inspect
313
418
  "#<DOM::Node: #{name}>"
314
419
  end