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
@@ -11,8 +11,18 @@ class Document < Element
11
11
  end
12
12
  end
13
13
 
14
- def window
15
- Window.new(`#@native.defaultView`)
14
+ if Browser.supports? 'Document.view'
15
+ def window
16
+ Window.new(`#@native.defaultView`)
17
+ end
18
+ elsif Browser.supports? 'Document.window'
19
+ def window
20
+ Window.new(`#@native.parentWindow`)
21
+ end
22
+ else
23
+ def window
24
+ raise NotImplementedError, 'window from document unsupported'
25
+ end
16
26
  end
17
27
 
18
28
  def create_text(content)
@@ -28,15 +38,11 @@ class Document < Element
28
38
  }
29
39
  }
30
40
 
31
- xpath(what).first || css(what).first
41
+ css(what).first || xpath(what).first
32
42
  end
33
43
 
34
44
  alias at []
35
45
 
36
- def cookies
37
- Cookies.new(@native) if defined?(`#@native.cookie`)
38
- end
39
-
40
46
  def document
41
47
  self
42
48
  end
@@ -45,10 +51,6 @@ class Document < Element
45
51
  "#<DOM::Document: #{children.inspect}>"
46
52
  end
47
53
 
48
- def location
49
- Location.new(`#@native.location`) if `#@native.location`
50
- end
51
-
52
54
  def title
53
55
  `#@native.title`
54
56
  end
@@ -1,8 +1,10 @@
1
1
  require 'browser/dom/element/position'
2
2
  require 'browser/dom/element/offset'
3
3
  require 'browser/dom/element/scroll'
4
+ require 'browser/dom/element/size'
4
5
 
5
6
  require 'browser/dom/element/input'
7
+ require 'browser/dom/element/image'
6
8
 
7
9
  module Browser; module DOM
8
10
 
@@ -13,11 +15,12 @@ class Element < Node
13
15
 
14
16
  def self.new(node)
15
17
  if self == Element
16
- case `node.nodeName`.downcase
17
- when :input
18
- Input.new(node)
18
+ name = `node.nodeName`.capitalize
19
19
 
20
- else super
20
+ if Element.const_defined?(name)
21
+ Element.const_get(name).new(node)
22
+ else
23
+ super
21
24
  end
22
25
  else
23
26
  super
@@ -33,13 +36,23 @@ class Element < Node
33
36
  alias_native :id
34
37
 
35
38
  def add_class(*names)
36
- `#@native.className = #{(class_names + names).uniq.join ' '}`
39
+ classes = class_names + names
40
+
41
+ unless classes.empty?
42
+ `#@native.className = #{classes.uniq.join ' '}`
43
+ end
37
44
 
38
45
  self
39
46
  end
40
47
 
41
48
  def remove_class(*names)
42
- `#@native.className = #{(class_names - names).join ' '}`
49
+ classes = class_names - names
50
+
51
+ if classes.empty?
52
+ `#@native.removeAttribute('class')`
53
+ else
54
+ `#@native.className = #{classes.join ' '}`
55
+ end
43
56
 
44
57
  self
45
58
  end
@@ -102,7 +115,23 @@ class Element < Node
102
115
  end
103
116
 
104
117
  def size(*inc)
105
- Size.new(`#@native.offsetWidth`, `#@native.offsetHeight`)
118
+ Size.new(self, *inc)
119
+ end
120
+
121
+ def height
122
+ size.height
123
+ end
124
+
125
+ def height=(value)
126
+ size.height = value
127
+ end
128
+
129
+ def width
130
+ size.width
131
+ end
132
+
133
+ def width=(value)
134
+ size.width = value
106
135
  end
107
136
 
108
137
  def position
@@ -173,23 +202,53 @@ class Element < Node
173
202
  }.flatten.uniq
174
203
  end
175
204
 
176
- def css(path)
177
- NodeSet.new(document, Native::Array.new(`#@native.querySelectorAll(path)`))
205
+ if Browser.supports? 'Query.css'
206
+ def css(path)
207
+ %x{
208
+ try {
209
+ var result = #@native.querySelectorAll(path);
210
+
211
+ return #{NodeSet.new(document,
212
+ Native::Array.new(`result`))};
213
+ }
214
+ catch(e) {
215
+ return #{NodeSet.new(document)};
216
+ }
217
+ }
218
+ end
219
+ elsif Browser.loaded? 'Sizzle'
220
+ def css(path)
221
+ NodeSet.new(document, `Sizzle(#{path}, #@native)`)
222
+ end
223
+ else
224
+ def css(selector)
225
+ raise NotImplementedError, 'query by CSS selector unsupported'
226
+ end
178
227
  end
