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
@@ -2,7 +2,7 @@ module Browser; module DOM; class Event
2
2
 
3
3
  class Animation < Event
4
4
  def self.supported?
5
- not $$[:AnimationEvent].nil?
5
+ Browser.supports? 'Event.Animation'
6
6
  end
7
7
 
8
8
  class Definition < Definition
@@ -15,9 +15,21 @@ class Animation < Event
15
15
  end
16
16
  end
17
17
 
18
- def self.create(name, &block)
19
- new(`new AnimationEvent(#{name}, #{Definition.new(&block)})`)
20
- end
18
+ if Browser.supports? 'Event.constructor'
19
+ def self.construct(name, desc)
20
+ `new AnimationEvent(#{name}, #{desc})`
21
+ end
22
+ elsif Browser.supports? 'Event.create'
23
+ def self.construct(name, desc)
24
+ %x{
25
+ var event = document.createEvent("AnimationEvent");
26
+ event.initAnimationEvent(name, desc.bubbles, desc.cancelable,
27
+ desc.animationName, desc.elapsedTime);
28
+
29
+ return event;
30
+ }
31
+ end
32
+ end if supported?
21
33
 
22
34
  alias_native :name, :animationName
23
35
  alias_native :elapsed, :elapsedTime
@@ -2,7 +2,7 @@ module Browser; module DOM; class Event
2
2
 
3
3
  class AudioProcessing < Event
4
4
  def self.supported?
5
- not $$[:AudioProcessingEvent].nil?
5
+ Browser.supports? 'Event.AudioProcessing'
6
6
  end
7
7
 
8
8
  class Definition < Definition
@@ -19,9 +19,11 @@ class AudioProcessing < Event
19
19
  end
20
20
  end
21
21
 
22
- def self.create(name, &block)
23
- new(`new AudioProcessingEvent(#{name}, #{Definition.new(&block)})`)
24
- end
22
+ if Browser.supports? 'Event.constructor'
23
+ def self.construct(name, desc)
24
+ `new AudioProcessingEvent(#{name}, #{desc})`
25
+ end
26
+ end if supported?
25
27
 
26
28
  alias_native :time, :playbackTime
27
29
  alias_native :input, :inputBuffer
@@ -7,30 +7,33 @@ class Event
7
7
  include Native
8
8
 
9
9
  def self.new(&block)
10
- data = super(`{}`)
10
+ data = super(`{ bubbles: true, cancelable: true }`)
11
11
  block.call(data) if block
12
12
 
13
13
  data.to_n
14
14
  end
15
15
 
16
- def bubbles!
17
- `#@native.bubbles = true`
16
+ def bubbles=(value)
17
+ `#@native.bubbles = #{value}`
18
18
  end
19
19
 
20
- def cancelable!
21
- `#@native.cancelable = true`
20
+ def cancelable=(value)
21
+ `#@native.cancelable = #{value}`
22
22
  end
23
23
  end
24
24
 
25
25
  module Target
26
+ # @private
26
27
  def self.converters
27
28
  @converters ||= []
28
29
  end
29
30
 
31
+ # @private
30
32
  def self.register(&block)
31
33
  converters << block
32
34
  end
33
35
 
36
+ # @private
34
37
  def self.convert(value)
35
38
  return value unless native?(value)
36
39
 
@@ -55,60 +58,183 @@ class Event
55
58
  attr_reader :target, :name, :selector
56
59
 
57
60
  def initialize(target, name, selector = nil, &block)
