opal-browser 0.2.0.beta1 → 0.3.2
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 +3 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +17 -3
- data/LICENSE +2 -1
- data/README.md +183 -52
- 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 +8 -6
- data/lib/opal-browser.rb +1 -0
- data/opal/browser/animation_frame.rb +26 -1
- 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 -11
- data/opal/browser/canvas/gradient.rb +1 -11
- data/opal/browser/canvas/style.rb +3 -11
- data/opal/browser/canvas/text.rb +1 -11
- data/opal/browser/canvas.rb +17 -13
- data/opal/browser/console.rb +3 -1
- data/opal/browser/cookies.rb +78 -42
- 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 +193 -0
- data/opal/browser/delay.rb +41 -7
- data/opal/browser/dom/attribute.rb +13 -12
- data/opal/browser/dom/builder.rb +31 -17
- data/opal/browser/dom/document.rb +174 -42
- 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 +111 -0
- 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 +82 -0
- 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 +48 -1
- data/opal/browser/dom/element/media.rb +17 -0
- data/opal/browser/dom/element/offset.rb +5 -0
- data/opal/browser/dom/element/position.rb +11 -2
- data/opal/browser/dom/element/scroll.rb +123 -24
- data/opal/browser/dom/element/select.rb +42 -0
- data/opal/browser/dom/element/size.rb +17 -0
- data/opal/browser/dom/element/template.rb +11 -0
- data/opal/browser/dom/element/textarea.rb +26 -0
- data/opal/browser/dom/element.rb +468 -238
- data/opal/browser/dom/mutation_observer.rb +4 -4
- data/opal/browser/dom/node.rb +142 -60
- data/opal/browser/dom/node_set.rb +73 -44
- data/opal/browser/dom/shadow_root.rb +12 -0
- data/opal/browser/dom/text.rb +2 -2
- data/opal/browser/dom.rb +40 -16
- data/opal/browser/effects.rb +180 -3
- data/opal/browser/event/all.rb +26 -0
- data/opal/browser/{dom/event → event}/animation.rb +4 -2
- data/opal/browser/{dom/event → event}/audio_processing.rb +4 -2
- data/opal/browser/{dom/event → event}/base.rb +98 -9
- data/opal/browser/{dom/event → event}/before_unload.rb +4 -2
- data/opal/browser/{dom/event → event}/clipboard.rb +11 -2
- data/opal/browser/{dom/event → event}/close.rb +4 -2
- data/opal/browser/{dom/event → event}/composition.rb +4 -2
- data/opal/browser/{dom/event → event}/custom.rb +3 -3
- data/opal/browser/event/data_transfer.rb +95 -0
- data/opal/browser/{dom/event → event}/device_light.rb +4 -2
- data/opal/browser/{dom/event → event}/device_motion.rb +4 -2
- data/opal/browser/{dom/event → event}/device_orientation.rb +4 -2
- data/opal/browser/{dom/event → event}/device_proximity.rb +4 -2
- data/opal/browser/{dom/event → event}/drag.rb +11 -7
- data/opal/browser/{dom/event → event}/focus.rb +4 -2
- data/opal/browser/{dom/event → event}/gamepad.rb +5 -3
- data/opal/browser/{dom/event → event}/hash_change.rb +4 -2
- data/opal/browser/{dom/event → event}/keyboard.rb +16 -3
- data/opal/browser/{dom/event → event}/message.rb +4 -2
- data/opal/browser/{dom/event → event}/mouse.rb +12 -8
- data/opal/browser/{dom/event → event}/page_transition.rb +4 -2
- data/opal/browser/{dom/event → event}/pop_state.rb +4 -2
- data/opal/browser/{dom/event → event}/progress.rb +4 -2
- data/opal/browser/{dom/event → event}/sensor.rb +4 -2
- data/opal/browser/{dom/event → event}/storage.rb +4 -2
- data/opal/browser/{dom/event → event}/touch.rb +4 -2
- data/opal/browser/{dom/event → event}/ui.rb +2 -2
- data/opal/browser/{dom/event → event}/wheel.rb +4 -2
- data/opal/browser/event.rb +163 -0
- data/opal/browser/event_source.rb +2 -2
- data/opal/browser/form_data.rb +225 -0
- data/opal/browser/history.rb +4 -8
- data/opal/browser/http/binary.rb +1 -0
- data/opal/browser/http/headers.rb +16 -2
- data/opal/browser/http/request.rb +46 -48
- data/opal/browser/http/response.rb +5 -1
- data/opal/browser/http.rb +25 -2
- data/opal/browser/immediate.rb +9 -5
- data/opal/browser/interval.rb +34 -11
- data/opal/browser/location.rb +7 -1
- data/opal/browser/navigator.rb +127 -7
- data/opal/browser/polyfill/visual_viewport.rb +216 -0
- data/opal/browser/screen.rb +3 -3
- 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 +8 -4
- data/opal/browser/storage.rb +53 -35
- data/opal/browser/support.rb +72 -5
- 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 +31 -3
- data/opal/browser/window/view.rb +15 -0
- data/opal/browser/window.rb +46 -25
- data/opal/browser.rb +1 -10
- data/opal/opal-browser.rb +1 -0
- data/opal-browser.gemspec +3 -3
- data/spec/database/sql_spec.rb +139 -0
- data/spec/delay_spec.rb +41 -0
- data/spec/dom/attribute_spec.rb +49 -0
- data/spec/dom/builder_spec.rb +25 -8
- data/spec/dom/document_spec.rb +22 -0
- data/spec/dom/element/attributes_spec.rb +52 -0
- data/spec/dom/element/custom_spec.rb +106 -0
- data/spec/dom/element/subclass_spec.rb +144 -0
- data/spec/dom/element_spec.rb +181 -4
- data/spec/dom/mutation_observer_spec.rb +12 -8
- data/spec/dom/node_set_spec.rb +44 -0
- 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 +59 -0
- data/spec/native_cached_wrapper_spec.rb +46 -0
- data/spec/runner.rb +62 -69
- data/spec/socket_spec.rb +16 -12
- data/spec/spec_helper.rb +2 -5
- data/spec/spec_helper_promise.rb.erb +25 -0
- data/spec/storage_spec.rb +1 -1
- metadata +172 -50
- data/.travis.yml +0 -60
- data/opal/browser/dom/event.rb +0 -253
- data/opal/browser/http/parameters.rb +0 -8
- data/opal/browser/window/scroll.rb +0 -59
data/opal/browser/storage.rb
CHANGED
|
@@ -27,8 +27,6 @@ class Storage
|
|
|
27
27
|
}]
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
include Enumerable
|
|
31
|
-
|
|
32
30
|
# @!attribute [r] name
|
|
33
31
|
# @return [String] the name of the storage
|
|
34
32
|
attr_reader :name
|
|
@@ -45,13 +43,7 @@ class Storage
|
|
|
45
43
|
@data = {}
|
|
46
44
|
|
|
47
45
|
autosave!
|
|
48
|
-
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# @!attribute [r] encoded_name
|
|
52
|
-
# @return [String] the generated name
|
|
53
|
-
def encoded_name
|
|
54
|
-
"$opal.storage.#@name"
|
|
46
|
+
reload
|
|
55
47
|
end
|
|
56
48
|
|
|
57
49
|
# Check if autosaving is enabled.
|
|
@@ -72,6 +64,8 @@ class Storage
|
|
|
72
64
|
@autosave = false
|
|
73
65
|
end
|
|
74
66
|
|
|
67
|
+
include Enumerable
|
|
68
|
+
|
|
75
69
|
# Iterate over the (key, value) pairs in the storage.
|
|
76
70
|
#
|
|
77
71
|
# @yield [key, value]
|
|
@@ -83,9 +77,8 @@ class Storage
|
|
|
83
77
|
self
|
|
84
78
|
end
|
|
85
79
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
@data[key]
|
|
80
|
+
def method_missing(*args, &block)
|
|
81
|
+
@data.__send__(*args, &block)
|
|
89
82
|
end
|
|
90
83
|
|
|
91
84
|
# Set a value in the storage.
|
|
@@ -98,7 +91,7 @@ class Storage
|
|
|
98
91
|
# Delete a value from the storage.
|
|
99
92
|
def delete(key)
|
|
100
93
|
@data.delete(key).tap {
|
|
101
|
-
save if autosave
|
|
94
|
+
save if autosave?
|
|
102
95
|
}
|
|
103
96
|
end
|
|
104
97
|
|
|
@@ -120,57 +113,82 @@ class Storage
|
|
|
120
113
|
end
|
|
121
114
|
end
|
|
122
115
|
|
|
123
|
-
#
|
|
124
|
-
|
|
116
|
+
# Call the block between a [#reload] and [#save].
|
|
117
|
+
def commit(&block)
|
|
118
|
+
autosave = @autosave
|
|
119
|
+
@autosave = false
|
|
120
|
+
result = nil
|
|
121
|
+
|
|
122
|
+
reload
|
|
123
|
+
|
|
124
|
+
begin
|
|
125
|
+
result = block.call
|
|
126
|
+
save
|
|
127
|
+
rescue
|
|
128
|
+
reload
|
|
129
|
+
raise
|
|
130
|
+
ensure
|
|
131
|
+
@autosave = autosave
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
result
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def to_h
|
|
138
|
+
@data
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# @!method reload
|
|
142
|
+
# Load the storage.
|
|
125
143
|
|
|
126
144
|
# @!method save
|
|
127
145
|
# Persist the current state to the storage.
|
|
128
146
|
|
|
129
147
|
if Browser.supports? 'Storage.local'
|
|
130
|
-
def
|
|
131
|
-
replace `#@window.localStorage[
|
|
148
|
+
def reload
|
|
149
|
+
replace `#@window.localStorage[#@name] || '{}'`
|
|
132
150
|
end
|
|
133
151
|
|
|
134
152
|
def save
|
|
135
|
-
`#@window.localStorage[
|
|
153
|
+
`#@window.localStorage[#@name] = #{JSON.dump(self)}`
|
|
136
154
|
end
|
|
137
155
|
elsif Browser.supports? 'Storage.global'
|
|
138
|
-
def
|
|
139
|
-
replace `#@window.globalStorage[#@window.location.hostname][
|
|
156
|
+
def reload
|
|
157
|
+
replace `#@window.globalStorage[#@window.location.hostname][#@name] || '{}'`
|
|
140
158
|
end
|
|
141
159
|
|
|
142
160
|
def save
|
|
143
|
-
`#@window.globalStorage[#@window.location.hostname][
|
|
161
|
+
`#@window.globalStorage[#@window.location.hostname][#@name] = #{JSON.dump(self)}`
|
|
144
162
|
end
|
|
145
163
|
elsif Browser.supports? 'Element.addBehavior'
|
|
146
|
-
def
|
|
164
|
+
def reload
|
|
147
165
|
%x{
|
|
148
166
|
#@element = #@window.document.createElement('link');
|
|
149
167
|
#@element.addBehavior('#default#userData');
|
|
150
168
|
|
|
151
169
|
#@window.document.getElementsByTagName('head')[0].appendChild(#@element);
|
|
152
170
|
|
|
153
|
-
#@element.load(
|
|
171
|
+
#@element.load(#@name);
|
|
154
172
|
}
|
|
155
173
|
|
|
156
|
-
replace `#@element.getAttribute(
|
|
174
|
+
replace `#@element.getAttribute(#@name) || '{}'`
|
|
157
175
|
end
|
|
158
176
|
|
|
159
177
|
def save
|
|
160
178
|
%x{
|
|
161
|
-
#@element.setAttribute(
|
|
162
|
-
#@element.save(
|
|
179
|
+
#@element.setAttribute(#@name, #{JSON.dump(self)});
|
|
180
|
+
#@element.save(#@name);
|
|
163
181
|
}
|
|
164
182
|
end
|
|
165
183
|
else
|
|
166
|
-
def
|
|
184
|
+
def reload
|
|
167
185
|
$document.cookies.options expires: 60 * 60 * 24 * 365
|
|
168
186
|
|
|
169
|
-
replace $document.cookies[
|
|
187
|
+
replace $document.cookies[@name]
|
|
170
188
|
end
|
|
171
189
|
|
|
172
190
|
def save
|
|
173
|
-
$document.cookies[
|
|
191
|
+
$document.cookies[@name] = JSON.dump(self)
|
|
174
192
|
end
|
|
175
193
|
end
|
|
176
194
|
|
|
@@ -178,12 +196,12 @@ class Storage
|
|
|
178
196
|
#
|
|
179
197
|
# @return [String] the JSON representation
|
|
180
198
|
def to_json
|
|
181
|
-
io = StringIO.new
|
|
199
|
+
io = StringIO.new << "{"
|
|
182
200
|
|
|
183
201
|
io << JSON.create_id.to_json << ":" << self.class.name.to_json << ","
|
|
184
202
|
|
|
185
|
-
each {|key, value|
|
|
186
|
-
io << key.to_json.
|
|
203
|
+
@data.each {|key, value|
|
|
204
|
+
io << key.to_json.to_s << ":" << value.to_json << ","
|
|
187
205
|
}
|
|
188
206
|
|
|
189
207
|
io.seek(-1, IO::SEEK_CUR)
|
|
@@ -202,12 +220,12 @@ class SessionStorage < Storage
|
|
|
202
220
|
Browser.supports? 'Storage.session'
|
|
203
221
|
end
|
|
204
222
|
|
|
205
|
-
def
|
|
206
|
-
replace `#@window.sessionStorage[
|
|
223
|
+
def reload
|
|
224
|
+
replace `#@window.sessionStorage[#@name] || '{}'`
|
|
207
225
|
end
|
|
208
226
|
|
|
209
227
|
def save
|
|
210
|
-
`#@window.sessionStorage[
|
|
228
|
+
`#@window.sessionStorage[#@name] = #{JSON.dump(self)}`
|
|
211
229
|
end
|
|
212
230
|
end
|
|
213
231
|
|
data/opal/browser/support.rb
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
# The engine the browser is running on.
|
|
2
|
+
#
|
|
3
|
+
# Keep in mind it uses the user agent to know, so it's not reliable in case of
|
|
4
|
+
# spoofing.
|
|
1
5
|
BROWSER_ENGINE = `/MSIE|WebKit|Presto|Gecko/.exec(navigator.userAgent)[0]`.downcase rescue :unknown
|
|
2
6
|
|
|
3
7
|
module Browser
|
|
4
8
|
# @private
|
|
5
9
|
@support = `{}`
|
|
6
10
|
|
|
11
|
+
# Check if the browser supports the given feature.
|
|
7
12
|
def self.supports?(feature)
|
|
8
13
|
if defined?(`#@support[#{feature}]`)
|
|
9
14
|
return `#@support[#{feature}]`
|
|
@@ -25,8 +30,11 @@ module Browser
|
|
|
25
30
|
when 'ActiveX'
|
|
26
31
|
defined?(`window.ActiveXObject`)
|
|
27
32
|
|
|
33
|
+
when 'WebSQL'
|
|
34
|
+
defined?(`window.openDatabase`)
|
|
35
|
+
|
|
28
36
|
when 'Query.css'
|
|
29
|
-
defined?(`
|
|
37
|
+
defined?(`document.querySelectorAll`)
|
|
30
38
|
|
|
31
39
|
when 'Query.xpath'
|
|
32
40
|
defined?(`document.evaluate`)
|
|
@@ -62,6 +70,9 @@ module Browser
|
|
|
62
70
|
defined?(`document.documentElement.currentStyle`)
|
|
63
71
|
|
|
64
72
|
when 'Window.send'
|
|
73
|
+
defined?(`window.postMessage`)
|
|
74
|
+
|
|
75
|
+
when 'Window.send (Asynchronous)'
|
|
65
76
|
if defined?(`window.postMessage`) && !defined?(`window.importScripts`)
|
|
66
77
|
%x{
|
|
67
78
|
var ok = true,
|
|
@@ -70,11 +81,14 @@ module Browser
|
|
|
70
81
|
window.onmessage = function() { ok = false; };
|
|
71
82
|
window.postMessage("", "*")
|
|
72
83
|
window.onmessage = old;
|
|
73
|
-
}
|
|
74
84
|
|
|
75
|
-
|
|
85
|
+
return ok;
|
|
86
|
+
}
|
|
76
87
|
end
|
|
77
88
|
|
|
89
|
+
when 'Window.send (Synchronous)'
|
|
90
|
+
!supports?('Window.send (Asynchronous)')
|
|
91
|
+
|
|
78
92
|
when 'Window.innerSize'
|
|
79
93
|
defined?(`window.innerHeight`)
|
|
80
94
|
|
|
@@ -84,11 +98,54 @@ module Browser
|
|
|
84
98
|
when 'Window.scroll'
|
|
85
99
|
defined?(`document.documentElement.scrollLeft`)
|
|
86
100
|
|
|
101
|
+
when 'Window.scrollBy'
|
|
102
|
+
defined?(`document.documentElement.scrollBy`)
|
|
103
|
+
|
|
87
104
|
when 'Window.pageOffset'
|
|
88
105
|
defined?(`window.pageXOffset`)
|
|
89
106
|
|
|
107
|
+
when 'Attr.isId'
|
|
108
|
+
%x{
|
|
109
|
+
var div = document.createElement('div');
|
|
110
|
+
div.setAttribute('id', 'xxxxxxxxxxxxx');
|
|
111
|
+
|
|
112
|
+
return typeof(div.attributes['id'].isId) !== "undefined";
|
|
113
|
+
}
|
|
114
|
+
|
|
90
115
|
when 'Element.addBehavior'
|
|
91
|
-
defined?(`document.
|
|
116
|
+
defined?(`document.documentElement.addBehavior`)
|
|
117
|
+
|
|
118
|
+
when 'Element.className'
|
|
119
|
+
%x{
|
|
120
|
+
var div = document.createElement("div");
|
|
121
|
+
div.setAttribute('className', 'x');
|
|
122
|
+
|
|
123
|
+
return div.className === 'x';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
when 'Element.class'
|
|
127
|
+
%x{
|
|
128
|
+
var div = document.createElement("div");
|
|
129
|
+
div.setAttribute('class', 'x');
|
|
130
|
+
|
|
131
|
+
return div.className === 'x';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
when 'Element.for'
|
|
135
|
+
%x{
|
|
136
|
+
var label = document.createElement("label");
|
|
137
|
+
label.setAttribute('for', 'x');
|
|
138
|
+
|
|
139
|
+
return label.htmlFor === 'x';
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
when 'Element.htmlFor'
|
|
143
|
+
%x{
|
|
144
|
+
var label = document.createElement("label");
|
|
145
|
+
label.setAttribute('htmlFor', 'x');
|
|
146
|
+
|
|
147
|
+
return label.htmlFor === 'x';
|
|
148
|
+
}
|
|
92
149
|
|
|
93
150
|
when 'Element.clientSize'
|
|
94
151
|
defined?(`document.documentElement.clientHeight`)
|
|
@@ -128,7 +185,7 @@ module Browser
|
|
|
128
185
|
`new MouseEvent("click")`
|
|
129
186
|
|
|
130
187
|
true
|
|
131
|
-
rescue
|
|
188
|
+
rescue StandardError, JS::Error
|
|
132
189
|
false
|
|
133
190
|
end
|
|
134
191
|
|
|
@@ -215,11 +272,21 @@ module Browser
|
|
|
215
272
|
|
|
216
273
|
when 'Animation.cancelRequest (Chrome)', 'Animation.cancelRequest (Safari)'
|
|
217
274
|
defined?(`window.webkitCancelRequestAnimationFrame`)
|
|
275
|
+
|
|
276
|
+
when 'Audio'
|
|
277
|
+
defined?(`window.AudioContext`)
|
|
278
|
+
|
|
279
|
+
when 'Audio (Safari)', 'Audio (Chrome)'
|
|
280
|
+
defined?(`window.webkitAudioContext`)
|
|
281
|
+
|
|
282
|
+
when 'Custom Elements'
|
|
283
|
+
defined?(`window.customElements`)
|
|
218
284
|
end
|
|
219
285
|
|
|
220
286
|
`#@support[#{feature}] = #{support}`
|
|
221
287
|
end
|
|
222
288
|
|
|
289
|
+
# Check if the given polyfill is loaded.
|
|
223
290
|
def self.loaded?(name)
|
|
224
291
|
case name
|
|
225
292
|
when 'Sizzle'
|
data/opal/browser/utils.rb
CHANGED
|
@@ -1,51 +1,133 @@
|
|
|
1
1
|
module Browser
|
|
2
|
+
Promise = defined?(PromiseV2) ? PromiseV2 : ::Promise
|
|
3
|
+
|
|
2
4
|
Size = Struct.new(:width, :height)
|
|
3
5
|
Position = Struct.new(:x, :y)
|
|
6
|
+
|
|
7
|
+
# {Browser::NativeCachedWrapper} is a special case of {Native::Wrapper}.
|
|
8
|
+
#
|
|
9
|
+
# What this module does is it makes sure that your Ruby objects
|
|
10
|
+
# are mapped 1:1 to your Javascript objects. So that for instance
|
|
11
|
+
# your `$document.at_css('body')` is always the same Ruby object.
|
|
12
|
+
#
|
|
13
|
+
# You can only use it if your final `.new` is of the signature
|
|
14
|
+
# `.new(native)` and your native (probably DOM) object persists and
|
|
15
|
+
# doesn't mind arbitrary properties.
|
|
16
|
+
#
|
|
17
|
+
# The rule of thumb is: if it does overload `#initialize`'s signature
|
|
18
|
+
# and not `.new`'s - it won't work. Use {Native::Wrapper} in this case.
|
|
19
|
+
module NativeCachedWrapper
|
|
20
|
+
def self.included(klass)
|
|
21
|
+
klass.include Native::Wrapper
|
|
22
|
+
klass.extend NativeCachedWrapperClassMethods
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def restricted?
|
|
26
|
+
!!@restricted
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Change a native reference and make sure the change is reflected on JS
|
|
30
|
+
# side as well. This method is used by Node#initialize_copy. Please don't
|
|
31
|
+
# use this method outside of the cloning semantic.
|
|
32
|
+
def set_native_reference(native)
|
|
33
|
+
`#{native}.$$opal_native_cached = #{self}`
|
|
34
|
+
@native = native
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module NativeCachedWrapperClassMethods
|
|
39
|
+
# Check if we don't have access to arbitrary properties of a (presumably)
|
|
40
|
+
# native object.
|
|
41
|
+
private def restricted?(native)
|
|
42
|
+
%x{
|
|
43
|
+
try {
|
|
44
|
+
typeof(#{native}.$$try_restricted_access);
|
|
45
|
+
} catch (e) {
|
|
46
|
+
if (e.name == 'SecurityError') return true;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def new(native)
|
|
53
|
+
# We can't access arbitrary properties if an element is restricted
|
|
54
|
+
# i.e. the DOM element is an item we can't fully access due to CORS.
|
|
55
|
+
if restricted?(native)
|
|
56
|
+
# Let's try to bypass any further initializers... may be ugly, but
|
|
57
|
+
# works.
|
|
58
|
+
obj = allocate
|
|
59
|
+
obj.instance_variable_set :@native, native
|
|
60
|
+
obj.instance_variable_set :@restricted, true
|
|
61
|
+
return obj
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# It's not a native element? Weird, better throw an exception.
|
|
65
|
+
raise ArgumentError if !native?(native)
|
|
66
|
+
|
|
67
|
+
if defined? `#{native}.$$opal_native_cached`
|
|
68
|
+
`#{native}.$$opal_native_cached`
|
|
69
|
+
else
|
|
70
|
+
`#{native}.$$opal_native_cached = #{super(native)}`
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
4
74
|
end
|
|
5
75
|
|
|
6
76
|
class Object
|
|
7
77
|
# Encode as URI.
|
|
8
78
|
#
|
|
79
|
+
# @deprecated Please use FormData.encode_uri
|
|
9
80
|
# @return [String] the {Object#to_s} encoded for usage as URI
|
|
10
81
|
def encode_uri
|
|
11
|
-
|
|
82
|
+
warn "opal-browser: Object#encode_uri is deprecated. Please use FormData.encode_uri"
|
|
83
|
+
FormData.encode_uri(to_s)
|
|
12
84
|
end
|
|
13
85
|
|
|
14
86
|
# Encode as URI component.
|
|
15
87
|
#
|
|
88
|
+
# @deprecated Please use FormData.encode
|
|
16
89
|
# @return [String] the {Object#to_s} encoded for usage as URI component
|
|
17
90
|
def encode_uri_component
|
|
18
|
-
|
|
91
|
+
warn "opal-browser: Object#encode_uri_component is deprecated. Please use FormData.encode"
|
|
92
|
+
FormData.encode(to_s)
|
|
19
93
|
end
|
|
20
94
|
end
|
|
21
95
|
|
|
22
96
|
class String
|
|
23
97
|
# Encode as URI component.
|
|
24
98
|
#
|
|
99
|
+
# @deprecated Please use FormData.encode
|
|
25
100
|
# @return [String] the string encoded for usage as URI component
|
|
26
101
|
def encode_uri_component
|
|
27
|
-
|
|
102
|
+
warn "opal-browser: String#encode_uri_component is deprecated. Please use FormData.encode"
|
|
103
|
+
FormData.encode(self)
|
|
28
104
|
end
|
|
29
105
|
|
|
30
106
|
# Encode as URI.
|
|
31
107
|
#
|
|
108
|
+
# @deprecated Please use FormData.encode_uri
|
|
32
109
|
# @return [String] the string encoded as URI
|
|
33
110
|
def encode_uri
|
|
34
|
-
|
|
111
|
+
warn "opal-browser: String#encode_uri is deprecated. Please use FormData.encode_uri"
|
|
112
|
+
FormData.encode_uri(self)
|
|
35
113
|
end
|
|
36
114
|
|
|
37
115
|
# Decode as URI component.
|
|
38
116
|
#
|
|
117
|
+
# @deprecated Please use FormData.decode
|
|
39
118
|
# @return [String] the string decoded as URI component
|
|
40
119
|
def decode_uri_component
|
|
41
|
-
|
|
120
|
+
warn "opal-browser: String#decode_uri_component is deprecated. Please use FormData.decode"
|
|
121
|
+
FormData.decode(self)
|
|
42
122
|
end
|
|
43
123
|
|
|
44
124
|
# Decode as URI.
|
|
45
125
|
#
|
|
126
|
+
# @deprecated Please use FormData.decode_uri
|
|
46
127
|
# @return [String] the string decoded as URI
|
|
47
128
|
def decode_uri
|
|
48
|
-
|
|
129
|
+
warn "opal-browser: String#decode_uri is deprecated. Please use FormData.decode_uri"
|
|
130
|
+
FormData.decode_uri(self)
|
|
49
131
|
end
|
|
50
132
|
end
|
|
51
133
|
|
|
@@ -54,21 +136,19 @@ class Hash
|
|
|
54
136
|
#
|
|
55
137
|
# @param string [String] the URL encoded form
|
|
56
138
|
#
|
|
139
|
+
# @deprecated Please use FormData.parse_query
|
|
57
140
|
# @return [Hash]
|
|
58
141
|
def self.decode_uri(string)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
[name.decode_uri_component, value.decode_uri_component]
|
|
63
|
-
}]
|
|
142
|
+
warn "opal-browser: Hash.decode_uri is deprecated. Please use FormData.parse_query"
|
|
143
|
+
FormData.parse_query(string)
|
|
64
144
|
end
|
|
65
145
|
|
|
66
146
|
# Encode the Hash to an URL form.
|
|
67
147
|
#
|
|
148
|
+
# @deprecated Please use FormData.build_query
|
|
68
149
|
# @return [String] the URL encoded form
|
|
69
150
|
def encode_uri
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}.join(?&)
|
|
151
|
+
warn "opal-browser: Hash#encode_uri is deprecated. Please use FormData.build_query"
|
|
152
|
+
FormData.build_query(self)
|
|
73
153
|
end
|
|
74
154
|
end
|
data/opal/browser/version.rb
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Firefox browsers need either a flag or a polyfill
|
|
2
|
+
require "browser/polyfill/visual_viewport"
|
|
3
|
+
|
|
4
|
+
module Browser
|
|
5
|
+
# The mobile web contains two viewports, the Layout and Visual viewport.
|
|
6
|
+
# The Layout viewport is what a page lays out its elements into and the
|
|
7
|
+
# Visual viewport is what is actually visible on the screen. When the user
|
|
8
|
+
# pinch-zooms into the page, the visual viewport shrinks but the layout viewport
|
|
9
|
+
# is unchanged. UI like the on-screen keyboard (OSK) can also shrink the visual
|
|
10
|
+
# viewport without affecting the layout viewport.
|
|
11
|
+
#
|
|
12
|
+
# https://github.com/WICG/visual-viewport
|
|
13
|
+
# https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport
|
|
14
|
+
class VisualViewport
|
|
15
|
+
include Native::Wrapper
|
|
16
|
+
include Event::Target
|
|
17
|
+
|
|
18
|
+
alias_native :offset_left, :offsetLeft
|
|
19
|
+
alias_native :offset_top, :offsetTop
|
|
20
|
+
alias_native :page_left, :pageLeft
|
|
21
|
+
alias_native :page_top, :pageTop
|
|
22
|
+
alias_native :width, :width
|
|
23
|
+
alias_native :height, :height
|
|
24
|
+
alias_native :scale, :scale
|
|
25
|
+
|
|
26
|
+
attr_accessor :native
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class Window
|
|
30
|
+
def visual_viewport
|
|
31
|
+
@visual_viewport ||= VisualViewport.new(`#@native.visualViewport`)
|
|
32
|
+
|
|
33
|
+
# Polyfill can take some time to load
|
|
34
|
+
@visual_viewport.native ||= `#@native.visualViewport`
|
|
35
|
+
|
|
36
|
+
@visual_viewport
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/opal/browser/window/size.rb
CHANGED
|
@@ -1,20 +1,34 @@
|
|
|
1
1
|
module Browser; class Window
|
|
2
2
|
|
|
3
|
+
# Allows access and manipulation of the {Window} size.
|
|
3
4
|
class Size
|
|
5
|
+
# @private
|
|
4
6
|
def initialize(window)
|
|
5
7
|
@window = window
|
|
6
8
|
@native = window.to_n
|
|
7
9
|
end
|
|
8
10
|
|
|
9
|
-
def set(
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
def set(*args)
|
|
12
|
+
if Hash === args.first
|
|
13
|
+
width, height = args.first.values_at(:width, :height)
|
|
14
|
+
else
|
|
15
|
+
width, height = args
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
width ||= self.width
|
|
19
|
+
height ||= self.height
|
|
12
20
|
|
|
13
21
|
`#@native.resizeTo(#{width}, #{height})`
|
|
14
22
|
|
|
15
23
|
self
|
|
16
24
|
end
|
|
17
25
|
|
|
26
|
+
# @!attribute width
|
|
27
|
+
# @return [Integer] the width of the window
|
|
28
|
+
|
|
29
|
+
# @!attribute height
|
|
30
|
+
# @return [Integer] the height of the window
|
|
31
|
+
|
|
18
32
|
if Browser.supports? 'Window.outerSize'
|
|
19
33
|
def width
|
|
20
34
|
`#@native.outerWidth`
|
|
@@ -40,6 +54,20 @@ class Size
|
|
|
40
54
|
def height=(value)
|
|
41
55
|
set(height: value)
|
|
42
56
|
end
|
|
57
|
+
|
|
58
|
+
# @!attribute inner_width
|
|
59
|
+
# @return [Integer] the inner width of the window
|
|
60
|
+
|
|
61
|
+
def inner_width
|
|
62
|
+
`#@native.innerWidth`
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @!attribute inner_height
|
|
66
|
+
# @return [Integer] the inner height of the window
|
|
67
|
+
|
|
68
|
+
def inner_height
|
|
69
|
+
`#@native.innerHeight`
|
|
70
|
+
end
|
|
43
71
|
end
|
|
44
72
|
|
|
45
73
|
end; end
|
data/opal/browser/window/view.rb
CHANGED
|
@@ -31,6 +31,21 @@ class View
|
|
|
31
31
|
raise NotImplementedError, 'window size unsupported'
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
|
+
|
|
35
|
+
# Get a device pixel ratio. Can be used to handle desktop browser
|
|
36
|
+
# zoom, retina devices and custom screen scale for mobile devices.
|
|
37
|
+
# Use $window.visual_viewport.scale to handle mobile zoom.
|
|
38
|
+
def zoom
|
|
39
|
+
`#@native.devicePixelRatio`
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Handle #pixel_ratio changes. This will trigger a block on zoom.
|
|
43
|
+
def on_zoom &block
|
|
44
|
+
%x{
|
|
45
|
+
var mqString = "(resolution: " + #@native.devicePixelRatio + "dppx)";
|
|
46
|
+
#@native.matchMedia(mqString).addListener(#{block.to_n});
|
|
47
|
+
}
|
|
48
|
+
end
|
|
34
49
|
end
|
|
35
50
|
|
|
36
51
|
end; end
|