179
228
 
180
- def xpath(path)
181
- result = []
229
+ if Browser.supports?('Query.xpath') || Browser.loaded?('wicked-good-xpath')
230
+ if Browser.loaded? 'wicked-good-xpath'
231
+ `wgxpath.install()`
232
+ end
182
233
 
183
- begin
234
+ def xpath(path)
184
235
  %x{
185
- var tmp = (#@native.ownerDocument || #@native).evaluate(
186
- path, #@native, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
236
+ try {
237
+ var result = (#@native.ownerDocument || #@native).evaluate(path,
238
+ #@native, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
187
239
 
188
- result = #{Native::Array.new(`tmp`, get: :snapshotItem, length: :snapshotLength)};
240
+ return #{NodeSet.new(document,
241
+ Native::Array.new(`result`, get: :snapshotItem, length: :snapshotLength))};
242
+ }
243
+ catch (e) {
244
+ return #{NodeSet.new(document)};
245
+ }
189
246
  }
190
- rescue; end
191
-
192
- NodeSet.new(document, result)
247
+ end
248
+ else
249
+ def xpath(path)
250
+ raise NotImplementedError, 'query by XPath unsupported'
251
+ end
193
252
  end
194
253
 
195
254
  def style(data = nil, &block)
@@ -201,29 +260,41 @@ class Element < Node
201
260
  style.replace(data)
202
261
  elsif data.is_a?(Enumerable)
203
262
  style.assign(data)
204
- end
205
-
206
- if block
263
+ elsif block
207
264
  style.apply(&block)
208
265
  end
209
266
 
210
267
  self
211
268
  end
212
269
 
213
- def style!
214
- CSS::Declaration.new(`#{window.to_n}.getComputedStyle(#@native, null)`)
270
+ if Browser.supports? 'CSS.computed'
271
+ def style!
272
+ CSS::Declaration.new(`#{window.to_n}.getComputedStyle(#@native, null)`)
273
+ end
274
+ elsif Browser.supports? 'CSS.current'
275
+ def style!
276
+ CSS::Declaration.new(`#@native.currentStyle`)
277
+ end
278
+ else
279
+ def style!
280
+ raise NotImplementedError, 'computed style unsupported'
281
+ end
215
282
  end
216
283
 
217
284
  def data(what)
218
- unless defined?(`#@native.$data`)
219
- `#@native.$data = {}`
220
- end
221
-
222
285
  if Hash === what
286
+ unless defined?(`#@native.$data`)
287
+ `#@native.$data = {}`
288
+ end
289
+
223
290
  what.each {|name, value|
224
291
  `#@native.$data[name] = value`
225
292
  }
226
293
  else
