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
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
module Browser
|
|
2
|
+
|
|
3
|
+
class FormData
|
|
4
|
+
include NativeCachedWrapper
|
|
5
|
+
|
|
6
|
+
module Converter
|
|
7
|
+
# Encode as URI component.
|
|
8
|
+
#
|
|
9
|
+
# @return [String] the string encoded for usage as URI component
|
|
10
|
+
def encode(string)
|
|
11
|
+
`encodeURIComponent(#{string})`
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Decode as URI component.
|
|
15
|
+
#
|
|
16
|
+
# @return [String] the string decoded as URI component
|
|
17
|
+
def decode(string)
|
|
18
|
+
`decodeURIComponent(#{string})`
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Encode as URI.
|
|
22
|
+
#
|
|
23
|
+
# @return [String] the string encoded as URI
|
|
24
|
+
def encode_uri(string)
|
|
25
|
+
`encodeURI(#{string})`
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Decode as URI.
|
|
29
|
+
#
|
|
30
|
+
# @return [String] the string decoded as URI
|
|
31
|
+
def decode_uri(string)
|
|
32
|
+
`decodeURI(#{string})`
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Flattens a hash to build a flat array, later to be formatted to
|
|
36
|
+
# produce a nested query.
|
|
37
|
+
#
|
|
38
|
+
# This code should be compatible with what Rack::Utils#build_nested_query [1]
|
|
39
|
+
# does.
|
|
40
|
+
#
|
|
41
|
+
# [1] https://github.com/rack/rack/blob/master/lib/rack/utils.rb
|
|
42
|
+
def flatten(value, key="")
|
|
43
|
+
case value
|
|
44
|
+
when Hash
|
|
45
|
+
out = []
|
|
46
|
+
value.each do |k,v|
|
|
47
|
+
k = "#{key}[#{k}]" if key != ''
|
|
48
|
+
out += flatten(v,k)
|
|
49
|
+
end
|
|
50
|
+
out
|
|
51
|
+
when Array
|
|
52
|
+
out = []
|
|
53
|
+
value.each do |v|
|
|
54
|
+
k = "#{key}[]"
|
|
55
|
+
out += flatten(v,k)
|
|
56
|
+
end
|
|
57
|
+
out
|
|
58
|
+
else
|
|
59
|
+
[[key,value]]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Converts a flat array to a Hash.
|
|
64
|
+
#
|
|
65
|
+
# This code should be compatible with what Rack::Utils#parse_nested_query [1]
|
|
66
|
+
# does.
|
|
67
|
+
#
|
|
68
|
+
# [1] https://github.com/rack/rack/blob/master/lib/rack/utils.rb
|
|
69
|
+
def unflatten(array)
|
|
70
|
+
out = {}
|
|
71
|
+
array.each do |k,v|
|
|
72
|
+
path = [k.split("[").first] + k.scan(/\[(.*?)\]/).flatten
|
|
73
|
+
c = out
|
|
74
|
+
|
|
75
|
+
set = proc { |v,weak| } # Do nothing for the first level
|
|
76
|
+
|
|
77
|
+
path.each do |i|
|
|
78
|
+
case i
|
|
79
|
+
when "" # Array
|
|
80
|
+
set.([], true)
|
|
81
|
+
set = proc do |v,weak|
|
|
82
|
+
c << v
|
|
83
|
+
c = c.last
|
|
84
|
+
end
|
|
85
|
+
else # Hash
|
|
86
|
+
set.({}, true)
|
|
87
|
+
set = proc do |v,weak|
|
|
88
|
+
c[i] ||= v
|
|
89
|
+
c[i] = v if !weak
|
|
90
|
+
c = c[i]
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
set.(v, false)
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
out
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Checks if a query Hash contains any files.
|
|
101
|
+
def contain_files?(hash)
|
|
102
|
+
flatten(hash).any? { |k,v| [File, Blob].include?(v.class) }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Convert a query Hash to a query string
|
|
106
|
+
#
|
|
107
|
+
# @return [String] the string encoded as URI
|
|
108
|
+
def build_query(hash, sep=?&)
|
|
109
|
+
flatten(hash).map { |k,v| encode(k) + ?= + encode(v.to_s) }.join(sep)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Convert a query Hash to a FormData instance
|
|
113
|
+
#
|
|
114
|
+
# @return [FormData] the instance of FormData
|
|
115
|
+
def build_form_data(hash)
|
|
116
|
+
fd = FormData.create
|
|
117
|
+
flatten(hash).each { |k,v| fd << [k,v] }
|
|
118
|
+
fd
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Convert a query string to a query Hash
|
|
122
|
+
#
|
|
123
|
+
# @return [Hash] the query hash
|
|
124
|
+
def parse_query(string, sep=?&)
|
|
125
|
+
unflatten(string.split(sep).map { |s| s.split(?=).map(&method(:decode)) })
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Converts a JS native value to a wrapped one if possible.
|
|
129
|
+
#
|
|
130
|
+
# @return [String, File, Blob]
|
|
131
|
+
def from_native(n)
|
|
132
|
+
%x{
|
|
133
|
+
var c = #{n}.constructor;
|
|
134
|
+
if (c === File) {
|
|
135
|
+
#{n = File.new(n)}
|
|
136
|
+
}
|
|
137
|
+
else if (c === Blob) {
|
|
138
|
+
#{n = Blob.new(n)}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
n
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
extend Converter
|
|
146
|
+
include Enumerable
|
|
147
|
+
|
|
148
|
+
# Create a new FormData instance
|
|
149
|
+
def self.create(hash=nil)
|
|
150
|
+
if Hash === hash
|
|
151
|
+
FormData.build_form_data(hash)
|
|
152
|
+
elsif DOM::Element::Form === hash
|
|
153
|
+
new(`new FormData(#{hash.to_n})`)
|
|
154
|
+
else
|
|
155
|
+
new(`new FormData()`)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Append a tuple to this FormData instance
|
|
160
|
+
#
|
|
161
|
+
# @param tuple [Array(String, String), Array(String, Blob), Array(String, File),
|
|
162
|
+
# Array(String, Blob, String), Array(String, File, String)]
|
|
163
|
+
# a tuple of a key, value and possibly a filename
|
|
164
|
+
def <<(tuple)
|
|
165
|
+
key, value, filename = tuple
|
|
166
|
+
|
|
167
|
+
unless filename
|
|
168
|
+
`#@native.append(#{key}, #{Native.convert(value)})`
|
|
169
|
+
else
|
|
170
|
+
`#@native.append(#{key}, #{Native.convert(value)}, #{filename})`
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Get a field from this FormData instance with a given name
|
|
175
|
+
def [](key)
|
|
176
|
+
FormData.from_native(`#@native.get(#{key})`)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Set a field in this FormData instance with a given name
|
|
180
|
+
def set(key, value, filename = nil)
|
|
181
|
+
unless filename
|
|
182
|
+
`#@native.set(#{key}, #{Native.convert(value)})`
|
|
183
|
+
else
|
|
184
|
+
`#@native.set(#{key}, #{Native.convert(value)}, #{filename})`
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
alias []= set
|
|
188
|
+
|
|
189
|
+
# Convert to hash
|
|
190
|
+
def to_h
|
|
191
|
+
hash = {}
|
|
192
|
+
%x{
|
|
193
|
+
var pair, v, e = #@native.entries();
|
|
194
|
+
while (true) {
|
|
195
|
+
v = e.next();
|
|
196
|
+
if (v.done) break;
|
|
197
|
+
pair = v.value;
|
|
198
|
+
#{hash[`pair[0]`] = FormData.from_native(`pair[1]`)}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
hash
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Convert to array
|
|
205
|
+
def to_a
|
|
206
|
+
to_h.to_a
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Iterate over all elements of this FormData
|
|
210
|
+
def each(&block)
|
|
211
|
+
to_h.each(&block)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Checks if a field of this name exists in this FormData instance
|
|
215
|
+
def include?(key)
|
|
216
|
+
`#@native.has(#{key})`
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Delete a field from this FormData instance
|
|
220
|
+
def delete(key)
|
|
221
|
+
`#@native.delete(#{key})`
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
end
|
data/opal/browser/history.rb
CHANGED
|
@@ -11,7 +11,7 @@ class History
|
|
|
11
11
|
Browser.supports? 'History'
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
include
|
|
14
|
+
include Browser::NativeCachedWrapper
|
|
15
15
|
|
|
16
16
|
# @!attribute [r] length
|
|
17
17
|
# @return [Integer] how many items are in the history
|
|
@@ -36,9 +36,7 @@ class History
|
|
|
36
36
|
# @param item [String] the item to push in the history
|
|
37
37
|
# @param data [Object] additional state to push
|
|
38
38
|
def push(item, data = nil)
|
|
39
|
-
data
|
|
40
|
-
|
|
41
|
-
`#@native.pushState(data, null, item)`
|
|
39
|
+
`#@native.pushState(#{data.to_n}, null, item)`
|
|
42
40
|
end
|
|
43
41
|
|
|
44
42
|
# Replace the current history item with another.
|
|
@@ -46,15 +44,13 @@ class History
|
|
|
46
44
|
# @param item [String] the item to replace with
|
|
47
45
|
# @param data [Object] additional state to replace
|
|
48
46
|
def replace(item, data = nil)
|
|
49
|
-
data
|
|
50
|
-
|
|
51
|
-
`#@native.replaceState(data, null, item)`
|
|
47
|
+
`#@native.replaceState(#{data.to_n}, null, item)`
|
|
52
48
|
end
|
|
53
49
|
|
|
54
50
|
# @!attribute [r] current
|
|
55
51
|
# @return [String] the current item
|
|
56
52
|
def current
|
|
57
|
-
$window.location.
|
|
53
|
+
$window.location.full_path
|
|
58
54
|
end
|
|
59
55
|
|
|
60
56
|
# @!attribute [r] state
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
module Browser; module HTTP
|
|
2
2
|
|
|
3
3
|
class Request
|
|
4
|
-
include Native
|
|
4
|
+
include Native::Wrapper
|
|
5
|
+
include Event::Target
|
|
5
6
|
|
|
6
7
|
# Default headers.
|
|
7
8
|
HEADERS = {
|
|
@@ -10,6 +11,8 @@ class Request
|
|
|
10
11
|
'Accept' => 'text/javascript, text/html, application/xml, text/xml, */*'
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
STATES = %w[uninitialized loading loaded interactive complete]
|
|
15
|
+
|
|
13
16
|
# @!attribute [r] headers
|
|
14
17
|
# @return [Headers] the request headers
|
|
15
18
|
attr_reader :headers
|
|
@@ -191,8 +194,12 @@ class Request
|
|
|
191
194
|
# @param what [Symbol, String] the event name
|
|
192
195
|
#
|
|
193
196
|
# @yieldparam response [Response] the response for the event
|
|
194
|
-
def on(what, &block)
|
|
195
|
-
|
|
197
|
+
def on(what, *, &block)
|
|
198
|
+
if STATES.include?(what) || %w[success failure].include?(what) || Integer === what
|
|
199
|
+
@callbacks[what] << block
|
|
200
|
+
else
|
|
201
|
+
super
|
|
202
|
+
end
|
|
196
203
|
end
|
|
197
204
|
|
|
198
205
|
# Open the request.
|
|
@@ -229,7 +236,7 @@ class Request
|
|
|
229
236
|
url += ??
|
|
230
237
|
end
|
|
231
238
|
|
|
232
|
-
url += @query
|
|
239
|
+
url += FormData.build_query(@query)
|
|
233
240
|
end
|
|
234
241
|
|
|
235
242
|
`#@native.open(#{@method.to_s.upcase}, #{url.to_s}, #{@asynchronous}, #{@user.to_n}, #{@password.to_n})`
|
|
@@ -289,14 +296,29 @@ class Request
|
|
|
289
296
|
|
|
290
297
|
if String === parameters
|
|
291
298
|
data = parameters
|
|
292
|
-
elsif Hash === parameters && !parameters.empty?
|
|
293
|
-
data = parameters
|
|
294
|
-
|
|
295
|
-
|
|
299
|
+
elsif (Hash === parameters && !parameters.empty?) || FormData === parameters
|
|
300
|
+
data = if Hash === parameters
|
|
301
|
+
if FormData.contain_files?(parameters)
|
|
302
|
+
FormData.build_form_data(parameters)
|
|
303
|
+
else
|
|
304
|
+
FormData.build_query(parameters)
|
|
305
|
+
end
|
|
306
|
+
else #if FormData === parameters
|
|
307
|
+
parameters
|
|
308
|
+
end
|
|
296
309
|
|
|
297
310
|
unless @content_type
|
|
298
|
-
|
|
311
|
+
if FormData === data
|
|
312
|
+
# I thought it's done this way, but it isn't. It actually is
|
|
313
|
+
# "multipart/form-data; boundary=-----------.......". Let's miss it
|
|
314
|
+
# purposefully, because it's filled in automatically in this example.
|
|
315
|
+
# `#@native.setRequestHeader('Content-Type', 'multipart/form-data')`
|
|
316
|
+
else
|
|
317
|
+
`#@native.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')`
|
|
318
|
+
end
|
|
299
319
|
end
|
|
320
|
+
|
|
321
|
+
data = data.to_n
|
|
300
322
|
else
|
|
301
323
|
data = `null`
|
|
302
324
|
end
|
|
@@ -314,7 +336,7 @@ class Request
|
|
|
314
336
|
private
|
|
315
337
|
def callback
|
|
316
338
|
-> event {
|
|
317
|
-
state =
|
|
339
|
+
state = STATES[`#@native.readyState`]
|
|
318
340
|
res = response
|
|
319
341
|
|
|
320
342
|
@callbacks[state].each { |b| b.(res) }
|
|
@@ -4,7 +4,7 @@ module Browser; module HTTP
|
|
|
4
4
|
|
|
5
5
|
# Represents an HTTP response.
|
|
6
6
|
class Response
|
|
7
|
-
include Native
|
|
7
|
+
include Native::Wrapper
|
|
8
8
|
|
|
9
9
|
Status = Struct.new(:code, :text)
|
|
10
10
|
|
|
@@ -47,6 +47,10 @@ class Response
|
|
|
47
47
|
!success?
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
# @!attribute [r] url
|
|
51
|
+
# @return [String] the response URL (after redirects)
|
|
52
|
+
alias_native :url, :responseURL
|
|
53
|
+
|
|
50
54
|
# @!attribute [r] text
|
|
51
55
|
# @return [String] the response body as text
|
|
52
56
|
def text
|
data/opal/browser/http.rb
CHANGED
data/opal/browser/immediate.rb
CHANGED
data/opal/browser/location.rb
CHANGED
|
@@ -4,7 +4,7 @@ module Browser
|
|
|
4
4
|
#
|
|
5
5
|
# @see https://developer.mozilla.org/en-US/docs/Web/API/Location
|
|
6
6
|
class Location
|
|
7
|
-
include
|
|
7
|
+
include Browser::NativeCachedWrapper
|
|
8
8
|
|
|
9
9
|
# Change the location.
|
|
10
10
|
#
|
|
@@ -66,6 +66,12 @@ class Location
|
|
|
66
66
|
# @return [String] the query part of the location URI
|
|
67
67
|
alias_native :query, :search
|
|
68
68
|
alias_native :query=, :search=
|
|
69
|
+
|
|
70
|
+
# Returns the full path of the location URI, including
|
|
71
|
+
# the query string and fragment, eg. /site?a=b#c
|
|
72
|
+
def full_path
|
|
73
|
+
path + query + fragment
|
|
74
|
+
end
|
|
69
75
|
end
|
|
70
76
|
|
|
71
77
|
class Window
|
data/opal/browser/navigator.rb
CHANGED
|
@@ -4,7 +4,7 @@ module Browser
|
|
|
4
4
|
#
|
|
5
5
|
# @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator
|
|
6
6
|
class Navigator
|
|
7
|
-
include
|
|
7
|
+
include Browser::NativeCachedWrapper
|
|
8
8
|
|
|
9
9
|
Version = Struct.new(:major, :minor, :build)
|
|
10
10
|
Product = Struct.new(:name, :version)
|
|
@@ -12,7 +12,7 @@ class Navigator
|
|
|
12
12
|
|
|
13
13
|
# Representation of a MIME type.
|
|
14
14
|
class MimeType
|
|
15
|
-
include
|
|
15
|
+
include Browser::NativeCachedWrapper
|
|
16
16
|
|
|
17
17
|
# @!attribute [r] plugin
|
|
18
18
|
# @return [Plugin] the plugin for the MIME type
|
|
@@ -62,7 +62,7 @@ class Navigator
|
|
|
62
62
|
alias_native :version
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
# Representation for the
|
|
65
|
+
# Representation for the array of plugins.
|
|
66
66
|
#
|
|
67
67
|
# @see https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins
|
|
68
68
|
class Plugins < Native::Array
|
|
@@ -160,13 +160,114 @@ class Navigator
|
|
|
160
160
|
rescue
|
|
161
161
|
false
|
|
162
162
|
end
|
|
163
|
+
|
|
164
|
+
# Representation of user location based on Geolocation API
|
|
165
|
+
#
|
|
166
|
+
# Example usage:
|
|
167
|
+
# ```
|
|
168
|
+
# $window.navigator.geolocate.then do |pos|
|
|
169
|
+
# puts "#{pos.coords.latitude}, #{pos.coords.longitude}, #{pos.coords.accuracy}"
|
|
170
|
+
# end
|
|
171
|
+
# ```
|
|
172
|
+
#
|
|
173
|
+
# @see https://developer.mozilla.org/en-US/docs/Web/API/Position
|
|
174
|
+
class Position
|
|
175
|
+
include Browser::NativeCachedWrapper
|
|
176
|
+
|
|
177
|
+
class Coords
|
|
178
|
+
include Native::Wrapper
|
|
179
|
+
|
|
180
|
+
# @!attribute [r] latitude
|
|
181
|
+
alias_native :latitude
|
|
182
|
+
# @!attribute [r] longitude
|
|
183
|
+
alias_native :longitude
|
|
184
|
+
# @!attribute [r] altitude
|
|
185
|
+
alias_native :altitude
|
|
186
|
+
# @!attribute [r] accuracy
|
|
187
|
+
alias_native :accuracy
|
|
188
|
+
# @!attribute [r] altitude_accuracy
|
|
189
|
+
alias_native :altitude_accuracy, :altitudeAccuracy
|
|
190
|
+
# @!attribute [r] heading
|
|
191
|
+
alias_native :heading
|
|
192
|
+
# @!attribute [r] speed
|
|
193
|
+
alias_native :speed
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# @!attribute [r] timestamp
|
|
197
|
+
alias_native :timestamp
|
|
198
|
+
|
|
199
|
+
def coords
|
|
200
|
+
@coords ||= Coords.new(`#@native.coords`)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Geolocates the user once
|
|
205
|
+
#
|
|
206
|
+
# @return [Promise] promise that resolves to the {Position} object
|
|
207
|
+
def geolocate(max_age: 0, timeout: Float::INFINITY, high_accuracy: false)
|
|
208
|
+
promise = Promise.new
|
|
209
|
+
succ = proc { |i| promise.resolve(Position.new(i)) }
|
|
210
|
+
fail = proc { |i| promise.reject(Native(i)) }
|
|
211
|
+
opts = {maxAge: max_age, timeout: timeout, enableHighAccuracy: high_accuracy}
|
|
212
|
+
`#@native.geolocation.getCurrentPosition(#{succ.to_n}, #{fail.to_n}, #{opts.to_n})`
|
|
213
|
+
promise
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Geolocates the user multiple times and calls a block with his location
|
|
217
|
+
# until #stop_tracking is called with a returned id. Calls a proc named error
|
|
218
|
+
# if error happens.
|
|
219
|
+
#
|
|
220
|
+
# @return [Integer] an ID that can be used as an argument to #stop_tracking
|
|
221
|
+
def track(max_age: 0, timeout: Float::INFINITY, high_accuracy: false, error: proc{|i|}, &block)
|
|
222
|
+
opts = {maxAge: max_age, timeout: timeout, enableHighAccuracy: high_accuracy}
|
|
223
|
+
succ = proc { |i| block.call(Position.new(i)) }
|
|
224
|
+
fail = proc { |i| error.call(Native(i)) }
|
|
225
|
+
`#@native.geolocation.watchPosition(#{succ.to_n}, #{fail.to_n}, #{opts.to_n})`
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def stop_tracking(id)
|
|
229
|
+
`#@native.geolocation.clearWatch(#{id})`
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Triggers a vibration on a device. A pattern can be either a number of
|
|
233
|
+
# miliseconds for a vibration length, or an array of lengths (in
|
|
234
|
+
# miliseconds) which describes a vibration pattern - first element of said
|
|
235
|
+
# array describes how long the device should vibrate, second - how long to
|
|
236
|
+
# stop for and so on.
|
|
237
|
+
def vibrate(pattern)
|
|
238
|
+
`#@native.vibrate(#{pattern.to_n})`
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Check a battery status of user device. This API is deprecated in the browser
|
|
242
|
+
# context and usable mainly in privileged contexts.
|
|
243
|
+
#
|
|
244
|
+
# @return [Promise] a promise that resolves with a battery status
|
|
245
|
+
#
|
|
246
|
+
# @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getBattery
|
|
247
|
+
def get_battery
|
|
248
|
+
promise = Promise.new
|
|
249
|
+
yes = proc { |r| promise.resolve(Native(r)) }
|
|
250
|
+
no = proc { |r| promise.reject(Native(r)) }
|
|
251
|
+
`#@native.getBattery().then(#{yes.to_n}).catch(#{no.to_n})`
|
|
252
|
+
promise
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Queue to send a small amount of data to a server.
|
|
256
|
+
#
|
|
257
|
+
# @param url [String] url to trigger
|
|
258
|
+
# @param payload [String, Blob, FormData, Hash] data to send
|
|
259
|
+
#
|
|
260
|
+
# @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon
|
|
261
|
+
def send_beacon(url, payload=nil)
|
|
262
|
+
`#@native.sendBeacon(#{url}, #{payload.to_n})`
|
|
263
|
+
end
|
|
163
264
|
end
|
|
164
265
|
|
|
165
266
|
class Window
|
|
166
267
|
# @!attribute [r] navigator
|
|
167
268
|
# @return [Navigator] the navigator
|
|
168
269
|
def navigator
|
|
169
|
-
Navigator.new(`#@native.navigator`) if `#@native.navigator`
|
|
270
|
+
@navigator ||= Navigator.new(`#@native.navigator`) if `#@native.navigator`
|
|
170
271
|
end
|
|
171
272
|
end
|
|
172
273
|
|