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