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
@@ -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