opal-browser 0.2.0.beta1 → 0.3.2

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 (218) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/build.yml +95 -0
  3. data/.gitignore +3 -0
  4. data/CHANGELOG.md +8 -0
  5. data/Gemfile +17 -3
  6. data/LICENSE +2 -1
  7. data/README.md +183 -52
  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 +8 -6
  78. data/lib/opal-browser.rb +1 -0
  79. data/opal/browser/animation_frame.rb +26 -1
  80. data/opal/browser/audio/node.rb +121 -0
  81. data/opal/browser/audio/param_schedule.rb +43 -0
  82. data/opal/browser/audio.rb +66 -0
  83. data/opal/browser/blob.rb +94 -0
  84. data/opal/browser/canvas/data.rb +1 -11
  85. data/opal/browser/canvas/gradient.rb +1 -11
  86. data/opal/browser/canvas/style.rb +3 -11
  87. data/opal/browser/canvas/text.rb +1 -11
  88. data/opal/browser/canvas.rb +17 -13
  89. data/opal/browser/console.rb +3 -1
  90. data/opal/browser/cookies.rb +78 -42
  91. data/opal/browser/crypto.rb +79 -0
  92. data/opal/browser/css/declaration.rb +1 -1
  93. data/opal/browser/css/rule.rb +1 -1
  94. data/opal/browser/css/style_sheet.rb +2 -2
  95. data/opal/browser/css.rb +23 -7
  96. data/opal/browser/database/sql.rb +193 -0
  97. data/opal/browser/delay.rb +41 -7
  98. data/opal/browser/dom/attribute.rb +13 -12
  99. data/opal/browser/dom/builder.rb +31 -17
  100. data/opal/browser/dom/document.rb +174 -42
  101. data/opal/browser/dom/document_fragment.rb +18 -0
  102. data/opal/browser/dom/document_or_shadow_root.rb +19 -0
  103. data/opal/browser/dom/element/attributes.rb +111 -0
  104. data/opal/browser/dom/element/button.rb +31 -0
  105. data/opal/browser/dom/element/custom.rb +177 -0
  106. data/opal/browser/dom/element/data.rb +82 -0
  107. data/opal/browser/dom/element/editable.rb +47 -0
  108. data/opal/browser/dom/element/form.rb +38 -0
  109. data/opal/browser/dom/element/iframe.rb +37 -0
  110. data/opal/browser/dom/element/image.rb +2 -0
  111. data/opal/browser/dom/element/input.rb +48 -1
  112. data/opal/browser/dom/element/media.rb +17 -0
  113. data/opal/browser/dom/element/offset.rb +5 -0
  114. data/opal/browser/dom/element/position.rb +11 -2
  115. data/opal/browser/dom/element/scroll.rb +123 -24
  116. data/opal/browser/dom/element/select.rb +42 -0
  117. data/opal/browser/dom/element/size.rb +17 -0
  118. data/opal/browser/dom/element/template.rb +11 -0
  119. data/opal/browser/dom/element/textarea.rb +26 -0
  120. data/opal/browser/dom/element.rb +468 -238
  121. data/opal/browser/dom/mutation_observer.rb +4 -4
  122. data/opal/browser/dom/node.rb +142 -60
  123. data/opal/browser/dom/node_set.rb +73 -44
  124. data/opal/browser/dom/shadow_root.rb +12 -0
  125. data/opal/browser/dom/text.rb +2 -2
  126. data/opal/browser/dom.rb +40 -16
  127. data/opal/browser/effects.rb +180 -3
  128. data/opal/browser/event/all.rb +26 -0
  129. data/opal/browser/{dom/event → event}/animation.rb +4 -2
  130. data/opal/browser/{dom/event → event}/audio_processing.rb +4 -2
  131. data/opal/browser/{dom/event → event}/base.rb +98 -9
  132. data/opal/browser/{dom/event → event}/before_unload.rb +4 -2
  133. data/opal/browser/{dom/event → event}/clipboard.rb +11 -2
  134. data/opal/browser/{dom/event → event}/close.rb +4 -2
  135. data/opal/browser/{dom/event → event}/composition.rb +4 -2
  136. data/opal/browser/{dom/event → event}/custom.rb +3 -3
  137. data/opal/browser/event/data_transfer.rb +95 -0
  138. data/opal/browser/{dom/event → event}/device_light.rb +4 -2
  139. data/opal/browser/{dom/event → event}/device_motion.rb +4 -2
  140. data/opal/browser/{dom/event → event}/device_orientation.rb +4 -2
  141. data/opal/browser/{dom/event → event}/device_proximity.rb +4 -2
  142. data/opal/browser/{dom/event → event}/drag.rb +11 -7
  143. data/opal/browser/{dom/event → event}/focus.rb +4 -2
  144. data/opal/browser/{dom/event → event}/gamepad.rb +5 -3
  145. data/opal/browser/{dom/event → event}/hash_change.rb +4 -2
  146. data/opal/browser/{dom/event → event}/keyboard.rb +16 -3
  147. data/opal/browser/{dom/event → event}/message.rb +4 -2
  148. data/opal/browser/{dom/event → event}/mouse.rb +12 -8
  149. data/opal/browser/{dom/event → event}/page_transition.rb +4 -2
  150. data/opal/browser/{dom/event → event}/pop_state.rb +4 -2
  151. data/opal/browser/{dom/event → event}/progress.rb +4 -2
  152. data/opal/browser/{dom/event → event}/sensor.rb +4 -2
  153. data/opal/browser/{dom/event → event}/storage.rb +4 -2
  154. data/opal/browser/{dom/event → event}/touch.rb +4 -2
  155. data/opal/browser/{dom/event → event}/ui.rb +2 -2
  156. data/opal/browser/{dom/event → event}/wheel.rb +4 -2
  157. data/opal/browser/event.rb +163 -0
  158. data/opal/browser/event_source.rb +2 -2
  159. data/opal/browser/form_data.rb +225 -0
  160. data/opal/browser/history.rb +4 -8
  161. data/opal/browser/http/binary.rb +1 -0
  162. data/opal/browser/http/headers.rb +16 -2
  163. data/opal/browser/http/request.rb +46 -48
  164. data/opal/browser/http/response.rb +5 -1
  165. data/opal/browser/http.rb +25 -2
  166. data/opal/browser/immediate.rb +9 -5
  167. data/opal/browser/interval.rb +34 -11
  168. data/opal/browser/location.rb +7 -1
  169. data/opal/browser/navigator.rb +127 -7
  170. data/opal/browser/polyfill/visual_viewport.rb +216 -0
  171. data/opal/browser/screen.rb +3 -3
  172. data/opal/browser/setup/base.rb +6 -0
  173. data/opal/browser/setup/full.rb +13 -0
  174. data/opal/browser/setup/large.rb +17 -0
  175. data/opal/browser/setup/mini.rb +8 -0
  176. data/opal/browser/setup/traditional.rb +10 -0
  177. data/opal/browser/socket.rb +8 -4
  178. data/opal/browser/storage.rb +53 -35
  179. data/opal/browser/support.rb +72 -5
  180. data/opal/browser/utils.rb +94 -14
  181. data/opal/browser/version.rb +1 -1
  182. data/opal/browser/visual_viewport.rb +39 -0
  183. data/opal/browser/window/size.rb +31 -3
  184. data/opal/browser/window/view.rb +15 -0
  185. data/opal/browser/window.rb +46 -25
  186. data/opal/browser.rb +1 -10
  187. data/opal/opal-browser.rb +1 -0
  188. data/opal-browser.gemspec +3 -3
  189. data/spec/database/sql_spec.rb +139 -0
  190. data/spec/delay_spec.rb +41 -0
  191. data/spec/dom/attribute_spec.rb +49 -0
  192. data/spec/dom/builder_spec.rb +25 -8
  193. data/spec/dom/document_spec.rb +22 -0
  194. data/spec/dom/element/attributes_spec.rb +52 -0
  195. data/spec/dom/element/custom_spec.rb +106 -0
  196. data/spec/dom/element/subclass_spec.rb +144 -0
  197. data/spec/dom/element_spec.rb +181 -4
  198. data/spec/dom/mutation_observer_spec.rb +12 -8
  199. data/spec/dom/node_set_spec.rb +44 -0
  200. data/spec/dom/node_spec.rb +48 -0
  201. data/spec/dom_spec.rb +8 -0
  202. data/spec/event_source_spec.rb +15 -12
  203. data/spec/{dom/event_spec.rb → event_spec.rb} +44 -15
  204. data/spec/history_spec.rb +23 -19
  205. data/spec/http_spec.rb +19 -31
  206. data/spec/immediate_spec.rb +5 -4
  207. data/spec/interval_spec.rb +59 -0
  208. data/spec/native_cached_wrapper_spec.rb +46 -0
  209. data/spec/runner.rb +62 -69
  210. data/spec/socket_spec.rb +16 -12
  211. data/spec/spec_helper.rb +2 -5
  212. data/spec/spec_helper_promise.rb.erb +25 -0
  213. data/spec/storage_spec.rb +1 -1
  214. metadata +172 -50
  215. data/.travis.yml +0 -60
  216. data/opal/browser/dom/event.rb +0 -253
  217. data/opal/browser/http/parameters.rb +0 -8
  218. data/opal/browser/window/scroll.rb +0 -59
