reactive-router 0.7.3 → 0.7.4
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/lib/reactive-router.rb +1 -0
- data/lib/reactive-router/component.rb +22 -10
- data/lib/reactive-router/history.rb +134 -0
- data/lib/reactive-router/router.rb +89 -11
- data/lib/reactive-router/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a37cfefc5d18c03f42d0302fd1e56360ab0acdf
|
4
|
+
data.tar.gz: c367a01366dca24fed30dfa4bbf332d7b6e83163
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84257330b586a80d5d958207e31f2797bf95e4ee8538c4ffd4fd1bc80f8c47b93302ef1b1eb9c10da86e6500ad5a34d90c7e2b9c60eb107cf6f523359528f157
|
7
|
+
data.tar.gz: 5d130e422da66bcbc0ed5f3bd7c89f69c312349de727086fe26ab41fdae9019c27203794cf4ccd997cc16b18ab65bb76556e3f084de4e55de8bc7c0e6c7d6b69
|
data/lib/reactive-router.rb
CHANGED
@@ -2,27 +2,39 @@ module React
|
|
2
2
|
module Component
|
3
3
|
|
4
4
|
module ClassMethods
|
5
|
-
|
5
|
+
|
6
|
+
def url_param_evaluators
|
7
|
+
@url_param_evaluators ||= {}
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :evaluated_url_params
|
11
|
+
|
6
12
|
def router_param(name, &block)
|
7
|
-
|
8
|
-
|
9
|
-
|
13
|
+
|
14
|
+
url_param_evaluators[name] = block
|
15
|
+
|
16
|
+
class << self
|
17
|
+
define_method name do
|
18
|
+
evaluated_url_params[name]
|
19
|
+
end
|
10
20
|
end
|
11
|
-
|
12
|
-
|
21
|
+
|
22
|
+
define_method name do
|
23
|
+
self.class.send(name)
|
13
24
|
end
|
25
|
+
|
14
26
|
end
|
15
|
-
|
27
|
+
|
16
28
|
end
|
17
29
|
|
18
|
-
def route_handler
|
19
|
-
Router::RR::RouteHandler()
|
30
|
+
def route_handler(*args)
|
31
|
+
Router::RR::RouteHandler(*args)
|
20
32
|
end
|
21
33
|
|
22
34
|
def link(opts = {}, &block)
|
23
35
|
opts[:params] = opts[:params].to_n if opts[:params]
|
24
36
|
Router::RR::Link(opts, &block)
|
25
37
|
end
|
26
|
-
|
38
|
+
|
27
39
|
end
|
28
40
|
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
class History
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def setup_handler
|
6
|
+
unless @handlers_setup
|
7
|
+
%x{
|
8
|
+
if (window.addEventListener) {
|
9
|
+
window.addEventListener('popstate', #{method(:window_history_pop_handler).to_n}, false);
|
10
|
+
} else {
|
11
|
+
window.attachEvent('onpopstate', #{method(:window_history_pop_handler).to_n});
|
12
|
+
}
|
13
|
+
}
|
14
|
+
end
|
15
|
+
@handlers_setup = true
|
16
|
+
end
|
17
|
+
|
18
|
+
def current_path
|
19
|
+
@current_path ||= `decodeURI(window.location.pathname + window.location.search)`
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_accessor :history
|
23
|
+
|
24
|
+
def [](name)
|
25
|
+
(@histories ||= {})[name]
|
26
|
+
end
|
27
|
+
|
28
|
+
def []=(name, value)
|
29
|
+
(@histories ||= {})[name] = value
|
30
|
+
end
|
31
|
+
|
32
|
+
def window_history_pop_handler(event)
|
33
|
+
return if `event.state === undefined`
|
34
|
+
if `event.state == null` # happens when popping off outer dialog
|
35
|
+
puts "pop handler pops off last value"
|
36
|
+
old_history = @history
|
37
|
+
@current_path = ""
|
38
|
+
@history = nil
|
39
|
+
`ReactRouter.History.length = 0`
|
40
|
+
old_history.on_state_change.call(:inactive) if old_history.on_state_change
|
41
|
+
else
|
42
|
+
puts "pop handler #{`event.state.history_id`}, #{`ReactRouter.History.length`} -> #{`event.state.history_length`}, #{`event.state.path`}"
|
43
|
+
old_history = @history
|
44
|
+
old_history_length = `ReactRouter.History.length`
|
45
|
+
@current_path = `event.state.path`
|
46
|
+
@history= History[`event.state.history_id`]
|
47
|
+
`ReactRouter.History.length = event.state.history_length`
|
48
|
+
if old_history != @history
|
49
|
+
if `ReactRouter.History.length` > old_history_length
|
50
|
+
puts "activating "
|
51
|
+
@history.on_state_change.call(:active) if @history.on_state_change
|
52
|
+
else
|
53
|
+
puts "deactivating"
|
54
|
+
old_history.on_state_change.call(:inactive) if old_history.on_state_change
|
55
|
+
end
|
56
|
+
end
|
57
|
+
@history.notify_listeners(:pop)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def push_path(path)
|
62
|
+
puts "pushing path #{path}"
|
63
|
+
`window.history.pushState({ path: path, history_id: #{@history.name}, history_length: (ReactRouter.History.length += 1)}, '', path);`
|
64
|
+
@current_path = path
|
65
|
+
@history.notify_listeners(:push)
|
66
|
+
end
|
67
|
+
|
68
|
+
def replace_path(path)
|
69
|
+
puts "replacing path #{path}"
|
70
|
+
`window.history.replaceState({ path: path, history_id: #{@history.name}, history_length: ReactRouter.History.length}, '', path);`
|
71
|
+
@current_path = path
|
72
|
+
@history.notify_listeners(:replace)
|
73
|
+
end
|
74
|
+
|
75
|
+
def pop_path
|
76
|
+
`window.history.go(-1)`
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
attr_reader :location
|
81
|
+
attr_reader :on_state_change
|
82
|
+
attr_reader :name
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
"History<#{@name}>"
|
86
|
+
end
|
87
|
+
|
88
|
+
def initialize(name, preactivate_path = nil, &on_state_change)
|
89
|
+
@name = name
|
90
|
+
if History[@name]
|
91
|
+
raise "a history location named #{@name} already exists"
|
92
|
+
else
|
93
|
+
History[@name] = self
|
94
|
+
end
|
95
|
+
@on_state_change = on_state_change
|
96
|
+
@initial_path = @preactivate_path = preactivate_path
|
97
|
+
self.class.setup_handler
|
98
|
+
@listeners = []
|
99
|
+
@location = {
|
100
|
+
addChangeListener: lambda { |listener| @listeners << listener unless @listeners.include? listener} ,
|
101
|
+
removeChangeListener: lambda { |listener| @listeners.delete(listener) },
|
102
|
+
push: lambda { |path| self.class.push_path(path) },
|
103
|
+
pop: lambda { self.class.pop_path },
|
104
|
+
replace: lambda { |path| self.class.replace_path path },
|
105
|
+
getCurrentPath: lambda { (@preactivate_path || self.class.current_path)},
|
106
|
+
toString: lambda { '<HistoryLocation>'}
|
107
|
+
}.to_n
|
108
|
+
end
|
109
|
+
|
110
|
+
def activate(initial_path = nil)
|
111
|
+
puts "activating #{self}"
|
112
|
+
@preactivate_path = nil
|
113
|
+
initial_path ||= @initial_path || self.class.current_path
|
114
|
+
current_history = self.class.history
|
115
|
+
self.class.history = self
|
116
|
+
@starting_history_length = `ReactRouter.History.length` if current_history != self
|
117
|
+
self.class.push_path initial_path
|
118
|
+
@on_state_change.call(:active) if @on_state_change and current_history != self
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
def deactivate
|
123
|
+
puts "deactivate go(#{@starting_history_length-`ReactRouter.History.length`})"
|
124
|
+
`window.history.go(#{@starting_history_length}-ReactRouter.History.length)`
|
125
|
+
self
|
126
|
+
end
|
127
|
+
|
128
|
+
def notify_listeners(type)
|
129
|
+
puts "#{self}.notify_listeners(#{type}) listeners_count: #{@listeners.count}, path: #{self.class.current_path}"
|
130
|
+
@listeners.each { |listener| `listener.call(#{@location}, {path: #{self.class.current_path}, type: type})` }
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
end
|
@@ -3,6 +3,9 @@ module React
|
|
3
3
|
|
4
4
|
module Router
|
5
5
|
|
6
|
+
class AbortTransition < Exception
|
7
|
+
end
|
8
|
+
|
6
9
|
class RR < React::NativeLibrary
|
7
10
|
imports ReactRouter
|
8
11
|
end
|
@@ -12,9 +15,56 @@ module React
|
|
12
15
|
|
13
16
|
include React::Component
|
14
17
|
include React::IsomorphicHelpers
|
15
|
-
|
18
|
+
|
19
|
+
native_mixin `ReactRouter.Navigation`
|
20
|
+
native_mixin `ReactRouter.State`
|
21
|
+
|
22
|
+
def get_path
|
23
|
+
path = `self.native.getPath()`
|
24
|
+
path = nil if `typeof path === 'undefined'`
|
25
|
+
path
|
26
|
+
end
|
27
|
+
|
28
|
+
def replace_with(route_or_path, params = nil, query = nil)
|
29
|
+
`self.native.replaceWith.apply(self.native, #{[route_or_path, params].compact})`
|
30
|
+
end
|
31
|
+
|
32
|
+
def transition_to(route_or_path, params = nil, query = nil)
|
33
|
+
`self.native.transitionTo.apply(self.native, #{[route_or_path, params].compact})`
|
34
|
+
end
|
35
|
+
|
36
|
+
static_call_back "willTransitionTo" do |transition, params, query, callback|
|
37
|
+
params = Hash.new(params)
|
38
|
+
query = Hash.new(query)
|
39
|
+
transition = `transition.path`
|
40
|
+
puts "willTransitionTo(#{transition}, #{params}, #{query})"
|
41
|
+
begin
|
42
|
+
params.each do |param, value|
|
43
|
+
if evaluator = url_param_evaluators[param]
|
44
|
+
evaluated_url_params[param] = evaluator.call(value)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
if self.respond_to? :will_transition_to
|
48
|
+
result = will_transition_to transition, params, query if self.respond_to? :will_transition_to
|
49
|
+
if result.is_a? Promise
|
50
|
+
result.then { |r| callback(r) }
|
51
|
+
else
|
52
|
+
callback.call()
|
53
|
+
end
|
54
|
+
else
|
55
|
+
callback.call()
|
56
|
+
end
|
57
|
+
rescue AbortTransition
|
58
|
+
raise "transition aborted"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
16
62
|
before_first_mount do |context|
|
17
|
-
|
63
|
+
|
64
|
+
@evaluated_url_params = {}
|
65
|
+
if !self.instance_methods.include?(:show) # if there is no show method this is NOT a top level router so we assume routing will begin elsewhere
|
66
|
+
@routing = true
|
67
|
+
elsif `typeof ReactRouter === 'undefined'`
|
18
68
|
if on_opal_client?
|
19
69
|
message = "ReactRouter not defined in browser assets - you must manually include it in your assets"
|
20
70
|
else
|
@@ -29,14 +79,24 @@ module React
|
|
29
79
|
|
30
80
|
export_component
|
31
81
|
|
82
|
+
optional_param :router_state # optional because it is not initially passed in but we add it when running the router
|
83
|
+
optional_param :query
|
84
|
+
optional_param :params
|
85
|
+
|
86
|
+
def url_params(params)
|
87
|
+
params[:params] || (params[:router_state] && params[:router_state][:params]) || {}
|
88
|
+
end
|
89
|
+
|
90
|
+
|
32
91
|
def render
|
33
92
|
if self.class.routing?
|
34
93
|
show
|
35
94
|
elsif on_opal_server?
|
36
95
|
self.class.routing!
|
37
|
-
routes = self.class.build_routes
|
96
|
+
routes = self.class.build_routes(true)
|
38
97
|
%x{
|
39
|
-
ReactRouter.run(#{routes}, window.reactive_router_static_location, function(root) {
|
98
|
+
ReactRouter.run(#{routes}, window.reactive_router_static_location, function(root, state) {
|
99
|
+
self.native.props.router_state = state
|
40
100
|
self.root = React.createElement(root, self.native.props);
|
41
101
|
});
|
42
102
|
}
|
@@ -54,6 +114,12 @@ module React
|
|
54
114
|
was_routing
|
55
115
|
end
|
56
116
|
|
117
|
+
# override self.location to provide application specific location handlers
|
118
|
+
|
119
|
+
def location
|
120
|
+
(@location ||= History.new("MainApp")).activate.location
|
121
|
+
end
|
122
|
+
|
57
123
|
after_mount do
|
58
124
|
unless self.class.routing!
|
59
125
|
dom_node = if `typeof React.findDOMNode === 'undefined'`
|
@@ -61,9 +127,10 @@ module React
|
|
61
127
|
else
|
62
128
|
`React.findDOMNode(#{self}.native)` # v0.13.0
|
63
129
|
end
|
64
|
-
routes = self.class.build_routes
|
130
|
+
routes = self.class.build_routes(true)
|
65
131
|
%x{
|
66
|
-
ReactRouter.run(#{routes},
|
132
|
+
ReactRouter.run(#{routes}, #{location}, function(root, state) {
|
133
|
+
self.native.props.router_state = state
|
67
134
|
React.render(React.createElement(root, self.native.props), #{dom_node});
|
68
135
|
});
|
69
136
|
}
|
@@ -74,17 +141,23 @@ module React
|
|
74
141
|
@routes_opts = opts
|
75
142
|
@routes_block = block
|
76
143
|
end
|
77
|
-
|
78
|
-
def self.
|
144
|
+
|
145
|
+
def self.routes_block
|
146
|
+
@routes_block
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.build_routes(generate_node = nil)
|
150
|
+
#raise "You must define a routes block in a router component" unless @routes_block
|
79
151
|
routes_opts = @routes_opts.dup
|
80
|
-
routes_opts[:handler] ||= self
|
81
|
-
route(routes_opts, generate_node
|
152
|
+
routes_opts[:handler] ||= self
|
153
|
+
route(routes_opts, generate_node, &@routes_block)
|
82
154
|
end
|
83
155
|
|
84
156
|
def self.route(opts = {}, generate_node = nil, &block)
|
157
|
+
block ||= opts[:handler].routes_block if opts[:handler].respond_to? :routes_block
|
85
158
|
opts = opts.dup
|
86
159
|
opts[:handler] = React::API.create_native_react_class(opts[:handler])
|
87
|
-
(generate_node ? RR::Route_as_node(opts, &block) : RR::Route(opts, &block))
|
160
|
+
(generate_node ? RR::Route_as_node(opts, &block) : RR::Route(opts, &block))
|
88
161
|
end
|
89
162
|
|
90
163
|
def self.default_route(ops = {}, &block)
|
@@ -95,6 +168,11 @@ module React
|
|
95
168
|
RR::Redirect(opts, &block)
|
96
169
|
end
|
97
170
|
|
171
|
+
def self.not_found(opts={}, &block)
|
172
|
+
opts[:handler] = React::API.create_native_react_class(opts[:handler])
|
173
|
+
RR::NotFoundRoute(opts, &block)
|
174
|
+
end
|
175
|
+
|
98
176
|
end
|
99
177
|
end
|
100
178
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reactive-router
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam George
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- Rakefile
|
65
65
|
- lib/reactive-router.rb
|
66
66
|
- lib/reactive-router/component.rb
|
67
|
+
- lib/reactive-router/history.rb
|
67
68
|
- lib/reactive-router/router.rb
|
68
69
|
- lib/reactive-router/version.rb
|
69
70
|
- lib/reactive-router/window_location.rb
|