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,15 +1,18 @@
1
1
  module Browser
2
2
 
3
- # This class wraps `setInterval`.
3
+ # Allows you to create an interval that executes the function every given
4
+ # seconds.
5
+ #
6
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/Window.setInterval
4
7
  class Interval
5
8
  # @!attribute [r] every
6
- # @return [Number] the seconds every which the block is called
9
+ # @return [Float] the seconds every which the block is called
7
10
  attr_reader :every
8
11
 
9
12
  # Create and start an interval.
10
13
  #
11
14
  # @param window [Window] the window to start the interval on
12
- # @param time [Number] seconds every which to call the block
15
+ # @param time [Float] seconds every which to call the block
13
16
  def initialize(window, time, &block)
14
17
  @window = Native.convert(window)
15
18
  @every = time
@@ -32,20 +35,14 @@ class Interval
32
35
  end
33
36
 
34
37
  # Abort the interval, it won't be possible to start it again.
35
- #
36
- # @return [self]
37
38
  def abort
38
39
  `#@window.clearInterval(#@id)`
39
40
 
40
41
  @aborted = true
41
42
  @id = nil
42
-
43
- self
44
43
  end
45
44
 
46
45
  # Stop the interval, it will be possible to start it again.
47
- #
48
- # @return [self]
49
46
  def stop
50
47
  `#@window.clearInterval(#@id)`
51
48
 
@@ -54,16 +51,12 @@ class Interval
54
51
  end
55
52
 
56
53
  # Start the interval if it has been stopped.
57
- #
58
- # @return [self]
59
54
  def start
60
55
  raise "the interval has been aborted" if aborted?
61
56
 
62
57
  return unless stopped?
63
58
 
64
59
  @id = `#@window.setInterval(#{@block.to_n}, #@every * 1000)`
65
-
66
- self
67
60
  end
68
61
  end
69
62
 
@@ -71,6 +64,7 @@ class Window
71
64
  # Execute the block every given seconds.
72
65
  #
73
66
  # @param time [Float] the seconds between every call
67
+ #
74
68
  # @return [Interval] the object representing the interval
75
69
  def every(time, &block)
76
70
  Interval.new(@native, time, &block)
@@ -80,6 +74,7 @@ end
80
74
  end
81
75
 
82
76
  class Proc
77
+ # (see Browser::Window#every)
83
78
  def every(time)
84
79
  $window.every(time, &self)
85
80
  end
@@ -1,5 +1,8 @@
1
1
  module Browser
2
2
 
3
+ # Allows manipulation of a location, usually from {Window} and {DOM::Document}.
4
+ #
5
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/Location
3
6
  class Location
4
7
  include Native
5
8
 
@@ -66,9 +69,16 @@ class Location
66
69
  end
67
70
 
68
71
  class Window
69
- # Get the {Location} object for this window.
70
- #
71
- # @return [Location]
72
+ # @!attribute [r] location
73
+ # @return [Location] the location for the window
74
+ def location
75
+ Location.new(`#@native.location`) if `#@native.location`
76
+ end
77
+ end
78
+
79
+ class DOM::Document < DOM::Element
80
+ # @!attribute [r] location
81
+ # @return [Location] the location for the document
72
82
  def location
73
83
  Location.new(`#@native.location`) if `#@native.location`
74
84
  end
@@ -1,6 +1,8 @@
1
1
  module Browser
2
2
 
3
- # Class that represents the browser attributes.
3
+ # Representation of the navigator application.
4
+ #
5
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator
4
6
  class Navigator
5
7
  include Native
6
8
 
@@ -8,7 +10,7 @@ class Navigator
8
10
  Product = Struct.new(:name, :version)
9
11
  Vendor = Struct.new(:name, :version)
10
12
 
11
- # Class that represents a MIME type.
13
+ # Representation of a MIME type.
12
14
  class MimeType
13
15
  include Native
14
16
 
@@ -33,7 +35,9 @@ class Navigator
33
35
  alias_native :type
34
36
  end
35
37
 
36
- # Class to represent a browser plugin.
38
+ # Representation of a navigator plugin.
39
+ #
40
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/Plugin
37
41
  class Plugin < Native::Array
38
42
  def initialize(plugin)
39
43
  super plugin do |m|
@@ -140,9 +144,8 @@ class Navigator
140
144
  end
141
145
 
142
146
  class Window
143
- # Get the {Navigator} object for this window.
144
- #
145
- # @return [Navigator]
147
+ # @!attribute [r] navigator
148
+ # @return [Navigator] the navigator
146
149
  def navigator
147
150
  Navigator.new(`#@native.navigator`) if `#@native.navigator`
148
151
  end
@@ -1,5 +1,8 @@
1
1
  module Browser
2
2
 
3
+ # Representation of the screen the window is being rendered on.
4
+ #
5
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/Window.screen
3
6
  class Screen
4
7
  include Native
5
8
  include DOM::Event::Target
@@ -8,30 +11,53 @@ class Screen
8
11
  Screen.new(value) if Native.is_a?(value, `window.Screen`)
