opal-browser 0.2.0 → 0.3.3

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 (202) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/build.yml +78 -0
  3. data/.gitignore +3 -0
  4. data/CHANGELOG.md +11 -0
  5. data/Gemfile +17 -3
  6. data/LICENSE +2 -1
  7. data/README.md +131 -54
  8. data/Rakefile +29 -1
  9. data/config.ru +20 -3
  10. data/docs/polyfills.md +24 -0
  11. data/examples/2048/Gemfile +6 -0
  12. data/examples/2048/README.md +13 -0
  13. data/examples/2048/app/application.rb +169 -0
  14. data/examples/2048/config.ru +9 -0
  15. data/examples/canvas/Gemfile +6 -0
  16. data/examples/canvas/README.md +9 -0
  17. data/examples/canvas/app/application.rb +55 -0
  18. data/examples/canvas/config.ru +9 -0
  19. data/examples/component/Gemfile +6 -0
  20. data/examples/component/README.md +10 -0
  21. data/examples/component/app/application.rb +66 -0
  22. data/examples/component/config.ru +9 -0
  23. data/examples/integrations/README.md +24 -0
  24. data/examples/integrations/dynamic-rack-opal-sprockets-server/Gemfile +6 -0
  25. data/examples/integrations/dynamic-rack-opal-sprockets-server/README.md +16 -0
  26. data/examples/integrations/dynamic-rack-opal-sprockets-server/app/application.rb +6 -0
  27. data/examples/integrations/dynamic-rack-opal-sprockets-server/config.ru +9 -0
  28. data/examples/integrations/dynamic-roda-roda-sprockets/.gitignore +1 -0
  29. data/examples/integrations/dynamic-roda-roda-sprockets/Gemfile +7 -0
  30. data/examples/integrations/dynamic-roda-roda-sprockets/README.md +22 -0
  31. data/examples/integrations/dynamic-roda-roda-sprockets/Rakefile +4 -0
  32. data/examples/integrations/dynamic-roda-roda-sprockets/app/application.rb +6 -0
  33. data/examples/integrations/dynamic-roda-roda-sprockets/app.rb +32 -0
  34. data/examples/integrations/dynamic-roda-roda-sprockets/config.ru +3 -0
  35. data/examples/integrations/dynamic-roda-tilt/.gitignore +1 -0
  36. data/examples/integrations/dynamic-roda-tilt/Gemfile +8 -0
  37. data/examples/integrations/dynamic-roda-tilt/README.md +17 -0
  38. data/examples/integrations/dynamic-roda-tilt/Rakefile +6 -0
  39. data/examples/integrations/dynamic-roda-tilt/app/application.rb +6 -0
  40. data/examples/integrations/dynamic-roda-tilt/app.rb +50 -0
  41. data/examples/integrations/dynamic-roda-tilt/config.ru +3 -0
  42. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/Gemfile +7 -0
  43. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/README.md +16 -0
  44. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/app/application.rb +6 -0
  45. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/config.ru +29 -0
  46. data/examples/integrations/static-bash/.gitignore +2 -0
  47. data/examples/integrations/static-bash/Gemfile +3 -0
  48. data/examples/integrations/static-bash/README.md +8 -0
  49. data/examples/integrations/static-bash/app/application.rb +6 -0
  50. data/examples/integrations/static-bash/build.sh +4 -0
  51. data/examples/integrations/static-bash/index.html +10 -0
  52. data/examples/integrations/static-bash-opal-parser/.gitignore +3 -0
  53. data/examples/integrations/static-bash-opal-parser/Gemfile +3 -0
  54. data/examples/integrations/static-bash-opal-parser/README.md +10 -0
  55. data/examples/integrations/static-bash-opal-parser/build.sh +4 -0
  56. data/examples/integrations/static-bash-opal-parser/index.html +19 -0
  57. data/examples/integrations/static-rake/.gitignore +1 -0
  58. data/examples/integrations/static-rake/Gemfile +4 -0
  59. data/examples/integrations/static-rake/README.md +7 -0
  60. data/examples/integrations/static-rake/Rakefile +10 -0
  61. data/examples/integrations/static-rake/app/application.rb +6 -0
  62. data/examples/integrations/static-rake/index.html +9 -0
  63. data/examples/integrations/static-rake-guard/.gitignore +1 -0
  64. data/examples/integrations/static-rake-guard/Gemfile +6 -0
  65. data/examples/integrations/static-rake-guard/Guardfile +3 -0
  66. data/examples/integrations/static-rake-guard/README.md +10 -0
  67. data/examples/integrations/static-rake-guard/Rakefile +10 -0
  68. data/examples/integrations/static-rake-guard/app/application.rb +6 -0
  69. data/examples/integrations/static-rake-guard/index.html +9 -0
  70. data/examples/svg/.gitignore +1 -0
  71. data/examples/svg/Gemfile +4 -0
  72. data/examples/svg/README.md +7 -0
  73. data/examples/svg/Rakefile +10 -0
  74. data/examples/svg/app/application.rb +11 -0
  75. data/examples/svg/index.html +17 -0
  76. data/examples/svg/index.svg +6 -0
  77. data/index.html.erb +2 -3
  78. data/opal/browser/audio/node.rb +121 -0
  79. data/opal/browser/audio/param_schedule.rb +43 -0
  80. data/opal/browser/audio.rb +66 -0
  81. data/opal/browser/blob.rb +94 -0
  82. data/opal/browser/canvas/data.rb +1 -1
  83. data/opal/browser/canvas/gradient.rb +1 -1
  84. data/opal/browser/canvas/style.rb +3 -1
  85. data/opal/browser/canvas/text.rb +1 -1
  86. data/opal/browser/canvas.rb +17 -3
  87. data/opal/browser/console.rb +3 -1
  88. data/opal/browser/cookies.rb +72 -34
  89. data/opal/browser/crypto.rb +79 -0
  90. data/opal/browser/css/declaration.rb +1 -1
  91. data/opal/browser/css/rule.rb +1 -1
  92. data/opal/browser/css/style_sheet.rb +2 -2
  93. data/opal/browser/css.rb +23 -7
  94. data/opal/browser/database/sql.rb +7 -8
  95. data/opal/browser/delay.rb +16 -0
  96. data/opal/browser/dom/attribute.rb +1 -1
  97. data/opal/browser/dom/builder.rb +29 -10
  98. data/opal/browser/dom/document.rb +81 -13
  99. data/opal/browser/dom/document_fragment.rb +18 -0
  100. data/opal/browser/dom/document_or_shadow_root.rb +19 -0
  101. data/opal/browser/dom/element/attributes.rb +28 -4
  102. data/opal/browser/dom/element/button.rb +31 -0
  103. data/opal/browser/dom/element/custom.rb +177 -0
  104. data/opal/browser/dom/element/data.rb +17 -2
  105. data/opal/browser/dom/element/editable.rb +47 -0
  106. data/opal/browser/dom/element/form.rb +38 -0
  107. data/opal/browser/dom/element/iframe.rb +37 -0
  108. data/opal/browser/dom/element/image.rb +2 -0
  109. data/opal/browser/dom/element/input.rb +36 -0
  110. data/opal/browser/dom/element/media.rb +17 -0
  111. data/opal/browser/dom/element/scroll.rb +106 -74
  112. data/opal/browser/dom/element/select.rb +6 -0
  113. data/opal/browser/dom/element/size.rb +12 -0
  114. data/opal/browser/dom/element/template.rb +2 -0
  115. data/opal/browser/dom/element/textarea.rb +2 -0
  116. data/opal/browser/dom/element.rb +194 -50
  117. data/opal/browser/dom/mutation_observer.rb +2 -2
  118. data/opal/browser/dom/node.rb +53 -13
  119. data/opal/browser/dom/node_set.rb +13 -2
  120. data/opal/browser/dom/shadow_root.rb +12 -0
  121. data/opal/browser/dom/text.rb +2 -2
  122. data/opal/browser/dom.rb +38 -5
  123. data/opal/browser/effects.rb +170 -4
  124. data/opal/browser/event/all.rb +26 -0
  125. data/opal/browser/event/animation.rb +2 -0
  126. data/opal/browser/event/audio_processing.rb +2 -0
  127. data/opal/browser/event/base.rb +35 -4
  128. data/opal/browser/event/before_unload.rb +2 -0
  129. data/opal/browser/event/clipboard.rb +9 -0
  130. data/opal/browser/event/close.rb +2 -0
  131. data/opal/browser/event/composition.rb +2 -0
  132. data/opal/browser/event/custom.rb +1 -1
  133. data/opal/browser/event/data_transfer.rb +95 -0
  134. data/opal/browser/event/device_light.rb +2 -0
  135. data/opal/browser/event/device_motion.rb +2 -0
  136. data/opal/browser/event/device_orientation.rb +2 -0
  137. data/opal/browser/event/device_proximity.rb +2 -0
  138. data/opal/browser/event/drag.rb +9 -5
  139. data/opal/browser/event/focus.rb +2 -0
  140. data/opal/browser/event/gamepad.rb +3 -1
  141. data/opal/browser/event/hash_change.rb +2 -0
  142. data/opal/browser/event/keyboard.rb +14 -1
  143. data/opal/browser/event/message.rb +2 -0
  144. data/opal/browser/event/mouse.rb +10 -6
  145. data/opal/browser/event/page_transition.rb +2 -0
  146. data/opal/browser/event/pop_state.rb +2 -0
  147. data/opal/browser/event/progress.rb +2 -0
  148. data/opal/browser/event/sensor.rb +2 -0
  149. data/opal/browser/event/storage.rb +2 -0
  150. data/opal/browser/event/touch.rb +2 -0
  151. data/opal/browser/event/wheel.rb +2 -0
  152. data/opal/browser/event.rb +26 -116
  153. data/opal/browser/event_source.rb +1 -1
  154. data/opal/browser/form_data.rb +225 -0
  155. data/opal/browser/history.rb +4 -8
  156. data/opal/browser/http/request.rb +32 -10
  157. data/opal/browser/http/response.rb +5 -1
  158. data/opal/browser/http.rb +0 -2
  159. data/opal/browser/immediate.rb +0 -2
  160. data/opal/browser/location.rb +7 -1
  161. data/opal/browser/navigator.rb +105 -4
  162. data/opal/browser/polyfill/visual_viewport.rb +216 -0
  163. data/opal/browser/screen.rb +2 -2
  164. data/opal/browser/setup/base.rb +6 -0
  165. data/opal/browser/setup/full.rb +13 -0
  166. data/opal/browser/setup/large.rb +17 -0
  167. data/opal/browser/setup/mini.rb +8 -0
  168. data/opal/browser/setup/traditional.rb +10 -0
  169. data/opal/browser/socket.rb +3 -3
  170. data/opal/browser/storage.rb +2 -2
  171. data/opal/browser/support.rb +46 -22
  172. data/opal/browser/utils.rb +94 -14
  173. data/opal/browser/version.rb +1 -1
  174. data/opal/browser/visual_viewport.rb +39 -0
  175. data/opal/browser/window/size.rb +14 -0
  176. data/opal/browser/window/view.rb +15 -0
  177. data/opal/browser/window.rb +29 -16
  178. data/opal/browser.rb +1 -11
  179. data/opal-browser.gemspec +3 -3
  180. data/spec/database/sql_spec.rb +43 -35
  181. data/spec/delay_spec.rb +15 -12
  182. data/spec/dom/document_spec.rb +10 -8
  183. data/spec/dom/element/custom_spec.rb +106 -0
  184. data/spec/dom/element/subclass_spec.rb +144 -0
  185. data/spec/dom/element_spec.rb +42 -0
  186. data/spec/dom/mutation_observer_spec.rb +12 -8
  187. data/spec/dom/node_spec.rb +48 -0
  188. data/spec/dom_spec.rb +8 -0
  189. data/spec/event_source_spec.rb +15 -12
  190. data/spec/{dom/event_spec.rb → event_spec.rb} +44 -15
  191. data/spec/history_spec.rb +23 -19
  192. data/spec/http_spec.rb +19 -31
  193. data/spec/immediate_spec.rb +5 -4
  194. data/spec/interval_spec.rb +18 -9
  195. data/spec/native_cached_wrapper_spec.rb +46 -0
  196. data/spec/runner.rb +37 -62
  197. data/spec/socket_spec.rb +15 -12
  198. data/spec/spec_helper.rb +2 -1
  199. data/spec/spec_helper_promise.rb.erb +25 -0
  200. metadata +120 -16
  201. data/.travis.yml +0 -74
  202. data/opal/browser/window/scroll.rb +0 -59
