bowser 0.5.4 → 1.0.0
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 +4 -4
- data/.rspec +1 -0
- data/Gemfile +3 -0
- data/README.md +16 -6
- data/bin/console +2 -2
- data/bowser.gemspec +1 -0
- data/lib/bowser/version.rb +1 -1
- data/opal/bowser/element.rb +3 -2
- data/opal/bowser/file_list.rb +1 -1
- data/opal/bowser/geolocation.rb +1 -1
- data/opal/bowser/http.rb +1 -3
- data/opal/bowser/indexed_db.rb +42 -22
- data/opal/bowser/promise.rb +166 -0
- data/opal/bowser/service_worker.rb +1 -1
- data/opal/bowser/window.rb +19 -7
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68cdf98fa8eacbad1336d1a69623d7cc5eeec542f8444e8b3ddc5dde76881abc
|
4
|
+
data.tar.gz: 9bf407b1709c4495a9b67dee92bba52877ea403b875dbaea3c485c7d70607304
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e001a975cd34a1dedab2dae89e6f83f0c3e0d92d9d1b7f316d9953d7ced53efae81b8b23e6f40ccb542f26a8358db5f3792bd91b689d03ae523401023124d10a
|
7
|
+
data.tar.gz: e57b4be10b4009cd1548190c02642182763978e87832688e4daaa3be60883a7742007fec341ecd76950d48ec634727b14e922175dd2bc239e90701ac05cd5a72
|
data/.rspec
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -29,24 +29,34 @@ Bowser.document # Handle to the current document
|
|
29
29
|
Bowser.window # Handle to the current window
|
30
30
|
```
|
31
31
|
|
32
|
-
###
|
32
|
+
### HTTP support
|
33
33
|
|
34
|
-
To
|
34
|
+
To load HTTP support, require it by running:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
require 'bowser/http'
|
38
|
+
```
|
39
|
+
|
40
|
+
To make HTTP requests to your API, you can use `Bowser::HTTP.fetch`:
|
35
41
|
|
36
42
|
```ruby
|
37
43
|
Bowser::HTTP.fetch('/api/things')
|
38
44
|
```
|
39
45
|
|
40
|
-
It returns a `Promise
|
46
|
+
It returns a [`Bowser::Promise`](https://github.com/clearwater-rb/bowser/blob/master/opal/bowser/promise.rb), on which you can call `then` or `catch` in order to execute a block of code based on success or failure, respectively.
|
41
47
|
|
42
48
|
```ruby
|
43
49
|
Bowser::HTTP.fetch(url)
|
50
|
+
.then(&:json) # JSONify the response
|
44
51
|
.then { |response| do_something_with(response.json) }
|
45
|
-
.
|
46
|
-
.always { log "Fetched #{url}" }
|
52
|
+
.catch { |exception| warn exception.message }
|
47
53
|
```
|
48
54
|
|
49
|
-
The
|
55
|
+
To make `POST` requests, you can pass the `method` keyword argument. The body of the post is represented in the `data` keyword argument. This is in contrast to the ES6 `fetch` function, which uses `body`, but requires a string. The `data` argument lets you pass in a string or a hash, which will be converted to JSON:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
Bowser::HTTP.fetch(url, method: :post, data: { name: 'Bowser' })
|
59
|
+
```
|
50
60
|
|
51
61
|
## Contributing
|
52
62
|
|
data/bin/console
CHANGED
data/bowser.gemspec
CHANGED
data/lib/bowser/version.rb
CHANGED
data/opal/bowser/element.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'bowser/event_target'
|
2
|
-
require 'bowser/file_list'
|
3
2
|
require 'bowser/delegate_native'
|
4
|
-
require 'bowser/iterable'
|
5
3
|
|
6
4
|
module Bowser
|
5
|
+
autoload :FileList, 'bowser/file_list'
|
6
|
+
autoload :Iterable, 'bowser/iterable'
|
7
|
+
|
7
8
|
# Wrap a native DOM element
|
8
9
|
class Element
|
9
10
|
include EventTarget
|
data/opal/bowser/file_list.rb
CHANGED
data/opal/bowser/geolocation.rb
CHANGED
data/opal/bowser/http.rb
CHANGED
data/opal/bowser/indexed_db.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'bowser/event_target'
|
2
|
-
require 'promise'
|
2
|
+
require 'bowser/promise'
|
3
3
|
|
4
4
|
module Bowser
|
5
5
|
class IndexedDB
|
@@ -20,18 +20,17 @@ module Bowser
|
|
20
20
|
end
|
21
21
|
request.on :success do |event|
|
22
22
|
@native = event.target.result
|
23
|
+
@open = true
|
23
24
|
|
24
25
|
@thens.each(&:call)
|
25
|
-
@thens
|
26
|
+
@thens = []
|
26
27
|
end
|
27
28
|
|
28
29
|
request.on :upgradeneeded do |event|
|
29
|
-
puts 'upgradeneeded'
|
30
30
|
@native = event.target.result
|
31
31
|
|
32
32
|
if block_given?
|
33
33
|
yield self
|
34
|
-
puts 'upgraded'
|
35
34
|
else
|
36
35
|
raise ArgumentError, "You must provide a block to `#{self.class}.new` in order to set up the database if the user's browser does not have it."
|
37
36
|
end
|
@@ -49,15 +48,33 @@ module Bowser
|
|
49
48
|
# is the end state we want after this method call anyway.
|
50
49
|
end
|
51
50
|
|
51
|
+
def [] store
|
52
|
+
transaction(store).object_store(store)
|
53
|
+
end
|
54
|
+
|
55
|
+
def put **things # TODO: Come up with a less terrible name
|
56
|
+
things.each do |store_name, records|
|
57
|
+
transaction(store_name, :readwrite)
|
58
|
+
.object_store(store_name)
|
59
|
+
.tap do |store|
|
60
|
+
records.each do |record|
|
61
|
+
store.put record
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
52
67
|
def transaction name, mode=:readonly
|
53
68
|
Transaction.new(`#@native.transaction(#{name}, #{mode})`)
|
54
69
|
end
|
55
70
|
|
56
71
|
def then &block
|
57
|
-
if @
|
58
|
-
block.call
|
72
|
+
if @open
|
73
|
+
Promise.resolve block.call
|
59
74
|
else
|
60
|
-
|
75
|
+
Promise.new do |p|
|
76
|
+
@thens << proc { p.resolve block.call }
|
77
|
+
end
|
61
78
|
end
|
62
79
|
end
|
63
80
|
|
@@ -111,22 +128,25 @@ module Bowser
|
|
111
128
|
p
|
112
129
|
end
|
113
130
|
|
114
|
-
def get_all klass, count:
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
131
|
+
def get_all klass, count: nil, index: nil
|
132
|
+
Promise.new do |p|
|
133
|
+
query = block_given? ? yield(Query.new) : `undefined`
|
134
|
+
|
135
|
+
request = if index
|
136
|
+
index(index).get_all(klass, count: count)
|
137
|
+
else
|
138
|
+
Request.new(`#@native.getAll(#{query}, #{count || `undefined`})`)
|
139
|
+
end
|
140
|
+
request.on :success do |event|
|
141
|
+
p.resolve event.target.result.map { |js_obj|
|
142
|
+
`delete #{js_obj}.$$id` # Remove old Ruby runtime metadata
|
143
|
+
`Object.assign(#{klass.allocate}, #{js_obj})`
|
144
|
+
}
|
145
|
+
end
|
146
|
+
request.on :error do |event|
|
147
|
+
p.reject event.target.result
|
148
|
+
end
|
127
149
|
end
|
128
|
-
|
129
|
-
p
|
130
150
|
end
|
131
151
|
|
132
152
|
def index name
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module Bowser
|
2
|
+
class Promise
|
3
|
+
attr_reader :value
|
4
|
+
|
5
|
+
def self.race promises
|
6
|
+
new do |promise|
|
7
|
+
promises.each do |p|
|
8
|
+
p.then { |value| promise.resolve value }
|
9
|
+
p.catch { |reason| promise.reject reason }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.all promises
|
15
|
+
new do |promise|
|
16
|
+
promises.each do |p|
|
17
|
+
p.then do |value|
|
18
|
+
promise.resolve promises.map(&:value) if promises.all?(&:resolved?)
|
19
|
+
end
|
20
|
+
|
21
|
+
p.catch { |reason| promise.reject reason }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.resolve value=nil
|
27
|
+
new { |p| p.resolve value }
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.reject value
|
31
|
+
new { |p| p.reject value }
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
@callbacks = []
|
36
|
+
|
37
|
+
yield self if block_given?
|
38
|
+
end
|
39
|
+
|
40
|
+
def then &block
|
41
|
+
self.class.new do |p|
|
42
|
+
callback = SuccessCallback.new(p, block)
|
43
|
+
|
44
|
+
if pending?
|
45
|
+
@callbacks << callback
|
46
|
+
elsif resolved?
|
47
|
+
callback.resolve value
|
48
|
+
elsif rejected?
|
49
|
+
callback.reject value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def catch &block
|
55
|
+
self.class.new do |p|
|
56
|
+
callback = FailureCallback.new(p, block)
|
57
|
+
|
58
|
+
if pending?
|
59
|
+
@callbacks << callback
|
60
|
+
elsif resolved?
|
61
|
+
callback.resolve value
|
62
|
+
elsif rejected?
|
63
|
+
callback.reject value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def resolve value=nil
|
69
|
+
return if settled?
|
70
|
+
|
71
|
+
case value
|
72
|
+
when NativeValue
|
73
|
+
resolve_value value
|
74
|
+
when self
|
75
|
+
reject TypeError.new('Cannot resolve a promise with itself')
|
76
|
+
when Promise
|
77
|
+
value
|
78
|
+
.then { |v| resolve v }
|
79
|
+
.catch { |v| reject v }
|
80
|
+
else
|
81
|
+
resolve_value value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def resolve_value value
|
86
|
+
@value = value
|
87
|
+
@state = :resolved
|
88
|
+
@callbacks.each { |callback| callback.resolve value }
|
89
|
+
@callbacks.clear
|
90
|
+
end
|
91
|
+
|
92
|
+
def reject reason
|
93
|
+
return if settled?
|
94
|
+
|
95
|
+
case value
|
96
|
+
when Promise
|
97
|
+
value.catch { |v| reject v }
|
98
|
+
else
|
99
|
+
@value = reason
|
100
|
+
@state = :rejected
|
101
|
+
@callbacks.each do |callback|
|
102
|
+
callback.reject reason
|
103
|
+
end
|
104
|
+
@callbacks.clear
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def resolved?
|
109
|
+
@state == :resolved
|
110
|
+
end
|
111
|
+
|
112
|
+
def rejected?
|
113
|
+
@state == :rejected
|
114
|
+
end
|
115
|
+
|
116
|
+
def pending?
|
117
|
+
!settled?
|
118
|
+
end
|
119
|
+
|
120
|
+
def settled?
|
121
|
+
rejected? || resolved?
|
122
|
+
end
|
123
|
+
|
124
|
+
class Callback
|
125
|
+
def initialize promise, block
|
126
|
+
@promise = promise
|
127
|
+
@block = block || proc { |value| value }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class SuccessCallback < Callback
|
132
|
+
def resolve value
|
133
|
+
@promise.resolve @block.call(value)
|
134
|
+
rescue => e
|
135
|
+
reject e
|
136
|
+
end
|
137
|
+
|
138
|
+
def reject value
|
139
|
+
@promise.reject value
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class FailureCallback < Callback
|
144
|
+
def resolve value
|
145
|
+
@promise.resolve value
|
146
|
+
end
|
147
|
+
|
148
|
+
def reject value
|
149
|
+
@promise.resolve @block.call(value)
|
150
|
+
rescue => e
|
151
|
+
@promise.reject e
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
NativeValue = Object.new.tap do |native|
|
156
|
+
# Determines whether something is a native JS value. Returns false if
|
157
|
+
# we're not running on a JS VM. Otherwise, it returns whether the value
|
158
|
+
# is a JS primitive (string, number, undefined, null) or a native JS
|
159
|
+
# object.
|
160
|
+
def native.=== value
|
161
|
+
RUBY_ENGINE == 'opal' &&
|
162
|
+
`value == null || value.$$is_string || value.$$is_number || !('$$class' in value)`
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
data/opal/bowser/window.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'bowser/delegate_native'
|
2
2
|
require 'bowser/event_target'
|
3
|
+
require 'bowser/promise'
|
3
4
|
|
4
5
|
module Bowser
|
5
6
|
module Window
|
@@ -20,17 +21,24 @@ module Bowser
|
|
20
21
|
end
|
21
22
|
else
|
22
23
|
def animation_frame &block
|
23
|
-
delay(
|
24
|
+
delay(0, &block)
|
24
25
|
self
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
|
-
# Run the given block after the specified number of seconds has passed.
|
29
|
-
#
|
30
|
-
# @param duration [Numeric] the number of seconds to wait
|
31
29
|
def delay duration, &block
|
32
|
-
|
33
|
-
|
30
|
+
Promise.new do |p|
|
31
|
+
function = proc do
|
32
|
+
begin
|
33
|
+
yield if block_given?
|
34
|
+
p.resolve
|
35
|
+
rescue => e
|
36
|
+
p.reject e
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
set_timeout duration, &block
|
41
|
+
end
|
34
42
|
end
|
35
43
|
|
36
44
|
# Run the given block every `duration` seconds
|
@@ -38,7 +46,11 @@ module Bowser
|
|
38
46
|
# @param duration [Numeric] the number of seconds between runs
|
39
47
|
def interval duration, &block
|
40
48
|
`setInterval(function() { #{block.call} }, duration * 1000)`
|
41
|
-
|
49
|
+
end
|
50
|
+
alias set_interval interval
|
51
|
+
|
52
|
+
def set_timeout duration, &block
|
53
|
+
`setTimeout(function() { #{block.call} }, duration * 1000)`
|
42
54
|
end
|
43
55
|
|
44
56
|
# @return [Location] the browser's Location object
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bowser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamie Gaskins
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: opal
|
@@ -72,6 +72,20 @@ dependencies:
|
|
72
72
|
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rspec
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
75
89
|
description:
|
76
90
|
email:
|
77
91
|
- jgaskins@gmail.com
|
@@ -109,6 +123,7 @@ files:
|
|
109
123
|
- opal/bowser/http/response.rb
|
110
124
|
- opal/bowser/indexed_db.rb
|
111
125
|
- opal/bowser/iterable.rb
|
126
|
+
- opal/bowser/promise.rb
|
112
127
|
- opal/bowser/service_worker.rb
|
113
128
|
- opal/bowser/service_worker/cache_storage.rb
|
114
129
|
- opal/bowser/service_worker/clients.rb
|
@@ -141,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
156
|
version: '0'
|
142
157
|
requirements: []
|
143
158
|
rubyforge_project:
|
144
|
-
rubygems_version: 2.7.
|
159
|
+
rubygems_version: 2.7.6
|
145
160
|
signing_key:
|
146
161
|
specification_version: 4
|
147
162
|
summary: Minimalist browser support for Opal apps
|