opal-browser 0.1.0.beta1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (257) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/build.yml +95 -0
  3. data/.gitignore +3 -0
  4. data/.yardopts +1 -1
  5. data/Gemfile +22 -3
  6. data/LICENSE +20 -0
  7. data/README.md +200 -20
  8. data/Rakefile +29 -1
  9. data/config.ru +20 -2
  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 +24 -0
  78. data/lib/opal-browser.rb +1 -0
  79. data/opal/browser/animation_frame.rb +92 -10
  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 +2 -12
  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 +86 -28
  89. data/opal/browser/console.rb +6 -38
  90. data/opal/browser/cookies.rb +90 -27
  91. data/opal/browser/crypto.rb +79 -0
  92. data/opal/browser/css/declaration.rb +1 -6
  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 +94 -0
  98. data/opal/browser/dom/attribute.rb +16 -9
  99. data/opal/browser/dom/builder.rb +35 -25
  100. data/opal/browser/dom/character_data.rb +43 -7
  101. data/opal/browser/dom/document.rb +171 -37
  102. data/opal/browser/dom/document_fragment.rb +18 -0
  103. data/opal/browser/dom/document_or_shadow_root.rb +19 -0
  104. data/opal/browser/dom/element/attributes.rb +111 -0
  105. data/opal/browser/dom/element/button.rb +31 -0
  106. data/opal/browser/dom/element/custom.rb +177 -0
  107. data/opal/browser/dom/element/data.rb +82 -0
  108. data/opal/browser/dom/element/editable.rb +47 -0
  109. data/opal/browser/dom/element/form.rb +38 -0
  110. data/opal/browser/dom/element/iframe.rb +37 -0
  111. data/opal/browser/dom/element/image.rb +25 -0
  112. data/opal/browser/dom/element/input.rb +48 -1
  113. data/opal/browser/dom/element/media.rb +17 -0
  114. data/opal/browser/dom/element/offset.rb +32 -10
  115. data/opal/browser/dom/element/position.rb +11 -2
  116. data/opal/browser/dom/element/scroll.rb +139 -20
  117. data/opal/browser/dom/element/select.rb +42 -0
  118. data/opal/browser/dom/element/size.rb +46 -0
  119. data/opal/browser/dom/element/template.rb +11 -0
  120. data/opal/browser/dom/element/textarea.rb +26 -0
  121. data/opal/browser/dom/element.rb +496 -168
  122. data/opal/browser/dom/mutation_observer.rb +69 -9
  123. data/opal/browser/dom/node.rb +270 -83
  124. data/opal/browser/dom/node_set.rb +74 -41
  125. data/opal/browser/dom/shadow_root.rb +12 -0
  126. data/opal/browser/dom/text.rb +18 -3
  127. data/opal/browser/dom.rb +40 -18
  128. data/opal/browser/effects.rb +180 -3
  129. data/opal/browser/event/all.rb +26 -0
  130. data/opal/browser/event/animation.rb +40 -0
  131. data/opal/browser/{dom/event → event}/audio_processing.rb +10 -6
  132. data/opal/browser/event/base.rb +461 -0
  133. data/opal/browser/event/before_unload.rb +17 -0
  134. data/opal/browser/event/clipboard.rb +37 -0
  135. data/opal/browser/event/close.rb +49 -0
  136. data/opal/browser/event/composition.rb +52 -0
  137. data/opal/browser/event/custom.rb +65 -0
  138. data/opal/browser/event/data_transfer.rb +95 -0
  139. data/opal/browser/event/device_light.rb +25 -0
  140. data/opal/browser/{dom/event → event}/device_motion.rb +21 -6
  141. data/opal/browser/event/device_orientation.rb +50 -0
  142. data/opal/browser/{dom/event → event}/device_proximity.rb +10 -6
  143. data/opal/browser/event/drag.rb +123 -0
  144. data/opal/browser/event/focus.rb +41 -0
  145. data/opal/browser/event/gamepad.rb +62 -0
  146. data/opal/browser/{dom/event → event}/hash_change.rb +10 -6
  147. data/opal/browser/event/keyboard.rb +128 -0
  148. data/opal/browser/event/message.rb +72 -0
  149. data/opal/browser/{dom/event → event}/mouse.rb +37 -32
  150. data/opal/browser/event/page_transition.rb +25 -0
  151. data/opal/browser/event/pop_state.rb +35 -0
  152. data/opal/browser/event/progress.rb +45 -0
  153. data/opal/browser/event/sensor.rb +17 -0
  154. data/opal/browser/{dom/event → event}/storage.rb +10 -6
  155. data/opal/browser/{dom/event → event}/touch.rb +14 -21
  156. data/opal/browser/event/ui.rb +38 -0
  157. data/opal/browser/{dom/event → event}/wheel.rb +6 -4
  158. data/opal/browser/event.rb +163 -0
  159. data/opal/browser/event_source.rb +7 -4
  160. data/opal/browser/form_data.rb +225 -0
  161. data/opal/browser/history.rb +53 -21
  162. data/opal/browser/http/binary.rb +1 -0
  163. data/opal/browser/http/headers.rb +21 -2
  164. data/opal/browser/http/request.rb +83 -55
  165. data/opal/browser/http/response.rb +5 -1
  166. data/opal/browser/http.rb +47 -9
  167. data/opal/browser/immediate.rb +128 -10
  168. data/opal/browser/interval.rb +41 -23
  169. data/opal/browser/location.rb +20 -4
  170. data/opal/browser/navigator.rb +136 -13
  171. data/opal/browser/polyfill/visual_viewport.rb +216 -0
  172. data/opal/browser/screen.rb +34 -8
  173. data/opal/browser/setup/base.rb +6 -0
  174. data/opal/browser/setup/full.rb +13 -0
  175. data/opal/browser/setup/large.rb +17 -0
  176. data/opal/browser/setup/mini.rb +8 -0
  177. data/opal/browser/setup/traditional.rb +10 -0
  178. data/opal/browser/socket.rb +16 -8
  179. data/opal/browser/storage.rb +155 -52
  180. data/opal/browser/support.rb +299 -0
  181. data/opal/browser/utils.rb +116 -18
  182. data/opal/browser/version.rb +1 -1
  183. data/opal/browser/visual_viewport.rb +39 -0
  184. data/opal/browser/window/size.rb +47 -9
  185. data/opal/browser/window/view.rb +37 -4
  186. data/opal/browser/window.rb +46 -26
  187. data/opal/browser.rb +1 -10
  188. data/opal/opal-browser.rb +1 -0
  189. data/opal-browser.gemspec +10 -12
  190. data/spec/database/sql_spec.rb +139 -0
  191. data/spec/delay_spec.rb +41 -0
  192. data/spec/dom/attribute_spec.rb +49 -0
  193. data/spec/dom/builder_spec.rb +36 -19
  194. data/spec/dom/document_spec.rb +28 -6
  195. data/spec/dom/element/attributes_spec.rb +52 -0
  196. data/spec/dom/element/custom_spec.rb +106 -0
  197. data/spec/dom/element/subclass_spec.rb +144 -0
  198. data/spec/dom/element_spec.rb +184 -7
  199. data/spec/dom/mutation_observer_spec.rb +13 -9
  200. data/spec/dom/node_set_spec.rb +44 -0
  201. data/spec/dom/node_spec.rb +87 -27
  202. data/spec/dom_spec.rb +19 -9
  203. data/spec/event_source_spec.rb +18 -15
  204. data/spec/{dom/event_spec.rb → event_spec.rb} +55 -26
  205. data/spec/history_spec.rb +32 -19
  206. data/spec/http_spec.rb +25 -36
  207. data/spec/immediate_spec.rb +10 -7
  208. data/spec/interval_spec.rb +59 -0
  209. data/spec/native_cached_wrapper_spec.rb +46 -0
  210. data/spec/runner.rb +107 -0
  211. data/spec/socket_spec.rb +18 -14
  212. data/spec/spec_helper.rb +2 -4
  213. data/spec/spec_helper_promise.rb.erb +25 -0
  214. data/spec/storage_spec.rb +7 -7
  215. data/spec/wgxpath.install.js +49 -0
  216. data/spec/window_spec.rb +2 -2
  217. metadata +181 -93
  218. data/opal/browser/compatibility/animation_frame.rb +0 -93
  219. data/opal/browser/compatibility/dom/document/window.rb +0 -15
  220. data/opal/browser/compatibility/dom/element/css.rb +0 -15
  221. data/opal/browser/compatibility/dom/element/matches.rb +0 -31
  222. data/opal/browser/compatibility/dom/element/offset.rb +0 -20
  223. data/opal/browser/compatibility/dom/element/scroll.rb +0 -25
  224. data/opal/browser/compatibility/dom/element/style.rb +0 -15
  225. data/opal/browser/compatibility/dom/mutation_observer.rb +0 -47
  226. data/opal/browser/compatibility/http/request.rb +0 -15
  227. data/opal/browser/compatibility/immediate.rb +0 -107
  228. data/opal/browser/compatibility/window/scroll.rb +0 -27
  229. data/opal/browser/compatibility/window/size.rb +0 -13
  230. data/opal/browser/compatibility/window/view.rb +0 -13
  231. data/opal/browser/compatibility.rb +0 -59
  232. data/opal/browser/dom/compatibility.rb +0 -8
  233. data/opal/browser/dom/event/animation.rb +0 -26
  234. data/opal/browser/dom/event/base.rb +0 -207
  235. data/opal/browser/dom/event/before_unload.rb +0 -13
  236. data/opal/browser/dom/event/clipboard.rb +0 -26
  237. data/opal/browser/dom/event/close.rb +0 -35
  238. data/opal/browser/dom/event/composition.rb +0 -38
  239. data/opal/browser/dom/event/custom.rb +0 -30
  240. data/opal/browser/dom/event/device_light.rb +0 -21
  241. data/opal/browser/dom/event/device_orientation.rb +0 -36
  242. data/opal/browser/dom/event/drag.rb +0 -113
  243. data/opal/browser/dom/event/focus.rb +0 -23
  244. data/opal/browser/dom/event/gamepad.rb +0 -47
  245. data/opal/browser/dom/event/keyboard.rb +0 -93
  246. data/opal/browser/dom/event/message.rb +0 -50
  247. data/opal/browser/dom/event/page_transition.rb +0 -21
  248. data/opal/browser/dom/event/pop_state.rb +0 -21
  249. data/opal/browser/dom/event/progress.rb +0 -31
  250. data/opal/browser/dom/event/sensor.rb +0 -13
  251. data/opal/browser/dom/event/ui.rb +0 -22
  252. data/opal/browser/dom/event.rb +0 -240
  253. data/opal/browser/http/compatibility.rb +0 -1
  254. data/opal/browser/http/parameters.rb +0 -8
  255. data/opal/browser/timeout.rb +0 -60
  256. data/opal/browser/window/compatibility.rb +0 -3
  257. data/opal/browser/window/scroll.rb +0 -49