@@ -1,5 +1,3 @@
1
- require 'promise'
2
-
3
1
  require 'browser/canvas/style'
4
2
  require 'browser/canvas/text'
5
3
  require 'browser/canvas/data'
@@ -8,7 +6,7 @@ require 'browser/canvas/gradient'
8
6
  module Browser
9
7
 
10
8
  class Canvas
11
- include Native
9
+ include Native::Wrapper
12
10
 
13
11
  attr_reader :element, :style, :text
14
12
 
@@ -59,6 +57,14 @@ class Canvas
59
57
  @element[:height].to_i
60
58
  end
61
59
 
60
+ def width=(new_width)
61
+ @element[:width] = new_width.to_i
62
+ end
63
+
64
+ def height=(new_height)
65
+ @element[:height] = new_height.to_i
66
+ end
67
+
62
68
  def append_to(parent)
63
69
  @element.append_to(parent)
64
70
  end
@@ -312,6 +318,14 @@ class Canvas
312
318
  def to_data(type = undefined)
313
319
  `#{@element.to_n}.toDataUrl(type)`
314
320
  end
321
+
322
+ def to_dom(*)
323
+ @element
324
+ end
325
+
326
+ def on(*args, &block); @element.on(*args, &block); end
327
+ def one(*args, &block); @element.one(*args, &block); end
328
+ def off(*args, &block); @element.off(*args, &block); end
315
329
  end
