reactive-router 0.7.3 → 0.7.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|