294
+ return self["data-#{what}"] if self["data-#{what}"]
295
+
296
+ return unless defined?(`#@native.$data`)
297
+
227
298
  %x{
228
299
  var value = #@native.$data[what];
229
300
 
@@ -237,10 +308,37 @@ class Element < Node
237
308
  end
238
309
  end
239
310
 
240
- def matches?(selector)
241
- `#@native.matches(#{selector})`
311
+ if Browser.supports? 'Element.matches'
312
+ def matches?(selector)
313
+ `#@native.matches(#{selector})`
314
+ end
315
+ elsif Browser.supports? 'Element.matches (Opera)'
316
+ def matches?(selector)
317
+ `#@native.oMatchesSelector(#{selector})`
318
+ end
319
+ elsif Browser.supports? 'Element.matches (Internet Explorer)'
320
+ def matches?(selector)
321
+ `#@native.msMatchesSelector(#{selector})`
322
+ end
323
+ elsif Browser.supports? 'Element.matches (Firefox)'
324
+ def matches?(selector)
325
+ `#@native.mozMatchesSelector(#{selector})`
326
+ end
327
+ elsif Browser.supports? 'Element.matches (Chrome)'
328
+ def matches?(selector)
329
+ `#@native.webkitMatchesSelector(#{selector})`
330
+ end
331
+ elsif Browser.loaded? 'Sizzle'
332
+ def matches?(selector)
333
+ `Sizzle.matchesSelector(#@native, #{selector})`
334
+ end
335
+ else
336
+ def matches?(selector)
337
+ raise NotImplementedError, 'selector matching unsupported'
338
+ end
242
339
  end
243
340
 
341
+ # @abstract
244
342
  def window
245
343
  document.window
246
344
  end
@@ -0,0 +1,23 @@
1
+ module Browser; module DOM; class Element < Node
2
+
3
+ class Image < Element
4
+ def complete?
5
+ `#@native.complete`
6
+ end
7
+
8
+ def cross?
9
+ `#@native.crossOrigin`
10
+ end
11
+
12
+ def height
13
+ `#@native.naturalHeight`
14
+ end
15
+
16
+ def width
17
+ `#@native.naturalWidth`
18
+ end
19
+ end
20
+
21
+ Img = Image
22
+
23
+ end; end; end
@@ -1,6 +1,8 @@
1
1
  module Browser; module DOM; class Element < Node
2
2
 
3
3
  class Offset
4
+ attr_reader :element
5
+
4
6
  def initialize(element)
5
7
  @element = element
6
8
  @native = element.to_n
@@ -26,18 +28,33 @@ class Offset
26
28
  set nil, value
27
29
  end
28
30
 
29
- def get
30
- doc = @element.document
31
- root = doc.root.to_n
32
- win = doc.window.to_n
31
+ if Browser.supports? 'Element.getBoundingClientRect'
32
+ def get
33
+ doc = @element.document
34
+ root = doc.root.to_n
35
+ win = doc.window.to_n
36
+
37
+ %x{
38
+ var box = #@native.getBoundingClientRect(),
39
+ y = box.top + (#{win}.pageYOffset || #{root}.scrollTop) - (#{root}.clientTop || 0),
40
+ x = box.left + (#{win}.pageXOffset || #{root}.scrollLeft) - (#{root}.clientLeft || 0);
41
+ }
33
42
 
34
- %x{
35
- var box = #@native.getBoundingClientRect(),
36
- y = box.top + (#{win}.pageYOffset || #{root}.scrollTop) - (#{root}.clientTop || 0),
37
- x = box.left + (#{win}.pageXOffset || #{root}.scrollLeft) - (#{root}.clientLeft || 0);
38
- }
43
+ Browser::Position.new(`x`, `y`)
44
+ end
45
+ else
46
+ def get
47
+ doc = document
48
+ root = doc.root.to_n
49
+ win = doc.window.to_n
39
50
 
40
- Browser::Position.new(`x`, `y`)
51
+ %x{
52
+ var y = (#{win}.pageYOffset || #{root}.scrollTop) - (#{root}.clientTop || 0),
53
+ x = (#{win}.pageXOffset || #{root}.scrollLeft) - (#{root}.clientLeft || 0);
54
+ }
55
+
56
+ Browser::Position.new(`x`, `y`)
57
+ end
41
58
  end
42
59
 
43
60
  def set(*value)
@@ -6,8 +6,38 @@ class Scroll
6
6
  @native = element.to_n
7
7
  end
8
8
 
9
- def position
10
- Browser::Position.new(`#@native.scrollLeft`, `#@native.scrollTop`)
9
+ if Browser.supports? 'Element.scroll'
10
+ def to(what)
11
+ x = what[:x] || self.x
12
+ y = what[:y] || self.y
13
+
14
+ `#@native.scrollTop = #{y}`
15
+ `#@native.scrollLeft = #{x}`
16
+ end
17
+
18
+ def position
19
+ Browser::Position.new(`#@native.scrollLeft`, `#@native.scrollTop`)
20
+ end
21
+ elsif Browser.supports? 'Element.pageOffset'
22
+ def to(what)
23
+ x = what[:x] || self.x
24
+ y = what[:y] || self.y
25
+
26
+ `#@native.pageYOffset = #{y}`
27
+ `#@native.pageXOffset = #{x}`
28
+ end
29
+
30
+ def position
31
+ Position.new(`#@native.pageXOffset`, `#@native.pageYOffset`)
32
+ end
33
+ else
34
+ def to(what)
35
+ raise NotImplementedError, 'scroll on element unsupported'
36
+ end
37
+
38
+ def position
39
+ raise NotImplementedError, 'scroll on element unsupported'
40
+ end
11
41
  end
12
42
 
13
43
  def x
@@ -18,16 +48,6 @@ class Scroll
18
48
  position.y
19
49
  end
20
50
 
21
- def to(what)
22
- x = what[:x] || self.x
23
- y = what[:y] || self.y
24
-
25
- `#@native.scrollTop = #{y}`
26
- `#@native.scrollLeft = #{x}`
27
-
28
- self
29
- end
30
-
31
51
  def height
32
52
  `#@native.scrollHeight`
33
53
  end
@@ -0,0 +1,29 @@
1
+ module Browser; module DOM; class Element < Node
2
+
3
+ class Size
4
+ attr_reader :element
5
+
6
+ def initialize(element, *inc)
7
+ @element = element
8
+ @native = element.to_n
9
+ @include = inc
10
+ end
11
+
12
+ def width
13
+ `#@native.offsetWidth`
14
+ end
15
+
16
+ def width=(value)
17
+ @element.style[:width] = value
18
+ end
19
+
20
+ def height
21
+ `#@native.offsetHeight`
22
+ end
23
+
24
+ def height=(value)
25
+ @element.style[:height] = value
26
+ end
27
+ end
28
+
29
+ end; end; end
@@ -1,5 +1,4 @@
1
1
  require 'browser/dom/event/base'
2
-
3
2
  require 'browser/dom/event/ui'
4
3
  require 'browser/dom/event/mouse'
5
4
  require 'browser/dom/event/keyboard'
@@ -31,46 +30,15 @@ require 'browser/dom/event/close'
31
30
  module Browser; module DOM
32
31
 
33
32
  class Event
34
- def self.names
35
- return @names if @names
36
-
37
- @names = Hash.new { |_, k| k }
38
- @names.merge!({
39
- load: 'DOMContentLoaded',
40
- hover: 'mouse:over'
41
- })
33
+ def self.aliases
34
+ @aliases ||= {
35
+ 'dom:load' => 'DOMContentLoaded',
36
+ 'hover' => 'mouse:over'
37
+ }
42
38
  end
43
39
 
44
40
  def self.name_for(name)
45
- names[name].gsub(?:, '')
46
- end
47
-
48
- def self.classes
49
- @classes ||= {
50
- Animation => $$[:AnimationEvent],
51
- AudioProcessing => $$[:AudioProcessingEvent],
52
- BeforeUnload => $$[:BeforeUnloadEvent],
53
- Composition => $$[:CompositionEvent],
54
- Clipboard => $$[:ClipboardEvent],
55
- DeviceLight => $$[:DeviceLightEvent],
56
- DeviceMotion => $$[:DeviceMotionEvent],
57
- DeviceOrientation => $$[:DeviceOrientationEvent],
58
- DeviceProximity => $$[:DeviceProximityEvent],
59
- Drag => $$[:DragEvent],
60
- Gamepad => $$[:GamepadEvent],
61
- HashChange => $$[:HashChangeEvent],
62
- Progress => $$[:ProgressEvent],
63
- PageTransition => $$[:PageTransitionEvent],
64
- PopState => $$[:PopStateEvent],
65
- Storage => $$[:StorageEvent],
66
- Touch => $$[:TouchEvent],
67
- Sensor => $$[:SensorEvent],
68
- Mouse => $$[:MouseEvent],
69
- Keyboard => $$[:KeyboardEvent],
70
- Focus => $$[:FocusEvent],
71
- Wheel => $$[:WheelEvent],
72
- Custom => $$[:CustomEvent]
73
- }
41
+ (aliases[name] || name).gsub(?:, '')
74
42
  end
75
43
 
76
44
  def self.class_for(name)
@@ -149,66 +117,95 @@ class Event
149
117
  when 'wheel'
150
118
  Wheel
151
119
 
152
- when 'abort', 'afterprint', 'beforeprint', 'cached', 'canplay', 'canplaythrough',
153
- 'change', 'chargingchange', 'chargingtimechange', 'checking', 'close',
154
- 'dischargingtimechange', 'DOMContentLoaded', 'downloading', 'durationchange',
155
- 'emptied', 'ended', 'error', 'fullscreenchange', 'fullscreenerror', 'input',
156
- 'invalid', 'levelchange', 'loadeddata', 'loadedmetadata', 'noupdate', 'obsolete',
157
- 'offline', 'online', 'open', 'orientationchange', 'pause', 'pointerlockchange',
158
- 'pointerlockerror', 'play', 'playing', 'ratechange', 'readystatechange', 'reset',
159
- 'seeked', 'seeking', 'stalled', 'submit', 'success', 'suspend', 'timeupdate',
160
- 'updateready', 'visibilitychange', 'volumechange', 'waiting'
120
+ when 'abort', 'afterprint', 'beforeprint', 'cached', 'canplay',
121
+ 'canplaythrough', 'change', 'chargingchange', 'chargingtimechange',
122
+ 'checking', 'close', 'dischargingtimechange', 'DOMContentLoaded',
123
+ 'downloading', 'durationchange', 'emptied', 'ended', 'error',
124
+ 'fullscreenchange', 'fullscreenerror', 'input', 'invalid',
125
+ 'levelchange', 'loadeddata', 'loadedmetadata', 'noupdate', 'obsolete',
126
+ 'offline', 'online', 'open', 'orientationchange', 'pause',
127
+ 'pointerlockchange', 'pointerlockerror', 'play', 'playing',
128
+ 'ratechange', 'readystatechange', 'reset', 'seeked', 'seeking',
129
+ 'stalled', 'submit', 'success', 'suspend', 'timeupdate', 'updateready',
130
+ 'visibilitychange', 'volumechange', 'waiting'
161
131
  Event
162
132
 
163
133
  else
164
134
  Custom
165
135
  end
136
+ end
166
137
 
167
- if type != Event && type.supported?
168
- type
169
- else
170
- Event
171
- end
138
+ def self.supported?
139
+ true
172
140
  end
173
141
 
174
142
  def self.create(name, *args, &block)
175
143
  name = name_for(name)
176
144
  klass = class_for(name)
177
145
 
178
- event = if klass == self
179
- new(`new window.Event(#{name}, #{Definition.new(&block)})`)
180
- else
181
- klass.create(name, &block)
182
- end
183
-
146
+ event = klass.new(klass.construct(name, klass.const_get(:Definition).new(&block)))
184
147
  event.arguments = args
185
148
 
186
149
  event
187
150
  end
188
151
 
189
- def self.new(value, *args)
190
- klass, _ = classes.find {|_, constructor|
191
- Native.is_a?(value, constructor)
192
- }
152
+ if Browser.supports? 'Event.constructor'
153
+ def self.construct(name, desc)
154
+ `new Event(#{name}, #{desc})`
155
+ end
156
+ elsif Browser.supports? 'Event.create'
157
+ def self.construct(name, desc)
158
+ %x{
159
+ var event = document.createEvent("HTMLEvents");
160
+ event.initEvent(name, desc.bubbles, desc.cancelable);
161
+
162
+ #{return Native(`event`).merge!(desc)};
163
+ }
164
+ end
165
+ elsif Browser.supports? 'Event.createObject'
166
+ def self.construct(name, desc)
167
+ Native(`document.createEventObject()`) \
168
+ .merge!(desc) \
169
+ .merge!(`{ type: name }`) \
170
+ .to_n
171
+ end
172
+ else
173
+ def self.construct(name, desc)
174
+ Native(desc).merge!(`{ type: name }`).to_n
175
+ end
176
+ end
177
+
178
+ def self.new(value, callback = nil)
179
+ return super unless self == Event
193
180
 
194
- if !klass || klass == self
195
- super(value, *args)
181
+ klass = class_for(callback ? callback.name : `value.type`)
182
+
183
+ if klass == Event
184
+ super
196
185
  else
197
- klass.new(value, *args)
186
+ klass.new(value, callback)
198
187
  end
199
188
  end
200
189
 
201
- attr_reader :target, :callback
190
+ attr_reader :callback
191
+ attr_writer :on
202
192
 
203
- def initialize(native, callback = nil)
204
- super(native)
193
+ def initialize(event, callback = nil)
194
+ super(event)
205
195
 
206
- @target = Target.convert(`#@native.target`)
207
- @callback, = callback # TODO: change this when super is fixed
196
+ @callback = callback
208
197
  end
209
198
 
210
- def off
211
- @callback.off if @callback
199
+ def name
200
+ `#@native.type`
201
+ end
202
+
203
+ def on
204
+ @on || Target.convert(`#@native.currentTarget`)
205
+ end
206
+
207
+ def target
208
+ Target.convert(`#@native.srcElement || #@native.target`)
212
209
  end
213
210
 
214
211
  def arguments
@@ -221,20 +218,36 @@ class Event
221
218
 
222
219
  alias_native :bubbles?, :bubbles
223
220
  alias_native :cancelable?, :cancelable
224
- alias_native :name, :type
225
221
  alias_native :data
226
222
  alias_native :phase, :eventPhase
227
223
  alias_native :at, :timeStamp
228
224
 
225
+ def off
226
+ @callback.off if @callback
227
+ end
228
+
229
229
  def stopped?
230
230
  `!!#@native.stopped`
231
231
  end
232
232
 
233
- def stop!
233
+ def stop
234
234
  `#@native.stopPropagation()` if defined?(`#@native.stopPropagation`)
235
- `#@native.preventDefault()` if defined?(`#@native.preventDefault`)
236
235
  `#@native.stopped = true`
237
236
  end
237
+
238
+ def prevent
239
+ `#@native.preventDefault()` if defined?(`#@native.preventDefault`)
240
+ `#@native.prevented = true`
241
+ end
242
+
243
+ def prevented?
244
+ `!!#@native.prevented`
245
+ end
246
+
247
+ def stop!
248
+ prevent
249
+ stop
250
+ end
238
251
  end
239
252
 
240
253
  end; end