@@ -1,21 +1,20 @@
1
1
  module Browser; module DOM
2
2
 
3
+ # Allows manipulation of a set of {Node}s.
3
4
  class NodeSet
4
- attr_reader :document
5
-
6
- def initialize(document, list = [])
7
- @document = document
8
- @literal = []
5
+ # Create a new {NodeSet} from the given nodes.
6
+ #
7
+ # Note that the nodes are flattened and converted with DOM automatically,
8
+ # this means you can pass {NodeSet}s and {Native::Array}s as well.
9
+ def self.[](*nodes)
10
+ new(nodes.flatten.map { |x| DOM(Native.convert(x)) }.uniq)
11
+ end
9
12
 
10
- list.each {|el|
11
- if NodeSet === el
12
- @literal.concat(el.to_a)
13
- else
14
- @literal.push DOM(Native.convert(el))
15
- end
16
- }
13
+ def initialize(literal)
14
+ @literal = literal
17
15
  end
18
16
 
17
+ # Any other method will be called on every node in the set.
19
18
  def method_missing(name, *args, &block)
20
19
  unless @literal.respond_to? name
21
20
  each {|el|
@@ -30,59 +29,93 @@ class NodeSet
30
29
  if `result === #@literal`
31
30
  self
32
31
  elsif Array === result
33
- NodeSet.new(@document, result)
32
+ NodeSet.new(result)
34
33
  else
35
34
  result
36
35
  end
37
36
  end
38
37
 
39
- def dup
40
- NodeSet.new(document, to_ary.dup)
38
+ def respond_to_missing?(name, *)
39
+ @literal.respond_to?(name)
41
40
  end
42
41
 
43
- def filter(expression)
44
- NodeSet.new(document, @literal.select { |node| node.matches?(expression) })
45
- end
42
+ # Get the first node matching the given CSS selectors.
43
+ #
44
+ # @param rules [Array<String>] the CSS selectors to match with
45
+ #
46
+ # @return [Node?]
47
+ def at_css(*rules)
48
+ each {|node|
49
+ if node = node.at_css(*rules)
50
+ return node
51
+ end
52
+ }
46
53
 
47
- def after(node)
48
- last.after node
54
+ nil
49
55
  end
50
56
 
51
- def at(path)
52
- raise NotImplementedError
53
- end
57
+ # Get the first node matching the given XPath.
58
+ #
59
+ # @param paths [Array<String>] the XPath to match with
60
+ #
61
+ # @return [Node?]
62
+ def at_xpath(*paths)
63
+ each {|node|
64
+ if node = node.at_xpath(*paths)
65
+ return node
66
+ end
67
+ }
54
68
 
55
- def at_css(*rules)
56
- raise NotImplementedError
69
+ nil
57
70
  end
58
71
 
59
- def at_xpath(*paths)
60
- raise NotImplementedError
72
+ # Query for children matching the given CSS selector.
73
+ #
74
+ # @param path [String] the CSS selector
75
+ #
76
+ # @return [NodeSet]
77
+ def css(path)
78
+ NodeSet[@literal.map {|node|
79
+ node.css(path)
80
+ }]
61
81
  end
62
82
 
63
- def before
64
- first.before
83
+ # Create another {NodeSet} with all the nodes that match the given
84
+ # expression.
85
+ #
86
+ # @param expression [String] a CSS selector
87
+ #
88
+ # @return [NodeSet] the new {NodeSet} with the matching nodes
89
+ def filter(expression)
90
+ NodeSet[@literal.select { |node| node =~ expression }]
65
91
  end
66
92
 
67
- def children
68
- result = NodeSet.new(document)
69
-
70
- each { |n| result.concat(n.children) }
71
-
72
- result
93
+ # Search for multiple selectors
94
+ def search(*what)
95
+ NodeSet[@literal.map { |node| node.search(*what) }]
73
96
  end
74
97
 
75
- def css(*paths)
76
- raise NotImplementedError
98
+ # Outer HTML of the entire nodeset
99
+ def outer_html
100
+ @literal.map(&:outer_html).join
77
101
  end
78
102
 
79
- def search(*what)
80
- map { |n| n.search(*what) }.flatten.uniq
103
+ # Query for children matching the given XPath.
104
+ #
105
+ # @param path [String] the XPath
106
+ #
107
+ # @return [NodeSet]
108
+ def xpath(path)
109
+ NodeSet[@literal.map {|node|
110
+ node.xpath(path)
111
+ }]
81
112
  end
82
113
 
83
- def inspect
84
- "#<DOM::NodeSet: #{@literal.inspect[1 .. -2]}"
114
+ def to_ary
115
+ @literal
85
116
  end
117
+
118
+ alias to_a to_ary
86
119
  end
87
120
 
88
121
  end; end
@@ -0,0 +1,12 @@
1
+ module Browser; module DOM
2
+
3
+ class ShadowRoot < DocumentFragment
4
+ include DocumentOrShadowRoot
5
+
6
+ # Use: Element#shadow
7
+ def self.create
8
+ raise ArgumentError
9
+ end
10
+ end
11
+
12
+ end; end
@@ -1,16 +1,31 @@
1
1
  module Browser; module DOM
2
2
 
3
+ # Encapsulates a text node.
4
+ #
5
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/Text
3
6
  class Text < CharacterData
4
- def self.create(*args)
5
- $document.create_text(*args)
7
+ # (see Document#create_text)
8
+ def self.create(content)
9
+ $document.create_text(content)
6
10
  end
7
11
 
12
+ # @!attribute [r] whole
13
+ # @return [String] the whole text
14
+ #
15
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/Text.wholeText
8
16
  def whole
9
17
  `#@native.wholeText`
10
18
  end
11
19
 
20
+ # Split the text node at a given offset.
21
+ #
22
+ # @param offset [Integer] the offset where to split the text node
23
+ #
24
+ # @return [Text] the newly created text node
25
+ #
26
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/Text.splitText
12
27
  def split(offset)
13
- `#@native.splitText(offset)`
28
+ DOM(`#@native.splitText(offset)`)
14
29
  end
15
30
 
16
31
  def inspect
data/opal/browser/dom.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'browser/dom/event'
2
1
  require 'browser/dom/node_set'
3
2
  require 'browser/dom/node'
4
3
  require 'browser/dom/attribute'
@@ -7,13 +6,12 @@ require 'browser/dom/text'
7
6
  require 'browser/dom/cdata'
8
7
  require 'browser/dom/comment'
9
8
  require 'browser/dom/element'
9
+ require 'browser/dom/document_or_shadow_root'
10
10
  require 'browser/dom/document'
11
11
  require 'browser/dom/document_fragment'
12
- require 'browser/dom/builder'
12
+ require 'browser/dom/shadow_root'
13
13
  require 'browser/dom/mutation_observer'
14
14
 
15
- require 'browser/dom/compatibility'
16
-
17
15
  module Kernel
18
16
  # Parse an XML string into a DOM usable {Browser::DOM::Document}
19
17
  #
@@ -36,29 +34,59 @@ module Kernel
36
34
  DOM(`doc`)
37
35
  end
38
36
 
39
- # Wrap a native element or create a DOM tree using the {Paggio::HTML} DSL.
37
+ # @overload DOM(document = $document, &block)
38
+ #
39
+ # Create a DOM tree using the {Paggio::HTML} DSL.
40
+ #
41
+ # @param document [Browser::DOM::Document] the document instance
42
+ # we intend to use
43
+ #
44
+ # @return [Browser::DOM::Node, Browser::DOM::NodeSet]
45
+ #
46
+ # @overload DOM(string, document = $document)
47
+ #
48
+ # Create a DOM tree from a HTML string.
49
+ #
50
+ # @param string [String] the HTML string
51
+ # @param document [Browser::DOM::Document] the document instance
52
+ # we intend to use
53
+ #
54
+ # @return [Browser::DOM::Node]
55
+ #
56
+ # @overload DOM(native)
57
+ #
58
+ # Wrap a native element to create a DOM tree.
59
+ #
60
+ # @param native [Native] the Native node
61
+ #
62
+ # @return [Browser::DOM::Node]
40
63
  #
41
- # @return [Browser::DOM::Node]
42
64
  def DOM(*args, &block)
43
65
  if block
44
66
  document = args.shift || $document
45
- element = args.shift
46
-
47
- roots = Browser::DOM::Builder.new(document, element, &block).to_a
67
+ roots = Browser::DOM::Builder.new(document, &block).to_a
48
68
 
49
69
  if roots.length == 1
50
70
  roots.first
51
71
  else
52
- Browser::DOM::NodeSet.new(document, roots)
72
+ Browser::DOM::NodeSet.new(roots)
53
73
  end
54
74
  else
55
75
  what = args.shift
56
76
  document = args.shift || $document
57
77
 
58
- if native?(what)
78
+ what = what.to_dom(document) if Opal.respond_to? what, :to_dom
79
+
80
+ if `typeof(#{what}) === 'undefined' || #{what} === null`
81
+ raise ArgumentError, 'argument is null'
82
+ elsif native?(what)
59
83
  Browser::DOM::Node.new(what)
60
84
  elsif Browser::DOM::Node === what
61
85
  what
86
+ elsif Opal.respond_to? what, :each # eg. NodeSet, Array
87
+ document.create_element("DIV").tap do |div|
88
+ div << what
89
+ end
62
90
  elsif String === what
63
91
  %x{
64
92
  var doc = #{Native.try_convert(document)}.createElement('div');
@@ -67,7 +95,7 @@ module Kernel
67
95
  return #{DOM(`doc.childNodes.length == 1 ? doc.childNodes[0] : doc`)};
68
96
  }
69
97
  else
70
- raise ArgumentError, "argument not DOM convertible"
98
+ raise ArgumentError, 'argument is not DOM convertible'
71
99
  end
72
100
  end
73
101
  end
@@ -76,12 +104,6 @@ end
76
104
  module Browser
77
105
 
78
106
  class Window
79
- include DOM::Event::Target
80
-
81
- target {|value|
82
- $window if `#{value} == window`
83
- }
84
-
85
107
  # Get the {DOM::Document} for this window.
86
108
  #
87
109
  # @return [DOM::Document]
@@ -1,39 +1,216 @@
1
+ require 'browser/animation_frame'
2
+
1
3
  module Browser; module DOM
2
4
 
3
5
  class Document < Element
6
+ # @!attribute [r] active_element
7
+ # @return [Element] the element with focus
4
8
  def active_element
5
9
  DOM(`#@native.activeElement`)
6
10
  end
7
11
  end
8
12
 
9
13
  class Element
14
+ # Show the element.
15
+ #
16
+ # @param what [Symbol] how to display it
10
17
  def show(what = :block)
11
18
  style[:display] = what
19
+ self
12
20
  end
13
21
 
22
+ # Hide the element.
14
23
  def hide
15
24
  style[:display] = :none
25
+ self
16
26
  end
17
27
 
18
- def toggle
19
- if style![:display] == :none
20
- show
28
+ def visible?
29
+ # Let's check if we want to lie about the real visibility of an element.
30
+ # It could be wise to lie about it when it's in a process of animation...
31
+ if !@virtually_visible.nil?
32
+ @virtually_visible
21
33
  else
34
+ style![:display] != :none
35
+ end
36
+ end
37
+
38
+ # Toggle the visibility of the element, hide it if it's shown, show it if
39
+ # it's hidden.
40
+ def toggle(what = :block)
41
+ if visible?
22
42
  hide
43
+ else
44
+ show(what)
23
45
  end
46
+ self
24
47
  end
25
48
 
49
+ # Set the focus on the element.
26
50
  def focus
27
51
  `#@native.focus()`
52
+ self
28
53
  end
29
54
 
55
+ # Blur the focus from the element.
30
56
  def blur
31
57
  `#@native.blur()`
58
+ self
32
59
  end
33
60
 
61
+ # Check if the element is focused.
34
62
  def focused?
35
63
  `#@native.hasFocus`
36
64
  end
65
+
66
+ # Queue the block to happen when currently queued animations finish or during
67
+ # the next animation frame.
68
+ def animation_queue &block
69
+ promise = Promise.new
70
+
71
+ promise_resolve = proc do
72
+ @animation_promise = nil if @animation_promise == promise
73
+ promise.resolve
74
+ end
75
+
76
+ @animation_promise = (@animation_promise || Promise.value(true)).then do
77
+ animation_frame do
78
+ yield promise_resolve
79
+ end
80
+ promise
81
+ end
82
+ end
83
+
84
+ # Transform an element smoothly using CSS transitions, jQuery style. Yield
85
+ # a block afterwards if it's provided.
86
+ def animate(properties, duration: 0.4.s, easing: :ease, resolve: false, &block)
87
+ animation_queue(resolve) do |res|
88
+ duration = 0.6.s if duration == :slow
89
+ duration = 0.2.s if duration == :fast
90
+
91
+ original_value = style['transition']
92
+
93
+ style['transition'] = [original_value,
94
+ *properties.keys.map do |key|
95
+ "#{key} #{duration} #{easing}"
96
+ end].compact.join(", ")
97
+
98
+ properties.each do |key, value|
99
+ style[key] = value
100
+ end
101
+
102
+ promise = Promise.new
103
+
104
+ one :transitionend do |*args|
105
+ style['transition'] = original_value
106
+
107
+ yield(*args) if block_given?
108
+
109
+ res.call
110
+ end
111
+ end
112
+ self
113
+ end
114
+
115
+ # Show a hidden element with a "fade in" animation. Yield a block afterwards.
116
+ def fade_in(**kwargs, &block)
117
+ animation_queue do |resolve|
118
+ if !visible?
119
+ @virtually_visible = true
120
+ show
121
+
122
+ style[:opacity] = 0.0
123
+ animate opacity: 1.0, **kwargs do |*args|
124
+ @virtually_visible = nil
125
+ style[:opacity] = nil
126
+ yield(*args) if block_given?
127
+ end
128
+ end
129
+ resolve.call
130
+ end
131
+ self
132
+ end
133
+
134
+ # Hide a visible element with a "fade out" animation. Yield a block afterwards.
135
+ def fade_out(**kwargs, &block)
136
+ animation_queue do |resolve|
137
+ if visible?
138
+ @virtually_visible = false
139
+
140
+ style[:opacity] = 1.0
141
+ animate opacity: 0.0, **kwargs do |*args|
142
+ @virtually_visible = nil
143
+ style[:opacity] = nil
144
+ hide
145
+ yield(*args) if block_given?
146
+ end
147
+ end
148
+ resolve.call
149
+ end
150
+ self
151
+ end
152
+
153
+ # Toggle a visibility of an element with a "fade in"/"fade out" animation. Yield
154
+ # a block afterwards.
155
+ def fade_toggle(**kwargs, &block)
156
+ if visible?
157
+ fade_out(**kwargs, &block)
158
+ else
159
+ fade_in(**kwargs, &block)
160
+ end
161
+ self
162
+ end
163
+
164
+ # Show a hidden element with a "slide down" animation. Yield a block afterwards.
165
+ def slide_down(**kwargs, &block)
166
+ animation_queue do |resolve|
167
+ if !visible?
168
+ @virtually_visible = true
169
+ show
170
+ height = size.height
171
+ orig_height = style[:height]
172
+ style[:height] = 0.px
173
+
174
+ animate height: height.px, **kwargs do |*args|
175
+ @virtually_visible = nil
176
+ style[:height] = orig_height
177
+ yield(*args) if block_given?
178
+ end
179
+ end
180
+ resolve.call
181
+ end
182
+ self
183
+ end
184
+
185
+ # Hide a visible element with a "slide up" animation. Yield a block afterwards.
186
+ def slide_up(**kwargs, &block)
187
+ animation_queue do |resolve|
188
+ if visible?
189
+ @virtually_visible = false
190
+ orig_height = style[:height]
191
+
192
+ animate height: 0.px, **kwargs do |*args|
193
+ @virtually_visible = nil
194
+ style[:height] = orig_height
195
+ hide
196
+ yield(*args) if block_given?
197
+ end
198
+ end
199
+ resolve.call
200
+ end
201
+ self
202
+ end
203
+
204
+ # Toggle a visibility of an element with a "slide up"/"slide down" animation.
205
+ # Yield a block afterwards.
206
+ def slide_toggle(**kwargs, &block)
207
+ if visible?
208
+ slide_up(**kwargs, &block)
209
+ else
210
+ slide_down(**kwargs, &block)
211
+ end
212
+ self
213
+ end
37
214
  end
38
215
 
39
216
  end; end
@@ -0,0 +1,26 @@
1
+ # browser/event/all: Load support for all events
2
+
3
+ require 'browser/event/focus'
4
+ require 'browser/event/wheel'
5
+ require 'browser/event/data_transfer'
6
+ require 'browser/event/composition'
7
+ require 'browser/event/animation'
8
+ require 'browser/event/audio_processing'
9
+ require 'browser/event/before_unload'
10
+ require 'browser/event/composition'
11
+ require 'browser/event/clipboard'
12
+ require 'browser/event/device_light'
13
+ require 'browser/event/device_motion'
14
+ require 'browser/event/device_orientation'
15
+ require 'browser/event/device_proximity'
16
+ require 'browser/event/drag'
17
+ require 'browser/event/gamepad'
18
+ require 'browser/event/hash_change'
19
+ require 'browser/event/progress'
20
+ require 'browser/event/page_transition'
21
+ require 'browser/event/pop_state'
22
+ require 'browser/event/storage'
23
+ require 'browser/event/touch'
24
+ require 'browser/event/sensor'
25
+ require 'browser/event/message'
26
+ require 'browser/event/close'
@@ -0,0 +1,40 @@
1
+ module Browser; class Event
2
+
3
+ class Animation < Event
4
+ handles 'animationend', 'animationiteration', 'animationstart'
5
+
6
+ def self.supported?
7
+ Browser.supports? 'Event.Animation'
8
+ end
9
+
10
+ class Definition < Definition
11
+ def animation=(value)
12
+ `#@native.animationName = #{value}`
13
+ end
14
+
15
+ def elapsed=(value)
16
+ `#@native.elapsedTime = #{value}`
17
+ end
18
+ end
19
+
20
+ if Browser.supports? 'Event.constructor'
21
+ def self.construct(name, desc)
22
+ `new AnimationEvent(#{name}, #{desc})`
23
+ end
24
+ elsif Browser.supports? 'Event.create'
25
+ def self.construct(name, desc)
26
+ %x{
27
+ var event = document.createEvent("AnimationEvent");
28
+ event.initAnimationEvent(name, desc.bubbles, desc.cancelable,
29
+ desc.animationName, desc.elapsedTime);
30
+
31
+ return event;
32
+ }
33
+ end
34
+ end if supported?
35
+
36
+ alias_native :name, :animationName
37
+ alias_native :elapsed, :elapsedTime
38
+ end
39
+
40
+ end; end
@@ -1,8 +1,10 @@
1
- module Browser; module DOM; class Event
1
+ module Browser; class Event
2
2
 
3
3
  class AudioProcessing < Event
4
+ handles 'audioprocess'
5
+
4
6
  def self.supported?
5
- not $$[:AudioProcessingEvent].nil?
7
+ Browser.supports? 'Event.AudioProcessing'
6
8
  end
7
9
 
8
10
  class Definition < Definition
@@ -19,13 +21,15 @@ class AudioProcessing < Event
19
21
  end
20
22
  end
21
23
 
22
- def self.create(name, &block)
23
- new(`new AudioProcessingEvent(#{name}, #{Definition.new(&block)})`)
24
- end
24
+ if Browser.supports? 'Event.constructor'
25
+ def self.construct(name, desc)
26
+ `new AudioProcessingEvent(#{name}, #{desc})`
27
+ end
28
+ end if supported?
25
29
 
26
30
  alias_native :time, :playbackTime
27
31
  alias_native :input, :inputBuffer
28
32
  alias_native :output, :outputBuffer
29
33
  end
30
34
 
31
- end; end; end
35
+ end; end