316
330
 
317
331
  Browser::DOM::Builder.for Canvas do |b, item|
@@ -1,10 +1,12 @@
1
+ warn "`console' has been moved to Opal's stdlib, please `require 'console'` instead." if RUBY_ENGINE_VERSION.to_f >= 0.9
2
+
1
3
  module Browser
2
4
 
3
5
  # Manipulate the browser console.
4
6
  #
5
7
  # @see https://developer.mozilla.org/en-US/docs/Web/API/console
6
8
  class Console
7
- include Native
9
+ include Browser::NativeCachedWrapper
8
10
 
9
11
  # Clear the console.
10
12
  def clear
@@ -1,14 +1,28 @@
1
- require 'stringio'
2
-
3
1
  module Browser
4
2
 
5
3
  # Allows manipulation of browser cookies.
6
4
  #
7
5
  # @see https://developer.mozilla.org/en-US/docs/Web/API/document.cookie
6
+ #
7
+ # Usage:
8
+ #
9
+ # cookies = $document.cookies
10
+ # cookies["my-cookie"] = "monster"
11
+ # cookies.delete("my-cookie")
12
+ #
13
+ # By default, cookies are stored JSON-encoded. You can supply a `raw:` option
14
+ # whenever you need to access/write the cookies in a raw way, eg.
15
+ #
16
+ # cookies["my-other-cookie", raw: true] = 123
17
+ #
18
+ # You can also set this option while referencing $document.cookies, eg.
19
+ #
20
+ # cookies = $document.cookies(raw: true)
21
+ # cookies["my-other-cookie"] = 123
8
22
  class Cookies
