bowser 0.4.3 → 0.5.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/.travis.yml +4 -9
- data/CHANGELOG.md +7 -0
- data/lib/bowser/version.rb +1 -1
- data/opal/bowser.rb +0 -3
- data/opal/bowser/delegate_native.rb +9 -1
- data/opal/bowser/document.rb +8 -0
- data/opal/bowser/element.rb +57 -4
- data/opal/bowser/event.rb +30 -0
- data/opal/bowser/event_target.rb +10 -0
- data/opal/bowser/file_list.rb +25 -0
- data/opal/bowser/http.rb +30 -0
- data/opal/bowser/http/form_data.rb +4 -0
- data/opal/bowser/http/request.rb +19 -0
- data/opal/bowser/http/response.rb +8 -0
- data/opal/bowser/indexed_db.rb +244 -0
- data/opal/bowser/service_worker.rb +43 -0
- data/opal/bowser/service_worker/cache_storage.rb +49 -0
- data/opal/bowser/service_worker/clients.rb +19 -0
- data/opal/bowser/service_worker/context.rb +71 -0
- data/opal/bowser/service_worker/extendable_event.rb +19 -0
- data/opal/bowser/service_worker/fetch_event.rb +28 -0
- data/opal/bowser/service_worker/promise.rb +101 -0
- data/opal/bowser/service_worker/request.rb +33 -0
- data/opal/bowser/service_worker/response.rb +41 -0
- data/opal/bowser/websocket.rb +18 -0
- data/opal/bowser/window.rb +28 -0
- metadata +13 -3
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'bowser/service_worker/response'
|
2
|
+
require 'bowser/service_worker/promise'
|
3
|
+
|
4
|
+
module Bowser
|
5
|
+
module ServiceWorker
|
6
|
+
class CacheStorage
|
7
|
+
def initialize
|
8
|
+
@native = `caches`
|
9
|
+
end
|
10
|
+
|
11
|
+
def match request, options={}
|
12
|
+
Promise.from_native(`
|
13
|
+
#@native.match(#{request.to_n}, #{options.to_n})
|
14
|
+
.then(#{proc { |value| value && Response.from_native(value) }})
|
15
|
+
`)
|
16
|
+
end
|
17
|
+
|
18
|
+
def has name
|
19
|
+
Promise.from_native(`#@native.has(name)`)
|
20
|
+
end
|
21
|
+
|
22
|
+
def open name
|
23
|
+
Promise.from_native(`
|
24
|
+
#@native.open(name)
|
25
|
+
.then(#{proc { |native| Cache.new(native) }})
|
26
|
+
.catch(#{proc { |native| `console.error(native)` }})
|
27
|
+
`)
|
28
|
+
end
|
29
|
+
|
30
|
+
class Cache
|
31
|
+
def initialize native
|
32
|
+
@native = native
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_all requests
|
36
|
+
Promise.from_native(`#@native.addAll(#{requests.map(&:to_n)})`)
|
37
|
+
end
|
38
|
+
|
39
|
+
def put request, response
|
40
|
+
Promise.from_native(`#@native.put(#{request.to_n}, #{response.to_n})`)
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_n
|
44
|
+
@native
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bowser/service_worker/promise'
|
2
|
+
|
3
|
+
module Bowser
|
4
|
+
module ServiceWorker
|
5
|
+
class Clients
|
6
|
+
def initialize native
|
7
|
+
@native = native
|
8
|
+
end
|
9
|
+
|
10
|
+
def claim
|
11
|
+
Promise.from_native(`#@native.claim()`)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_n
|
15
|
+
@native
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'opal'
|
2
|
+
require 'native'
|
3
|
+
require 'bowser/service_worker/extendable_event'
|
4
|
+
require 'bowser/service_worker/fetch_event'
|
5
|
+
require 'bowser/service_worker/cache_storage'
|
6
|
+
require 'bowser/service_worker/request'
|
7
|
+
require 'bowser/service_worker/response'
|
8
|
+
require 'bowser/service_worker/promise'
|
9
|
+
require 'bowser/service_worker/clients'
|
10
|
+
|
11
|
+
# Opal uses `self` internally, but we can use `this` to get the worker reference
|
12
|
+
%x{ var worker = this; }
|
13
|
+
|
14
|
+
module Bowser
|
15
|
+
module ServiceWorker
|
16
|
+
class Context
|
17
|
+
def initialize native
|
18
|
+
@native = native
|
19
|
+
end
|
20
|
+
|
21
|
+
def on event_name, &block
|
22
|
+
event_type = EVENT_TYPES.fetch(event_name) { ExtendableEvent }
|
23
|
+
handler = proc { |event| block.call(event_type.new(event)) }
|
24
|
+
|
25
|
+
%x{#@native.addEventListener(event_name, handler);}
|
26
|
+
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_n
|
31
|
+
@native
|
32
|
+
end
|
33
|
+
|
34
|
+
def caches
|
35
|
+
@caches ||= CacheStorage.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def fetch url
|
39
|
+
Promise.new do |promise|
|
40
|
+
%x{
|
41
|
+
fetch(#{url.to_n})
|
42
|
+
.then(#{proc { |response|
|
43
|
+
promise.resolve Response.from_native(response)
|
44
|
+
}})
|
45
|
+
.catch(#{proc { |error| promise.reject error }})
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def skip_waiting
|
51
|
+
Promise.from_native(`#{to_n}.skipWaiting()`)
|
52
|
+
end
|
53
|
+
|
54
|
+
def clients
|
55
|
+
@clients ||= Clients.new(`#{to_n}.clients`)
|
56
|
+
end
|
57
|
+
|
58
|
+
EVENT_TYPES = {
|
59
|
+
fetch: FetchEvent,
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.worker
|
66
|
+
Bowser::ServiceWorker::Context.new(`worker`)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.method_missing(*args, &block)
|
70
|
+
worker.send(*args, &block)
|
71
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Bowser
|
2
|
+
module ServiceWorker
|
3
|
+
class ExtendableEvent
|
4
|
+
def initialize native
|
5
|
+
@native = native
|
6
|
+
end
|
7
|
+
|
8
|
+
def wait_until promise
|
9
|
+
`#@native.waitUntil(#{promise.to_n})`
|
10
|
+
|
11
|
+
promise
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_n
|
15
|
+
@native
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'bowser/service_worker/request'
|
2
|
+
require 'bowser/service_worker/extendable_event'
|
3
|
+
|
4
|
+
module Bowser
|
5
|
+
module ServiceWorker
|
6
|
+
class FetchEvent < ExtendableEvent
|
7
|
+
def url
|
8
|
+
`#@native.request.url`
|
9
|
+
end
|
10
|
+
|
11
|
+
def reload?
|
12
|
+
`#@native.isReload`
|
13
|
+
end
|
14
|
+
|
15
|
+
def client_id
|
16
|
+
`#@native.clientId`
|
17
|
+
end
|
18
|
+
|
19
|
+
def request
|
20
|
+
@request ||= Request.from_native(`#@native.request`)
|
21
|
+
end
|
22
|
+
|
23
|
+
def respond_with promise
|
24
|
+
`#@native.respondWith(#{promise.then(&:to_n).to_n})`
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Bowser
|
2
|
+
module ServiceWorker
|
3
|
+
class Promise
|
4
|
+
attr_reader :value, :failure
|
5
|
+
|
6
|
+
def initialize &block
|
7
|
+
@native = `new Promise(function(resolve, reject) {
|
8
|
+
#{@resolve = `resolve`};
|
9
|
+
#{@reject = `reject`};
|
10
|
+
#{block.call(self) if block_given?};
|
11
|
+
})`
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.from_native promise
|
15
|
+
p = allocate
|
16
|
+
p.instance_exec { @native = promise }
|
17
|
+
p
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.all promises
|
21
|
+
from_native `Promise.all(#{promises.map(&:to_n)})`
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.race promises
|
25
|
+
from_native `Promise.race(#{promises.map(&:to_n)})`
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.reject reason
|
29
|
+
new.reject reason
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.resolve value
|
33
|
+
new.resolve value
|
34
|
+
end
|
35
|
+
|
36
|
+
def then &block
|
37
|
+
Promise.from_native `#@native.then(block)`
|
38
|
+
end
|
39
|
+
|
40
|
+
def fail &block
|
41
|
+
Promise.from_native `#@native.catch(block)`
|
42
|
+
end
|
43
|
+
|
44
|
+
def always &block
|
45
|
+
Promise.from_native `#@native.then(block).fail(block)`
|
46
|
+
end
|
47
|
+
|
48
|
+
def resolve value
|
49
|
+
return self if resolved?
|
50
|
+
if rejected?
|
51
|
+
`console.warn(#{self}, #{"tried to resolve, already #{resolved? ? 'resolved' : 'rejected'} with"}, #{@value || @failure})`
|
52
|
+
end
|
53
|
+
|
54
|
+
@value = value
|
55
|
+
@resolve.call value
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def reject failure
|
60
|
+
return self if rejected?
|
61
|
+
if resolved?
|
62
|
+
`console.warn(#{self}, #{"tried to reject, already #{resolved? ? 'resolved' : 'rejected'} with"}, #{@value || @failure})`
|
63
|
+
end
|
64
|
+
|
65
|
+
@failure = failure
|
66
|
+
@reject.call failure
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def realized?
|
71
|
+
resolved? || rejected?
|
72
|
+
end
|
73
|
+
|
74
|
+
def resolved?
|
75
|
+
!value.nil?
|
76
|
+
end
|
77
|
+
|
78
|
+
def rejected?
|
79
|
+
!failure.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_n
|
83
|
+
@native
|
84
|
+
end
|
85
|
+
|
86
|
+
%x{
|
87
|
+
Opal.defn(self, 'then', function(callback) {
|
88
|
+
var self = this;
|
89
|
+
|
90
|
+
#{self.then(&`callback`)};
|
91
|
+
});
|
92
|
+
|
93
|
+
Opal.defn(self, 'catch', function(callback) {
|
94
|
+
var self = this;
|
95
|
+
|
96
|
+
#{self.fail(&`callback`)};
|
97
|
+
});
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Bowser
|
2
|
+
module ServiceWorker
|
3
|
+
class Request
|
4
|
+
def initialize url, options={}
|
5
|
+
@url = url
|
6
|
+
@options = options
|
7
|
+
@native = `new Request(url, #{options.to_n})`
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.from_native native
|
11
|
+
request = allocate
|
12
|
+
request.instance_exec { @native = native }
|
13
|
+
request
|
14
|
+
end
|
15
|
+
|
16
|
+
def inspect
|
17
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)} @url=#{url.inspect}>"
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
inspect
|
22
|
+
end
|
23
|
+
|
24
|
+
def url
|
25
|
+
@url || `#@native.url`
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_n
|
29
|
+
@native
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Bowser
|
2
|
+
module ServiceWorker
|
3
|
+
class Response
|
4
|
+
def self.from_native native
|
5
|
+
new(native) if `#{native} != null`
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize native
|
9
|
+
@native = native
|
10
|
+
end
|
11
|
+
|
12
|
+
def json
|
13
|
+
@json ||= `#@native.json()`
|
14
|
+
end
|
15
|
+
|
16
|
+
def text
|
17
|
+
@text ||= `#@native.text()`
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_n
|
21
|
+
@native
|
22
|
+
end
|
23
|
+
|
24
|
+
def url
|
25
|
+
`#@native.url`
|
26
|
+
end
|
27
|
+
|
28
|
+
def status
|
29
|
+
`#@native.status`
|
30
|
+
end
|
31
|
+
|
32
|
+
def inspect
|
33
|
+
"#<#{self.class.name}:0x#{(object_id * 2).to_s(16)} @url=#{url.inspect} @status=#{status.inspect}>"
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
inspect
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/opal/bowser/websocket.rb
CHANGED
@@ -2,6 +2,7 @@ require 'bowser/window'
|
|
2
2
|
require 'json'
|
3
3
|
|
4
4
|
module Bowser
|
5
|
+
# A Ruby WebSocket class
|
5
6
|
class WebSocket
|
6
7
|
EVENT_NAMES = %w(
|
7
8
|
open
|
@@ -10,6 +11,8 @@ module Bowser
|
|
10
11
|
close
|
11
12
|
)
|
12
13
|
|
14
|
+
# param url [String] the URL to connect to
|
15
|
+
# keywordparam native [JS] the native WebSocket connection
|
13
16
|
def initialize url, native: `new WebSocket(url)`
|
14
17
|
@url = url
|
15
18
|
@native = native
|
@@ -20,6 +23,9 @@ module Bowser
|
|
20
23
|
on(:close) { @connected = false }
|
21
24
|
end
|
22
25
|
|
26
|
+
# Attach the given block as a handler for the specified event
|
27
|
+
#
|
28
|
+
# @param event_target [String] the name of the event to handle
|
23
29
|
def on event_name, &block
|
24
30
|
if EVENT_NAMES.include? event_name
|
25
31
|
@handlers[event_name] << block
|
@@ -28,16 +34,23 @@ module Bowser
|
|
28
34
|
end
|
29
35
|
end
|
30
36
|
|
37
|
+
# Send the given message across the connection
|
38
|
+
#
|
39
|
+
# @param msg [Hash, Array] the message to send. Should be a JSON-serializable structure.
|
31
40
|
def send_message msg
|
32
41
|
`#@native.send(#{JSON.dump(msg)})`
|
33
42
|
self
|
34
43
|
end
|
35
44
|
|
45
|
+
# @return [Boolean] true if this socket is connected, false otherwise
|
36
46
|
def connected?
|
37
47
|
@connected
|
38
48
|
end
|
39
49
|
|
40
50
|
# Reconnect the websocket after a short delay if it is interrupted
|
51
|
+
#
|
52
|
+
# @keywordparam delay [Numeric] the number of seconds to wait before
|
53
|
+
# reconnecting. Defaults to 1 second.
|
41
54
|
def autoreconnect!(delay: 1)
|
42
55
|
return if @autoreconnect
|
43
56
|
@autoreconnect = true
|
@@ -47,6 +60,9 @@ module Bowser
|
|
47
60
|
end
|
48
61
|
end
|
49
62
|
|
63
|
+
# Close the current connection
|
64
|
+
#
|
65
|
+
# @param reason [String, nil] the reason this socket is being closed
|
50
66
|
def close reason=`undefined`
|
51
67
|
`#@native.close(reason)`
|
52
68
|
end
|
@@ -113,6 +129,8 @@ module Bowser
|
|
113
129
|
|
114
130
|
module_function
|
115
131
|
|
132
|
+
# @param url [String] the URL to connect to
|
133
|
+
# @return [Bowser::WebSocket] a websocket connection to the given URL
|
116
134
|
def websocket *args
|
117
135
|
WebSocket.new(*args)
|
118
136
|
end
|
data/opal/bowser/window.rb
CHANGED
@@ -11,6 +11,9 @@ module Bowser
|
|
11
11
|
module_function
|
12
12
|
|
13
13
|
if `#@native.requestAnimationFrame !== undefined`
|
14
|
+
# Add the given block to the current iteration of the event loop. If this
|
15
|
+
# is called from another `animation_frame` call, the block is run in the
|
16
|
+
# following iteration of the event loop.
|
14
17
|
def animation_frame &block
|
15
18
|
`requestAnimationFrame(function() { #{block.call} })`
|
16
19
|
self
|
@@ -22,60 +25,84 @@ module Bowser
|
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
28
|
+
# Run the given block after the specified number of seconds has passed.
|
29
|
+
#
|
30
|
+
# @param duration [Numeric] the number of seconds to wait
|
25
31
|
def delay duration, &block
|
26
32
|
`setTimeout(function() { #{block.call} }, duration * 1000)`
|
27
33
|
self
|
28
34
|
end
|
29
35
|
|
36
|
+
# Run the given block every `duration` seconds
|
37
|
+
#
|
38
|
+
# @param duration [Numeric] the number of seconds between runs
|
30
39
|
def interval duration, &block
|
31
40
|
`setInterval(function() { #{block.call} }, duration * 1000)`
|
32
41
|
self
|
33
42
|
end
|
34
43
|
|
44
|
+
# @return [Location] the browser's Location object
|
35
45
|
def location
|
36
46
|
Location
|
37
47
|
end
|
38
48
|
|
49
|
+
# Scroll to the specified (x,y) coordinates
|
39
50
|
def scroll x, y
|
40
51
|
`window.scrollTo(x, y)`
|
41
52
|
end
|
42
53
|
|
54
|
+
# Wrapper for the browser's Location object
|
43
55
|
module Location
|
44
56
|
module_function
|
45
57
|
|
58
|
+
# The "hash" of the current URL
|
46
59
|
def hash
|
47
60
|
`window.location.hash`
|
48
61
|
end
|
49
62
|
|
63
|
+
# Set the hash of the URL
|
64
|
+
#
|
65
|
+
# @param hash [String] the new value of the URL hash
|
50
66
|
def hash= hash
|
51
67
|
`window.location.hash = hash`
|
52
68
|
end
|
53
69
|
|
70
|
+
# The path of the current URL
|
54
71
|
def path
|
55
72
|
`window.location.pathname`
|
56
73
|
end
|
57
74
|
|
75
|
+
# The full current URL
|
58
76
|
def href
|
59
77
|
`window.location.href`
|
60
78
|
end
|
61
79
|
|
80
|
+
# Set the current URL
|
81
|
+
#
|
82
|
+
# @param href [String] the URL to navigate to
|
62
83
|
def href= href
|
63
84
|
`window.location.href = href`
|
64
85
|
end
|
65
86
|
end
|
66
87
|
|
88
|
+
# The browser's history object
|
67
89
|
module History
|
68
90
|
module_function
|
69
91
|
|
92
|
+
# @return [Boolean] true if the browser supports pushState, false otherwise
|
70
93
|
def has_push_state?
|
71
94
|
`!!window.history.pushState`
|
72
95
|
end
|
73
96
|
|
97
|
+
# Navigate to the specified path without triggering a full page reload
|
98
|
+
#
|
99
|
+
# @param path [String] the path to navigate to
|
74
100
|
def push path
|
75
101
|
`window.history.pushState({}, '', path)`
|
76
102
|
end
|
77
103
|
end
|
78
104
|
|
105
|
+
# return [History] the browser's History object
|
79
106
|
def history
|
80
107
|
History
|
81
108
|
end
|
@@ -83,6 +110,7 @@ module Bowser
|
|
83
110
|
|
84
111
|
module_function
|
85
112
|
|
113
|
+
# return [Window] the browser's Window object
|
86
114
|
def window
|
87
115
|
Window
|
88
116
|
end
|