9
12
  }
10
13
 
14
+ Depth = Struct.new(:color, :pixel)
15
+
16
+ # @!attribute [r] width
17
+ # @return [Integer] the width of the screen in pixels
11
18
  alias_native :width
19
+
20
+ # @!attribute [r] height
21
+ # @return [Integer] the height of the screen in pixels
12
22
  alias_native :height
13
23
 
24
+ # @!attribute [r] size
25
+ # @return [Size] the size in pixels
14
26
  def size
15
27
  Size.new(width, height)
16
28
  end
17
29
 
30
+ # @!attribute [r] x
31
+ # @return [Integer] the offset from the top left corner of the screen in
32
+ # pixels
18
33
  alias_native :x, :top
34
+
35
+ # @!attribute [r] y
36
+ # @return [Integer] the offset from the top left corner of the screen in
37
+ # pixels
19
38
  alias_native :y, :left
20
39
 
40
+ # @!attribute [r] position
41
+ # @return [Position] the offset from the top left corner of the screen in
42
+ # pixels
21
43
  def position
22
44
  Position.new(x, y)
23
45
  end
24
46
 
25
- alias_native :color_depth, :colorDepth
26
- alias_native :pixel_depth, :pixelDepth
47
+ # @!attribute [r] depth
48
+ # @return [Depth] the screen depth
49
+ def depth
50
+ Depth.new(`#@native.colorDepth`, `#@native.pixelDepth`)
51
+ end
27
52
 
53
+ # @!attribute [r] orientation
54
+ # @return [String] the orientation of the screen
28
55
  alias_native :orientation
29
56
  end
30
57
 
31
58
  class Window
32
- # Get the {Screen} for this window.
33
- #
34
- # @return [Screen]
59
+ # @!attribute [r] screen
60
+ # @return [Screen] the screen for the window
35
61
  def screen
36
62
  Screen.new(`#@native.screen`)
37
63
  end
@@ -1,9 +1,12 @@
1
1
  module Browser
2
2
 
3
- # This class wraps `WebSocket`.
3
+ # A {Socket} allows the browser and a server to have a bidirectional data
4
+ # connection.
5
+ #
6
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
4
7
  class Socket
5
8
  def self.supported?
6
- defined? `window.WebSocket`
9
+ Browser.supports? :WebSocket
7
10
  end
8
11
 
9
12
  include Native
@@ -18,8 +21,9 @@ class Socket
18
21
  #
19
22
  # @param url [String] the URL to connect to
20
23
  # @param protocol [String] the protocol to use
21
- # @yield if the block has no parameters it's instance_exec'd, otherwise it's
22
- # called with self
24
+ #
25
+ # @yield if the block has no parameters it's `instance_exec`d, otherwise it's
26
+ # called with `self`
23
27
  def initialize(url, protocol = nil, &block)
24
28
  if native?(url)
25
29
  super(url)
@@ -1,19 +1,24 @@
1
- #--
2
- # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
- # Version 2, December 2004
4
- #
5
- # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
- # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
- #
8
- # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
- #++
10
-
11
1
  require 'json'
12
2
  require 'stringio'
13
3
 
14
4
  module Browser
15
5
 
16
- class Storage < Hash
6
+ # A {Storage} allows you to store data across page loads and browser
7
+ # restarts.
8
+ #
9
+ # Compatibility
10
+ # -------------
11
+ # The compatibility layer will try various implementations in the following
12
+ # order.
13
+ #
14
+ # + [window.localStorage](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage#localStorage)
15
+ # + [window.globalStorage](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage#globalStorage)
16
+ # + [document.body.addBehavior](http://msdn.microsoft.com/en-us/library/ms531424(VS.85).aspx)
17
+ # + [document.cookie](https://developer.mozilla.org/en-US/docs/Web/API/document.cookie)
18
+ #
19
+ # @see https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage
20
+ # @todo remove method_defined? checks when require order is fixed
21
+ class Storage
17
22
  def self.json_create(data)
18
23
  data.delete(JSON.create_id)
19
24
 
@@ -22,47 +27,106 @@ class Storage < Hash
22
27
  }]
23
28
  end
24
29
 
30
+ include Enumerable
31
+
32
+ # @!attribute [r] name
33
+ # @return [String] the name of the storage
25
34
  attr_reader :name
26
35
 
36
+ # Create a new storage on the given window with the given name.
37
+ #
38
+ # @param window [native] the window to save the storage to
39
+ # @param name [String] the name to use to discern different storages
27
40
  def initialize(window, name)
28
41
  super()
29
42
 
30
43
  @window = window
31
44
  @name = name
45
+ @data = {}
32
46
 
33
47
  autosave!
34
-
35
- init if respond_to? :init
48
+ init
36
49
  end
37
50
 
51
+ # @!attribute [r] encoded_name
52
+ # @return [String] the generated name
38
53
  def encoded_name
39
- "$opal.storage.#{@name}"
54
+ "$opal.storage.#@name"
40
55
  end