9
23
  # Default cookie options.
10
24
  DEFAULT = {
11
- expires: Time.now + 1.day,
25
+ expires: Time.now + 60 * 60 * 24,
12
26
  secure: false
13
27
  }
14
28
 
@@ -19,24 +33,34 @@ class Cookies
19
33
  # Create a new {Cookies} wrapper.
20
34
  #
21
35
  # @param document [native] the native document object
22
- def initialize(document)
36
+ # @param options [Hash] the default cookie options
37
+ def initialize(document, options = {})
23
38
  @document = document
24
- @options = DEFAULT.dup
39
+ @options = DEFAULT.merge(options)
25
40
  end
26
41
 
27
42
  # Access the cookie with the given name.
28
43
  #
29
44
  # @param name [String] the name of the cookie
45
+ # @param options [Hash] the options for the cookie
46
+ #
47
+ # @option options [Boolean] :raw get a raw cookie value, don't encode it with JSON
30
48
  #
31
49
  # @return [Object]
32
- def [](name)
33
- matches = `#@document.cookie`.scan(/#{Regexp.escape(name.encode_uri_component)}=([^;]*)/)
50
+ def [](name, options = {})
51
+ options = @options.merge(options)
52
+
53
+ matches = `#@document.cookie`.scan(/#{Regexp.escape(FormData.encode(name))}=([^;]*)/)
34
54
 
35
55
  return if matches.empty?
36
56
 
37
- result = matches.map {|cookie|
38
- JSON.parse(cookie.match(/^.*?=(.*)$/)[1].decode_uri_component)
39
- }
57
+ result = matches.flatten.map do |value|
58
+ if options[:raw]
59
+ FormData.decode(value)
60
+ else
61
+ JSON.parse(FormData.decode(value))
62
+ end
63
+ end
40
64
 
41
65
  result.length == 1 ? result.first : result
42
66
  end
@@ -47,36 +71,45 @@ class Cookies
47
71
  # @param value [Object] the data to set
48
72
  # @param options [Hash] the options for the cookie
49
73
  #
74
+ # @option options [Boolean] :raw don't encode a value with JSON
50
75
  # @option options [Integer] :max_age the max age of the cookie in seconds
51
76
  # @option options [Time] :expires the expire date
52
77
  # @option options [String] :path the path the cookie is valid on
53
78
  # @option options [String] :domain the domain the cookie is valid on
54
79
  # @option options [Boolean] :secure whether the cookie is secure or not
55
- def []=(name, value, options = {})
56
- `#@document.cookie = #{encode name, value.is_a?(String) ? value : JSON.dump(value), @options.merge(options)}`
80
+ def []=(name, options = {}, value)
81
+ options = @options.merge(options)
82
+ if options[:raw]
83
+ string = value.to_s
84
+ else
85
+ string = JSON.dump(value)
86
+ end
87
+ encoded_value = encode(name, string, options)
88
+ `#@document.cookie = #{encoded_value}`
57
89
  end
58
90
 
59
91
  # Delete a cookie.
60
92
  #
61
93
  # @param name [String] the name of the cookie
62
- def delete(name)
94
+ def delete(name, _options = {})
63
95
  `#@document.cookie = #{encode name, '', expires: Time.now}`
64
96
  end
65
97
 
66
98
  # @!attribute [r] keys
67
99
  # @return [Array<String>] all the cookie names
68
- def keys
69
- Array(`#@document.cookie.split(/; /)`).map {|cookie|
100
+ def keys(_options = {})
101
+ Array(`#@document.cookie.split(/; /)`).map do |cookie|
70
102
  cookie.split(/\s*=\s*/).first
71
- }
103
+ end
72
104
  end
73
105
 
74
106
  # @!attribute [r] values
75
107
  # @return [Array] all the cookie values
76
- def values
77
- keys.map {|key|
78
- self[key]
79
- }
108
+ def values(options = {})
109
+ options = @options.merge(options)
110
+ keys.map do |key|
111
+ self[key, options]
112
+ end
80
113
  end
81
114
 
82
115
  # Enumerate the cookies.
@@ -84,13 +117,18 @@ class Cookies
84
117
  # @yieldparam key [String] the name of the cookie
85
118
  # @yieldparam value [String] the value of the cookie
86
119
  #
120
+ # @param options [Hash] the options for the cookie
121
+ #
122
+ # @option options [Boolean] :raw don't encode a value with JSON
123
+ #
87
124
  # @return [self]
88
- def each(&block)
89
- return enum_for :each unless block
125
+ def each(options = {}, &block)
126
+ return enum_for :each, options unless block
127
+ options = @options.merge(options)
90
128
 
91
- keys.each {|key|
92
- yield key, self[key]
93
- }
129
+ keys.each do |key|
130
+ yield key, self[key, options]
131
+ end
94
132
 
95
133
  self
96
134
  end
@@ -98,35 +136,35 @@ class Cookies
98
136
  # Delete all the cookies
99
137
  #
100
138
  # @return [self]
101
- def clear
102
- keys.each {|key|
139
+ def clear(_options = {})
140
+ keys.each do |key|
103
141
  delete key
104
- }
142
+ end
105
143
 
106
144
  self
107
145
  end
108
146
 
109
147
  protected
110
148
  def encode(key, value, options = {})
111
- io = StringIO.new
149
+ io = []
112
150
 
113
- io << key.encode_uri_component << ?= << value.encode_uri_component << '; '
151
+ io << FormData.encode(key) << ?= << FormData.encode(value) << '; '
114
152
 
115
153
  io << 'max-age=' << options[:max_age] << '; ' if options[:max_age]
116
- io << 'expires=' << options[:expires].to_utc << '; ' if options[:expires]
154
+ io << 'expires=' << options[:expires].utc << '; ' if options[:expires]
117
155
  io << 'path=' << options[:path] << '; ' if options[:path]
118
156
  io << 'domain=' << options[:domain] << '; ' if options[:domain]
119
157
  io << 'secure' if options[:secure]
120
158
 
121
- io.string
159
+ io.join
122
160
  end
123
161
  end
124
162
 
125
163
  class DOM::Document < DOM::Element
126
164
  # @!attribute [r] cookies
127
165
  # @return [Cookies] the cookies for the document
128
- def cookies
129
- Cookies.new(@native) if defined?(`#@native.cookie`)
166
+ def cookies(options = {})
167
+ Cookies.new(@native, options) if defined?(`#@native.cookie`)
130
168
  end
131
169
  end
132
170
 
@@ -0,0 +1,79 @@
1
+ module Browser
2
+
3
+ # Implements (parts of) the web crypto interface
4
+ #
5
+ # https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API
6
+ class Crypto
7
+ include NativeCachedWrapper
8
+
9
+ class Digest
10
+ def initialize(buf)
11
+ @buffer = Buffer.new(buf)
12
+ end
13
+
14
+ attr_reader :buffer
15
+
16
+ # Convert a digest to a hexadecimal string
17
+ def to_hex
18
+ buffer.to_a.map { |i| "%02x" % i }.join
19
+ end
20
+
21
+ # Convert a digest to a binary string
22
+ def to_s
23
+ buffer.to_a.map { |i| "%c" % i }.join
24
+ end
25
+
26
+ # Convert a digest to a Base64-encoded string
27
+ #
28
+ # You will need to `require "base64"`
29
+ def to_b64
30
+ Base64.strict_encode64(to_s)
31
+ end
32
+
33
+ # Convert a digest to a urlsafe Base64-encoded string
34
+ #
35
+ # You will need to `require "base64"`
36
+ def to_u64(padding: false)
37
+ Base64.urlsafe_encode64(to_s, padding: padding)
38
+ end
39
+ end
40
+
41
+ # Compute a cryptographic digest of data (a Buffer). If block is given,
42
+ # it will call a block, otherwise it will return a Promise that will
43
+ # return once a digest is computed.
44
+ #
45
+ # Allowed values for algo: SHA-1, SHA-256 (default), SHA-368, SHA-512.
46
+ #
47
+ # The block/promise will be given an argument of type {Digest} which can
48
+ # be used to format a digest.
49
+ #
50
+ # Example:
51
+ # ```
52
+ # Browser::Blob.new(['test']).buffer.then { |b|
53
+ # $window.crypto.digest(b)
54
+ # }.then { |d|
55
+ # puts d.to_hex
56
+ # }
57
+ # ```
58
+ def digest data, algo = 'SHA-256', &block
59
+ promise = nil
60
+ unless block_given?
61
+ promise = Promise.new
62
+ block = proc { |i| promise.resolve(i) }
63
+ end
64
+ resblock = proc { |i| block.call(Digest.new(i)) }
65
+
66
+ `#@native.subtle.digest(algo, #{Native.convert(data)}).then(#{resblock.to_n})`
67
+ promise
68
+ end
69
+ end
70
+
71
+ class Window
72
+ # @!attribute [r] crypto
73
+ # @return [Crypto] the crypto interface of this window
74
+ def crypto
75
+ @crypto ||= Crypto.new(`#@native.crypto`)
76
+ end
77
+ end
78
+
79
+ end
@@ -1,7 +1,7 @@
1
1
  module Browser; module CSS
2
2
 
3
3
  class Declaration
4
- include Native
4
+ include Browser::NativeCachedWrapper
5
5
  include Enumerable
6
6
 
7
7
  def rule
@@ -1,7 +1,7 @@
1
1
  module Browser; module CSS
2
2
 
3
3
  class Rule
4
- include Native
4
+ include Browser::NativeCachedWrapper
5
5
 
6
6
  STYLE_RULE = 1
7
7
  CHARSET_RULE = 2
@@ -1,10 +1,10 @@
1
1
  module Browser; module CSS
2
2
 
3
3
  class StyleSheet
4
- include Native
4
+ include Browser::NativeCachedWrapper
5
5
 
6
6
  def initialize(what)
7
- if what.is_a? DOM::Element
7
+ if DOM::Element === what
8
8
  super(`#{what.to_n}.sheet`)
9
9
  else
10
10
  super(what)
data/opal/browser/css.rb CHANGED
@@ -4,19 +4,35 @@ require 'browser/css/rule'
4
4
  require 'browser/css/rule/style'
5
5
 
6
6
  module Kernel
7
- # Create a <style> element from a string or a block using the
8
- # {Browser::CSS::Builder} DSL.
7
+ # @overload CSS(document = $document, &block)
9
8
  #
10
- # @param text [String] the CSS text
11
- # @return [Browser::DOM::Element] the create <style> element
12
- def CSS(text = nil, &block)
13
- style = $document.create_element(:style)
9
+ # Create a `<style>` element from a {Paggio::CSS} DSL.
10
+ #
11
+ # @param document [Browser::DOM::Document] the document instance
12
+ # we intend to use
13
+ #
14
+ # @return [Browser::DOM::Element] the created `<style>` element
15
+ #
16
+ # @overload CSS(string, document = $document)
17
+ #
18
+ # Create a `<style>` element from a string.
19
+ #
20
+ # @param document [Browser::DOM::Document] the document instance
21
+ # we intend to use
22
+ #
23
+ # @return [Browser::DOM::Element] the created `<style>` element
24
+ def CSS(*args, &block)
25
+ document = if args.length > 1 || block_given?
26
+ args.pop
27
+ end || $document
28
+
29
+ style = document.create_element(:style)
14
30
  style[:type] = 'text/css'
15
31
 
16
32
  if block
17
33
  style.inner_text = Paggio.css(&block)
18
34
  else
19
- style.inner_text = text
35
+ style.inner_text = args.join("")
20
36
  end
21
37
 
22
38
  style
@@ -1,4 +1,3 @@
1
- require 'promise'
2
1
  require 'ostruct'
3
2
 
4
3
  module Browser; module Database
@@ -27,7 +26,7 @@ class SQL
27
26
  Timeout = Class.new(self)
28
27
  end
29
28
 
30
- include Native
29
+ include Native::Wrapper
31
30
 
32
31
  # @return [String] the name of the database
33
32
  attr_reader :name
@@ -73,7 +72,7 @@ class SQL
73
72
  return `#@native.version` unless block
74
73
 
75
74
  `#@native.changeVersion(#{from}, #{to},
76
- #{-> t { block.call(Transaction.new(self, t)) }})`
75
+ #{->(t) { block.call(Transaction.new(self, t)) }})`
77
76
  end
78
77
 
79
78
  # Start a transaction on the database.
@@ -82,12 +81,12 @@ class SQL
82
81
  def transaction(&block)
83
82
  raise ArgumentError, 'no block given' unless block
84
83
 
85
- `#@native.transaction(#{-> t { block.call(Transaction.new(self, t)) }})`
84
+ `#@native.transaction(#{->(t) { block.call(Transaction.new(self, t)) }})`
86
85
  end
87
86
 
88
87
  # Allows you to make changes to the database or read data from it.
89
88
  class Transaction
90
- include Native
89
+ include Native::Wrapper
91
90
 
92
91
  # @return [Database] the database the transaction has been created from
93
92
  attr_reader :database
@@ -109,8 +108,8 @@ class SQL
109
108
  promise = Promise.new
110
109
 
111
110
  `#@native.executeSql(#{query}, #{parameters},
112
- #{-> _, r { promise.resolve(Result.new(self, r)) }},
113
- #{-> _, e { promise.reject(Error.new(e)) }})`
111
+ #{->(_, r) { promise.resolve(Result.new(self, r)) }},
112
+ #{->(_, e) { promise.reject(Error.new(e)) }})`
114
113
 
115
114
  promise
116
115
  end
@@ -129,7 +128,7 @@ class SQL
129
128
  end
130
129
 
131
130
  class Result
132
- include Native
131
+ include Native::Wrapper
133
132
 
134
133
  # @return [Transaction] the transaction the result came from
135
134
  attr_reader :transaction
@@ -49,6 +49,17 @@ class Window
49
49
  def after!(time, &block)
50
50
  Delay.new(@native, time, &block)
51
51
  end
52
+
53
+ # Returns a promise that will resolve after the given seconds.
54
+ #
55
+ # @param time [Float] the seconds after it gets called
56
+ #
57
+ # @return [Promise] the promise that will resolve after timeout happens
58
+ def resolve_after(time)
59
+ promise = Promise.new
60
+ Delay.new(@native, time) { promise.resolve }.start
61
+ promise
62
+ end
52
63
  end
53
64
 
54
65
  end
@@ -63,6 +74,11 @@ module Kernel
63
74
  def after!(time, &block)
64
75
  $window.after!(time, &block)
65
76
  end
77
+
78
+ # (see Browser::Window#resolve_after)
79
+ def resolve_after(time)
80
+ $window.resolve_after(time)
81
+ end
66
82
  end
67
83
 
68
84
  class Proc
@@ -2,7 +2,7 @@ module Browser; module DOM
2
2
 
3
3
  # Encapsulates an {Element} attribute.
4
4
  class Attribute
5
- include Native
5
+ include Browser::NativeCachedWrapper
6
6
 
7
7
  # @!attribute [r] name
8
8
  # @return [String] the name of the attribute
@@ -38,10 +38,32 @@ class Builder
38
38
 
39
39
  attr_reader :document, :element
40
40
 
41
- def initialize(document, &block)
41
+ NEW_PAGGIO = (Paggio::HTML.instance_method(:build!) rescue false)
42
+
43
+ def initialize(document, builder=nil, &block)
42
44
  @document = document
43
- @builder = Paggio::HTML.new(&block)
44
- @roots = @builder.each.map { |e| Builder.build(self, e) }
45
+
46
+ # Compatibility issue due to an unreleased Paggio gem.
47
+ # Let's try to support both versions. When Paggio is released,
48
+ # we may remove it.
49
+
50
+ if NEW_PAGGIO
51
+ @builder = Paggio::HTML.new(defer: true, &block)
52
+
53
+ build = proc do
54
+ @builder.build!(force_call: !!builder)
55
+ @roots = @builder.each.map { |e| Builder.build(self, e) }
56
+ end
57
+
58
+ if builder
59
+ builder.extend!(@builder, &build)
60
+ else
61
+ build.()
62
+ end
63
+ else
64
+ @builder = Paggio::HTML.new(&block)
65
+ @roots = @builder.each.map { |e| Builder.build(self, e) }
66
+ end
45
67
  end
46
68
 
47
69
  def to_a
@@ -54,15 +76,12 @@ Builder.for String do |b, item|
54
76
  end
55
77
 
56
78
  Builder.for Paggio::HTML::Element do |b, item|
57
- dom = b.document.create_element(`item.name`)
79
+ options = {}
58
80
 
59
- if Hash === `item.attributes`
60
- dom.attributes.merge!(`item.attributes`)
61
- end
81
+ options[:attrs] = `item.attributes` if Hash === `item.attributes`
82
+ options[:classes] = `item.class_names`
62
83
 
63
- `item.class_names`.each {|value|
64
- dom.add_class value
65
- }
84
+ dom = b.document.create_element(`item.name`, **options)
66
85
 
67
86
  if on = `item.on || nil`
68
87
  on.each {|args, block|