atome-opal-browser 0.3.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (228) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +11 -0
  3. data/Gemfile +33 -0
  4. data/Gemfile.lock +122 -0
  5. data/LICENSE +20 -0
  6. data/README.md +301 -0
  7. data/Rakefile +63 -0
  8. data/bin/rake +7 -0
  9. data/bin/setup +8 -0
  10. data/config.ru +81 -0
  11. data/docs/polyfills.md +24 -0
  12. data/examples/2048/Gemfile +13 -0
  13. data/examples/2048/Gemfile.lock +41 -0
  14. data/examples/2048/README.md +13 -0
  15. data/examples/2048/app/application.rb +169 -0
  16. data/examples/2048/config.ru +9 -0
  17. data/examples/canvas/Gemfile +9 -0
  18. data/examples/canvas/README.md +9 -0
  19. data/examples/canvas/app/application.rb +55 -0
  20. data/examples/canvas/config.ru +9 -0
  21. data/examples/component/Gemfile +9 -0
  22. data/examples/component/Gemfile.lock +45 -0
  23. data/examples/component/README.md +10 -0
  24. data/examples/component/app/application.rb +66 -0
  25. data/examples/component/config.ru +9 -0
  26. data/examples/integrations/README.md +24 -0
  27. data/examples/integrations/dynamic-rack-opal-sprockets-server/Gemfile +7 -0
  28. data/examples/integrations/dynamic-rack-opal-sprockets-server/README.md +16 -0
  29. data/examples/integrations/dynamic-rack-opal-sprockets-server/app/application.rb +6 -0
  30. data/examples/integrations/dynamic-rack-opal-sprockets-server/config.ru +9 -0
  31. data/examples/integrations/dynamic-roda-roda-sprockets/.gitignore +1 -0
  32. data/examples/integrations/dynamic-roda-roda-sprockets/Gemfile +8 -0
  33. data/examples/integrations/dynamic-roda-roda-sprockets/README.md +22 -0
  34. data/examples/integrations/dynamic-roda-roda-sprockets/Rakefile +4 -0
  35. data/examples/integrations/dynamic-roda-roda-sprockets/app/application.rb +6 -0
  36. data/examples/integrations/dynamic-roda-roda-sprockets/app.rb +32 -0
  37. data/examples/integrations/dynamic-roda-roda-sprockets/config.ru +3 -0
  38. data/examples/integrations/dynamic-roda-tilt/.gitignore +1 -0
  39. data/examples/integrations/dynamic-roda-tilt/Gemfile +9 -0
  40. data/examples/integrations/dynamic-roda-tilt/README.md +17 -0
  41. data/examples/integrations/dynamic-roda-tilt/Rakefile +6 -0
  42. data/examples/integrations/dynamic-roda-tilt/app/application.rb +6 -0
  43. data/examples/integrations/dynamic-roda-tilt/app.rb +50 -0
  44. data/examples/integrations/dynamic-roda-tilt/config.ru +3 -0
  45. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/Gemfile +10 -0
  46. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/README.md +16 -0
  47. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/app/application.rb +6 -0
  48. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/config.ru +29 -0
  49. data/examples/integrations/static-bash/.gitignore +2 -0
  50. data/examples/integrations/static-bash/Gemfile +3 -0
  51. data/examples/integrations/static-bash/README.md +8 -0
  52. data/examples/integrations/static-bash/app/application.rb +6 -0
  53. data/examples/integrations/static-bash/build.sh +4 -0
  54. data/examples/integrations/static-bash/index.html +10 -0
  55. data/examples/integrations/static-bash-opal-parser/.gitignore +3 -0
  56. data/examples/integrations/static-bash-opal-parser/Gemfile +3 -0
  57. data/examples/integrations/static-bash-opal-parser/README.md +10 -0
  58. data/examples/integrations/static-bash-opal-parser/build.sh +4 -0
  59. data/examples/integrations/static-bash-opal-parser/index.html +19 -0
  60. data/examples/integrations/static-rake/.gitignore +1 -0
  61. data/examples/integrations/static-rake/Gemfile +7 -0
  62. data/examples/integrations/static-rake/README.md +7 -0
  63. data/examples/integrations/static-rake/Rakefile +10 -0
  64. data/examples/integrations/static-rake/app/application.rb +6 -0
  65. data/examples/integrations/static-rake/index.html +9 -0
  66. data/examples/integrations/static-rake-guard/.gitignore +1 -0
  67. data/examples/integrations/static-rake-guard/Gemfile +9 -0
  68. data/examples/integrations/static-rake-guard/Gemfile.lock +69 -0
  69. data/examples/integrations/static-rake-guard/Guardfile +3 -0
  70. data/examples/integrations/static-rake-guard/README.md +10 -0
  71. data/examples/integrations/static-rake-guard/Rakefile +10 -0
  72. data/examples/integrations/static-rake-guard/app/application.rb +6 -0
  73. data/examples/integrations/static-rake-guard/index.html +9 -0
  74. data/examples/svg/.gitignore +1 -0
  75. data/examples/svg/Gemfile +4 -0
  76. data/examples/svg/README.md +7 -0
  77. data/examples/svg/Rakefile +10 -0
  78. data/examples/svg/app/application.rb +11 -0
  79. data/examples/svg/index.html +17 -0
  80. data/examples/svg/index.svg +6 -0
  81. data/index.html.erb +24 -0
  82. data/lib/opal/browser.rb +4 -0
  83. data/lib/opal-browser.rb +1 -0
  84. data/opal/browser/animation_frame.rb +111 -0
  85. data/opal/browser/audio/node.rb +121 -0
  86. data/opal/browser/audio/param_schedule.rb +43 -0
  87. data/opal/browser/audio.rb +66 -0
  88. data/opal/browser/blob.rb +94 -0
  89. data/opal/browser/canvas/data.rb +63 -0
  90. data/opal/browser/canvas/gradient.rb +27 -0
  91. data/opal/browser/canvas/style.rb +115 -0
  92. data/opal/browser/canvas/text.rb +45 -0
  93. data/opal/browser/canvas.rb +335 -0
  94. data/opal/browser/console.rb +105 -0
  95. data/opal/browser/cookies.rb +171 -0
  96. data/opal/browser/crypto.rb +79 -0
  97. data/opal/browser/css/declaration.rb +83 -0
  98. data/opal/browser/css/rule/style.rb +16 -0
  99. data/opal/browser/css/rule.rb +48 -0
  100. data/opal/browser/css/style_sheet.rb +83 -0
  101. data/opal/browser/css/unit.rb +188 -0
  102. data/opal/browser/css.rb +40 -0
  103. data/opal/browser/database/sql.rb +193 -0
  104. data/opal/browser/delay.rb +94 -0
  105. data/opal/browser/dom/attribute.rb +26 -0
  106. data/opal/browser/dom/builder.rb +107 -0
  107. data/opal/browser/dom/cdata.rb +9 -0
  108. data/opal/browser/dom/character_data.rb +73 -0
  109. data/opal/browser/dom/comment.rb +9 -0
  110. data/opal/browser/dom/document.rb +217 -0
  111. data/opal/browser/dom/document_fragment.rb +25 -0
  112. data/opal/browser/dom/document_or_shadow_root.rb +19 -0
  113. data/opal/browser/dom/element/attributes.rb +111 -0
  114. data/opal/browser/dom/element/button.rb +31 -0
  115. data/opal/browser/dom/element/custom.rb +177 -0
  116. data/opal/browser/dom/element/data.rb +82 -0
  117. data/opal/browser/dom/element/editable.rb +47 -0
  118. data/opal/browser/dom/element/form.rb +38 -0
  119. data/opal/browser/dom/element/iframe.rb +37 -0
  120. data/opal/browser/dom/element/image.rb +25 -0
  121. data/opal/browser/dom/element/input.rb +64 -0
  122. data/opal/browser/dom/element/media.rb +43 -0
  123. data/opal/browser/dom/element/offset.rb +89 -0
  124. data/opal/browser/dom/element/position.rb +46 -0
  125. data/opal/browser/dom/element/scroll.rb +168 -0
  126. data/opal/browser/dom/element/select.rb +42 -0
  127. data/opal/browser/dom/element/size.rb +46 -0
  128. data/opal/browser/dom/element/template.rb +11 -0
  129. data/opal/browser/dom/element/textarea.rb +26 -0
  130. data/opal/browser/dom/element.rb +618 -0
  131. data/opal/browser/dom/mutation_observer.rb +178 -0
  132. data/opal/browser/dom/node.rb +504 -0
  133. data/opal/browser/dom/node_set.rb +121 -0
  134. data/opal/browser/dom/shadow_root.rb +12 -0
  135. data/opal/browser/dom/text.rb +36 -0
  136. data/opal/browser/dom.rb +124 -0
  137. data/opal/browser/effects.rb +216 -0
  138. data/opal/browser/event/all.rb +26 -0
  139. data/opal/browser/event/animation.rb +40 -0
  140. data/opal/browser/event/audio_processing.rb +35 -0
  141. data/opal/browser/event/base.rb +461 -0
  142. data/opal/browser/event/before_unload.rb +17 -0
  143. data/opal/browser/event/clipboard.rb +37 -0
  144. data/opal/browser/event/close.rb +49 -0
  145. data/opal/browser/event/composition.rb +52 -0
  146. data/opal/browser/event/custom.rb +65 -0
  147. data/opal/browser/event/data_transfer.rb +95 -0
  148. data/opal/browser/event/device_light.rb +25 -0
  149. data/opal/browser/event/device_motion.rb +53 -0
  150. data/opal/browser/event/device_orientation.rb +50 -0
  151. data/opal/browser/event/device_proximity.rb +35 -0
  152. data/opal/browser/event/drag.rb +123 -0
  153. data/opal/browser/event/focus.rb +41 -0
  154. data/opal/browser/event/gamepad.rb +62 -0
  155. data/opal/browser/event/hash_change.rb +30 -0
  156. data/opal/browser/event/keyboard.rb +128 -0
  157. data/opal/browser/event/message.rb +72 -0
  158. data/opal/browser/event/mouse.rb +258 -0
  159. data/opal/browser/event/page_transition.rb +25 -0
  160. data/opal/browser/event/pop_state.rb +35 -0
  161. data/opal/browser/event/progress.rb +45 -0
  162. data/opal/browser/event/sensor.rb +17 -0
  163. data/opal/browser/event/storage.rb +45 -0
  164. data/opal/browser/event/touch.rb +62 -0
  165. data/opal/browser/event/ui.rb +38 -0
  166. data/opal/browser/event/wheel.rb +51 -0
  167. data/opal/browser/event.rb +162 -0
  168. data/opal/browser/event_source.rb +70 -0
  169. data/opal/browser/form_data.rb +225 -0
  170. data/opal/browser/history.rb +86 -0
  171. data/opal/browser/http/binary.rb +58 -0
  172. data/opal/browser/http/headers.rb +109 -0
  173. data/opal/browser/http/request.rb +359 -0
  174. data/opal/browser/http/response.rb +119 -0
  175. data/opal/browser/http.rb +167 -0
  176. data/opal/browser/immediate.rb +161 -0
  177. data/opal/browser/interval.rb +111 -0
  178. data/opal/browser/location.rb +93 -0
  179. data/opal/browser/navigator.rb +274 -0
  180. data/opal/browser/polyfill/visual_viewport.rb +216 -0
  181. data/opal/browser/screen.rb +66 -0
  182. data/opal/browser/setup/base.rb +6 -0
  183. data/opal/browser/setup/full.rb +13 -0
  184. data/opal/browser/setup/large.rb +17 -0
  185. data/opal/browser/setup/mini.rb +8 -0
  186. data/opal/browser/setup/traditional.rb +10 -0
  187. data/opal/browser/socket.rb +123 -0
  188. data/opal/browser/storage.rb +252 -0
  189. data/opal/browser/support.rb +299 -0
  190. data/opal/browser/utils.rb +154 -0
  191. data/opal/browser/version.rb +3 -0
  192. data/opal/browser/visual_viewport.rb +39 -0
  193. data/opal/browser/window/size.rb +73 -0
  194. data/opal/browser/window/view.rb +51 -0
  195. data/opal/browser/window.rb +133 -0
  196. data/opal/browser.rb +1 -0
  197. data/opal/opal-browser.rb +1 -0
  198. data/opal-browser.gemspec +27 -0
  199. data/spec/database/sql_spec.rb +139 -0
  200. data/spec/delay_spec.rb +41 -0
  201. data/spec/dom/attribute_spec.rb +49 -0
  202. data/spec/dom/builder_spec.rb +86 -0
  203. data/spec/dom/document_spec.rb +62 -0
  204. data/spec/dom/element/attributes_spec.rb +52 -0
  205. data/spec/dom/element/custom_spec.rb +106 -0
  206. data/spec/dom/element/subclass_spec.rb +144 -0
  207. data/spec/dom/element_spec.rb +223 -0
  208. data/spec/dom/mutation_observer_spec.rb +41 -0
  209. data/spec/dom/node_set_spec.rb +44 -0
  210. data/spec/dom/node_spec.rb +214 -0
  211. data/spec/dom_spec.rb +23 -0
  212. data/spec/event_source_spec.rb +45 -0
  213. data/spec/event_spec.rb +156 -0
  214. data/spec/history_spec.rb +61 -0
  215. data/spec/http_spec.rb +76 -0
  216. data/spec/immediate_spec.rb +15 -0
  217. data/spec/interval_spec.rb +59 -0
  218. data/spec/json2.js +486 -0
  219. data/spec/native_cached_wrapper_spec.rb +46 -0
  220. data/spec/runner.rb +107 -0
  221. data/spec/sizzle.js +5 -0
  222. data/spec/socket_spec.rb +47 -0
  223. data/spec/spec_helper.rb +35 -0
  224. data/spec/spec_helper_promise.rb.erb +25 -0
  225. data/spec/storage_spec.rb +26 -0
  226. data/spec/wgxpath.install.js +49 -0
  227. data/spec/window_spec.rb +10 -0
  228. metadata +500 -0
