opal-browser 0.2.0 → 0.3.3
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 +78 -0
- data/.gitignore +3 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +17 -3
- data/LICENSE +2 -1
- data/README.md +131 -54
- data/Rakefile +29 -1
- data/config.ru +20 -3
- data/docs/polyfills.md +24 -0
- data/examples/2048/Gemfile +6 -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 +6 -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 +6 -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 +6 -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 +7 -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 +8 -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 +7 -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 +3 -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 +3 -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 +4 -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 +6 -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 +4 -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 +72 -34
- 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 +194 -50
- data/opal/browser/dom/mutation_observer.rb +2 -2
- data/opal/browser/dom/node.rb +53 -13
- data/opal/browser/dom/node_set.rb +13 -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 +46 -22
- 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 +120 -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
|
|
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
|
|
19
61
|
end
|
|
20
62
|
|
|
21
|
-
def self.
|
|
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,9 @@ 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)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
# FIXME: when block passing is fixed
|
|
278
|
-
doc = document
|
|
279
|
-
|
|
280
|
-
self << Builder.new(doc, self, &block).to_a
|
|
356
|
+
def inner_dom(builder=nil, &block)
|
|
357
|
+
self.inner_dom = Builder.new(document, builder, &block).to_a
|
|
358
|
+
self
|
|
281
359
|
end
|
|
282
360
|
|
|
283
361
|
# Set the inner DOM with the given node.
|
|
@@ -289,6 +367,16 @@ class Element < Node
|
|
|
289
367
|
self << node
|
|
290
368
|
end
|
|
291
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
|
+
|
|
292
380
|
def inspect
|
|
293
381
|
inspect = name.downcase
|
|
294
382
|
|
|
@@ -300,7 +388,7 @@ class Element < Node
|
|
|
300
388
|
inspect += '.' + class_names.join('.')
|
|
301
389
|
end
|
|
302
390
|
|
|
303
|
-
"
|
|
391
|
+
"#<#{self.class.name.gsub("Browser::","")}: #{inspect}>"
|
|
304
392
|
end
|
|
305
393
|
|
|
306
394
|
# @!attribute offset
|
|
@@ -319,16 +407,22 @@ class Element < Node
|
|
|
319
407
|
offset.set(*value)
|
|
320
408
|
end
|
|
321
409
|
|
|
410
|
+
# @!attribute outer_html
|
|
411
|
+
# @return [String] the outer HTML of the element
|
|
412
|
+
def outer_html
|
|
413
|
+
`#@native.outerHTML`
|
|
414
|
+
end
|
|
415
|
+
|
|
322
416
|
# @!attribute [r] position
|
|
323
417
|
# @return [Position] the position of the element
|
|
324
418
|
def position
|
|
325
|
-
Position.new(self)
|
|
419
|
+
@position ||= Position.new(self)
|
|
326
420
|
end
|
|
327
421
|
|
|
328
422
|
# @!attribute [r] scroll
|
|
329
423
|
# @return [Scroll] the scrolling for the element
|
|
330
424
|
def scroll
|
|
331
|
-
Scroll.new(self)
|
|
425
|
+
@scroll ||= Scroll.new(self)
|
|
332
426
|
end
|
|
333
427
|
|
|
334
428
|
# Search for all the children matching the given XPaths or CSS selectors.
|
|
@@ -346,6 +440,27 @@ class Element < Node
|
|
|
346
440
|
|
|
347
441
|
alias set_attribute []=
|
|
348
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
|
+
|
|
349
464
|
# @overload style()
|
|
350
465
|
#
|
|
351
466
|
# Return the style for the element.
|
|
@@ -429,6 +544,18 @@ class Element < Node
|
|
|
429
544
|
Size.new(self, *inc)
|
|
430
545
|
end
|
|
431
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
|
+
|
|
432
559
|
# @!attribute width
|
|
433
560
|
# @return [Integer] the width of the element
|
|
434
561
|
def width
|
|
@@ -456,7 +583,7 @@ class Element < Node
|
|
|
456
583
|
#@native, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)`,
|
|
457
584
|
get: :snapshotItem,
|
|
458
585
|
length: :snapshotLength)]
|
|
459
|
-
rescue
|
|
586
|
+
rescue StandardError, JS::Error
|
|
460
587
|
NodeSet[]
|
|
461
588
|
end
|
|
462
589
|
else
|
|
@@ -472,3 +599,20 @@ class Element < Node
|
|
|
472
599
|
end
|
|
473
600
|
|
|
474
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'
|
|
@@ -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
|