opal-browser 0.1.0.beta1 → 0.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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