opal-browser 0.2.0 → 0.3.0

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 (201) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/build.yml +95 -0
  3. data/.gitignore +2 -0
  4. data/Gemfile +17 -3
  5. data/LICENSE +2 -1
  6. data/README.md +116 -54
  7. data/Rakefile +29 -1
  8. data/config.ru +20 -3
  9. data/docs/polyfills.md +24 -0
  10. data/examples/2048/Gemfile +7 -0
  11. data/examples/2048/README.md +13 -0
  12. data/examples/2048/app/application.rb +169 -0
  13. data/examples/2048/config.ru +9 -0
  14. data/examples/canvas/Gemfile +7 -0
  15. data/examples/canvas/README.md +9 -0
  16. data/examples/canvas/app/application.rb +55 -0
  17. data/examples/canvas/config.ru +9 -0
  18. data/examples/component/Gemfile +7 -0
  19. data/examples/component/README.md +10 -0
  20. data/examples/component/app/application.rb +66 -0
  21. data/examples/component/config.ru +9 -0
  22. data/examples/integrations/README.md +24 -0
  23. data/examples/integrations/dynamic-rack-opal-sprockets-server/Gemfile +7 -0
  24. data/examples/integrations/dynamic-rack-opal-sprockets-server/README.md +16 -0
  25. data/examples/integrations/dynamic-rack-opal-sprockets-server/app/application.rb +6 -0
  26. data/examples/integrations/dynamic-rack-opal-sprockets-server/config.ru +9 -0
  27. data/examples/integrations/dynamic-roda-roda-sprockets/.gitignore +1 -0
  28. data/examples/integrations/dynamic-roda-roda-sprockets/Gemfile +8 -0
  29. data/examples/integrations/dynamic-roda-roda-sprockets/README.md +22 -0
  30. data/examples/integrations/dynamic-roda-roda-sprockets/Rakefile +4 -0
  31. data/examples/integrations/dynamic-roda-roda-sprockets/app/application.rb +6 -0
  32. data/examples/integrations/dynamic-roda-roda-sprockets/app.rb +32 -0
  33. data/examples/integrations/dynamic-roda-roda-sprockets/config.ru +3 -0
  34. data/examples/integrations/dynamic-roda-tilt/.gitignore +1 -0
  35. data/examples/integrations/dynamic-roda-tilt/Gemfile +9 -0
  36. data/examples/integrations/dynamic-roda-tilt/README.md +17 -0
  37. data/examples/integrations/dynamic-roda-tilt/Rakefile +6 -0
  38. data/examples/integrations/dynamic-roda-tilt/app/application.rb +6 -0
  39. data/examples/integrations/dynamic-roda-tilt/app.rb +50 -0
  40. data/examples/integrations/dynamic-roda-tilt/config.ru +3 -0
  41. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/Gemfile +8 -0
  42. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/README.md +16 -0
  43. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/app/application.rb +6 -0
  44. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/config.ru +29 -0
  45. data/examples/integrations/static-bash/.gitignore +2 -0
  46. data/examples/integrations/static-bash/Gemfile +4 -0
  47. data/examples/integrations/static-bash/README.md +8 -0
  48. data/examples/integrations/static-bash/app/application.rb +6 -0
  49. data/examples/integrations/static-bash/build.sh +4 -0
  50. data/examples/integrations/static-bash/index.html +10 -0
  51. data/examples/integrations/static-bash-opal-parser/.gitignore +3 -0
  52. data/examples/integrations/static-bash-opal-parser/Gemfile +4 -0
  53. data/examples/integrations/static-bash-opal-parser/README.md +10 -0
  54. data/examples/integrations/static-bash-opal-parser/build.sh +4 -0
  55. data/examples/integrations/static-bash-opal-parser/index.html +19 -0
  56. data/examples/integrations/static-rake/.gitignore +1 -0
  57. data/examples/integrations/static-rake/Gemfile +5 -0
  58. data/examples/integrations/static-rake/README.md +7 -0
  59. data/examples/integrations/static-rake/Rakefile +10 -0
  60. data/examples/integrations/static-rake/app/application.rb +6 -0
  61. data/examples/integrations/static-rake/index.html +9 -0
  62. data/examples/integrations/static-rake-guard/.gitignore +1 -0
  63. data/examples/integrations/static-rake-guard/Gemfile +7 -0
  64. data/examples/integrations/static-rake-guard/Guardfile +3 -0
  65. data/examples/integrations/static-rake-guard/README.md +10 -0
  66. data/examples/integrations/static-rake-guard/Rakefile +10 -0
  67. data/examples/integrations/static-rake-guard/app/application.rb +6 -0
  68. data/examples/integrations/static-rake-guard/index.html +9 -0
  69. data/examples/svg/.gitignore +1 -0
  70. data/examples/svg/Gemfile +5 -0
  71. data/examples/svg/README.md +7 -0
  72. data/examples/svg/Rakefile +10 -0
  73. data/examples/svg/app/application.rb +11 -0
  74. data/examples/svg/index.html +17 -0
  75. data/examples/svg/index.svg +6 -0
  76. data/index.html.erb +2 -3
  77. data/opal/browser/audio/node.rb +121 -0
  78. data/opal/browser/audio/param_schedule.rb +43 -0
  79. data/opal/browser/audio.rb +66 -0
  80. data/opal/browser/blob.rb +94 -0
  81. data/opal/browser/canvas/data.rb +1 -1
  82. data/opal/browser/canvas/gradient.rb +1 -1
  83. data/opal/browser/canvas/style.rb +3 -1
  84. data/opal/browser/canvas/text.rb +1 -1
  85. data/opal/browser/canvas.rb +17 -3
  86. data/opal/browser/console.rb +3 -1
  87. data/opal/browser/cookies.rb +16 -7
  88. data/opal/browser/crypto.rb +79 -0
  89. data/opal/browser/css/declaration.rb +1 -1
  90. data/opal/browser/css/rule.rb +1 -1
  91. data/opal/browser/css/style_sheet.rb +2 -2
  92. data/opal/browser/css.rb +23 -7
  93. data/opal/browser/database/sql.rb +7 -8
  94. data/opal/browser/delay.rb +16 -0
  95. data/opal/browser/dom/attribute.rb +1 -1
  96. data/opal/browser/dom/builder.rb +29 -10
  97. data/opal/browser/dom/document.rb +81 -13
  98. data/opal/browser/dom/document_fragment.rb +18 -0
  99. data/opal/browser/dom/document_or_shadow_root.rb +19 -0
  100. data/opal/browser/dom/element/attributes.rb +28 -4
  101. data/opal/browser/dom/element/button.rb +31 -0
  102. data/opal/browser/dom/element/custom.rb +177 -0
  103. data/opal/browser/dom/element/data.rb +17 -2
  104. data/opal/browser/dom/element/editable.rb +47 -0
  105. data/opal/browser/dom/element/form.rb +38 -0
  106. data/opal/browser/dom/element/iframe.rb +37 -0
  107. data/opal/browser/dom/element/image.rb +2 -0
  108. data/opal/browser/dom/element/input.rb +36 -0
  109. data/opal/browser/dom/element/media.rb +17 -0
  110. data/opal/browser/dom/element/scroll.rb +106 -74
  111. data/opal/browser/dom/element/select.rb +6 -0
  112. data/opal/browser/dom/element/size.rb +12 -0
  113. data/opal/browser/dom/element/template.rb +2 -0
  114. data/opal/browser/dom/element/textarea.rb +2 -0
  115. data/opal/browser/dom/element.rb +193 -48
  116. data/opal/browser/dom/mutation_observer.rb +2 -2
  117. data/opal/browser/dom/node.rb +53 -13
  118. data/opal/browser/dom/node_set.rb +11 -2
  119. data/opal/browser/dom/shadow_root.rb +12 -0
  120. data/opal/browser/dom/text.rb +2 -2
  121. data/opal/browser/dom.rb +38 -5
  122. data/opal/browser/effects.rb +170 -4
  123. data/opal/browser/event/all.rb +26 -0
  124. data/opal/browser/event/animation.rb +2 -0
  125. data/opal/browser/event/audio_processing.rb +2 -0
  126. data/opal/browser/event/base.rb +35 -4
  127. data/opal/browser/event/before_unload.rb +2 -0
  128. data/opal/browser/event/clipboard.rb +9 -0
  129. data/opal/browser/event/close.rb +2 -0
  130. data/opal/browser/event/composition.rb +2 -0
  131. data/opal/browser/event/custom.rb +1 -1
  132. data/opal/browser/event/data_transfer.rb +95 -0
  133. data/opal/browser/event/device_light.rb +2 -0
  134. data/opal/browser/event/device_motion.rb +2 -0
  135. data/opal/browser/event/device_orientation.rb +2 -0
  136. data/opal/browser/event/device_proximity.rb +2 -0
  137. data/opal/browser/event/drag.rb +9 -5
  138. data/opal/browser/event/focus.rb +2 -0
  139. data/opal/browser/event/gamepad.rb +3 -1
  140. data/opal/browser/event/hash_change.rb +2 -0
  141. data/opal/browser/event/keyboard.rb +14 -1
  142. data/opal/browser/event/message.rb +2 -0
  143. data/opal/browser/event/mouse.rb +10 -6
  144. data/opal/browser/event/page_transition.rb +2 -0
  145. data/opal/browser/event/pop_state.rb +2 -0
  146. data/opal/browser/event/progress.rb +2 -0
  147. data/opal/browser/event/sensor.rb +2 -0
  148. data/opal/browser/event/storage.rb +2 -0
  149. data/opal/browser/event/touch.rb +2 -0
  150. data/opal/browser/event/wheel.rb +2 -0
  151. data/opal/browser/event.rb +26 -116
  152. data/opal/browser/event_source.rb +1 -1
  153. data/opal/browser/form_data.rb +225 -0
  154. data/opal/browser/history.rb +4 -8
  155. data/opal/browser/http/request.rb +32 -10
  156. data/opal/browser/http/response.rb +5 -1
  157. data/opal/browser/http.rb +0 -2
  158. data/opal/browser/immediate.rb +0 -2
  159. data/opal/browser/location.rb +7 -1
  160. data/opal/browser/navigator.rb +105 -4
  161. data/opal/browser/polyfill/visual_viewport.rb +216 -0
  162. data/opal/browser/screen.rb +2 -2
  163. data/opal/browser/setup/base.rb +6 -0
  164. data/opal/browser/setup/full.rb +13 -0
  165. data/opal/browser/setup/large.rb +17 -0
  166. data/opal/browser/setup/mini.rb +8 -0
  167. data/opal/browser/setup/traditional.rb +10 -0
  168. data/opal/browser/socket.rb +3 -3
  169. data/opal/browser/storage.rb +2 -2
  170. data/opal/browser/support.rb +13 -1
  171. data/opal/browser/utils.rb +94 -14
  172. data/opal/browser/version.rb +1 -1
  173. data/opal/browser/visual_viewport.rb +39 -0
  174. data/opal/browser/window/size.rb +14 -0
  175. data/opal/browser/window/view.rb +15 -0
  176. data/opal/browser/window.rb +29 -16
  177. data/opal/browser.rb +1 -11
  178. data/opal-browser.gemspec +3 -3
  179. data/spec/database/sql_spec.rb +43 -35
  180. data/spec/delay_spec.rb +15 -12
  181. data/spec/dom/document_spec.rb +10 -8
  182. data/spec/dom/element/custom_spec.rb +106 -0
  183. data/spec/dom/element/subclass_spec.rb +144 -0
  184. data/spec/dom/element_spec.rb +42 -0
  185. data/spec/dom/mutation_observer_spec.rb +12 -8
  186. data/spec/dom/node_spec.rb +48 -0
  187. data/spec/dom_spec.rb +8 -0
  188. data/spec/event_source_spec.rb +15 -12
  189. data/spec/{dom/event_spec.rb → event_spec.rb} +44 -15
  190. data/spec/history_spec.rb +23 -19
  191. data/spec/http_spec.rb +19 -31
  192. data/spec/immediate_spec.rb +5 -4
  193. data/spec/interval_spec.rb +18 -9
  194. data/spec/native_cached_wrapper_spec.rb +46 -0
  195. data/spec/runner.rb +37 -62
  196. data/spec/socket_spec.rb +15 -12
  197. data/spec/spec_helper.rb +2 -1
  198. data/spec/spec_helper_promise.rb.erb +25 -0
  199. metadata +119 -16
  200. data/.travis.yml +0 -74
  201. data/opal/browser/window/scroll.rb +0 -59
