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,193 @@
|
|
|
1
|
+
require 'ostruct'
|
|
2
|
+
|
|
3
|
+
module Browser; module Database
|
|
4
|
+
|
|
5
|
+
class SQL
|
|
6
|
+
# Check if the browser supports WebSQL.
|
|
7
|
+
def self.supported?
|
|
8
|
+
Browser.supports? 'WebSQL'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Error < StandardError
|
|
12
|
+
def self.new(error)
|
|
13
|
+
return super if self != Error
|
|
14
|
+
|
|
15
|
+
[Unknown, Database, Version, TooLarge, Quota, Syntax, Constraint, Timeout] \
|
|
16
|
+
[`error.code`].new(`error.message`)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Unknown = Class.new(self)
|
|
20
|
+
Database = Class.new(self)
|
|
21
|
+
Version = Class.new(self)
|
|
22
|
+
TooLarge = Class.new(self)
|
|
23
|
+
Quota = Class.new(self)
|
|
24
|
+
Syntax = Class.new(self)
|
|
25
|
+
Constraint = Class.new(self)
|
|
26
|
+
Timeout = Class.new(self)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
include Native::Wrapper
|
|
30
|
+
|
|
31
|
+
# @return [String] the name of the database
|
|
32
|
+
attr_reader :name
|
|
33
|
+
|
|
34
|
+
# @return [String] the description for the database
|
|
35
|
+
attr_reader :description
|
|
36
|
+
|
|
37
|
+
# @return [Integer] the size constraint in bytes
|
|
38
|
+
attr_reader :size
|
|
39
|
+
|
|
40
|
+
# Open a database with the given name and options.
|
|
41
|
+
#
|
|
42
|
+
# @param name [String] the name for the database
|
|
43
|
+
# @param options [Hash] options to open the database
|
|
44
|
+
#
|
|
45
|
+
# @option options [String] :description the description for the database
|
|
46
|
+
# @option options [String] :version ('') the expected version of the database
|
|
47
|
+
# @option options [Integer] :size (5 * 1024 * 1024) the size constraint in bytes
|
|
48
|
+
def initialize(name, options = {})
|
|
49
|
+
@name = name
|
|
50
|
+
@description = options[:description] || name
|
|
51
|
+
@version = options[:version] || ''
|
|
52
|
+
@size = options[:size] || 2 * 1024 * 1024
|
|
53
|
+
|
|
54
|
+
super(`window.openDatabase(#{name}, #{@version}, #{@description}, #{@size})`)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @overload version()
|
|
58
|
+
#
|
|
59
|
+
# Get the version of the database.
|
|
60
|
+
#
|
|
61
|
+
# @return [String]
|
|
62
|
+
#
|
|
63
|
+
# @overload version(from, to, &block)
|
|
64
|
+
#
|
|
65
|
+
# Migrate the database to a new version.
|
|
66
|
+
#
|
|
67
|
+
# @param from [String] the version you're migrating from
|
|
68
|
+
# @param to [String] the version you're migrating to
|
|
69
|
+
#
|
|
70
|
+
# @yieldparam transaction [Transaction] the transaction to work with
|
|
71
|
+
def version(from = nil, to = nil, &block)
|
|
72
|
+
return `#@native.version` unless block
|
|
73
|
+
|
|
74
|
+
`#@native.changeVersion(#{from}, #{to},
|
|
75
|
+
#{->(t) { block.call(Transaction.new(self, t)) }})`
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Start a transaction on the database.
|
|
79
|
+
#
|
|
80
|
+
# @yieldparam transaction [Transaction] the transaction to work on
|
|
81
|
+
def transaction(&block)
|
|
82
|
+
raise ArgumentError, 'no block given' unless block
|
|
83
|
+
|
|
84
|
+
`#@native.transaction(#{->(t) { block.call(Transaction.new(self, t)) }})`
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Allows you to make changes to the database or read data from it.
|
|
88
|
+
class Transaction
|
|
89
|
+
include Native::Wrapper
|
|
90
|
+
|
|
91
|
+
# @return [Database] the database the transaction has been created from
|
|
92
|
+
attr_reader :database
|
|
93
|
+
|
|
94
|
+
# @private
|
|
95
|
+
def initialize(database, transaction)
|
|
96
|
+
@database = database
|
|
97
|
+
|
|
98
|
+
super(transaction)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Query the database.
|
|
102
|
+
#
|
|
103
|
+
# @param query [String] the SQL query to send
|
|
104
|
+
# @param parameters [Array] optional bind parameters for the query
|
|
105
|
+
#
|
|
106
|
+
# @return [Promise]
|
|
107
|
+
def query(query, *parameters)
|
|
108
|
+
promise = Promise.new
|
|
109
|
+
|
|
110
|
+
`#@native.executeSql(#{query}, #{parameters},
|
|
111
|
+
#{->(_, r) { promise.resolve(Result.new(self, r)) }},
|
|
112
|
+
#{->(_, e) { promise.reject(Error.new(e)) }})`
|
|
113
|
+
|
|
114
|
+
promise
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Represents a row.
|
|
119
|
+
class Row < OpenStruct
|
|
120
|
+
# @private
|
|
121
|
+
def initialize(row)
|
|
122
|
+
super(Hash.new(row))
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def inspect
|
|
126
|
+
"#<SQL::Row: #{Hash.new(@native).inspect}>"
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
class Result
|
|
131
|
+
include Native::Wrapper
|
|
132
|
+
|
|
133
|
+
# @return [Transaction] the transaction the result came from
|
|
134
|
+
attr_reader :transaction
|
|
135
|
+
|
|
136
|
+
# @return [SQL] the database the result came from
|
|
137
|
+
attr_reader :database
|
|
138
|
+
|
|
139
|
+
# @private
|
|
140
|
+
def initialize(transaction, result)
|
|
141
|
+
@transaction = transaction
|
|
142
|
+
@database = transaction.database
|
|
143
|
+
|
|
144
|
+
super(result)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
include Enumerable
|
|
148
|
+
|
|
149
|
+
# Get a row from the result.
|
|
150
|
+
#
|
|
151
|
+
# @param index [Integer] the index for the row
|
|
152
|
+
#
|
|
153
|
+
# @return [Row]
|
|
154
|
+
def [](index)
|
|
155
|
+
if index < 0
|
|
156
|
+
index += length
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
unless index < 0 || index >= length
|
|
160
|
+
Row.new(`#@native.rows.item(index)`)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Enumerate over the rows.
|
|
165
|
+
#
|
|
166
|
+
# @yieldparam row [Row]
|
|
167
|
+
#
|
|
168
|
+
# @return [self]
|
|
169
|
+
def each(&block)
|
|
170
|
+
return enum_for :each unless block
|
|
171
|
+
|
|
172
|
+
%x{
|
|
173
|
+
for (var i = 0, length = #@native.rows.length; i < length; i++) {
|
|
174
|
+
#{block.call(self[`i`])};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
self
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# @!attribute [r] length
|
|
182
|
+
# @return [Integer] number of rows in the result
|
|
183
|
+
def length
|
|
184
|
+
`#@native.rows.length`
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# @!attribute [r] affected
|
|
188
|
+
# @return [Integer] number of affected rows
|
|
189
|
+
alias_native :affected, :rowsAffected
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
end; end
|
data/opal/browser/delay.rb
CHANGED
|
@@ -17,8 +17,6 @@ class Delay
|
|
|
17
17
|
@window = Native.convert(window)
|
|
18
18
|
@after = time
|
|
19
19
|
@block = block
|
|
20
|
-
|
|
21
|
-
start
|
|
22
20
|
end
|
|
23
21
|
|
|
24
22
|
# Abort the timeout.
|
|
@@ -39,10 +37,48 @@ class Window
|
|
|
39
37
|
#
|
|
40
38
|
# @return [Delay] the object representing the timeout
|
|
41
39
|
def after(time, &block)
|
|
40
|
+
Delay.new(@native, time, &block).tap(&:start)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Execute a block after the given seconds, you have to call [#start] on it
|
|
44
|
+
# yourself.
|
|
45
|
+
#
|
|
46
|
+
# @param time [Float] the seconds after it gets called
|
|
47
|
+
#
|
|
48
|
+
# @return [Delay] the object representing the timeout
|
|
49
|
+
def after!(time, &block)
|
|
42
50
|
Delay.new(@native, time, &block)
|
|
43
51
|
end
|
|
52
|
+
|
|
53
|
+
# Returns a promise that will resolve after the given seconds.
|
|
54
|
+
#
|
|
55
|
+
# @param time [Float] the seconds after it gets called
|
|
56
|
+
#
|
|
57
|
+
# @return [Promise] the promise that will resolve after timeout happens
|
|
58
|
+
def resolve_after(time)
|
|
59
|
+
promise = Promise.new
|
|
60
|
+
Delay.new(@native, time) { promise.resolve }.start
|
|
61
|
+
promise
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
44
65
|
end
|
|
45
66
|
|
|
67
|
+
module Kernel
|
|
68
|
+
# (see Browser::Window#after)
|
|
69
|
+
def after(time, &block)
|
|
70
|
+
$window.after(time, &block)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# (see Browser::Window#after!)
|
|
74
|
+
def after!(time, &block)
|
|
75
|
+
$window.after!(time, &block)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# (see Browser::Window#resolve_after)
|
|
79
|
+
def resolve_after(time)
|
|
80
|
+
$window.resolve_after(time)
|
|
81
|
+
end
|
|
46
82
|
end
|
|
47
83
|
|
|
48
84
|
class Proc
|
|
@@ -50,11 +86,9 @@ class Proc
|
|
|
50
86
|
def after(time)
|
|
51
87
|
$window.after(time, &self)
|
|
52
88
|
end
|
|
53
|
-
end
|
|
54
89
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
$window.after(time, &block)
|
|
90
|
+
# (see Browser::Window#after!)
|
|
91
|
+
def after!(time)
|
|
92
|
+
$window.after!(time, &self)
|
|
59
93
|
end
|
|
60
94
|
end
|
|
@@ -2,23 +2,24 @@ module Browser; module DOM
|
|
|
2
2
|
|
|
3
3
|
# Encapsulates an {Element} attribute.
|
|
4
4
|
class Attribute
|
|
5
|
-
include
|
|
6
|
-
|
|
7
|
-
# Returns true if the attribute is an id.
|
|
8
|
-
def id?
|
|
9
|
-
`#@native.isId`
|
|
10
|
-
end
|
|
5
|
+
include Browser::NativeCachedWrapper
|
|
11
6
|
|
|
12
7
|
# @!attribute [r] name
|
|
13
8
|
# @return [String] the name of the attribute
|
|
14
|
-
|
|
15
|
-
`#@native.name`
|
|
16
|
-
end
|
|
9
|
+
alias_native :name
|
|
17
10
|
|
|
18
|
-
# @!attribute
|
|
11
|
+
# @!attribute value
|
|
19
12
|
# @return [String] the value of the attribute
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
alias_native :value
|
|
14
|
+
alias_native :value=
|
|
15
|
+
|
|
16
|
+
# Returns true if the attribute is an id.
|
|
17
|
+
if Browser.supports? 'Attr.isId'
|
|
18
|
+
alias_native :id?, :isId
|
|
19
|
+
else
|
|
20
|
+
def id?
|
|
21
|
+
name == :id
|
|
22
|
+
end
|
|
22
23
|
end
|
|
23
24
|
end
|
|
24
25
|
|
data/opal/browser/dom/builder.rb
CHANGED
|
@@ -29,23 +29,40 @@ class Builder
|
|
|
29
29
|
def self.build(builder, item)
|
|
30
30
|
to_h.each {|klass, block|
|
|
31
31
|
if klass === item
|
|
32
|
-
|
|
32
|
+
return block.call(builder, item)
|
|
33
33
|
end
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
raise ArgumentError, "cannot build unknown item #{item}"
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
attr_reader :document, :element
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
NEW_PAGGIO = (Paggio::HTML.instance_method(:build!) rescue false)
|
|
42
|
+
|
|
43
|
+
def initialize(document, builder=nil, &block)
|
|
40
44
|
@document = document
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
|
|
46
|
+
# Compatibility issue due to an unreleased Paggio gem.
|
|
47
|
+
# Let's try to support both versions. When Paggio is released,
|
|
48
|
+
# we may remove it.
|
|
49
|
+
|
|
50
|
+
if NEW_PAGGIO
|
|
51
|
+
@builder = Paggio::HTML.new(defer: true, &block)
|
|
52
|
+
|
|
53
|
+
build = proc do
|
|
54
|
+
@builder.build!(force_call: !!builder)
|
|
55
|
+
@roots = @builder.each.map { |e| Builder.build(self, e) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if builder
|
|
59
|
+
builder.extend!(@builder, &build)
|
|
60
|
+
else
|
|
61
|
+
build.()
|
|
62
|
+
end
|
|
63
|
+
else
|
|
64
|
+
@builder = Paggio::HTML.new(&block)
|
|
65
|
+
@roots = @builder.each.map { |e| Builder.build(self, e) }
|
|
49
66
|
end
|
|
50
67
|
end
|
|
51
68
|
|
|
@@ -59,15 +76,12 @@ Builder.for String do |b, item|
|
|
|
59
76
|
end
|
|
60
77
|
|
|
61
78
|
Builder.for Paggio::HTML::Element do |b, item|
|
|
62
|
-
|
|
79
|
+
options = {}
|
|
63
80
|
|
|
64
|
-
if Hash === `item.attributes`
|
|
65
|
-
|
|
66
|
-
end
|
|
81
|
+
options[:attrs] = `item.attributes` if Hash === `item.attributes`
|
|
82
|
+
options[:classes] = `item.class_names`
|
|
67
83
|
|
|
68
|
-
`item.
|
|
69
|
-
dom.add_class value
|
|
70
|
-
}
|
|
84
|
+
dom = b.document.create_element(`item.name`, **options)
|
|
71
85
|
|
|
72
86
|
if on = `item.on || nil`
|
|
73
87
|
on.each {|args, block|
|
|
@@ -1,34 +1,13 @@
|
|
|
1
|
-
require 'browser/location'
|
|
2
|
-
|
|
3
1
|
module Browser; module DOM
|
|
4
2
|
|
|
5
3
|
class Document < Element
|
|
6
|
-
|
|
7
|
-
if ns = options[:namespace]
|
|
8
|
-
DOM(`#@native.createElementNS(#{ns}, #{name})`)
|
|
9
|
-
else
|
|
10
|
-
DOM(`#@native.createElement(name)`)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
if Browser.supports? 'Document.view'
|
|
15
|
-
def window
|
|
16
|
-
Window.new(`#@native.defaultView`)
|
|
17
|
-
end
|
|
18
|
-
elsif Browser.supports? 'Document.window'
|
|
19
|
-
def window
|
|
20
|
-
Window.new(`#@native.parentWindow`)
|
|
21
|
-
end
|
|
22
|
-
else
|
|
23
|
-
def window
|
|
24
|
-
raise NotImplementedError, 'window from document unsupported'
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def create_text(content)
|
|
29
|
-
DOM(`#@native.createTextNode(#{content})`)
|
|
30
|
-
end
|
|
4
|
+
include DocumentOrShadowRoot
|
|
31
5
|
|
|
6
|
+
# Get the first element matching the given ID, CSS selector or XPath.
|
|
7
|
+
#
|
|
8
|
+
# @param what [String] ID, CSS selector or XPath
|
|
9
|
+
#
|
|
10
|
+
# @return [Element?] the first matching element
|
|
32
11
|
def [](what)
|
|
33
12
|
%x{
|
|
34
13
|
var result = #@native.getElementById(what);
|
|
@@ -43,42 +22,195 @@ class Document < Element
|
|
|
43
22
|
|
|
44
23
|
alias at []
|
|
45
24
|
|
|
25
|
+
# @!attribute [r] body
|
|
26
|
+
# @return [Element?] the body element of the document
|
|
27
|
+
def body
|
|
28
|
+
DOM(`#@native.body`)
|
|
29
|
+
rescue ArgumentError
|
|
30
|
+
raise '$document.body is not defined; try to wrap your code in $document.ready{}'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Create a new element for the document.
|
|
34
|
+
#
|
|
35
|
+
# @param name [String] the node name
|
|
36
|
+
# @param builder [Browser::DOM::Builder] optional builder to append element to
|
|
37
|
+
# @param options [String] :namespace optional namespace name
|
|
38
|
+
# @param options [String] :is optional WebComponents is parameter
|
|
39
|
+
# @param options [String] :id optional id to set
|
|
40
|
+
# @param options [Array<String>] :classes optional classes to set
|
|
41
|
+
# @param options [Hash] :attrs optional attributes to set
|
|
42
|
+
#
|
|
43
|
+
# @return [Element]
|
|
44
|
+
def create_element(name, builder=nil, **options, &block)
|
|
45
|
+
opts = {}
|
|
46
|
+
|
|
47
|
+
if options[:is] ||= (options.dig(:attrs, :is))
|
|
48
|
+
opts[:is] = options[:is]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if ns = options[:namespace]
|
|
52
|
+
elem = `#@native.createElementNS(#{ns}, #{name}, #{opts.to_n})`
|
|
53
|
+
else
|
|
54
|
+
elem = `#@native.createElement(name, #{opts.to_n})`
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if options[:classes]
|
|
58
|
+
`#{elem}.className = #{Array(options[:classes]).join(" ")}`
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if options[:id]
|
|
62
|
+
`#{elem}.id = #{options[:id]}`
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
if options[:attrs]
|
|
66
|
+
options[:attrs].each do |k,v|
|
|
67
|
+
next unless v
|
|
68
|
+
`#{elem}.setAttribute(#{k}, #{v})`
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
dom = DOM(elem)
|
|
73
|
+
|
|
74
|
+
if block_given?
|
|
75
|
+
dom.inner_dom(builder, &block)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
if builder
|
|
79
|
+
builder << dom
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
dom
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Create a new document fragment.
|
|
86
|
+
#
|
|
87
|
+
# @return [DocumentFragment]
|
|
88
|
+
def create_document_fragment
|
|
89
|
+
DOM(`#@native.createDocumentFragment()`)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Create a new text node for the document.
|
|
93
|
+
#
|
|
94
|
+
# @param content [String] the text content
|
|
95
|
+
#
|
|
96
|
+
# @return [Text]
|
|
97
|
+
def create_text(content)
|
|
98
|
+
DOM(`#@native.createTextNode(#{content})`)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Create a new comment node for the document.
|
|
102
|
+
#
|
|
103
|
+
# @param content [String] the comment content
|
|
104
|
+
#
|
|
105
|
+
# @return [Comment]
|
|
106
|
+
def create_comment(content)
|
|
107
|
+
DOM(`#@native.createComment(#{content})`)
|
|
108
|
+
end
|
|
109
|
+
|
|
46
110
|
def document
|
|
47
111
|
self
|
|
48
112
|
end
|
|
49
113
|
|
|
114
|
+
# @!attribute [r] head
|
|
115
|
+
# @return [Element?] the head element of the document
|
|
116
|
+
def head
|
|
117
|
+
DOM(`#@native.getElementsByTagName("head")[0]`)
|
|
118
|
+
end
|
|
119
|
+
|
|
50
120
|
def inspect
|
|
51
|
-
"#<DOM::Document
|
|
121
|
+
"#<DOM::Document>"
|
|
52
122
|
end
|
|
53
123
|
|
|
54
|
-
|
|
55
|
-
|
|
124
|
+
if Browser.supports? 'Event.addListener'
|
|
125
|
+
def ready(&block)
|
|
126
|
+
raise ArgumentError, 'no block given' unless block
|
|
127
|
+
|
|
128
|
+
return block.call if ready?
|
|
129
|
+
|
|
130
|
+
on 'dom:load' do |e|
|
|
131
|
+
e.off
|
|
132
|
+
|
|
133
|
+
block.call
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
elsif Browser.supports? 'Event.attach'
|
|
137
|
+
def ready(&block)
|
|
138
|
+
raise ArgumentError, 'no block given' unless block
|
|
139
|
+
|
|
140
|
+
return block.call if ready?
|
|
141
|
+
|
|
142
|
+
on 'ready:state:change' do |e|
|
|
143
|
+
if ready?
|
|
144
|
+
e.off
|
|
145
|
+
|
|
146
|
+
block.call
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
else
|
|
151
|
+
# Wait for the document to be ready and call the block.
|
|
152
|
+
def ready(&block)
|
|
153
|
+
raise NotImplementedError, 'document ready unsupported'
|
|
154
|
+
end
|
|
56
155
|
end
|
|
57
156
|
|
|
58
|
-
|
|
59
|
-
|
|
157
|
+
# Check if the document is ready.
|
|
158
|
+
def ready?
|
|
159
|
+
`#@native.readyState === "complete" || #@native.readyState === "interactive"`
|
|
60
160
|
end
|
|
61
161
|
|
|
162
|
+
# @!attribute referrer
|
|
163
|
+
# @return [String] the referring document, or empty string if direct access
|
|
164
|
+
def referrer
|
|
165
|
+
`#@native.referrer`
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# @!attribute root
|
|
169
|
+
# @return [Element?] the root element of the document
|
|
62
170
|
def root
|
|
63
171
|
DOM(`#@native.documentElement`)
|
|
64
172
|
end
|
|
65
173
|
|
|
66
|
-
def
|
|
67
|
-
|
|
174
|
+
def root=(element)
|
|
175
|
+
`#@native.documentElement = #{Native.convert(element)}`
|
|
68
176
|
end
|
|
69
177
|
|
|
70
|
-
|
|
71
|
-
|
|
178
|
+
# @!attribute title
|
|
179
|
+
# @return [String] the document title
|
|
180
|
+
def title
|
|
181
|
+
`#@native.title`
|
|
72
182
|
end
|
|
73
183
|
|
|
74
|
-
def
|
|
75
|
-
|
|
76
|
-
CSS::StyleSheet.new(e)
|
|
77
|
-
}
|
|
184
|
+
def title=(value)
|
|
185
|
+
`#@native.title = value`
|
|
78
186
|
end
|
|
79
187
|
|
|
80
|
-
|
|
81
|
-
|
|
188
|
+
# @!attribute [r] hidden?
|
|
189
|
+
# @return [Boolean] is the page considered hidden?
|
|
190
|
+
def hidden?
|
|
191
|
+
`#@native.hidden`
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# @!attribute [r] visibility
|
|
195
|
+
# @return [String] the visibility state of the document - prerender, hidden or visible
|
|
196
|
+
def visibility
|
|
197
|
+
`#@native.visibilityState`
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
if Browser.supports? 'Document.view'
|
|
201
|
+
def window
|
|
202
|
+
Window.new(`#@native.defaultView`)
|
|
203
|
+
end
|
|
204
|
+
elsif Browser.supports? 'Document.window'
|
|
205
|
+
def window
|
|
206
|
+
Window.new(`#@native.parentWindow`)
|
|
207
|
+
end
|
|
208
|
+
else
|
|
209
|
+
# @!attribute [r] window
|
|
210
|
+
# @return [Window] the window for the document
|
|
211
|
+
def window
|
|
212
|
+
raise NotImplementedError, 'window from document unsupported'
|
|
213
|
+
end
|
|
82
214
|
end
|
|
83
215
|
end
|
|
84
216
|
|
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
module Browser; module DOM
|
|
2
2
|
|
|
3
|
+
# TODO: DocumentFragment is not a subclass of Element, but
|
|
4
|
+
# a subclass of Node. It implements a ParentNode.
|
|
5
|
+
#
|
|
6
|
+
# @see https://github.com/opal/opal-browser/pull/46
|
|
3
7
|
class DocumentFragment < Element
|
|
8
|
+
def self.new(node)
|
|
9
|
+
if self == DocumentFragment
|
|
10
|
+
if defined? `#{node}.mode`
|
|
11
|
+
ShadowRoot.new(node)
|
|
12
|
+
else
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
else
|
|
16
|
+
super
|
|
17
|
+
end
|
|
18
|
+
end
|
|
4
19
|
|
|
20
|
+
def self.create
|
|
21
|
+
$document.create_document_fragment
|
|
22
|
+
end
|
|
5
23
|
end
|
|
6
24
|
|
|
7
25
|
end; end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Browser; module DOM
|
|
2
|
+
|
|
3
|
+
# Document and ShadowRoot have some methods and properties in common.
|
|
4
|
+
# This solution mimics how it's done in DOM.
|
|
5
|
+
#
|
|
6
|
+
# @see https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot
|
|
7
|
+
module DocumentOrShadowRoot
|
|
8
|
+
# @!attribute [r] style_sheets
|
|
9
|
+
# @return [Array<CSS::StyleSheet>] the style sheets for the document
|
|
10
|
+
def style_sheets
|
|
11
|
+
Native::Array.new(`#@native.styleSheets`) {|e|
|
|
12
|
+
CSS::StyleSheet.new(e)
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
alias stylesheets style_sheets
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end; end
|