diff --git a/examples/animations/app.js b/examples/animations/app.js
index 964cd23de9..95be4af9e7 100644
--- a/examples/animations/app.js
+++ b/examples/animations/app.js
@@ -36,7 +36,7 @@ var Image = React.createClass({
var routes = (
-
+
);
diff --git a/examples/dynamic-segments/app.js b/examples/dynamic-segments/app.js
index 79b38b1501..cf8287beb9 100644
--- a/examples/dynamic-segments/app.js
+++ b/examples/dynamic-segments/app.js
@@ -49,8 +49,8 @@ var Task = React.createClass({
var routes = (
-
-
+
+
);
diff --git a/modules/helpers/Path.js b/modules/helpers/Path.js
index 052ee07d89..5e2044dc2a 100644
--- a/modules/helpers/Path.js
+++ b/modules/helpers/Path.js
@@ -140,11 +140,25 @@ var Path = {
return path;
},
+ /**
+ * Returns true if the given path is absolute.
+ */
+ isAbsolute: function (path) {
+ return path.charAt(0) === '/';
+ },
+
/**
* Returns a normalized version of the given path.
*/
- normalize: function (path) {
+ normalize: function (path, parentRoute) {
return path.replace(/^\/*/, '/');
+ },
+
+ /**
+ * Joins two URL paths together.
+ */
+ join: function (a, b) {
+ return a.replace(/\/*$/, '/') + b;
}
};
diff --git a/modules/helpers/makePath.js b/modules/helpers/makePath.js
index e29b1ccd69..f650b2db4a 100644
--- a/modules/helpers/makePath.js
+++ b/modules/helpers/makePath.js
@@ -8,8 +8,8 @@ var Path = require('./Path');
*/
function makePath(to, params, query) {
var path;
- if (to.charAt(0) === '/') {
- path = Path.normalize(to); // Absolute path.
+ if (Path.isAbsolute(path)) {
+ path = Path.normalize(to);
} else {
var route = RouteStore.getRouteByName(to);
diff --git a/modules/stores/RouteStore.js b/modules/stores/RouteStore.js
index ae8935ec67..3c8baebcce 100644
--- a/modules/stores/RouteStore.js
+++ b/modules/stores/RouteStore.js
@@ -48,10 +48,18 @@ var RouteStore = {
props.name || props.path
);
+ var parentPath = (parentRoute && parentRoute.props.path) || '/';
+
if ((props.path || props.name) && !props.isDefault && !props.catchAll) {
- props.path = Path.normalize(props.path || props.name);
+ var path = props.path || props.name;
+
+ // Relative paths extend their parent.
+ if (!Path.isAbsolute(path))
+ path = Path.join(parentPath, path);
+
+ props.path = Path.normalize(path);
} else {
- props.path = (parentRoute && parentRoute.props.path) || '/';
+ props.path = parentPath;
if (props.catchAll)
props.path += '*';
diff --git a/specs/RouteStore.spec.js b/specs/RouteStore.spec.js
index ded71e5b14..9cf5e1b3f5 100644
--- a/specs/RouteStore.spec.js
+++ b/specs/RouteStore.spec.js
@@ -28,6 +28,31 @@ describe('when a route is looked up by name', function () {
});
describe('when registering a route', function () {
+
+ describe('that starts with /', function() {
+ it('does not inherit the parent path', function() {
+ var child;
+ var route = Route({ name: 'home', handler: App },
+ child = Route({ path: '/foo', handler: App })
+ );
+ RouteStore.registerRoute(route);
+ expect(child.props.path).toEqual('/foo');
+ RouteStore.unregisterRoute(route);
+ });
+ });
+
+ describe('that does not start with /', function() {
+ it('inherits the parent path', function() {
+ var child;
+ var route = Route({ name: 'home', handler: App },
+ child = Route({ path: 'foo', handler: App })
+ );
+ RouteStore.registerRoute(route);
+ expect(child.props.path).toEqual('/home/foo');
+ RouteStore.unregisterRoute(route);
+ });
+ });
+
describe('with no handler', function () {
it('throws an Error', function () {
expect(function () {