@@ -0,0 +1,94 @@
1
+ module Browser
2
+
3
+ class Blob
4
+ include NativeCachedWrapper
5
+
6
+ # Create a new blob from anything that Blob API supports
7
+ def self.create(from, options={})
8
+ new(`new Blob(#{Native.convert(from)}, #{options.to_n})`)
9
+ end
10
+
11
+ # @!attribute [r] size
12
+ # @return [Integer] blob size in bytes
13
+ def size
14
+ `#@native.size`
15
+ end
16
+
17
+ # @!attribute [r] type
18
+ # @return [String] blob mime type
19
+ def type
20
+ `#@native.type`
21
+ end
22
+
23
+ # Convert a blob to a UTF-8 encoded string.
24
+ #
25
+ # If block is given it will be called with a parameter once we receive
26
+ # the text. Otherwise return a {Promise} which will resolve once we
27
+ # receive it.
28
+ def text(&block)
29
+ promise = nil
30
+ unless block_given?
31
+ promise = Promise.new
32
+ block = proc { |i| promise.resolve(i) }
33
+ end
34
+ `#@native.text().then(#{block.to_n})`
35
+ promise
36
+ end
37
+
38
+ # {Buffer} view into the blob
39
+ #
40
+ # If block is given it will be called with a parameter once we receive
41
+ # the buffer. Otherwise return a {Promise} which will resolve once we
42
+ # receive it.
43
+ def buffer
44
+ promise = nil
45
+ unless block_given?
46
+ promise = Promise.new
47
+ block = proc { |i| promise.resolve(i) }
48
+ end
49
+ resblock = proc { |i| block.call(Buffer.new(i)) }
50
+ `#@native.arrayBuffer().then(#{resblock.to_n})`
51
+ promise
52
+ end
53
+
54
+ # Create a new blob by slicing this blob
55
+ def slice(start, finish=nil)
56
+ Blob.new(`#@native.slice(#{start}, #{finish})`)
57
+ end
58
+
59
+ # Convert a blob to an URL that can be used to reference this blob in DOM
60
+ # eg. display some multimedia
61
+ def to_url(window=$window)
62
+ `#{window.to_n}.URL.createObjectURL(#@native)`
63
+ end
64
+
65
+ # Rename a blob and return a {File} with a new name.
66
+ #
67
+ # @return [File] a renamed blob
68
+ def rename(new_filename)
69
+ File.create([self], new_filename, type: type,
70
+ lastModified: respond_to?(:last_modified) ?
71
+ last_modified : Time.now)
72
+ end
73
+ end
74
+
75
+ class File < Blob
76
+ # Create a new file from anything that File API supports
77
+ def self.create(from, name, options={})
78
+ new(`new File(#{Native.convert(from)}, #{name}, #{options.to_n})`)
79
+ end
80
+
81
+ # @!attribute [r] last_modified
82
+ # @return [Time] last modified date of this file
83
+ def last_modified
84
+ Time.at(`#@native.lastModified`/1000.0)
85
+ end
86
+
87
+ # @!attribute [r] name
88
+ # @return [String] filename
89
+ def name
90
+ `#@native.name`
91
+ end
92
+ end
93
+
94
+ end
@@ -1,13 +1,3 @@
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
  module Browser; class Canvas
