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
|
@@ -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
|
data/opal/browser/http/binary.rb
CHANGED
|
@@ -14,6 +14,8 @@ class Headers
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
# Create {Headers} from a hash.
|
|
17
|
+
#
|
|
18
|
+
# @param hash [Hash]
|
|
17
19
|
def self.[](hash)
|
|
18
20
|
result = new
|
|
19
21
|
|
|
@@ -36,9 +38,11 @@ class Headers
|
|
|
36
38
|
@hash.clear
|
|
37
39
|
end
|
|
38
40
|
|
|
39
|
-
#
|
|
41
|
+
# Enumerate over the headers.
|
|
42
|
+
#
|
|
43
|
+
# @yieldparam name [String] the name of the header
|
|
44
|
+
# @yieldparam value [String] the value of the header
|
|
40
45
|
#
|
|
41
|
-
# @yield [name, value] the header name and value
|
|
42
46
|
# @return [self]
|
|
43
47
|
def each(&block)
|
|
44
48
|
return enum_for :each unless block
|
|
@@ -51,10 +55,18 @@ class Headers
|
|
|
51
55
|
end
|
|
52
56
|
|
|
53
57
|
# Get the value of a header.
|
|
58
|
+
#
|
|
59
|
+
# @param name [String] the name of the header
|
|
60
|
+
#
|
|
61
|
+
# @return [String] the value of the header
|
|
54
62
|
def [](name)
|
|
55
63
|
@hash[name.downcase]
|
|
56
64
|
end
|
|
57
65
|
|
|
66
|
+
# Set a value for the header.
|
|
67
|
+
#
|
|
68
|
+
# @param name [String] the name of the header
|
|
69
|
+
# @param value [String] the value of the header
|
|
58
70
|
def []=(name, value)
|
|
59
71
|
header = Header.new(name, value)
|
|
60
72
|
|
|
@@ -64,6 +76,7 @@ class Headers
|
|
|
64
76
|
# Push a header.
|
|
65
77
|
#
|
|
66
78
|
# @param header [Header] the header to push
|
|
79
|
+
#
|
|
67
80
|
# @return [self]
|
|
68
81
|
def <<(header)
|
|
69
82
|
@hash[header.name.downcase] = header
|
|
@@ -76,6 +89,7 @@ class Headers
|
|
|
76
89
|
# Merge in place other headers.
|
|
77
90
|
#
|
|
78
91
|
# @param other [Headers, Hash, #each] the headers to merge
|
|
92
|
+
#
|
|
79
93
|
# @return [self]
|
|
80
94
|
def merge!(other)
|
|
81
95
|
other.each {|name, value|
|
|
@@ -1,25 +1,18 @@
|
|
|
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
|
-
|
|
8
|
-
# @param method [Symbol] the HTTP method to use
|
|
9
|
-
# @param url [String, #to_s] the URL to request
|
|
10
|
-
# @param parameters [String, Hash] the parameters to send
|
|
11
|
-
def self.open(method, url, parameters = nil, &block)
|
|
12
|
-
request = new(&block)
|
|
13
|
-
request.open(method, url)
|
|
14
|
-
request.send(*parameters)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
DEFAULT_HEADERS = {
|
|
7
|
+
# Default headers.
|
|
8
|
+
HEADERS = {
|
|
18
9
|
'X-Requested-With' => 'XMLHttpRequest',
|
|
19
10
|
'X-Opal-Version' => RUBY_ENGINE_VERSION,
|
|
20
11
|
'Accept' => 'text/javascript, text/html, application/xml, text/xml, */*'
|
|
21
12
|
}
|
|
22
13
|
|
|
14
|
+
STATES = %w[uninitialized loading loaded interactive complete]
|
|
15
|
+
|
|
23
16
|
# @!attribute [r] headers
|
|
24
17
|
# @return [Headers] the request headers
|
|
25
18
|
attr_reader :headers
|
|
@@ -45,7 +38,7 @@ class Request
|
|
|
45
38
|
|
|
46
39
|
@parameters = {}
|
|
47
40
|
@query = {}
|
|
48
|
-
@headers = Headers[
|
|
41
|
+
@headers = Headers[HEADERS]
|
|
49
42
|
@method = :get
|
|
50
43
|
@asynchronous = true
|
|
51
44
|
@binary = false
|
|
@@ -104,21 +97,13 @@ class Request
|
|
|
104
97
|
end
|
|
105
98
|
|
|
106
99
|
# Make the request asynchronous.
|
|
107
|
-
#
|
|
108
|
-
# @return [self]
|
|
109
100
|
def asynchronous!
|
|
110
101
|
@asynchronous = true
|
|
111
|
-
|
|
112
|
-
self
|
|
113
102
|
end
|
|
114
103
|
|
|
115
104
|
# Make the request synchronous.
|
|
116
|
-
#
|
|
117
|
-
# @return [self]
|
|
118
105
|
def synchronous!
|
|
119
106
|
@asynchronous = false
|
|
120
|
-
|
|
121
|
-
self
|
|
122
107
|
end
|
|
123
108
|
|
|
124
109
|
# Check the request is binary.
|
|
@@ -129,8 +114,6 @@ class Request
|
|
|
129
114
|
# Make the request binary.
|
|
130
115
|
def binary!
|
|
131
116
|
@binary = true
|
|
132
|
-
|
|
133
|
-
self
|
|
134
117
|
end
|
|
135
118
|
|
|
136
119
|
# Check if the request is cacheable.
|
|
@@ -139,12 +122,8 @@ class Request
|
|
|
139
122
|
end
|
|
140
123
|
|
|
141
124
|
# Disable caching for this request.
|
|
142
|
-
#
|
|
143
|
-
# @return [self]
|
|
144
125
|
def no_cache!
|
|
145
126
|
@cacheable = false
|
|
146
|
-
|
|
147
|
-
self
|
|
148
127
|
end
|
|
149
128
|
|
|
150
129
|
# Get or set the user used for authentication.
|
|
@@ -213,13 +192,14 @@ class Request
|
|
|
213
192
|
# Register an event on the request.
|
|
214
193
|
#
|
|
215
194
|
# @param what [Symbol, String] the event name
|
|
216
|
-
# @yield [response] yields the {Response}
|
|
217
195
|
#
|
|
218
|
-
# @
|
|
219
|
-
def on(what, &block)
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
196
|
+
# @yieldparam response [Response] the response for the event
|
|
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
|
|
223
203
|
end
|
|
224
204
|
|
|
225
205
|
# Open the request.
|
|
@@ -242,22 +222,27 @@ class Request
|
|
|
242
222
|
|
|
243
223
|
url = @url
|
|
244
224
|
|
|
225
|
+
# add a dummy random parameter to the query to try circumvent caching
|
|
245
226
|
unless cacheable?
|
|
246
227
|
@query[:_] = rand
|
|
247
228
|
end
|
|
248
229
|
|
|
230
|
+
# add the encoded query to the @url, prepending the right character if
|
|
231
|
+
# there was already a query in the defined @url or not
|
|
249
232
|
unless @query.empty?
|
|
250
|
-
if url.include
|
|
233
|
+
if url.include? ??
|
|
251
234
|
url += ?&
|
|
252
235
|
else
|
|
253
236
|
url += ??
|
|
254
237
|
end
|
|
255
238
|
|
|
256
|
-
url += @query
|
|
239
|
+
url += FormData.build_query(@query)
|
|
257
240
|
end
|
|
258
241
|
|
|
259
242
|
`#@native.open(#{@method.to_s.upcase}, #{url.to_s}, #{@asynchronous}, #{@user.to_n}, #{@password.to_n})`
|
|
260
243
|
|
|
244
|
+
# if there are no registered callbacks no point in setting the event
|
|
245
|
+
# handler
|
|
261
246
|
unless @callbacks.empty?
|
|
262
247
|
`#@native.onreadystatechange = #{callback}`
|
|
263
248
|
end
|
|
@@ -277,6 +262,8 @@ class Request
|
|
|
277
262
|
|
|
278
263
|
raise 'the request has already been sent' if sent?
|
|
279
264
|
|
|
265
|
+
# try to circumvent caching setting an If-Modified-Since header with a very
|
|
266
|
+
# old date
|
|
280
267
|
unless cacheable?
|
|
281
268
|
`#@native.setRequestHeader("If-Modified-Since", "Tue, 11 Sep 2001 12:46:00 GMT")`
|
|
282
269
|
end
|
|
@@ -309,14 +296,29 @@ class Request
|
|
|
309
296
|
|
|
310
297
|
if String === parameters
|
|
311
298
|
data = parameters
|
|
312
|
-
elsif Hash === parameters && !parameters.empty?
|
|
313
|
-
data = parameters
|
|
314
|
-
|
|
315
|
-
|
|
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
|
|
316
309
|
|
|
317
310
|
unless @content_type
|
|
318
|
-
|
|
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
|
|
319
319
|
end
|
|
320
|
+
|
|
321
|
+
data = data.to_n
|
|
320
322
|
else
|
|
321
323
|
data = `null`
|
|
322
324
|
end
|
|
@@ -327,18 +329,14 @@ class Request
|
|
|
327
329
|
end
|
|
328
330
|
|
|
329
331
|
# Abort the request.
|
|
330
|
-
#
|
|
331
|
-
# @return [self]
|
|
332
332
|
def abort
|
|
333
333
|
`#@native.abort()`
|
|
334
|
-
|
|
335
|
-
self
|
|
336
334
|
end
|
|
337
335
|
|
|
338
336
|
private
|
|
339
337
|
def callback
|
|
340
|
-
|
|
341
|
-
state =
|
|
338
|
+
-> event {
|
|
339
|
+
state = STATES[`#@native.readyState`]
|
|
342
340
|
res = response
|
|
343
341
|
|
|
344
342
|
@callbacks[state].each { |b| b.(res) }
|
|
@@ -354,7 +352,7 @@ private
|
|
|
354
352
|
@callbacks[:failure].each { |b| b.(res) }
|
|
355
353
|
end
|
|
356
354
|
end
|
|
357
|
-
}
|
|
355
|
+
}
|
|
358
356
|
end
|
|
359
357
|
end
|
|
360
358
|
|
|
@@ -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
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'promise'
|
|
2
|
-
|
|
3
1
|
require 'browser/http/binary'
|
|
4
2
|
require 'browser/http/headers'
|
|
5
3
|
require 'browser/http/request'
|
|
@@ -8,6 +6,7 @@ require 'browser/http/response'
|
|
|
8
6
|
module Browser
|
|
9
7
|
|
|
10
8
|
module HTTP
|
|
9
|
+
# Check if HTTP requests are supported.
|
|
11
10
|
def self.supported?
|
|
12
11
|
Browser.supports?('XHR') || Browser.supports?('ActiveXObject')
|
|
13
12
|
end
|
|
@@ -18,6 +17,8 @@ module HTTP
|
|
|
18
17
|
# @param url [String] the URL to request
|
|
19
18
|
# @param data [String, Hash] the data to send
|
|
20
19
|
#
|
|
20
|
+
# @yieldparam request [Request] the request to configure
|
|
21
|
+
#
|
|
21
22
|
# @return [Promise] a promise that will be resolved with the response
|
|
22
23
|
def self.send(method, url, data = nil, &block)
|
|
23
24
|
Promise.new.tap {|promise|
|
|
@@ -37,6 +38,8 @@ module HTTP
|
|
|
37
38
|
#
|
|
38
39
|
# @param url [String] the URL to request
|
|
39
40
|
#
|
|
41
|
+
# @yieldparam request [Request] the request to configure
|
|
42
|
+
#
|
|
40
43
|
# @return [Promise] a promise that will be resolved with the response
|
|
41
44
|
def self.get(url, &block)
|
|
42
45
|
send(:get, url, &block)
|
|
@@ -46,6 +49,8 @@ module HTTP
|
|
|
46
49
|
#
|
|
47
50
|
# @param url [String] the URL to request
|
|
48
51
|
#
|
|
52
|
+
# @yieldparam request [Request] the request to configure
|
|
53
|
+
#
|
|
49
54
|
# @return [Promise] a promise that will be resolved with the response
|
|
50
55
|
def self.head(url, &block)
|
|
51
56
|
send(:head, url, &block)
|
|
@@ -56,6 +61,8 @@ module HTTP
|
|
|
56
61
|
# @param url [String] the URL to request
|
|
57
62
|
# @param data [String, Hash] the data to send
|
|
58
63
|
#
|
|
64
|
+
# @yieldparam request [Request] the request to configure
|
|
65
|
+
#
|
|
59
66
|
# @return [Promise] a promise that will be resolved with the response
|
|
60
67
|
def self.post(url, data = nil, &block)
|
|
61
68
|
send(:post, url, data, &block)
|
|
@@ -66,6 +73,8 @@ module HTTP
|
|
|
66
73
|
# @param url [String] the URL to request
|
|
67
74
|
# @param data [String, Hash] the data to send
|
|
68
75
|
#
|
|
76
|
+
# @yieldparam request [Request] the request to configure
|
|
77
|
+
#
|
|
69
78
|
# @return [Promise] a promise that will be resolved with the response
|
|
70
79
|
def self.put(url, data = nil, &block)
|
|
71
80
|
send(:put, url, data, &block)
|
|
@@ -76,6 +85,8 @@ module HTTP
|
|
|
76
85
|
# @param url [String] the URL to request
|
|
77
86
|
# @param data [String, Hash] the data to send
|
|
78
87
|
#
|
|
88
|
+
# @yieldparam request [Request] the request to configure
|
|
89
|
+
#
|
|
79
90
|
# @return [Promise] a promise that will be resolved with the response
|
|
80
91
|
def self.delete(url, data = nil, &block)
|
|
81
92
|
send(:delete, url, data, &block)
|
|
@@ -87,6 +98,8 @@ module HTTP
|
|
|
87
98
|
# @param url [String] the URL to request
|
|
88
99
|
# @param data [String, Hash] the data to send
|
|
89
100
|
#
|
|
101
|
+
# @yieldparam request [Request] the request to configure
|
|
102
|
+
#
|
|
90
103
|
# @return [Response] the response
|
|
91
104
|
def self.send!(method, url, data = nil, &block)
|
|
92
105
|
Request.new(&block).open(method, url, false).send(data)
|
|
@@ -96,6 +109,8 @@ module HTTP
|
|
|
96
109
|
#
|
|
97
110
|
# @param url [String] the URL to request
|
|
98
111
|
#
|
|
112
|
+
# @yieldparam request [Request] the request to configure
|
|
113
|
+
#
|
|
99
114
|
# @return [Response] the response
|
|
100
115
|
def self.get!(url, &block)
|
|
101
116
|
send!(:get, url, &block)
|
|
@@ -105,6 +120,8 @@ module HTTP
|
|
|
105
120
|
#
|
|
106
121
|
# @param url [String] the URL to request
|
|
107
122
|
#
|
|
123
|
+
# @yieldparam request [Request] the request to configure
|
|
124
|
+
#
|
|
108
125
|
# @return [Response] the response
|
|
109
126
|
def self.head!(url, &block)
|
|
110
127
|
send!(:head, url, &block)
|
|
@@ -115,6 +132,8 @@ module HTTP
|
|
|
115
132
|
# @param url [String] the URL to request
|
|
116
133
|
# @param data [String, Hash] the data to send
|
|
117
134
|
#
|
|
135
|
+
# @yieldparam request [Request] the request to configure
|
|
136
|
+
#
|
|
118
137
|
# @return [Response] the response
|
|
119
138
|
def self.post!(url, data = nil, &block)
|
|
120
139
|
send!(:post, url, data, &block)
|
|
@@ -125,6 +144,8 @@ module HTTP
|
|
|
125
144
|
# @param url [String] the URL to request
|
|
126
145
|
# @param data [String, Hash] the data to send
|
|
127
146
|
#
|
|
147
|
+
# @yieldparam request [Request] the request to configure
|
|
148
|
+
#
|
|
128
149
|
# @return [Response] the response
|
|
129
150
|
def self.put!(url, data = nil, &block)
|
|
130
151
|
send!(:put, url, data, &block)
|
|
@@ -135,6 +156,8 @@ module HTTP
|
|
|
135
156
|
# @param url [String] the URL to request
|
|
136
157
|
# @param data [String, Hash] the data to send
|
|
137
158
|
#
|
|
159
|
+
# @yieldparam request [Request] the request to configure
|
|
160
|
+
#
|
|
138
161
|
# @return [Response] the response
|
|
139
162
|
def self.delete!(url, data = nil, &block)
|
|
140
163
|
send!(:delete, url, data, &block)
|
data/opal/browser/immediate.rb
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'promise'
|
|
2
|
-
|
|
3
1
|
module Browser
|
|
4
2
|
|
|
5
3
|
# Class to easily create and dispatch an immediate call.
|
|
@@ -37,7 +35,6 @@ class Immediate
|
|
|
37
35
|
|
|
38
36
|
# @!method prevent
|
|
39
37
|
# Prevent the immediate from being called once scheduled.
|
|
40
|
-
|
|
41
38
|
if Browser.supports? 'Immediate'
|
|
42
39
|
def dispatch
|
|
43
40
|
@id = `window.setImmediate(function() {
|
|
@@ -58,7 +55,7 @@ class Immediate
|
|
|
58
55
|
def prevent
|
|
59
56
|
`window.msClearImmediate(#@id)`
|
|
60
57
|
end
|
|
61
|
-
elsif Browser.supports? 'Window.send'
|
|
58
|
+
elsif Browser.supports? 'Window.send (Asynchronous)'
|
|
62
59
|
# @private
|
|
63
60
|
@@tasks = {}
|
|
64
61
|
|
|
@@ -77,7 +74,7 @@ class Immediate
|
|
|
77
74
|
@id = rand(1_000_000).to_s
|
|
78
75
|
@@tasks[@id] = [@function, @arguments, @block]
|
|
79
76
|
|
|
80
|
-
$window.send
|
|
77
|
+
$window.send "#{@@prefix}#{@id}"
|
|
81
78
|
end
|
|
82
79
|
|
|
83
80
|
def prevent
|
|
@@ -132,6 +129,13 @@ end
|
|
|
132
129
|
|
|
133
130
|
end
|
|
134
131
|
|
|
132
|
+
module Kernel
|
|
133
|
+
# (see Immediate.new)
|
|
134
|
+
def defer(*args, &block)
|
|
135
|
+
Browser::Immediate.new(block, args).tap(&:dispatch)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
135
139
|
class Proc
|
|
136
140
|
# (see Immediate.new)
|
|
137
141
|
def defer(*args, &block)
|