Skip to content

Commit 637c0ac

Browse files
committedOct 3, 2014
[added] <Routes fixedPath>
1 parent f0d599a commit 637c0ac

File tree

14 files changed

+125
-169
lines changed

14 files changed

+125
-169
lines changed
 

‎examples/data-flow/app.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ var Routes = Router.Routes;
66
var Link = Router.Link;
77

88
var App = React.createClass({
9+
10+
mixins: [ Router.Transitions ],
11+
912
getInitialState: function() {
1013
return {
1114
tacos: [
@@ -28,7 +31,7 @@ var App = React.createClass({
2831
return taco.name != removedTaco;
2932
});
3033
this.setState({tacos: tacos});
31-
Router.transitionTo('/');
34+
this.transitionTo('/');
3235
},
3336

3437
render: function() {

‎examples/master-detail/app.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ var Index = React.createClass({
132132
});
133133

134134
var Contact = React.createClass({
135+
136+
mixins: [ Router.Transitions ],
137+
135138
getStateFromStore: function(props) {
136139
props = props || this.props;
137140
return {
@@ -164,7 +167,7 @@ var Contact = React.createClass({
164167

165168
destroy: function() {
166169
ContactStore.removeContact(this.props.params.id);
167-
Router.transitionTo('/');
170+
this.transitionTo('/');
168171
},
169172

170173
render: function() {
@@ -182,14 +185,17 @@ var Contact = React.createClass({
182185
});
183186

184187
var NewContact = React.createClass({
188+
189+
mixins: [ Router.Transitions ],
190+
185191
createContact: function(event) {
186192
event.preventDefault();
187193
ContactStore.addContact({
188194
first: this.refs.first.getDOMNode().value,
189195
last: this.refs.last.getDOMNode().value
190196
}, function(contact) {
191-
Router.transitionTo('contact', { id: contact.id });
192-
});
197+
this.transitionTo('contact', { id: contact.id });
198+
}.bind(this));
193199
},
194200

195201
render: function() {

‎examples/transitions/app.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ var Dashboard = React.createClass({
2626
});
2727

2828
var Form = React.createClass({
29+
30+
mixins: [ Router.Transitions ],
31+
2932
statics: {
3033
willTransitionFrom: function(transition, component) {
3134
if (component.refs.userInput.getDOMNode().value !== '') {
@@ -39,7 +42,7 @@ var Form = React.createClass({
3942
handleSubmit: function(event) {
4043
event.preventDefault();
4144
this.refs.userInput.getDOMNode().value = '';
42-
Router.transitionTo('/');
45+
this.transitionTo('/');
4346
},
4447

4548
render: function() {

‎modules/locations/HashLocation.js

+22-20
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,35 @@ var LocationDispatcher = require('../dispatchers/LocationDispatcher');
55
var getWindowPath = require('../utils/getWindowPath');
66

77
function getHashPath() {
8-
return window.location.hash.substr(1) || '/';
8+
return window.location.hash.substr(1);
99
}
1010

11+
var _actionType;
12+
1113
function ensureSlash() {
1214
var path = getHashPath();
1315

1416
if (path.charAt(0) === '/')
1517
return true;
1618

17-
HashLocation.replace('/' + path, _actionSender);
19+
HashLocation.replace('/' + path);
1820

1921
return false;
2022
}
2123

22-
var _actionType, _actionSender;
23-
2424
function onHashChange() {
2525
if (ensureSlash()) {
26+
var path = getHashPath();
27+
2628
LocationDispatcher.handleViewAction({
27-
type: _actionType,
28-
path: getHashPath(),
29-
sender: _actionSender || window
29+
// If we don't have an _actionType then all we know is the hash
30+
// changed. It was probably caused by the user clicking the Back
31+
// button, but may have also been the Forward button.
32+
type: _actionType || LocationActions.POP,
33+
path: getHashPath()
3034
});
3135

32-
_actionSender = null;
36+
_actionType = null;
3337
}
3438
}
3539

@@ -49,18 +53,19 @@ var HashLocation = {
4953
'You cannot use HashLocation in an environment with no DOM'
5054
);
5155

56+
ensureSlash();
57+
58+
LocationDispatcher.handleViewAction({
59+
type: LocationActions.SETUP,
60+
path: getHashPath()
61+
});
62+
5263
if (window.addEventListener) {
5364
window.addEventListener('hashchange', onHashChange, false);
5465
} else {
5566
window.attachEvent('onhashchange', onHashChange);
5667
}
5768

58-
LocationDispatcher.handleViewAction({
59-
type: LocationActions.SETUP,
60-
path: getHashPath(),
61-
sender: window
62-
});
63-
6469
_isSetup = true;
6570
},
6671

@@ -74,21 +79,18 @@ var HashLocation = {
7479
_isSetup = false;
7580
},
7681

77-
push: function (path, sender) {
82+
push: function (path) {
7883
_actionType = LocationActions.PUSH;
79-
_actionSender = sender;
8084
window.location.hash = path;
8185
},
8286

83-
replace: function (path, sender) {
87+
replace: function (path) {
8488
_actionType = LocationActions.REPLACE;
85-
_actionSender = sender;
8689
window.location.replace(getWindowPath() + '#' + path);
8790
},
8891

89-
pop: function (sender) {
92+
pop: function () {
9093
_actionType = LocationActions.POP;
91-
_actionSender = sender;
9294
window.history.back();
9395
},
9496

‎modules/locations/HistoryLocation.js

+11-20
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,11 @@ var LocationActions = require('../actions/LocationActions');
44
var LocationDispatcher = require('../dispatchers/LocationDispatcher');
55
var getWindowPath = require('../utils/getWindowPath');
66

7-
var _actionSender;
8-
97
function onPopState() {
108
LocationDispatcher.handleViewAction({
119
type: LocationActions.POP,
12-
path: getWindowPath(),
13-
sender: _actionSender || window
10+
path: getWindowPath()
1411
});
15-
16-
_actionSender = null;
1712
}
1813

1914
var _isSetup = false;
@@ -32,18 +27,17 @@ var HistoryLocation = {
3227
'You cannot use HistoryLocation in an environment with no DOM'
3328
);
3429

30+
LocationDispatcher.handleViewAction({
31+
type: LocationActions.SETUP,
32+
path: getWindowPath()
33+
});
34+
3535
if (window.addEventListener) {
3636
window.addEventListener('popstate', onPopState, false);
3737
} else {
3838
window.attachEvent('popstate', onPopState);
3939
}
4040

41-
LocationDispatcher.handleViewAction({
42-
type: LocationActions.SETUP,
43-
path: getWindowPath(),
44-
sender: window
45-
});
46-
4741
_isSetup = true;
4842
},
4943

@@ -57,28 +51,25 @@ var HistoryLocation = {
5751
_isSetup = false;
5852
},
5953

60-
push: function (path, sender) {
54+
push: function (path) {
6155
window.history.pushState({ path: path }, '', path);
6256

6357
LocationDispatcher.handleViewAction({
6458
type: LocationActions.PUSH,
65-
path: getWindowPath(),
66-
sender: sender
59+
path: getWindowPath()
6760
});
6861
},
6962

70-
replace: function (path, sender) {
63+
replace: function (path) {
7164
window.history.replaceState({ path: path }, '', path);
7265

7366
LocationDispatcher.handleViewAction({
7467
type: LocationActions.REPLACE,
75-
path: getWindowPath(),
76-
sender: sender
68+
path: getWindowPath()
7769
});
7870
},
7971

80-
pop: function (sender) {
81-
_actionSender = sender;
72+
pop: function () {
8273
window.history.back();
8374
},
8475

‎modules/locations/MemoryLocation.js

-67
This file was deleted.

‎modules/locations/RefreshLocation.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ var RefreshLocation = {
1919

2020
LocationDispatcher.handleViewAction({
2121
type: LocationActions.SETUP,
22-
path: getWindowPath(),
23-
sender: window
22+
path: getWindowPath()
2423
});
2524
},
2625

‎modules/mixins/PathDelegate.js

+13-16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ var React = require('react');
22
var invariant = require('react/lib/invariant');
33
var PathState = require('./PathState');
44
var RouteContainer = require('./RouteContainer');
5+
var LocationActions = require('../actions/LocationActions');
56
var HashLocation = require('../locations/HashLocation');
67
var Path = require('../utils/Path');
78

@@ -62,52 +63,48 @@ var PathDelegate = {
6263
* Transitions to the URL specified in the arguments by pushing
6364
* a new URL onto the history stack.
6465
*/
65-
transitionTo: function (to, params, query, sender) {
66-
sender = sender || this;
67-
66+
transitionTo: function (to, params, query) {
6867
var path = this.makePath(to, params, query);
6968
var location = this.getLocation();
7069

71-
// If we have a location, route the transition through it.
70+
// If we have a location, route the transition
71+
// through it so the URL is updated as well.
7272
if (location) {
73-
location.push(path, this);
73+
location.push(path);
7474
} else if (this.updatePath) {
75-
this.updatePath(path, this);
75+
this.updatePath(path, LocationActions.PUSH);
7676
}
7777
},
7878

7979
/**
8080
* Transitions to the URL specified in the arguments by replacing
8181
* the current URL in the history stack.
8282
*/
83-
replaceWith: function (to, params, query, sender) {
84-
sender = sender || this;
85-
83+
replaceWith: function (to, params, query) {
8684
var path = this.makePath(to, params, query);
8785
var location = this.getLocation();
8886

89-
// If we have a location, route the transition through it.
87+
// If we have a location, route the transition
88+
// through it so the URL is updated as well.
9089
if (location) {
91-
location.replace(path, sender);
90+
location.replace(path);
9291
} else if (this.updatePath) {
93-
this.updatePath(path, sender);
92+
this.updatePath(path, LocationActions.REPLACE);
9493
}
9594
},
9695

9796
/**
9897
* Transitions to the previous URL.
9998
*/
100-
goBack: function (sender) {
101-
sender = sender || this;
102-
99+
goBack: function () {
103100
var location = this.getLocation();
104101

105102
invariant(
106103
location,
107104
'You cannot goBack without a location'
108105
);
109106

110-
location.pop(sender);
107+
location.pop();
111108
}
112109

113110
};

‎modules/mixins/PathState.js

+26-23
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
var React = require('react');
2+
var invariant = require('react/lib/invariant');
13
var canUseDOM = require('react/lib/ExecutionEnvironment').canUseDOM;
24
var HashLocation = require('../locations/HashLocation');
35
var HistoryLocation = require('../locations/HistoryLocation');
46
var RefreshLocation = require('../locations/RefreshLocation');
5-
var PathStore = require('../stores/PathStore');
67
var supportsHistory = require('../utils/supportsHistory');
8+
var PathStore = require('../stores/PathStore');
79

810
/**
911
* A hash of { name: location } pairs.
@@ -16,29 +18,22 @@ var NAMED_LOCATIONS = {
1618

1719
/**
1820
* A mixin for components that need to know the current URL path. Components
19-
* that use it may specify a `location` prop that they use to track changes
20-
* to the URL. They also get:
21+
* that use it get two things:
2122
*
22-
* 1. An `updatePath` method that is called when the
23+
* 1. An optional `location` prop that they use to track
24+
* changes to the URL
25+
* 2. An `updatePath` method that is called when the
2326
* current URL path changes
24-
* 2. A `getCurrentPath` method they can use to get
25-
* the current URL path
2627
*
2728
* Example:
2829
*
2930
* var PathWatcher = React.createClass({
3031
*
3132
* mixins: [ Router.PathState ],
3233
*
33-
* getInitialState: function () {
34-
* return {
35-
* currentPath: this.getCurrentPath()
36-
* };
37-
* },
38-
*
39-
* updatePath: function () {
34+
* updatePath: function (path, actionType) {
4035
* this.setState({
41-
* currentPath: this.getCurrentPath()
36+
* currentPath: path
4237
* });
4338
* }
4439
*
@@ -48,6 +43,8 @@ var PathState = {
4843

4944
propTypes: {
5045

46+
fixedPath: React.PropTypes.string,
47+
5148
location: function (props, propName, componentName) {
5249
var location = props[propName];
5350

@@ -59,8 +56,8 @@ var PathState = {
5956

6057
getDefaultProps: function () {
6158
return {
62-
location: canUseDOM ? HashLocation : null,
63-
path: null
59+
fixedPath: null,
60+
location: canUseDOM ? HashLocation : null
6461
};
6562
},
6663

@@ -84,11 +81,16 @@ var PathState = {
8481
componentWillMount: function () {
8582
var location = this.getLocation();
8683

84+
invariant(
85+
this.props.fixedPath == null || this.getLocation() == null,
86+
'You cannot use a fixed path with a location. Choose one or the other'
87+
);
88+
8789
if (location && location.setup)
8890
location.setup();
8991

9092
if (this.updatePath)
91-
this.updatePath(this.getCurrentPath(), this);
93+
this.updatePath(this.getCurrentPath(), this.getCurrentActionType());
9294
},
9395

9496
componentDidMount: function () {
@@ -99,16 +101,17 @@ var PathState = {
99101
PathStore.removeChangeListener(this.handlePathChange);
100102
},
101103

102-
handlePathChange: function (sender) {
104+
handlePathChange: function () {
103105
if (this.isMounted() && this.updatePath)
104-
this.updatePath(this.getCurrentPath(), sender);
106+
this.updatePath(this.getCurrentPath(), this.getCurrentActionType());
105107
},
106108

107-
/**
108-
* Returns the current URL path.
109-
*/
110109
getCurrentPath: function () {
111-
return PathStore.getCurrentPath();
110+
return this.props.fixedPath || PathStore.getCurrentPath();
111+
},
112+
113+
getCurrentActionType: function () {
114+
return PathStore.getCurrentActionType();
112115
}
113116

114117
};

‎modules/mixins/RouteLookup.js

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ var RouteLookup = {
1818
return this.context.routeContainer.getRoutes();
1919
},
2020

21+
/**
22+
* See RouteContainer#getNamedRoutes.
23+
*/
24+
getNamedRoutes: function () {
25+
return this.context.routeContainer.getNamedRoutes();
26+
},
27+
2128
/**
2229
* See RouteContainer#getRouteByName.
2330
*/

‎modules/mixins/ScrollDelegate.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ var ScrollDelegate = {
2424
* Updates the current scroll position according to the last
2525
* one that was recorded for the given path.
2626
*/
27-
updateScroll: function (path, sender) {
27+
updateScroll: function (path, actionType) {
2828
if (this._scrollPositions) {
2929
var behavior = this.getScrollBehavior();
3030
var position = this._scrollPositions[path];
3131

3232
if (behavior && position)
33-
behavior.updateScrollPosition(position, sender);
33+
behavior.updateScrollPosition(position, actionType);
3434
}
3535
}
3636

‎modules/mixins/ScrollState.js

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
var canUseDOM = require('react/lib/ExecutionEnvironment').canUseDOM;
21
var invariant = require('react/lib/invariant');
2+
var canUseDOM = require('react/lib/ExecutionEnvironment').canUseDOM;
3+
var LocationActions = require('../actions/LocationActions');
34

45
/**
56
* A scroll behavior that attempts to imitate the default behavior
67
* of modern browsers.
78
*/
89
var ImitateBrowserBehavior = {
910

10-
updateScrollPosition: function (position, sender) {
11-
if (sender === window) {
12-
window.scrollTo(position.x, position.y);
13-
} else {
14-
// Clicking on links always scrolls the window to the top.
15-
window.scrollTo(0, 0);
11+
updateScrollPosition: function (position, actionType) {
12+
switch (actionType) {
13+
case LocationActions.PUSH:
14+
case LocationActions.REPLACE:
15+
window.scrollTo(0, 0);
16+
break;
17+
case LocationActions.POP:
18+
window.scrollTo(position.x, position.y);
19+
break;
1620
}
1721
}
1822

@@ -69,7 +73,7 @@ var ScrollState = {
6973
var behavior = this.props.scrollBehavior;
7074

7175
if (typeof behavior === 'string')
72-
behavior = NAMED_SCROLL_STRATEGIES[behavior];
76+
behavior = NAMED_SCROLL_BEHAVIORS[behavior];
7377

7478
return behavior;
7579
},

‎modules/mixins/TransitionHandler.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ var TransitionHandler = {
335335
/**
336336
* See PathState.
337337
*/
338-
updatePath: function (path, sender) {
338+
updatePath: function (path, actionType) {
339339
if (this.state.path === path)
340340
return; // Nothing to do!
341341

@@ -351,7 +351,7 @@ var TransitionHandler = {
351351
self.props.onAbortedTransition.call(self, transition);
352352
} else {
353353
self.emitChange();
354-
self.updateScroll(path, sender);
354+
self.updateScroll(path, actionType);
355355
}
356356
});
357357
},

‎modules/stores/PathStore.js

+12-4
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ var LocationDispatcher = require('../dispatchers/LocationDispatcher');
55
var CHANGE_EVENT = 'change';
66
var _events = new EventEmitter;
77

8-
function notifyChange(sender) {
9-
_events.emit(CHANGE_EVENT, sender);
8+
function notifyChange() {
9+
_events.emit(CHANGE_EVENT);
1010
}
1111

12-
var _currentPath;
12+
var _currentPath, _currentActionType;
1313

1414
/**
1515
* The PathStore keeps track of the current URL path.
@@ -31,6 +31,13 @@ var PathStore = {
3131
return _currentPath;
3232
},
3333

34+
/**
35+
* Returns the type of the action that changed the URL.
36+
*/
37+
getCurrentActionType: function () {
38+
return _currentActionType;
39+
},
40+
3441
dispatchToken: LocationDispatcher.register(function (payload) {
3542
var action = payload.action;
3643

@@ -41,7 +48,8 @@ var PathStore = {
4148
case LocationActions.POP:
4249
if (_currentPath !== action.path) {
4350
_currentPath = action.path;
44-
notifyChange(action.sender);
51+
_currentActionType = action.type;
52+
notifyChange();
4553
}
4654
break;
4755
}

0 commit comments

Comments
 (0)
Please sign in to comment.