12
2
 
13
3
  class Data
@@ -27,7 +17,7 @@ class Data
27
17
  data
28
18
  end
29
19
 
30
- include Native
20
+ include Native::Wrapper
31
21
 
32
22
  attr_reader :x, :y, :width, :height
33
23
 
@@ -1,17 +1,7 @@
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
  module Browser; class Canvas
12
2
 
13
3
  class Gradient
14
- include Native
4
+ include Native::Wrapper
15
5
 
16
6
  attr_reader :context
17
7
 
@@ -1,17 +1,7 @@
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
  module Browser; class Canvas
12
2
 
13
3
  class StyleObject
14
- include Native
4
+ include Native::Wrapper
15
5
 
16
6
  attr_reader :context
17
7
 
@@ -66,10 +56,12 @@ class Style < StyleObject
66
56
 
67
57
  def smooth!
68
58
  `#@native.mozImageSmoothingEnabled = #{@smooth = true}`
59
+ `#@native.imageSmoothingEnabled = #{@smooth = true}`
69
60
  end
70
61
 
71
62
  def no_smooth!
72
63
  `#@native.mozImageSmoothingEnabled = #{@smooth = false}`
64
+ `#@native.imageSmoothingEnabled = #{@smooth = false}`
73
65
  end
74
66
  end