58
- %x{
59
- callback = #{self};
60
- func = function(event) {
61
- event = #{::Browser::DOM::Event.new(`event`, `callback`)};
61
+ @target = target
62
+ @name = name
63
+ @selector = selector
64
+ @block = block
65
+ end
62
66
 
63
- if (!#{`event`.stopped?}) {
64
- #{block.call(`event`, *`event`.arguments)};
65
- }
67
+ def call(e)
68
+ to_proc.call(e)
69
+ end
66
70
 
67
- return !#{`event`.stopped?};
71
+ def to_proc
72
+ @proc ||= -> event {
73
+ %x{
74
+ if (!event.currentTarget) {
75
+ event.currentTarget = self.target.native;
76
+ }
68
77
  }
78
+
79
+ event = Event.new(event, self)
80
+
81
+ unless event.stopped?
82
+ @block.call(event, *event.arguments)
83
+ end
84
+
85
+ !event.prevented?
69
86
  }
87
+ end
70
88
 
71
- @function = `func`
72
- @target = target
73
- @name = name
74
- @selector = selector
89
+ def event
90
+ Event.class_for(@name)
75
91
  end
76
92
 
77
93
  def off
78
94
  target.off(self)
79
95
  end
96
+ end
80
97
 
81
- def to_n
82
- @function
98
+ class Delegate
99
+ def initialize(target, name, pair)
100
+ @target = target
101
+ @name = name
102
+ @pair = pair
103
+ end
104
+
105
+ def off
106
+ delegate = @target.delegated[@name]
107
+ delegate.last.delete(@pair)
108
+
109
+ if delegate.last.empty?
110
+ delegate.first.off
111
+ delegate.delete(@name)
112
+ end
83
113
  end
84
114
  end
85
115
 
86
- def on(name, selector = nil, &block)
87
- raise ArgumentError, 'no block has been passed' unless block
116
+ Delegates = Struct.new(:callback, :handlers)
88
117
 
89
- name = Event.name_for(name)
90
- callback = Callback.new(self, name, selector, &block)
118
+ def on(name, selector = nil, &block)
119
+ raise ArgumentError, 'no block has been given' unless block
91
120
 
92
- callbacks.push(callback)
121
+ name = Event.name_for(name)
93
122
 
94
123
  if selector
95
- observe
96
- deferred << [name, selector, block]
124
+ unless delegate = delegated[name]
125
+ delegate = delegated[name] = Delegates.new
126
+
127
+ if %w[blur focus].include?(name)
128
+ delegate.callback = on! name do |e|
129
+ delegate(delegate, e)
130
+ end
131
+ else
132
+ delegate.callback = on name do |e|
133
+ delegate(delegate, e)
134
+ end
135
+ end
97
136
 
98
- css(selector).on(name, &block)
137
+ pair = [selector, block]
138
+ delegate.handlers = [pair]
139
+
140
+ Delegate.new(self, name, pair)
141
+ else
142
+ pair = [selector, block]
143
+ delegate.handlers << pair
144
+
145
+ Delegate.new(self, name, pair)
146
+ end
99
147
  else
100
- `#@native.addEventListener(#{name}, #{callback.to_n})`
148
+ callback = Callback.new(self, name, selector, &block)
149
+ callbacks.push(callback)
150
+
151
+ attach(callback)
152
+ end
153
+ end
154
+
155
+ def on!(name, &block)
156
+ raise ArgumentError, 'no block has been given' unless block
157
+
158
+ name = Event.name_for(name)
159
+ callback = Callback.new(self, name, &block)
160
+ callbacks.push(callback)
161
+
162
+ attach!(callback)
163
+ end
164
+
165
+ if Browser.supports? 'Event.addListener'
166
+ def attach(callback)
167
+ `#@native.addEventListener(#{callback.name}, #{callback.to_proc})`
168
+
169
+ callback
170
+ end
171
+
172
+ def attach!(callback)
173
+ `#@native.addEventListener(#{callback.name}, #{callback.to_proc}, true)`
174
+
175
+ callback
176
+ end
177
+ elsif Browser.supports? 'Event.attach'
178
+ def attach(callback)
179
+ if callback.event == Custom
180
+ %x{
181
+ if (!#@native.$custom) {
182
+ #@native.$custom = function(event) {
183
+ for (var i = 0, length = #@native.$callbacks.length; i < length; i++) {
184
+ var callback = #@native.$callbacks[i];
185
+
186
+ if (#{`callback`.event == Custom}) {
187
+ event.type = callback.name;
188
+
189
+ #{`callback`.call(`event`)};
190
+ }
191
+ }
192
+ };
193
+
194
+ #@native.attachEvent("ondataavailable", #@native.$custom);
195
+ }
196
+ }
197
+ else
198
+ `#@native.attachEvent("on" + #{callback.name}, #{callback.to_proc})`
199
+ end
200
+
201
+ callback
101
202
  end
102
203
 
103
- callback
204
+ def attach!(callback)
205
+ case callback.name
206
+ when :blur
207
+ `#@native.attachEvent("onfocusout", #{callback.to_proc})`
208
+
209
+ when :focus
210
+ `#@native.attachEvent("onfocusin", #{callback.to_proc})`
211
+
212
+ else
213
+ warn "attach: capture doesn't work on this browser"
214
+ attach(callback)
215
+ end
216
+
217
+ callback
218
+ end
219
+ else
220
+ # @todo implement polyfill
221
+ # @private
222
+ def attach(*)
223
+ raise NotImplementedError
224
+ end
225
+
226
+ # @todo implement polyfill
227
+ # @private
228
+ def attach!(*)
229
+ raise NotImplementedError
230
+ end
104
231
  end
105
232
 
106
233
  def off(what = nil)
107
234
  case what
108
235
  when Callback
109
236
  callbacks.delete(what)
110
-
111
- `#@native.removeEventListener(#{what.name}, #{what.to_n}, false)`
237
+ detach(what)
112
238
 
113
239
  when String
114
240
  if what.include?(?*) or what.include?(??)
@@ -118,7 +244,7 @@ class Event
118
244
 
119
245
  callbacks.delete_if {|callback|
120
246
  if callback.name == what
121
- `#@native.removeEventListener(#{callback.name}, #{callback.to_n}, false)`
247
+ detach(callback)
122
248
 
123
249
  true
124
250
  end
@@ -128,7 +254,7 @@ class Event
128
254
  when Regexp
129
255
  callbacks.delete_if {|callback|
130
256
  if callback.name =~ what
131
- `#@native.removeEventListener(#{callback.name}, #{callback.to_n}, false)`
257
+ detach(callback)
132
258
 
133
259
  true
134
260
  end
@@ -136,19 +262,73 @@ class Event
136
262
 
137
263
  else
138
264
  callbacks.each {|callback|
139
- `#@native.removeEventListener(#{callback.name}, #{callback.to_n}, false)`
265
+ detach(callback)
140
266
  }
141
267
 
142
268
  callbacks.clear
143
269
  end
144
270
  end
145
271
 
272
+ if Browser.supports? 'Event.removeListener'
273
+ def detach(callback)
274
+ `#@native.removeEventListener(#{callback.name}, #{callback.to_proc}, false)`
275
+ end
276
+ elsif Browser.supports? 'Event.detach'
277
+ def detach(callback)
278
+ if callback.event == Custom
279
+ if callbacks.none? { |c| c.event == Custom }
280
+ %x{
281
+ #@native.detachEvent("ondataavailable", #@native.$custom);
282
+
283
+ delete #@native.$custom;
284
+ }
285
+ end
286
+ else
287
+ `#@native.detachEvent("on" + #{callback.name}, #{callback.to_proc})`
288
+ end
289
+ end
290
+ else
291
+ # @todo implement internal handler thing
292
+ # @private
293
+ def detach(callback)
294
+ raise NotImplementedError
295
+ end
296
+ end
297
+
146
298
  def trigger(event, *args, &block)
147
299
  if event.is_a? String
148
300
  event = Event.create(event, *args, &block)
149
301
  end
150
302
 
151
- `#@native.dispatchEvent(#{event.to_n})`
303
+ dispatch(event)
304
+ end
305
+
306
+ # Trigger the event without bubbling.
307
+ def trigger!(event, *args, &block)
308
+ trigger event, *args do |e|
309
+ block.call(e) if block
310
+ e.bubbles = false
311
+ end
312
+ end
313
+
314
+ if Browser.supports? 'Event.dispatch'
315
+ def dispatch(event)
316
+ `#@native.dispatchEvent(#{event.to_n})`
317
+ end
318
+ elsif Browser.supports? 'Event.fire'
319
+ def dispatch(event)
320
+ if Custom === event
321
+ `#@native.fireEvent("ondataavailable", #{event.to_n})`
322
+ else
323
+ `#@native.fireEvent("on" + #{event.name}, #{event.to_n})`
324
+ end
325
+ end
326
+ else
327
+ # @todo implement polyfill
328
+ # @private
329
+ def dispatch(*)
330
+ raise NotImplementedError
331
+ end
152
332
  end
153
333
 
154
334
  private
@@ -162,44 +342,29 @@ class Event
162
342
  }
163
343
  end
164
344
 
165
- def observe
345
+ def delegated
166
346
  %x{
167
- if (!#@native.$observer) {
168
- #@native.$observer = #{MutationObserver.new {|mutations|
169
- mutations.each {|mutation|
170
- mutation.added.each {|node|
171
- next unless Element === node
172
-
173
- defer(node)
174
- }
175
- }
176
- }};
177
-
178
- #{`#@native.$observer`.observe(@native, children: true, tree: true)}
347
+ if (!#@native.$delegated) {
348
+ #@native.$delegated = #{{}};
179
349
  }
350
+
351
+ return #@native.$delegated;
180
352
  }
181
353
  end
182
354
 
183
- def deferred
184
- %x{
185
- if (!#@native.$deferred) {
186
- #@native.$deferred = [];
187
- }
355
+ def delegate(delegates, event, element = event.target)
356
+ return if element.nil? || element == event.on
188
357
 
189
- return #@native.$deferred;
190
- }
191
- end
358
+ delegates.handlers.each {|selector, block|
359
+ if element.matches? selector
360
+ new = event.dup
361
+ new.on = element
192
362
 
193
- def defer(node)
194
- deferred.each {|name, selector, block|
195
- if node.matches?(selector)
196
- node.on(name, &block)
363
+ block.call new, *new.arguments
197
364
  end
198
-
199
- node.elements.each {|el|
200
- defer(el)
201
- }
202
365
  }
366
+
367
+ delegate(delegates, event, element.parent)
203
368
  end
204
369
  end
205
370
  end