@@ -32,9 +32,17 @@ class Attributes
32
32
  end
33
33
 
34
34
  if namespace = options[:namespace] || @namespace
35
- `#@native.setAttributeNS(#{namespace.to_s}, #{name.to_s}, #{value})`
35
+ if value
36
+ `#@native.setAttributeNS(#{namespace.to_s}, #{name.to_s}, #{value})`
37
+ else
38
+ `#@native.removeAttributeNS(#{namespace.to_s}, #{name.to_s})`
39
+ end
36
40
  else
37
- `#@native.setAttribute(#{name.to_s}, #{value.to_s})`
41
+ if value
42
+ `#@native.setAttribute(#{name.to_s}, #{value.to_s})`
43
+ else
44
+ `#@native.removeAttribute(#{name.to_s})`
45
+ end
38
46
  end
39
47
  end
40
48
  else
@@ -48,13 +56,29 @@ class Attributes
48
56
 
49
57
  def []=(name, value, options = {})
50
58
  if namespace = options[:namespace] || @namespace
51
- `#@native.setAttributeNS(#{namespace.to_s}, #{name.to_s}, #{value})`
59
+ if value
60
+ `#@native.setAttributeNS(#{namespace.to_s}, #{name.to_s}, #{value})`
61
+ else
62
+ `#@native.removeAttributeNS(#{namespace.to_s}, #{name.to_s})`
63
+ end
52
64
  else