75
67
 
@@ -1,17 +1,7 @@
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
  module Browser; class Canvas
12
2
 
13
3
  class Text
14
- include Native
4
+ include Native::Wrapper
15
5
 
16
6
  attr_reader :context
17
7
 
@@ -1,15 +1,3 @@
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
- require 'promise'
12
-
13
1
  require 'browser/canvas/style'
14
2
  require 'browser/canvas/text'
15
3
  require 'browser/canvas/data'
@@ -18,7 +6,7 @@ require 'browser/canvas/gradient'
18
6
  module Browser
19
7
 
20
8
  class Canvas
21
- include Native
9
+ include Native::Wrapper
22
10
 
23
11
  attr_reader :element, :style, :text
24
12
 
@@ -69,6 +57,14 @@ class Canvas
69
57
  @element[:height].to_i
70
58
  end
71
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
+
72
68
  def append_to(parent)
73
69
  @element.append_to(parent)
74
70
  end
@@ -322,6 +318,14 @@ class Canvas
322
318
  def to_data(type = undefined)
323
319
  `#{@element.to_n}.toDataUrl(type)`
324
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
325
329
  end
326
330
 
327
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,66 +33,83 @@ 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
43
67
 
44
68
  # Set a cookie.
45
69
  #
46
- # Options
47
- # -------
48
- # + **max_age** - the max age of the cookie in seconds
49
- # + **expires** - the expire date as {Time}
50
- # + **path** - the path where the cookie is valid on
51
- # + **domain** - the domain where the cookie is valid on
52
- # + **secure** - whether the cookie is secure or not
53
- #
54
70
  # @param name [String] the name of the cookie
55
71
  # @param value [Object] the data to set
56
72
  # @param options [Hash] the options for the cookie
