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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73020402b77bb3c9e6fd7b7ecb6e5473a1909629
4
- data.tar.gz: 83324993db70d197472abb0f6e54d45b87fb40f0
3
+ metadata.gz: 4a37cfefc5d18c03f42d0302fd1e56360ab0acdf
4
+ data.tar.gz: c367a01366dca24fed30dfa4bbf332d7b6e83163
5
5
  SHA512:
6
- metadata.gz: c13b7252cf9d88f0bae57f3abbf1d549a8ed972c145688eea7e866556a15cba181293caffbe16fcd19cd38a588d5ee39d53e34de4c135d1e89721e7e58d79e43
7
- data.tar.gz: 84d07d8faf68375b6360fedf326415d8f586e886caf44e9ec1d326d90d8a7404cc55e3da894fe0ddc1a1d02de31f038b77e26823f77f16366bb5e571ff2aede5
6
+ metadata.gz: 84257330b586a80d5d958207e31f2797bf95e4ee8538c4ffd4fd1bc80f8c47b93302ef1b1eb9c10da86e6500ad5a34d90c7e2b9c60eb107cf6f523359528f157
7
+ data.tar.gz: 5d130e422da66bcbc0ed5f3bd7c89f69c312349de727086fe26ab41fdae9019c27203794cf4ccd997cc16b18ab65bb76556e3f084de4e55de8bc7c0e6c7d6b69
@@ -1,6 +1,7 @@
1
1
  if RUBY_ENGINE == 'opal'
2
2
  require 'reactive-ruby'
3
3
  require 'reactive-router/component'
4
+ require 'reactive-router/history'
4
5
  require 'reactive-router/router'
5
6
  require 'reactive-router/version'
6
7
  else
@@ -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
- define_state name
8
- before_mount do
9
- send("#{name}!", yield(params[:params][name]))
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
- before_receive_props do |new_params|
12
- send("#{name}!", yield(new_params[:params][name]))
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
- if `typeof ReactRouter === 'undefined'`
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}, ReactRouter.HistoryLocation, function(root) {
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.build_routes
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 = true, &@routes_block)
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
 
@@ -1,3 +1,3 @@
1
1
  module ReactiveRouter
2
- VERSION = "0.7.3"
2
+ VERSION = "0.7.4"
3
3
  end
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.3
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-07 00:00:00.000000000 Z
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