53
- `#@native.setAttribute(#{name.to_s}, #{value.to_s})`
65
+ if value
66
+ `#@native.setAttribute(#{name.to_s}, #{value.to_s})`
67
+ else
68
+ `#@native.removeAttribute(#{name.to_s})`
69
+ end
54
70
  end
55
71
  end
56
72
  end
57
73
 
74
+ # Deletes an attribute with a given name
75
+ # @return [String] an attribute value before deletion
76
+ def delete(name)
77
+ attr = self[name]
78
+ self[name] = nil
79
+ attr
80
+ end
81
+
58
82
  include Enumerable
59
83
 
60
84
  def each(&block)
@@ -0,0 +1,31 @@
1
+ module Browser; module DOM; class Element < Node
2
+
3
+ class Button < Element
4
+ def_selector "button"
5
+
6
+ def disabled?
7
+ `#@native.disabled`
8
+ end
9
+
10
+ def disabled=(value)
11
+ `#@native.disabled = #{value}`
12
+ end
13
+
14
+ def autofocus?
15
+ `#@native.autofocus`
16
+ end
17
+
18
+ def autofocus=(value)
19
+ `#@native.autofocus = #{value}`
20
+ end
21
+
22
+ def name_
23
+ `#@native.name`
24
+ end
25
+
26
+ def name_=(value)
27
+ `#@native.name = #{value}`
28
+ end
29
+ end
30
+
31
+ end; end; end
@@ -0,0 +1,177 @@
1
+ # use_strict: true
2
+ # helpers: truthy
3
+
4
+ module Browser; module DOM; class Element < Node
5
+
6
+ # CustomElements implementation for opal-browser. See examples/custom_elements/.
7
+ #
8
+ # @see https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements
9
+ # @abstract This class should not be used directly. Please extend it and implement needed methods.
10
+ class Custom < Element
11
+ # The reason why we wrap class definition with an eval is kind of selfish. I want it to work
12
+ # with opal-optimizer which doesn't support the new class syntax. I would do it with prototypes,
13
+ # but the prototypes system is so messy I gave up.
14
+ #
15
+ # Therefore, for it to be cleaned up, one of those two must happen:
16
+ # - we raise the supported ES version in Opal and we implement those ES syntax features in
17
+ # rkelly-turbo. And then we remove the polyfill.
18
+ # - we reimplement it in terms of prototypes.
19
+ %x{
20
+ var make_custom_class = Function('self,base_class',
21
+ '"use strict"; \
22
+ var klass = class extends base_class { \
23
+ constructor() { \
24
+ super(); \
25
+ self.$_dispatch_constructor(this); \
26
+ } \
27
+ connectedCallback() { \
28
+ return this.$$opal_native_cached.$attached(); \
29
+ } \
30
+ disconnectedCallback() { \
31
+ return this.$$opal_native_cached.$detached(); \
32
+ } \
33
+ adoptedCallback() { \
34
+ return this.$$opal_native_cached.$adopted(); \
35
+ } \
36
+ attributeChangedCallback(attr, from, to) { \
37
+ if (from === null) from = Opal.nil; \
38
+ if (to === null) to = Opal.nil; \
39
+ return this.$$opal_native_cached.$attribute_changed(attr, from, to); \
40
+ } \
41
+ \
42
+ static get observedAttributes() { \
43
+ return self.$observed_attributes(); \
44
+ } \
45
+ }; \
46
+ klass.$$opal_class = self; \
47
+ return klass;'
48
+ );
49
+ } if Browser.supports? 'Custom Elements' #'
50
+
51
+ module ClassMethods
52
+ if Browser.supports? 'Custom Elements'
53
+ # Defines a new custom element. This should come as the last call
54
+ # in the class definition, because at this point the methods may
55
+ # be called!
56
+ #
57
+ # @opalopt uses:_dispatch_constructor,attached,detached,adopted,attribute_changed,observed_attributes
58
+ def def_custom(tag_name, base_class: nil, extends: nil)
59
+ if `base_class !== nil`
60
+ elsif self.superclass == Custom
61
+ base_class = `HTMLElement`
62
+ elsif self.ancestors.include? Custom
63
+ base_class = `#{self.superclass}.custom_class`
64
+ else
65
+ raise ArgumentError, "You must define base_class"
66
+ end
67
+
68
+ @custom_class = `make_custom_class(self, #{base_class})`
69
+ @observed_attributes ||= []
70
+
71
+ def_selector tag_name
72
+
73
+ %x{
74
+ if ($truthy(#{extends})) customElements.define(#{tag_name}, #{@custom_class}, {extends: #{extends}});
75
+ else customElements.define(#{tag_name}, #{@custom_class});
76
+ }
77
+ end
78
+ elsif Browser.supports? 'MutationObserver'
79
+ # Can we polyfill it?
80
+ Browser::DOM::MutationObserver.new do |obs|
81
+ obs.each do |e|
82
+ target = e.target
83
+
84
+ case e.type
85
+ when :attribute
86
+ if Custom::Mixin === target && target.class.observed_attributes.include?(e.name)
87
+ target.attribute_changed(e.name, e.old, target[e.name])
88
+ end
89
+ when :tree
90
+ e.added.each { |n| n.attached_once if Custom::Mixin === n }
91
+ e.removed.each { |n| n.detached_once if Custom::Mixin === n }
92
+ end
93
+ end
94
+ end.observe($document, tree: true, children: true, attributes: :old)
95
+ end
96
+
97
+ unless Browser.supports? 'Custom Elements'
98
+ # The polyfilled implementation. Define the selector and then
99
+ # try to upgrade the elements that are already in the document.
100
+ def def_custom(tag_name, base_class: nil, extends: nil)
101
+ def_selector tag_name
102
+
103
+ $document.body.css(tag_name).each do |elem|
104
+ _dispatch_constructor(elem.to_n)&.attached_once
105
+ end
106
+ end
107
+ end
108
+
109
+ private def _dispatch_constructor(obj)
110
+ %x{
111
+ if (typeof obj.$$opal_native_cached !== 'undefined') {
112
+ delete obj.$$opal_native_cached;
113
+ return self.$new(obj);
114
+ }
115
+ else {
116
+ self.$new(obj);
117
+ return nil;
118
+ }
119
+ }
120
+ end
121
+
122
+ # This must be defined before def_custom is called!
123
+ attr_accessor :observed_attributes
124
+
125
+ attr_reader :custom_class
126
+ end
127
+
128
+ module Mixin
129
+ def self.included(klass)
130
+ klass.extend ClassMethods
131
+ end
132
+
133
+ # @abstract
134
+ def attached
135
+ end
136
+
137
+ # @abstract
138
+ def detached
139
+ end
140
+
141
+ # @abstract
142
+ def adopted
143
+ end
144
+
145
+ # Note: for this method to fire, you will need to define
146
+ # the observed attributes.
147
+ #
148
+ # @abstract
149
+ def attribute_changed(attr, from, to)
150
+ end
151
+
152
+ # Return true if the node is a custom element.
153
+ def custom?
154
+ true
155
+ end
156
+
157
+ # Those methods keep track of the attachment status of the elements,
158
+ # so that #attached/#detached isn't called twice.
159
+ unless Browser.supports? 'Custom Elements'
160
+ # @private
161
+ def attached_once
162
+ attached unless @_polyfill_attached
163
+ @_polyfill_attached = true
164
+ end
165
+
166
+ # @private
167
+ def detached_once
168
+ detached if @_polyfill_attached
169
+ @_polyfill_attached = false
170
+ end
171
+ end
172
+ end
173
+
174
+ include Mixin
175
+ end
176
+
177
+ end; end; end
@@ -36,7 +36,7 @@ class Data
36
36
 
37
37
  def assign(data)
38
38
  data.each {|name, value|
39
- `#@native.$data[name] = value`
39
+ self[name] = value
40
40
  }
41
41
 
42
42
  self
@@ -60,7 +60,22 @@ class Data
60
60
  end
61
61
 
62
62
  def []=(name, value)
63
- `#@native.$data[name] = value`
63
+ `delete #@native.$data[name]`
64
+ if [true, false, nil].include?(value)
65
+ @element["data-#{name}"] = value
66
+ elsif value.respond_to? :to_str
67
+ @element["data-#{name}"] = value.to_str
68
+ elsif value.respond_to? :to_int
69
+ @element["data-#{name}"] = value.to_int.to_s
70
+ else
71
+ `#@native.$data[name] = value`
72
+ end
73
+ end
74
+
75
+ def delete(name)
76
+ data = self[name]
77
+ self[name] = nil
78
+ data
64
79
  end
65
80
  end
66
81
 
@@ -0,0 +1,47 @@
1
+ module Browser; module DOM
2
+
3
+ class Element < Node
4
+ # @!attribute editable
5
+ # @return [Boolean?] the value of contentEditable for this element
6
+ def editable
7
+ case `#@native.contentEditable`
8
+ when "true"
9
+ true
10
+ when "false"
11
+ false
12
+ when "inherit"
13
+ nil
14
+ end
15
+ end
16
+
17
+ def editable=(value)
18
+ value = case value
19
+ when true
20
+ "true"
21
+ when false
22
+ "false"
23
+ when nil
24
+ "inherit"
25
+ end
26
+ `#@native.contentEditable = #{value}`
27
+ end
28
+
29
+ def editable?
30
+ `#@native.isContentEditable`
31
+ end
32
+
33
+ # Execute a contentEditable command
34
+ def edit(command, value=nil)
35
+ command = command.gsub(/_./) { |i| i[1].upcase }
36
+
37
+ focus
38
+
39
+ if value
40
+ `#{document}.native.execCommand(#{command}, false, #{value})`
41
+ else
42
+ `#{document}.native.execCommand(#{command}, false)`
43
+ end
44
+ end
45
+ end
46
+
47
+ end; end
@@ -0,0 +1,38 @@
1
+ module Browser; module DOM; class Element < Node
2
+
3
+ class Form < Element
4
+ def_selector "form"
5
+
6
+ # Capture the content of this form to a new {FormData} object,
7
+ #
8
+ # @return [FormData]
9
+ def form_data
10
+ FormData.create(self)
11
+ end
12
+
13
+ # Submit a form. This will fire a submit event.
14
+ def submit
15
+ `#@native.submit()`
16
+ end
17
+
18
+ # Reset a form. This will fire a reset event.
19
+ def reset
20
+ `#@native.reset()`
21
+ end
22
+
23
+ alias_native :action
24
+ alias_native :action=
25
+ alias_native :method
26
+ alias_native :method=
27
+ alias_native :target
28
+ alias_native :target=
29
+ alias_native :encoding
30
+ alias_native :encoding=
31
+
32
+ # Return a NodeSet containing all form controls belonging to this form element.
33
+ def controls
34
+ NodeSet[Native::Array.new(`#@native.elements`)]
35
+ end
36
+ end
37
+
38
+ end; end; end
@@ -0,0 +1,37 @@
1
+ module Browser; module DOM; class Element < Node
2
+
3
+ class Iframe < Element
4
+ def_selector "iframe"
5
+
6
+ # @!attribute src
7
+ # @return [String] the URL of the page to embed
8
+ alias_native :src
9
+ alias_native :src=
10
+
11
+ # @!attribute [r] content_window
12
+ # @return [Window] window of content of this iframe
13
+ def content_window
14
+ Browser::Window.new(`#@native.contentWindow`)
15
+ end
16
+
17
+ # @!attribute [r] content_document
18
+ # @return [Document] document of content of this iframe
19
+ def content_document
20
+ DOM(`#@native.contentDocument || #@native.contentWindow.document`)
21
+ end
22
+
23
+ # Send a message to the iframe content's window.
24
+ #
25
+ # @param message [String] the message
26
+ # @param options [Hash] optional `to: target`
27
+ def send(message, options={})
28
+ content_window.send(message, options)
29
+ end
30
+ end
31
+
32
+ # Object is not an iframe, but acts the same.
33
+ class Object < Iframe
34
+ def_selector "object"
35
+ end
36
+
37
+ end; end; end
@@ -1,6 +1,8 @@
1
1
  module Browser; module DOM; class Element < Node
2
2
 
3
3
  class Image < Element
4
+ def_selector "img"
5
+
4
6
  def complete?
5
7
  `#@native.complete`
6
8
  end
@@ -1,6 +1,8 @@
1
1
  module Browser; module DOM; class Element < Node
2
2
 
3
3
  class Input < Element
4
+ def_selector "input"
5
+
4
6
  def value
5
7
  %x{
6
8
  if (#@native.value == "") {
@@ -16,13 +18,47 @@ class Input < Element
16
18
  `#@native.value = #{value}`
17
19
  end
18
20
 
21
+ def name_
22
+ `#@native.name`
23
+ end
24
+
25
+ def type
26
+ `#@native.type`
27
+ end
28
+
19
29
  def checked?
20
30
  `#@native.checked`
21
31
  end
22
32
 
33
+ def check!
34
+ `#@native.checked = 'checked'`
35
+ end
36
+
37
+ def uncheck!
38
+ `#@native.checked = ''`
39
+ end
40
+
41
+ def enabled?
42
+ `#@native.enabled`
43
+ end
44
+
45
+ def disable!
46
+ `#@native.disabled = 'disabled'`
47
+ end
48
+
49
+ def enable!
50
+ `#@native.disabled = ''`
51
+ end
52
+
23
53
  def clear
24
54
  `#@native.value = ''`
25
55
  end
56
+
57
+ # @!attribute [r] files
58
+ # @return [Array<File>] list of files attached to this {Input}
59
+ def files
60
+ Native::Array.new(`#@native.files`).map { |f| File.new(f.to_n) }
61
+ end
26
62
  end
27
63
 
28
64
  end; end; end
@@ -0,0 +1,17 @@
1
+ module Browser; module DOM; class Element < Node
2
+
3
+ class Media < Element
4
+ def play
5
+ `#@native.play()`
6
+ end
7
+ end
8
+
9
+ class Video < Media
10
+ def_selector "video"
11
+ end
12
+
13
+ class Audio < Media
14
+ def_selector "audio"
15
+ end
16
+
17
+ end; end; end