@@ -0,0 +1,618 @@
1
+ # Requires are moved to the bottom of this file.
2
+
3
+ module Browser; module DOM
4
+
5
+ class Element < Node
6
+ def self.create(*args, &block)
7
+ if Document === args.first
8
+ document = args.shift
9
+ else
10
+ document = $document
11
+ end
12
+
13
+ if self == Element
14
+ document.create_element(*args, &block)
15
+ elsif @tag_name
16
+ document.create_element(@tag_name, *args, &block)
17
+ elsif @selector
18
+ # That's crude, but should cover the most basic cases.
19
+ # Just in case, you can override it safely. To reiterate:
20
+ # .create is not to be used inside libraries, those are
21
+ # expected to use the Document#create_element API.
22
+ kwargs = {}
23
+ kwargs = args.pop if Hash === args.last
24
+ custom_attrs, custom_id, custom_classes = nil, nil, nil
25
+ tag_name = (@selector.scan(/^[\w-]+/).first || "div").upcase
26
+ classes = @selector.scan(/\.([\w-]+)/).flatten
27
+ classes |= custom_classes if custom_classes = kwargs.delete(:classes)
28
+ id = @selector.scan(/#([\w-]+)/).flatten.first
29
+ id = custom_id if custom_id = kwargs.delete(:id)
30
+ attrs = @selector.scan(/\[([\w-]+)=((["'])(.*?)\3|[\w_-]*)\]/).map { |a,b,_,d| [a,d||b] }.to_h
31
+ attrs = attrs.merge(custom_attrs) if custom_attrs = kwargs.delete(:attrs)
32
+ document.create_element(tag_name, *args, classes: classes, id: id, attrs: attrs, **kwargs, &block)
33
+ else
34
+ raise NotImplementedError
35
+ end
36
+ end
37
+
38
+ def self.subclasses
39
+ @subclasses ||= []
40
+ end
41
+
42
+ # Define a selector for subclass dispatch
43
+ #
44
+ # Example:
45
+ # ```
46
+ # class CustomElement < Browser::DOM::Element
47
+ # def_selector "div.hello-world"
48
+ # end
49
+ # ```
50
+ def self.def_selector(selector)
51
+ Element.subclasses << self
52
+
53
+ @selector = selector
54
+
55
+ # A special case to speedup dispatch
56
+ @tag_name = selector.upcase unless selector =~ /[^\w-]/
57
+ end
58
+
59
+ def self.selector
60
+ @selector
61
+ end
62
+
63
+ def self.tag_name
64
+ @tag_name
65
+ end
66
+
67
+ def self.new(*args, &block)
68
+ if args.length == 1 && !block_given? && Opal.native?(args[0])
69
+ # Use `.new` as a wrapping method.
70
+ node = args[0]
71
+ else
72
+ # Use `.new` as an alias for `.create`.
73
+ return create(*args, &block)
74
+ end
75
+
76
+ if self == Element
77
+ subclass = Element.subclasses.select do |subclass|
78
+ Element.native_is?(node, subclass)
79
+ end.last
80
+
81
+ if subclass
82
+ subclass.new(node)
83
+ else
84
+ super(node)
85
+ end
86
+ else
87
+ super(node)
88
+ end
89
+ end
90
+
91
+ include Event::Target
92
+
93
+ target {|value|
94
+ begin
95
+ DOM(value)
96
+ rescue StandardError, JS::Error
97
+ nil
98
+ end
99
+ }
100
+
101
+ def self.native_is? (native, klass)
102
+ if tag_name = klass.tag_name
103
+ is = `(#{native}.getAttribute("is") || "")`
104
+ `#{tag_name} === #{is}.toUpperCase() || #{tag_name} === #{native}.nodeName`
105
+ else
106
+ Element.native_matches?(native, klass.selector)
107
+ end
108
+ end
109
+
110
+ if Browser.supports? 'Element.matches'
111
+ def self.native_matches? (native, selector)
112
+ `#{native}.matches(#{selector})`
113
+ end
114
+ elsif Browser.supports? 'Element.matches (Opera)'
115
+ def self.native_matches? (native, selector)
116
+ `#{native}.oMatchesSelector(#{selector})`
117
+ end
118
+ elsif Browser.supports? 'Element.matches (Internet Explorer)'
119
+ def self.native_matches? (native, selector)
120
+ `#{native}.msMatchesSelector(#{selector})`
121
+ end
122
+ elsif Browser.supports? 'Element.matches (Firefox)'
123
+ def self.native_matches? (native, selector)
124
+ `#{native}.mozMatchesSelector(#{selector})`
125
+ end
126
+ elsif Browser.supports? 'Element.matches (Chrome)'
127
+ def self.native_matches? (native, selector)
128
+ `#{native}.webkitMatchesSelector(#{selector})`
129
+ end
130
+ elsif Browser.loaded? 'Sizzle'
131
+ def self.native_matches? (native, selector)
132
+ `Sizzle.matchesSelector(#{native}, #{selector})`
133
+ end
134
+ else
135
+ def self.native_matches? (native, selector)
136
+ raise NotImplementedError, 'selector matching unsupported'
137
+ end
138
+ end
139
+
140
+ # Check whether the element matches the given selector.
141
+ #
142
+ # @param selector [String] the CSS selector
143
+ def =~(selector)
144
+ Element.native_matches?(@native, selector)
145
+ end
146
+
147
+ # Allow for case expressions
148
+ alias === =~
149
+
150
+ # Query for children with the given XPpaths.
151
+ #
152
+ # @param paths [Array<String>] the XPaths to look for
153
+ #
154
+ # @return [NodeSet]
155
+ def /(*paths)
156
+ NodeSet[paths.map { |path| xpath(path) }]
157
+ end
158
+
159
+ # Get the attribute with the given name.
160
+ #
161
+ # @param name [String] the attribute name
162
+ # @param options [Hash] options for the attribute
163
+ #
164
+ # @option options [String] :namespace the namespace for the attribute
165
+ #
166
+ # @return [String?]
167
+ def [](name, options = {})
168
+ attributes.get(name, options)
169
+ end
170
+
171
+ # Set the attribute with the given name and value.
172
+ #
173
+ # @param name [String] the attribute name
174
+ # @param value [Object] the attribute value
175
+ # @param options [Hash] the options for the attribute
176
+ #
177
+ # @option options [String] :namespace the namespace for the attribute
178
+ def []=(name, value, options = {})
179
+ attributes.set(name, value, options)
180
+ end
181
+
182
+ # Add class names to the element.
183
+ #
184
+ # @param names [Array<String>] class names to add
185
+ #
186
+ # @return [self]
187
+ def add_class(*names)
188
+ classes = class_names + names
189
+
190
+ unless classes.empty?
191
+ `#@native.className = #{classes.uniq.join ' '}`
192
+ end
193
+
194
+ self
195
+ end
196
+
197
+ # Get the first node that matches the given CSS selector or XPath.
198
+ #
199
+ # @param path_or_selector [String] an XPath or CSS selector
200
+ #
201
+ # @return [Node?]
202
+ def at(path_or_selector)
203
+ xpath(path_or_selector).first || css(path_or_selector).first
204
+ end
205
+
206
+ # Get the first node matching the given CSS selectors.
207
+ #
208
+ # @param rules [Array<String>] the CSS selectors to match with
209
+ #
210
+ # @return [Node?]
211
+ def at_css(*rules)
212
+ result = nil
213
+
214
+ rules.each {|rule|
215
+ if result = css(rule).first
216
+ break
217
+ end
218
+ }
219
+
220
+ result
221
+ end
222
+
223
+ # Get the first node matching the given XPath.
224
+ #
225
+ # @param paths [Array<String>] the XPath to match with
226
+ #
227
+ # @return [Node?]
228
+ def at_xpath(*paths)
229
+ result = nil
230
+
231
+ paths.each {|path|
232
+ if result = xpath(path).first
233
+ break
234
+ end
235
+ }
236
+
237
+ result
238
+ end
239
+
240
+ alias attr []
241
+
242
+ alias attribute []
243
+
244
+ # @!attribute [r] attributes
245
+ # @return [Attributes] the attributes for the element
246
+ def attributes(options = {})
247
+ Attributes.new(self, options)
248
+ end
249
+
250
+ # @!attribute [r] attribute_nodes
251
+ # @return [NodeSet] the attribute nodes for the element
252
+ def attribute_nodes
253
+ NodeSet[Native::Array.new(`#@native.attributes`, get: :item)]
254
+ end
255
+
256
+ # @!attribute [r] class_name
257
+ # @return [String] all the element class names
258
+ alias_native :class_name, :className
259
+
260
+ # @!attribute [r] class_names
261
+ # @return [Array<String>] all the element class names
262
+ def class_names
263
+ `#@native.className`.split(/\s+/).reject(&:empty?)
264
+ end
265
+
266
+ if Browser.supports? 'Query.css'
267
+ def css(path)
268
+ NodeSet[Native::Array.new(`#@native.querySelectorAll(path)`)]
269
+ rescue StandardError, JS::Error
270
+ NodeSet[]
271
+ end
272
+ elsif Browser.loaded? 'Sizzle'
273
+ def css(path)
274
+ NodeSet[`Sizzle(path, #@native)`]
275
+ rescue StandardError, JS::Error
276
+ NodeSet[]
277
+ end
278
+ else
279
+ # Query for children matching the given CSS selector.
280
+ #
281
+ # @param selector [String] the CSS selector
282
+ #
283
+ # @return [NodeSet]
284
+ def css(selector)
285
+ raise NotImplementedError, 'query by CSS selector unsupported'
286
+ end
287
+ end
288
+
289
+ # Click the element. it fires the element's click event.
290
+ def click
291
+ `#@native.click()`
292
+ self
293
+ end
294
+
295
+ # @overload data()
296
+ #
297
+ # Return the data for the element.
298
+ #
299
+ # @return [Data]
300
+ #
301
+ # @overload data(hash)
302
+ #
303
+ # Set data on the element.
304
+ #
305
+ # @param hash [Hash] the data to set
306
+ #
307
+ # @return [self]
308
+ def data(value = nil)
309
+ data = Data.new(self)
310
+
311
+ return data unless value
312
+
313
+ if Hash === value
314
+ data.assign(value)
315
+ else
316
+ raise ArgumentError, 'unknown data type'
317
+ end
318
+
319
+ self
320
+ end
321
+
322
+ alias get_attribute []
323
+
324
+ alias get []
325
+
326
+ # @!attribute height
327
+ # @return [Integer] the height of the element
328
+ def height
329
+ size.height
330
+ end
331
+
332
+ def height=(value)
333
+ size.height = value
334
+ end
335
+
336
+ # @!attribute id
337
+ # @return [String?] the ID of the element
338
+ def id
339
+ %x{
340
+ var id = #@native.id;
341
+
342
+ if (id === "") {
343
+ return nil;
344
+ }
345
+ else {
346
+ return id;
347
+ }
348
+ }
349
+ end
350
+
351
+ def id=(value)
352
+ `#@native.id = #{value.to_s}`
353
+ end
354
+
355
+ # Set the inner DOM of the element using the {Builder}.
356
+ def inner_dom(builder=nil, &block)
357
+ self.inner_dom = Builder.new(document, builder, &block).to_a
358
+ self
359
+ end
360
+
361
+ # Set the inner DOM with the given node.
362
+ #
363
+ # (see #append_child)
364
+ def inner_dom=(node)
365
+ clear
366
+
367
+ self << node
368
+ end
369
+
370
+ # @!attribute inner_html
371
+ # @return [String] the inner HTML of the element
372
+ def inner_html
373
+ `#@native.innerHTML`
374
+ end
375
+
376
+ def inner_html=(value)
377
+ `#@native.innerHTML = #{value}`
378
+ end
379
+
380
+ def inspect
381
+ inspect = name.downcase
382
+
383
+ if id
384
+ inspect += '.' + id + '!'
385
+ end
386
+
387
+ unless class_names.empty?
388
+ inspect += '.' + class_names.join('.')
389
+ end
390
+
391
+ "#<#{self.class.name.gsub("Browser::","")}: #{inspect}>"
392
+ end
393
+
394
+ # @!attribute offset
395
+ # @return [Offset] the offset of the element
396
+ def offset(*values)
397
+ off = Offset.new(self)
398
+
399
+ unless values.empty?
400
+ off.set(*values)
401
+ end
402
+
403
+ off
404
+ end
405
+
406
+ def offset=(value)
407
+ offset.set(*value)
408
+ end
409
+
410
+ # @!attribute outer_html
411
+ # @return [String] the outer HTML of the element
412
+ def outer_html
413
+ `#@native.outerHTML`
414
+ end
415
+
416
+ # @!attribute [r] position
417
+ # @return [Position] the position of the element
418
+ def position
419
+ @position ||= Position.new(self)
420
+ end
421
+
422
+ # @!attribute [r] scroll
423
+ # @return [Scroll] the scrolling for the element
424
+ def scroll
425
+ @scroll ||= Scroll.new(self)
426
+ end
427
+
428
+ # Search for all the children matching the given XPaths or CSS selectors.
429
+ #
430
+ # @param selectors [Array<String>] mixed list of XPaths and CSS selectors
431
+ #
432
+ # @return [NodeSet]
433
+ def search(*selectors)
434
+ NodeSet.new selectors.map {|selector|
435
+ xpath(selector).to_a.concat(css(selector).to_a)
436
+ }.flatten.uniq
437
+ end
438
+
439
+ alias set []=
440
+
441
+ alias set_attribute []=
442
+
443
+ # Creates or accesses the shadow root of this element
444
+ #
445
+ # @param open [Boolean] set to false if you want to create a closed
446
+ # shadow root
447
+ #
448
+ # @return [ShadowRoot]
449
+ def shadow (open = true)
450
+ if root = `#@native.shadowRoot`
451
+ DOM(root)
452
+ else
453
+ DOM(`#@native.attachShadow({mode: #{open ? "open" : "closed"}})`)
454
+ end
455
+ end
456
+
457
+ # Checks for a presence of a shadow root of this element
458
+ #
459
+ # @return [Boolean]
460
+ def shadow?
461
+ `!!#@native.shadowRoot`
462
+ end
463
+
464
+ # @overload style()
465
+ #
466
+ # Return the style for the element.
467
+ #
468
+ # @return [CSS::Declaration]
469
+ #
470
+ # @overload style(data)
471
+ #
472
+ # Set the CSS style as string or set of values.
473
+ #
474
+ # @param data [String, Hash] the new style
475
+ #
476
+ # @return [self]
477
+ #
478
+ # @overload style(&block)
479
+ #
480
+ # Set the CSS style from a CSS builder DSL.
481
+ #
482
+ # @return [self]
483
+ def style(data = nil, &block)
484
+ style = CSS::Declaration.new(`#@native.style`)
485
+
486
+ return style unless data || block
487
+
488
+ if String === data
489
+ style.replace(data)
490
+ elsif Hash === data
491
+ style.assign(data)
492
+ elsif block
493
+ style.apply(&block)
494
+ else
495
+ raise ArgumentError, 'unknown data type'
496
+ end
497
+
498
+ self
499
+ end
500
+
501
+ if Browser.supports? 'CSS.computed'
502
+ def style!
503
+ CSS::Declaration.new(`#{window.to_n}.getComputedStyle(#@native, null)`)
504
+ end
505
+ elsif Browser.supports? 'CSS.current'
506
+ def style!
507
+ CSS::Declaration.new(`#@native.currentStyle`)
508
+ end
509
+ else
510
+ # @!attribute [r] style!
511
+ # @return [CSS::Declaration] get the computed style for the element
512
+ def style!
513
+ raise NotImplementedError, 'computed style unsupported'
514
+ end
515
+ end
516
+
517
+ # Remove an attribute from the element.
518
+ #
519
+ # @param name [String] the attribute name
520
+ def remove_attribute(name)
521
+ `#@native.removeAttribute(name)`
522
+ end
523
+
524
+ # Remove class names from the element.
525
+ #
526
+ # @param names [Array<String>] class names to remove
527
+ #
528
+ # @return [self]
529
+ def remove_class(*names)
530
+ classes = class_names - names
531
+
532
+ if classes.empty?
533
+ `#@native.removeAttribute('class')`
534
+ else
535
+ `#@native.className = #{classes.join ' '}`
536
+ end
537
+
538
+ self
539
+ end
540
+
541
+ # @!attribute [r] size
542
+ # @return [Size] the size of the element
543
+ def size(*inc)
544
+ Size.new(self, *inc)
545
+ end
546
+
547
+ # Toggle class names of the element.
548
+ #
549
+ # @param names [Array<String>] class names to toggle
550
+ #
551
+ # @return [self]
552
+ def toggle_class(*names)
553
+ to_remove, to_add = names.partition { |name| class_names.include? name }
554
+
555
+ add_class(*to_add)
556
+ remove_class(*to_remove)
557
+ end
558
+
559
+ # @!attribute width
560
+ # @return [Integer] the width of the element
561
+ def width
562
+ size.width
563
+ end
564
+
565
+ def width=(value)
566
+ size.width = value
567
+ end
568
+
569
+ # @!attribute [r] window
570
+ # @return [Window] the window for the element
571
+ def window
572
+ document.window
573
+ end
574
+
575
+ if Browser.supports?('Query.xpath') || Browser.loaded?('wicked-good-xpath')
576
+ if Browser.loaded? 'wicked-good-xpath'
577
+ `wgxpath.install()`
578
+ end
579
+
580
+ def xpath(path)
581
+ NodeSet[Native::Array.new(
582
+ `(#@native.ownerDocument || #@native).evaluate(path,
583
+ #@native, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)`,
584
+ get: :snapshotItem,
585
+ length: :snapshotLength)]
586
+ rescue StandardError, JS::Error
587
+ NodeSet[]
588
+ end
589
+ else
590
+ # Query for children matching the given XPath.
591
+ #
592
+ # @param path [String] the XPath
593
+ #
594
+ # @return [NodeSet]
595
+ def xpath(path)
596
+ raise NotImplementedError, 'query by XPath unsupported'
597
+ end
598
+ end
599
+ end
600
+
601
+ end; end
602
+
603
+ require 'browser/dom/element/attributes'
604
+ require 'browser/dom/element/data'
605
+ require 'browser/dom/element/position'
606
+ require 'browser/dom/element/offset'
607
+ require 'browser/dom/element/scroll'
608
+ require 'browser/dom/element/size'
609
+
610
+ require 'browser/dom/element/button'
611
+ require 'browser/dom/element/image'
612
+ require 'browser/dom/element/form'
613
+ require 'browser/dom/element/input'
614
+ require 'browser/dom/element/select'
615
+ require 'browser/dom/element/template'
616
+ require 'browser/dom/element/textarea'
617
+ require 'browser/dom/element/iframe'
618
+ require 'browser/dom/element/media'