57
- def []=(name, value, options = {})
58
- `#@document.cookie = #{encode name, value.is_a?(String) ? value : JSON.dump(value), @options.merge(options)}`
73
+ #
74
+ # @option options [Boolean] :raw don't encode a value with JSON
75
+ # @option options [Integer] :max_age the max age of the cookie in seconds
76
+ # @option options [Time] :expires the expire date
77
+ # @option options [String] :path the path the cookie is valid on
78
+ # @option options [String] :domain the domain the cookie is valid on
79
+ # @option options [Boolean] :secure whether the cookie is secure or not
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}`
59
89
  end
60
90
 
61
91
  # Delete a cookie.
62
92
  #
63
93
  # @param name [String] the name of the cookie
64
- def delete(name)
94
+ def delete(name, _options = {})
65
95
  `#@document.cookie = #{encode name, '', expires: Time.now}`
66
96
  end
67
97
 
68
98
  # @!attribute [r] keys
69
99
  # @return [Array<String>] all the cookie names
70
- def keys
71
- Array(`#@document.cookie.split(/; /)`).map {|cookie|
100
+ def keys(_options = {})
101
+ Array(`#@document.cookie.split(/; /)`).map do |cookie|
72
102
  cookie.split(/\s*=\s*/).first
73
- }
103
+ end
74
104
  end
75
105
 
76
106
  # @!attribute [r] values
77
107
  # @return [Array] all the cookie values
78
- def values
79
- keys.map {|key|
80
- self[key]
81
- }
108
+ def values(options = {})
109
+ options = @options.merge(options)
110
+ keys.map do |key|
111
+ self[key, options]
112
+ end
82
113
  end
83
114
 
84
115
  # Enumerate the cookies.
@@ -86,13 +117,18 @@ class Cookies
86
117
  # @yieldparam key [String] the name of the cookie
87
118
  # @yieldparam value [String] the value of the cookie
88
119
  #
120
+ # @param options [Hash] the options for the cookie
121
+ #
122
+ # @option options [Boolean] :raw don't encode a value with JSON
123
+ #
89
124
  # @return [self]
90
- def each(&block)
91
- return enum_for :each unless block
125
+ def each(options = {}, &block)
126
+ return enum_for :each, options unless block
127
+ options = @options.merge(options)
92
128
 
93
- keys.each {|key|
94
- yield key, self[key]
95
- }
129
+ keys.each do |key|
130
+ yield key, self[key, options]
131
+ end
96
132
 
97
133
  self
98
134
  end
@@ -100,35 +136,35 @@ class Cookies
100
136
  # Delete all the cookies
101
137
  #
102
138
  # @return [self]
103
- def clear
104
- keys.each {|key|
139
+ def clear(_options = {})
140
+ keys.each do |key|
105
141
  delete key
106
- }
142
+ end
107
143
 
108
144
  self
109
145
  end
110
146
 
111
147
  protected
112
148
  def encode(key, value, options = {})
113
- io = StringIO.new
149
+ io = []
114
150
 
115
- io << key.encode_uri_component << ?= << value.encode_uri_component << '; '
151
+ io << FormData.encode(key) << ?= << FormData.encode(value) << '; '
116
152
 
117
153
  io << 'max-age=' << options[:max_age] << '; ' if options[:max_age]
118
- io << 'expires=' << options[:expires].to_utc << '; ' if options[:expires]
154
+ io << 'expires=' << options[:expires].utc << '; ' if options[:expires]
119
155
  io << 'path=' << options[:path] << '; ' if options[:path]
120
156
  io << 'domain=' << options[:domain] << '; ' if options[:domain]
121
157
  io << 'secure' if options[:secure]
122
158
 
123
- io.string
159
+ io.join
124
160
  end
125
161
  end
126
162
 
127
163
  class DOM::Document < DOM::Element
128
164
  # @!attribute [r] cookies
129
165
  # @return [Cookies] the cookies for the document
130
- def cookies
131
- Cookies.new(@native) if defined?(`#@native.cookie`)
166
+ def cookies(options = {})
167
+ Cookies.new(@native, options) if defined?(`#@native.cookie`)
132
168
  end
133
169
  end
134
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