41
56
 
42
- def autosave?; @autosave; end
43
- def autosave!; @autosave = true; end
44
- def no_autosave!; @autosave = false; end
57
+ # Check if autosaving is enabled.
58
+ #
59
+ # When autosaving is enabled the {Storage} is saved every time a change is
60
+ # made, otherwise you'll have to save it manually yourself.
61
+ def autosave?
62
+ @autosave
63
+ end
64
+
65
+ # Enable autosaving.
66
+ def autosave!
67
+ @autosave = true
68
+ end
69
+
70
+ # Disable autosaving.
71
+ def no_autosave!
72
+ @autosave = false
73
+ end
74
+
75
+ # Iterate over the (key, value) pairs in the storage.
76
+ #
77
+ # @yield [key, value]
78
+ def each(&block)
79
+ return enum_for :each unless block
80
+
81
+ @data.each(&block)
82
+
83
+ self
84
+ end
45
85
 
46
- def replace(what)
47
- if what.is_a?(String)
48
- super JSON.parse(what)
86
+ # Get a value in the storage.
87
+ def [](key)
88
+ @data[key]
89
+ end
90
+
91
+ # Set a value in the storage.
92
+ def []=(key, value)
93
+ @data[key] = value
94
+
95
+ save if autosave?
96
+ end
97
+
98
+ # Delete a value from the storage.
99
+ def delete(key)
100
+ @data.delete(key).tap {
101
+ save if autosave
102
+ }
103
+ end
104
+
105
+ # Clear the storage.
106
+ def clear
107
+ @data.clear.tap {
108
+ save if autosave?
109
+ }
110
+ end
111
+
112
+ # Replace the current storage with the given one.
113
+ #
114
+ # @param new [Hash, String] if new is a {String} it will be parsed as JSON
115
+ def replace(new)
116
+ if String === new
117
+ @data.replace(JSON.parse(new))
49
118
  else
50
- super
119
+ @data.replace(new)
51
120
  end
52
121
  end
53
122
 
54
- %w([]= delete clear).each {|name|
55
- define_method name do |*args|
56
- # FIXME: remove the application when it's fixed
57
- super(*args).tap {
58
- save if autosave?
59
- }
60
- end
61
- }
123
+ # @!method init
124
+ # @private
62
125
 
63
- def save; end
126
+ # @!method save
127
+ # Persist the current state to the storage.
64
128
 
65
- if `window.localStorage`
129
+ if Browser.supports? 'Storage.local'
66
130
  def init
67
131
  replace `#@window.localStorage[#{encoded_name}] || '{}'`
68
132
  end
@@ -70,7 +134,7 @@ class Storage < Hash
70
134
  def save
71
135
  `#@window.localStorage[#{encoded_name}] = #{JSON.dump(self)}`
72
136
  end
73
- elsif `window.globalStorage`
137
+ elsif Browser.supports? 'Storage.global'
74
138
  def init
75
139
  replace `#@window.globalStorage[#@window.location.hostname][#{encoded_name}] || '{}'`
76
140
  end
@@ -78,7 +142,7 @@ class Storage < Hash
78
142
  def save
79
143
  `#@window.globalStorage[#@window.location.hostname][#{encoded_name}] = #{JSON.dump(self)}`
80
144
  end
81
- elsif `document.body.addBehavior`
145
+ elsif Browser.supports? 'Element.addBehavior'
82
146
  def init
83
147
  %x{
84
148
  #@element = #@window.document.createElement('link');
@@ -110,6 +174,9 @@ class Storage < Hash
110
174
  end
111
175
  end
112
176
 
177
+ # Convert the storage to JSON.
178
+ #
179
+ # @return [String] the JSON representation
113
180
  def to_json
114
181
  io = StringIO.new("{")
115
182
 
@@ -126,7 +193,15 @@ class Storage < Hash
126
193
  end
127
194
  end
128
195
 
196
+ # A {SessionStorage} allows you to store data across page reloads, as long as the session
197
+ # is active.
198
+ #
199
+ # @see https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage#sessionStorage
129
200
  class SessionStorage < Storage
201
+ def self.supported?
202
+ Browser.supports? 'Storage.session'
203
+ end
204
+
130
205
  def init
131
206
  replace `#@window.sessionStorage[#{encoded_name}] || '{}'`
132
207
  end
@@ -137,10 +212,20 @@ class SessionStorage < Storage
137
212
  end
138
213
 
139
214
  class Window
215
+ # Get a storage with the given name.
216
+ #
217
+ # @param name [Symbol] the name of the storage
218
+ #
219
+ # @return [Storage]
140
220
  def storage(name = :default)
141
221
  Storage.new(to_n, name)
142
222
  end
143
223
 
224
+ # Get a session storage with the given name.
225
+ #
226
+ # @param name [Symbol] the name of the storage
227
+ #
228
+ # @return [SessionStorage]
144
229
  def session_storage(name = :default)
145
230
  SessionStorage.new(to_n, name)
146
231
  end