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.
- checksums.yaml +5 -5
- data/.github/workflows/build.yml +95 -0
- data/.gitignore +2 -0
- data/Gemfile +17 -3
- data/LICENSE +2 -1
- data/README.md +116 -54
- data/Rakefile +29 -1
- data/config.ru +20 -3
- data/docs/polyfills.md +24 -0
- data/examples/2048/Gemfile +7 -0
- data/examples/2048/README.md +13 -0
- data/examples/2048/app/application.rb +169 -0
- data/examples/2048/config.ru +9 -0
- data/examples/canvas/Gemfile +7 -0
- data/examples/canvas/README.md +9 -0
- data/examples/canvas/app/application.rb +55 -0
- data/examples/canvas/config.ru +9 -0
- data/examples/component/Gemfile +7 -0
- data/examples/component/README.md +10 -0
- data/examples/component/app/application.rb +66 -0
- data/examples/component/config.ru +9 -0
- data/examples/integrations/README.md +24 -0
- data/examples/integrations/dynamic-rack-opal-sprockets-server/Gemfile +7 -0
- data/examples/integrations/dynamic-rack-opal-sprockets-server/README.md +16 -0
- data/examples/integrations/dynamic-rack-opal-sprockets-server/app/application.rb +6 -0
- data/examples/integrations/dynamic-rack-opal-sprockets-server/config.ru +9 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/.gitignore +1 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/Gemfile +8 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/README.md +22 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/Rakefile +4 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/app/application.rb +6 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/app.rb +32 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/config.ru +3 -0
- data/examples/integrations/dynamic-roda-tilt/.gitignore +1 -0
- data/examples/integrations/dynamic-roda-tilt/Gemfile +9 -0
- data/examples/integrations/dynamic-roda-tilt/README.md +17 -0
- data/examples/integrations/dynamic-roda-tilt/Rakefile +6 -0
- data/examples/integrations/dynamic-roda-tilt/app/application.rb +6 -0
- data/examples/integrations/dynamic-roda-tilt/app.rb +50 -0
- data/examples/integrations/dynamic-roda-tilt/config.ru +3 -0
- data/examples/integrations/dynamic-sinatra-opal-sprockets-server/Gemfile +8 -0
- data/examples/integrations/dynamic-sinatra-opal-sprockets-server/README.md +16 -0
- data/examples/integrations/dynamic-sinatra-opal-sprockets-server/app/application.rb +6 -0
- data/examples/integrations/dynamic-sinatra-opal-sprockets-server/config.ru +29 -0
- data/examples/integrations/static-bash/.gitignore +2 -0
- data/examples/integrations/static-bash/Gemfile +4 -0
- data/examples/integrations/static-bash/README.md +8 -0
- data/examples/integrations/static-bash/app/application.rb +6 -0
- data/examples/integrations/static-bash/build.sh +4 -0
- data/examples/integrations/static-bash/index.html +10 -0
- data/examples/integrations/static-bash-opal-parser/.gitignore +3 -0
- data/examples/integrations/static-bash-opal-parser/Gemfile +4 -0
- data/examples/integrations/static-bash-opal-parser/README.md +10 -0
- data/examples/integrations/static-bash-opal-parser/build.sh +4 -0
- data/examples/integrations/static-bash-opal-parser/index.html +19 -0
- data/examples/integrations/static-rake/.gitignore +1 -0
- data/examples/integrations/static-rake/Gemfile +5 -0
- data/examples/integrations/static-rake/README.md +7 -0
- data/examples/integrations/static-rake/Rakefile +10 -0
- data/examples/integrations/static-rake/app/application.rb +6 -0
- data/examples/integrations/static-rake/index.html +9 -0
- data/examples/integrations/static-rake-guard/.gitignore +1 -0
- data/examples/integrations/static-rake-guard/Gemfile +7 -0
- data/examples/integrations/static-rake-guard/Guardfile +3 -0
- data/examples/integrations/static-rake-guard/README.md +10 -0
- data/examples/integrations/static-rake-guard/Rakefile +10 -0
- data/examples/integrations/static-rake-guard/app/application.rb +6 -0
- data/examples/integrations/static-rake-guard/index.html +9 -0
- data/examples/svg/.gitignore +1 -0
- data/examples/svg/Gemfile +5 -0
- data/examples/svg/README.md +7 -0
- data/examples/svg/Rakefile +10 -0
- data/examples/svg/app/application.rb +11 -0
- data/examples/svg/index.html +17 -0
- data/examples/svg/index.svg +6 -0
- data/index.html.erb +2 -3
- data/opal/browser/audio/node.rb +121 -0
- data/opal/browser/audio/param_schedule.rb +43 -0
- data/opal/browser/audio.rb +66 -0
- data/opal/browser/blob.rb +94 -0
- data/opal/browser/canvas/data.rb +1 -1
- data/opal/browser/canvas/gradient.rb +1 -1
- data/opal/browser/canvas/style.rb +3 -1
- data/opal/browser/canvas/text.rb +1 -1
- data/opal/browser/canvas.rb +17 -3
- data/opal/browser/console.rb +3 -1
- data/opal/browser/cookies.rb +16 -7
- data/opal/browser/crypto.rb +79 -0
- data/opal/browser/css/declaration.rb +1 -1
- data/opal/browser/css/rule.rb +1 -1
- data/opal/browser/css/style_sheet.rb +2 -2
- data/opal/browser/css.rb +23 -7
- data/opal/browser/database/sql.rb +7 -8
- data/opal/browser/delay.rb +16 -0
- data/opal/browser/dom/attribute.rb +1 -1
- data/opal/browser/dom/builder.rb +29 -10
- data/opal/browser/dom/document.rb +81 -13
- data/opal/browser/dom/document_fragment.rb +18 -0
- data/opal/browser/dom/document_or_shadow_root.rb +19 -0
- data/opal/browser/dom/element/attributes.rb +28 -4
- data/opal/browser/dom/element/button.rb +31 -0
- data/opal/browser/dom/element/custom.rb +177 -0
- data/opal/browser/dom/element/data.rb +17 -2
- data/opal/browser/dom/element/editable.rb +47 -0
- data/opal/browser/dom/element/form.rb +38 -0
- data/opal/browser/dom/element/iframe.rb +37 -0
- data/opal/browser/dom/element/image.rb +2 -0
- data/opal/browser/dom/element/input.rb +36 -0
- data/opal/browser/dom/element/media.rb +17 -0
- data/opal/browser/dom/element/scroll.rb +106 -74
- data/opal/browser/dom/element/select.rb +6 -0
- data/opal/browser/dom/element/size.rb +12 -0
- data/opal/browser/dom/element/template.rb +2 -0
- data/opal/browser/dom/element/textarea.rb +2 -0
- data/opal/browser/dom/element.rb +193 -48
- data/opal/browser/dom/mutation_observer.rb +2 -2
- data/opal/browser/dom/node.rb +53 -13
- data/opal/browser/dom/node_set.rb +11 -2
- data/opal/browser/dom/shadow_root.rb +12 -0
- data/opal/browser/dom/text.rb +2 -2
- data/opal/browser/dom.rb +38 -5
- data/opal/browser/effects.rb +170 -4
- data/opal/browser/event/all.rb +26 -0
- data/opal/browser/event/animation.rb +2 -0
- data/opal/browser/event/audio_processing.rb +2 -0
- data/opal/browser/event/base.rb +35 -4
- data/opal/browser/event/before_unload.rb +2 -0
- data/opal/browser/event/clipboard.rb +9 -0
- data/opal/browser/event/close.rb +2 -0
- data/opal/browser/event/composition.rb +2 -0
- data/opal/browser/event/custom.rb +1 -1
- data/opal/browser/event/data_transfer.rb +95 -0
- data/opal/browser/event/device_light.rb +2 -0
- data/opal/browser/event/device_motion.rb +2 -0
- data/opal/browser/event/device_orientation.rb +2 -0
- data/opal/browser/event/device_proximity.rb +2 -0
- data/opal/browser/event/drag.rb +9 -5
- data/opal/browser/event/focus.rb +2 -0
- data/opal/browser/event/gamepad.rb +3 -1
- data/opal/browser/event/hash_change.rb +2 -0
- data/opal/browser/event/keyboard.rb +14 -1
- data/opal/browser/event/message.rb +2 -0
- data/opal/browser/event/mouse.rb +10 -6
- data/opal/browser/event/page_transition.rb +2 -0
- data/opal/browser/event/pop_state.rb +2 -0
- data/opal/browser/event/progress.rb +2 -0
- data/opal/browser/event/sensor.rb +2 -0
- data/opal/browser/event/storage.rb +2 -0
- data/opal/browser/event/touch.rb +2 -0
- data/opal/browser/event/wheel.rb +2 -0
- data/opal/browser/event.rb +26 -116
- data/opal/browser/event_source.rb +1 -1
- data/opal/browser/form_data.rb +225 -0
- data/opal/browser/history.rb +4 -8
- data/opal/browser/http/request.rb +32 -10
- data/opal/browser/http/response.rb +5 -1
- data/opal/browser/http.rb +0 -2
- data/opal/browser/immediate.rb +0 -2
- data/opal/browser/location.rb +7 -1
- data/opal/browser/navigator.rb +105 -4
- data/opal/browser/polyfill/visual_viewport.rb +216 -0
- data/opal/browser/screen.rb +2 -2
- data/opal/browser/setup/base.rb +6 -0
- data/opal/browser/setup/full.rb +13 -0
- data/opal/browser/setup/large.rb +17 -0
- data/opal/browser/setup/mini.rb +8 -0
- data/opal/browser/setup/traditional.rb +10 -0
- data/opal/browser/socket.rb +3 -3
- data/opal/browser/storage.rb +2 -2
- data/opal/browser/support.rb +13 -1
- data/opal/browser/utils.rb +94 -14
- data/opal/browser/version.rb +1 -1
- data/opal/browser/visual_viewport.rb +39 -0
- data/opal/browser/window/size.rb +14 -0
- data/opal/browser/window/view.rb +15 -0
- data/opal/browser/window.rb +29 -16
- data/opal/browser.rb +1 -11
- data/opal-browser.gemspec +3 -3
- data/spec/database/sql_spec.rb +43 -35
- data/spec/delay_spec.rb +15 -12
- data/spec/dom/document_spec.rb +10 -8
- data/spec/dom/element/custom_spec.rb +106 -0
- data/spec/dom/element/subclass_spec.rb +144 -0
- data/spec/dom/element_spec.rb +42 -0
- data/spec/dom/mutation_observer_spec.rb +12 -8
- data/spec/dom/node_spec.rb +48 -0
- data/spec/dom_spec.rb +8 -0
- data/spec/event_source_spec.rb +15 -12
- data/spec/{dom/event_spec.rb → event_spec.rb} +44 -15
- data/spec/history_spec.rb +23 -19
- data/spec/http_spec.rb +19 -31
- data/spec/immediate_spec.rb +5 -4
- data/spec/interval_spec.rb +18 -9
- data/spec/native_cached_wrapper_spec.rb +46 -0
- data/spec/runner.rb +37 -62
- data/spec/socket_spec.rb +15 -12
- data/spec/spec_helper.rb +2 -1
- data/spec/spec_helper_promise.rb.erb +25 -0
- metadata +119 -16
- data/.travis.yml +0 -74
- data/opal/browser/window/scroll.rb +0 -59
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module Browser; module DOM; class Element < Node
|
|
2
2
|
|
|
3
|
+
# @todo Consider using the new interfaces which allow for optional
|
|
4
|
+
# smooth transitions.
|
|
3
5
|
class Scroll
|
|
4
6
|
attr_reader :element
|
|
5
7
|
|
|
@@ -7,57 +9,114 @@ class Scroll
|
|
|
7
9
|
def initialize(element)
|
|
8
10
|
@element = element
|
|
9
11
|
@native = element.to_n
|
|
10
|
-
end
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
# Portable support for Window#scroll and Document#scroll
|
|
14
|
+
@scrolling_native = @native
|
|
15
|
+
if [Document, Window].include?(@element.class)
|
|
16
|
+
# If we are a window, let's become a document first.
|
|
17
|
+
if defined? `#@scrolling_native.document`
|
|
18
|
+
@scrolling_native = `#@scrolling_native.document`
|
|
19
|
+
end
|
|
20
|
+
# There were slight disagreements in the past which element
|
|
21
|
+
# should we handle.
|
|
22
|
+
if defined? `#@scrolling_native.documentElement.scrollTop`
|
|
23
|
+
@scrolling_native = `#@scrolling_native.documentElement`
|
|
24
|
+
elsif defined? `#@scrolling_native.body.scrollTop`
|
|
25
|
+
@scrolling_native = `#@scrolling_native.body`
|
|
19
26
|
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
20
29
|
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
# @overload to(x, y)
|
|
31
|
+
#
|
|
32
|
+
# Scroll to the given x and y.
|
|
33
|
+
#
|
|
34
|
+
# @param x [Integer] scroll to x on the x axis
|
|
35
|
+
# @param y [Integer] scroll to y on the y axis
|
|
36
|
+
#
|
|
37
|
+
# @overload to(hash)
|
|
38
|
+
#
|
|
39
|
+
# Scroll to the given x and y.
|
|
40
|
+
#
|
|
41
|
+
# @param hash [Hash] the descriptor
|
|
42
|
+
#
|
|
43
|
+
# @option hash [Integer] :x scroll to x on the x axis
|
|
44
|
+
# @option hash [Integer] :y scroll to y on the y axis
|
|
45
|
+
#
|
|
46
|
+
# @overload to(symbol)
|
|
47
|
+
#
|
|
48
|
+
# Scroll to :top or to :bottom
|
|
49
|
+
#
|
|
50
|
+
# @param symbol [Symbol] either :top or :bottom
|
|
51
|
+
def to(*args)
|
|
52
|
+
x, y = nil, nil
|
|
53
|
+
case args.first
|
|
54
|
+
when Hash
|
|
55
|
+
x = args.first[:x]
|
|
56
|
+
y = args.first[:y]
|
|
57
|
+
when :top
|
|
58
|
+
y = 0
|
|
59
|
+
when :bottom
|
|
60
|
+
y = 99999999
|
|
61
|
+
else
|
|
62
|
+
x, y = args
|
|
23
63
|
end
|
|
24
64
|
|
|
25
|
-
|
|
26
|
-
|
|
65
|
+
set(x, y) if x || y
|
|
66
|
+
|
|
67
|
+
self
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @overload by(x, y)
|
|
71
|
+
#
|
|
72
|
+
# Scroll by the given x and y.
|
|
73
|
+
#
|
|
74
|
+
# @param x [Integer] scroll by x on the x axis
|
|
75
|
+
# @param y [Integer] scroll by y on the y axis
|
|
76
|
+
#
|
|
77
|
+
# @overload by(hash)
|
|
78
|
+
#
|
|
79
|
+
# Scroll by the given x and y.
|
|
80
|
+
#
|
|
81
|
+
# @param hash [Hash] the descriptor
|
|
82
|
+
#
|
|
83
|
+
# @option hash [Integer] :x scroll by x on the x axis
|
|
84
|
+
# @option hash [Integer] :y scroll by y on the y axis
|
|
85
|
+
def by(*args)
|
|
86
|
+
case args.first
|
|
87
|
+
when Hash
|
|
88
|
+
x = args.first[:x] || 0
|
|
89
|
+
y = args.first[:y] || 0
|
|
90
|
+
else
|
|
91
|
+
x, y = args
|
|
27
92
|
end
|
|
28
|
-
elsif Browser.supports? 'Element.pageOffset'
|
|
29
|
-
def to(*args)
|
|
30
|
-
if Hash === args.first
|
|
31
|
-
x = args.first[:x] || self.x
|
|
32
|
-
y = args.first[:y] || self.y
|
|
33
|
-
else
|
|
34
|
-
x, y = args
|
|
35
|
-
end
|
|
36
93
|
|
|
37
|
-
|
|
38
|
-
|
|
94
|
+
set_by(x, y)
|
|
95
|
+
|
|
96
|
+
self
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
if Browser.supports? 'Element.scrollBy'
|
|
100
|
+
private def set_by(x, y)
|
|
101
|
+
`#@scrolling_native.scrollBy(#{x}, #{y})`
|
|
102
|
+
end
|
|
103
|
+
else
|
|
104
|
+
private def set_by(x, y)
|
|
105
|
+
set(self.x + x, self.y + y)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
if Browser.supports? 'Element.scroll'
|
|
110
|
+
private def set(x=nil, y=nil)
|
|
111
|
+
`#@scrolling_native.scrollTop = #{y}` if y
|
|
112
|
+
`#@scrolling_native.scrollLeft = #{x}` if x
|
|
39
113
|
end
|
|
40
114
|
|
|
41
115
|
def position
|
|
42
|
-
Position.new(`#@
|
|
116
|
+
Browser::Position.new(`#@scrolling_native.scrollLeft`, `#@scrolling_native.scrollTop`)
|
|
43
117
|
end
|
|
44
118
|
else
|
|
45
|
-
|
|
46
|
-
#
|
|
47
|
-
# Scroll to the given x and y.
|
|
48
|
-
#
|
|
49
|
-
# @param x [Integer] scroll to x on the x axis
|
|
50
|
-
# @param y [Integer] scroll to y on the y axis
|
|
51
|
-
#
|
|
52
|
-
# @overload to(hash)
|
|
53
|
-
#
|
|
54
|
-
# Scroll to the given x and y.
|
|
55
|
-
#
|
|
56
|
-
# @param hash [Hash] the descriptor
|
|
57
|
-
#
|
|
58
|
-
# @option hash [Integer] :x scroll to x on the x axis
|
|
59
|
-
# @option hash [Integer] :y scroll to y on the y axis
|
|
60
|
-
def to(*args)
|
|
119
|
+
private def set(x=nil, y=nil)
|
|
61
120
|
raise NotImplementedError, 'scroll on element unsupported'
|
|
62
121
|
end
|
|
63
122
|
|
|
@@ -81,55 +140,28 @@ class Scroll
|
|
|
81
140
|
# @!attribute [r] height
|
|
82
141
|
# @return [Integer] the height of the scroll
|
|
83
142
|
def height
|
|
84
|
-
`#@
|
|
143
|
+
`#@scrolling_native.scrollHeight`
|
|
85
144
|
end
|
|
86
145
|
|
|
87
146
|
# @!attribute [r] width
|
|
88
147
|
# @return [Integer] the width of the scroll
|
|
89
148
|
def width
|
|
90
|
-
`#@
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
# @overload by(x, y)
|
|
94
|
-
#
|
|
95
|
-
# Scroll by the given x and y.
|
|
96
|
-
#
|
|
97
|
-
# @param x [Integer] scroll by x on the x axis
|
|
98
|
-
# @param y [Integer] scroll by y on the y axis
|
|
99
|
-
#
|
|
100
|
-
# @overload by(hash)
|
|
101
|
-
#
|
|
102
|
-
# Scroll by the given x and y.
|
|
103
|
-
#
|
|
104
|
-
# @param hash [Hash] the descriptor
|
|
105
|
-
#
|
|
106
|
-
# @option hash [Integer] :x scroll by x on the x axis
|
|
107
|
-
# @option hash [Integer] :y scroll by y on the y axis
|
|
108
|
-
def by(*args)
|
|
109
|
-
if Hash === args.first
|
|
110
|
-
x = args.first[:x] || 0
|
|
111
|
-
y = args.first[:y] || 0
|
|
112
|
-
else
|
|
113
|
-
x, y = args
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
`#@native.scrollBy(#{x}, #{y})`
|
|
117
|
-
|
|
118
|
-
self
|
|
149
|
+
`#@scrolling_native.scrollWidth`
|
|
119
150
|
end
|
|
120
151
|
|
|
121
152
|
if Browser.supports? 'Element.scrollIntoViewIfNeeded'
|
|
122
|
-
def
|
|
123
|
-
`#@
|
|
153
|
+
def into_view(align = true)
|
|
154
|
+
`#@scrolling_native.scrollIntoViewIfNeeded(align)`
|
|
124
155
|
end
|
|
125
156
|
else
|
|
126
|
-
|
|
157
|
+
# Non-standard. Not supported by modern Firefox. Use {#into_view!}
|
|
158
|
+
def into_view(align = true)
|
|
127
159
|
raise NotImplementedError
|
|
128
160
|
end
|
|
129
161
|
end
|
|
130
162
|
|
|
131
|
-
def
|
|
132
|
-
`#@
|
|
163
|
+
def into_view!(align = true)
|
|
164
|
+
`#@scrolling_native.scrollIntoView(align)`
|
|
133
165
|
end
|
|
134
166
|
end
|
|
135
167
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module Browser; module DOM; class Element < Node
|
|
2
2
|
|
|
3
3
|
class Select < Element
|
|
4
|
+
def_selector "select"
|
|
5
|
+
|
|
4
6
|
def value
|
|
5
7
|
%x{
|
|
6
8
|
if (#@native.value == "") {
|
|
@@ -12,6 +14,10 @@ class Select < Element
|
|
|
12
14
|
}
|
|
13
15
|
end
|
|
14
16
|
|
|
17
|
+
def value= value
|
|
18
|
+
`#@native.value = #{value.to_n}`
|
|
19
|
+
end
|
|
20
|
+
|
|
15
21
|
def labels
|
|
16
22
|
NodeSet[Native::Array.new(`#@native.labels`)]
|
|
17
23
|
end
|
|
@@ -29,6 +29,18 @@ class Size
|
|
|
29
29
|
def height=(value)
|
|
30
30
|
@element.style[:height] = value
|
|
31
31
|
end
|
|
32
|
+
|
|
33
|
+
# @!attribute client_width
|
|
34
|
+
# @return [Integer] the content-box width of an element
|
|
35
|
+
def client_width
|
|
36
|
+
`#@native.clientWidth`
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @!attribute client_height
|
|
40
|
+
# @return [Integer] the content-box height of an element
|
|
41
|
+
def client_height
|
|
42
|
+
`#@native.clientHeight`
|
|
43
|
+
end
|
|
32
44
|
end
|
|
33
45
|
|
|
34
46
|
end; end; end
|
data/opal/browser/dom/element.rb
CHANGED
|
@@ -1,76 +1,152 @@
|
|
|
1
|
-
|
|
2
|
-
require 'browser/dom/element/data'
|
|
3
|
-
require 'browser/dom/element/position'
|
|
4
|
-
require 'browser/dom/element/offset'
|
|
5
|
-
require 'browser/dom/element/scroll'
|
|
6
|
-
require 'browser/dom/element/size'
|
|
7
|
-
|
|
8
|
-
require 'browser/dom/element/input'
|
|
9
|
-
require 'browser/dom/element/select'
|
|
10
|
-
require 'browser/dom/element/image'
|
|
11
|
-
require 'browser/dom/element/template'
|
|
12
|
-
require 'browser/dom/element/textarea'
|
|
1
|
+
# Requires are moved to the bottom of this file.
|
|
13
2
|
|
|
14
3
|
module Browser; module DOM
|
|
15
4
|
|
|
16
5
|
class Element < Node
|
|
17
|
-
def self.create(*args)
|
|
18
|
-
|
|
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
|
|
19
36
|
end
|
|
20
37
|
|
|
21
|
-
def self.
|
|
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
|
+
|
|
22
76
|
if self == Element
|
|
23
|
-
|
|
77
|
+
subclass = Element.subclasses.select do |subclass|
|
|
78
|
+
Element.native_is?(node, subclass)
|
|
79
|
+
end.last
|
|
24
80
|
|
|
25
|
-
if
|
|
26
|
-
|
|
81
|
+
if subclass
|
|
82
|
+
subclass.new(node)
|
|
27
83
|
else
|
|
28
|
-
super
|
|
84
|
+
super(node)
|
|
29
85
|
end
|
|
30
86
|
else
|
|
31
|
-
super
|
|
87
|
+
super(node)
|
|
32
88
|
end
|
|
33
89
|
end
|
|
34
90
|
|
|
35
91
|
include Event::Target
|
|
36
92
|
|
|
37
93
|
target {|value|
|
|
38
|
-
|
|
94
|
+
begin
|
|
95
|
+
DOM(value)
|
|
96
|
+
rescue StandardError, JS::Error
|
|
97
|
+
nil
|
|
98
|
+
end
|
|
39
99
|
}
|
|
40
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
|
+
|
|
41
110
|
if Browser.supports? 'Element.matches'
|
|
42
|
-
def
|
|
43
|
-
|
|
111
|
+
def self.native_matches? (native, selector)
|
|
112
|
+
`#{native}.matches(#{selector})`
|
|
44
113
|
end
|
|
45
114
|
elsif Browser.supports? 'Element.matches (Opera)'
|
|
46
|
-
def
|
|
47
|
-
|
|
115
|
+
def self.native_matches? (native, selector)
|
|
116
|
+
`#{native}.oMatchesSelector(#{selector})`
|
|
48
117
|
end
|
|
49
118
|
elsif Browser.supports? 'Element.matches (Internet Explorer)'
|
|
50
|
-
def
|
|
51
|
-
|
|
119
|
+
def self.native_matches? (native, selector)
|
|
120
|
+
`#{native}.msMatchesSelector(#{selector})`
|
|
52
121
|
end
|
|
53
122
|
elsif Browser.supports? 'Element.matches (Firefox)'
|
|
54
|
-
def
|
|
55
|
-
|
|
123
|
+
def self.native_matches? (native, selector)
|
|
124
|
+
`#{native}.mozMatchesSelector(#{selector})`
|
|
56
125
|
end
|
|
57
126
|
elsif Browser.supports? 'Element.matches (Chrome)'
|
|
58
|
-
def
|
|
59
|
-
|
|
127
|
+
def self.native_matches? (native, selector)
|
|
128
|
+
`#{native}.webkitMatchesSelector(#{selector})`
|
|
60
129
|
end
|
|
61
130
|
elsif Browser.loaded? 'Sizzle'
|
|
62
|
-
def
|
|
63
|
-
`Sizzle.matchesSelector(
|
|
131
|
+
def self.native_matches? (native, selector)
|
|
132
|
+
`Sizzle.matchesSelector(#{native}, #{selector})`
|
|
64
133
|
end
|
|
65
134
|
else
|
|
66
|
-
|
|
67
|
-
#
|
|
68
|
-
# @param selector [String] the CSS selector
|
|
69
|
-
def =~(selector)
|
|
135
|
+
def self.native_matches? (native, selector)
|
|
70
136
|
raise NotImplementedError, 'selector matching unsupported'
|
|
71
137
|
end
|
|
72
138
|
end
|
|
73
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
|
+
|
|
74
150
|
# Query for children with the given XPpaths.
|
|
75
151
|
#
|
|
76
152
|
# @param paths [Array<String>] the XPaths to look for
|
|
@@ -190,13 +266,13 @@ class Element < Node
|
|
|
190
266
|
if Browser.supports? 'Query.css'
|
|
191
267
|
def css(path)
|
|
192
268
|
NodeSet[Native::Array.new(`#@native.querySelectorAll(path)`)]
|
|
193
|
-
rescue
|
|
269
|
+
rescue StandardError, JS::Error
|
|
194
270
|
NodeSet[]
|
|
195
271
|
end
|
|
196
272
|
elsif Browser.loaded? 'Sizzle'
|
|
197
273
|
def css(path)
|
|
198
274
|
NodeSet[`Sizzle(path, #@native)`]
|
|
199
|
-
rescue
|
|
275
|
+
rescue StandardError, JS::Error
|
|
200
276
|
NodeSet[]
|
|
201
277
|
end
|
|
202
278
|
else
|
|
@@ -210,6 +286,12 @@ class Element < Node
|
|
|
210
286
|
end
|
|
211
287
|
end
|
|
212
288
|
|
|
289
|
+
# Click the element. it fires the element's click event.
|
|
290
|
+
def click
|
|
291
|
+
`#@native.click()`
|
|
292
|
+
self
|
|
293
|
+
end
|
|
294
|
+
|
|
213
295
|
# @overload data()
|
|
214
296
|
#
|
|
215
297
|
# Return the data for the element.
|
|
@@ -271,13 +353,10 @@ class Element < Node
|
|
|
271
353
|
end
|
|
272
354
|
|
|
273
355
|
# Set the inner DOM of the element using the {Builder}.
|
|
274
|
-
def inner_dom(&block)
|
|
356
|
+
def inner_dom(builder=nil, &block)
|
|
275
357
|
clear
|
|
276
358
|
|
|
277
|
-
|
|
278
|
-
doc = document
|
|
279
|
-
|
|
280
|
-
self << Builder.new(doc, self, &block).to_a
|
|
359
|
+
self << Builder.new(document, builder, &block).to_a
|
|
281
360
|
end
|
|
282
361
|
|
|
283
362
|
# Set the inner DOM with the given node.
|
|
@@ -289,6 +368,16 @@ class Element < Node
|
|
|
289
368
|
self << node
|
|
290
369
|
end
|
|
291
370
|
|
|
371
|
+
# @!attribute inner_html
|
|
372
|
+
# @return [String] the inner HTML of the element
|
|
373
|
+
def inner_html
|
|
374
|
+
`#@native.innerHTML`
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def inner_html=(value)
|
|
378
|
+
`#@native.innerHTML = #{value}`
|
|
379
|
+
end
|
|
380
|
+
|
|
292
381
|
def inspect
|
|
293
382
|
inspect = name.downcase
|
|
294
383
|
|
|
@@ -300,7 +389,7 @@ class Element < Node
|
|
|
300
389
|
inspect += '.' + class_names.join('.')
|
|
301
390
|
end
|
|
302
391
|
|
|
303
|
-
"
|
|
392
|
+
"#<#{self.class.name.gsub("Browser::","")}: #{inspect}>"
|
|
304
393
|
end
|
|
305
394
|
|
|
306
395
|
# @!attribute offset
|
|
@@ -319,16 +408,22 @@ class Element < Node
|
|
|
319
408
|
offset.set(*value)
|
|
320
409
|
end
|
|
321
410
|
|
|
411
|
+
# @!attribute outer_html
|
|
412
|
+
# @return [String] the outer HTML of the element
|
|
413
|
+
def outer_html
|
|
414
|
+
`#@native.outerHTML`
|
|
415
|
+
end
|
|
416
|
+
|
|
322
417
|
# @!attribute [r] position
|
|
323
418
|
# @return [Position] the position of the element
|
|
324
419
|
def position
|
|
325
|
-
Position.new(self)
|
|
420
|
+
@position ||= Position.new(self)
|
|
326
421
|
end
|
|
327
422
|
|
|
328
423
|
# @!attribute [r] scroll
|
|
329
424
|
# @return [Scroll] the scrolling for the element
|
|
330
425
|
def scroll
|
|
331
|
-
Scroll.new(self)
|
|
426
|
+
@scroll ||= Scroll.new(self)
|
|
332
427
|
end
|
|
333
428
|
|
|
334
429
|
# Search for all the children matching the given XPaths or CSS selectors.
|
|
@@ -346,6 +441,27 @@ class Element < Node
|
|
|
346
441
|
|
|
347
442
|
alias set_attribute []=
|
|
348
443
|
|
|
444
|
+
# Creates or accesses the shadow root of this element
|
|
445
|
+
#
|
|
446
|
+
# @param open [Boolean] set to false if you want to create a closed
|
|
447
|
+
# shadow root
|
|
448
|
+
#
|
|
449
|
+
# @return [ShadowRoot]
|
|
450
|
+
def shadow (open = true)
|
|
451
|
+
if root = `#@native.shadowRoot`
|
|
452
|
+
DOM(root)
|
|
453
|
+
else
|
|
454
|
+
DOM(`#@native.attachShadow({mode: #{open ? "open" : "closed"}})`)
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
# Checks for a presence of a shadow root of this element
|
|
459
|
+
#
|
|
460
|
+
# @return [Boolean]
|
|
461
|
+
def shadow?
|
|
462
|
+
`!!#@native.shadowRoot`
|
|
463
|
+
end
|
|
464
|
+
|
|
349
465
|
# @overload style()
|
|
350
466
|
#
|
|
351
467
|
# Return the style for the element.
|
|
@@ -429,6 +545,18 @@ class Element < Node
|
|
|
429
545
|
Size.new(self, *inc)
|
|
430
546
|
end
|
|
431
547
|
|
|
548
|
+
# Toggle class names of the element.
|
|
549
|
+
#
|
|
550
|
+
# @param names [Array<String>] class names to toggle
|
|
551
|
+
#
|
|
552
|
+
# @return [self]
|
|
553
|
+
def toggle_class(*names)
|
|
554
|
+
to_remove, to_add = names.partition { |name| class_names.include? name }
|
|
555
|
+
|
|
556
|
+
add_class(*to_add)
|
|
557
|
+
remove_class(*to_remove)
|
|
558
|
+
end
|
|
559
|
+
|
|
432
560
|
# @!attribute width
|
|
433
561
|
# @return [Integer] the width of the element
|
|
434
562
|
def width
|
|
@@ -456,7 +584,7 @@ class Element < Node
|
|
|
456
584
|
#@native, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)`,
|
|
457
585
|
get: :snapshotItem,
|
|
458
586
|
length: :snapshotLength)]
|
|
459
|
-
rescue
|
|
587
|
+
rescue StandardError, JS::Error
|
|
460
588
|
NodeSet[]
|
|
461
589
|
end
|
|
462
590
|
else
|
|
@@ -472,3 +600,20 @@ class Element < Node
|
|
|
472
600
|
end
|
|
473
601
|
|
|
474
602
|
end; end
|
|
603
|
+
|
|
604
|
+
require 'browser/dom/element/attributes'
|
|
605
|
+
require 'browser/dom/element/data'
|
|
606
|
+
require 'browser/dom/element/position'
|
|
607
|
+
require 'browser/dom/element/offset'
|
|
608
|
+
require 'browser/dom/element/scroll'
|
|
609
|
+
require 'browser/dom/element/size'
|
|
610
|
+
|
|
611
|
+
require 'browser/dom/element/button'
|
|
612
|
+
require 'browser/dom/element/image'
|
|
613
|
+
require 'browser/dom/element/form'
|
|
614
|
+
require 'browser/dom/element/input'
|
|
615
|
+
require 'browser/dom/element/select'
|
|
616
|
+
require 'browser/dom/element/template'
|
|
617
|
+
require 'browser/dom/element/textarea'
|
|
618
|
+
require 'browser/dom/element/iframe'
|
|
619
|
+
require 'browser/dom/element/media'
|
|
@@ -9,11 +9,11 @@ class MutationObserver
|
|
|
9
9
|
Browser.supports? :MutationObserver
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
include Native
|
|
12
|
+
include Native::Wrapper
|
|
13
13
|
|
|
14
14
|
# Encapsulates a recorded change.
|
|
15
15
|
class Record
|
|
16
|
-
include
|
|
16
|
+
include Browser::NativeCachedWrapper
|
|
17
17
|
|
|
18
18
|
# @!attribute [r] type
|
|
19
19
|
# @return [:attributes, :tree, :cdata] the type of the recorded change
|