opal-browser 0.2.0 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|