From c2cc3f29cb39eb96b5562420b2f4156ae3b79f54 Mon Sep 17 00:00:00 2001 From: Mark Nijhof Date: Wed, 17 Sep 2014 00:44:15 +0200 Subject: [PATCH] added the notion of router hierarchy was #82 Now all routers are automatically added to a list and enabled the use of this.navigate('../other_route') which then takes the parent route to execute navigate on. Not tested but this should also enable this.navigate('../../other/route'). Works as well with [Link href=../other_route]home[/Link] --- lib/RouterMixin.js | 22 ++++++- tests/browser.js | 153 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 171 insertions(+), 4 deletions(-) diff --git a/lib/RouterMixin.js b/lib/RouterMixin.js index 6522a78..c2f59fc 100644 --- a/lib/RouterMixin.js +++ b/lib/RouterMixin.js @@ -17,17 +17,25 @@ var RouterMixin = { }, childContextTypes: { - router: React.PropTypes.any + router: React.PropTypes.any, + routers: React.PropTypes.any }, getChildContext: function() { + var routers = this.context.routers || [] + if (routers.indexOf(this) === -1) { + routers.unshift(this) + } + return { - router: this + router: this, + routers: routers }; }, contextTypes: { - router: React.PropTypes.any + router: React.PropTypes.any, + routers: React.PropTypes.any }, getInitialState: function() { @@ -133,6 +141,14 @@ var RouterMixin = { * @param {Callback} cb */ navigate: function(path, navigation, cb) { + var levels = path.split('../'); + if (levels.length > 1) { + var newPath = "/" + levels[levels.length-1]; + var gotoContext = levels.length-1; + this.context.routers[gotoContext].navigate(newPath, navigation, cb); + return; + } + path = join(this.state.prefix, path); this.getEnvironment().setPath(path, navigation, cb); }, diff --git a/tests/browser.js b/tests/browser.js index 88f6cfb..7a7ddf5 100644 --- a/tests/browser.js +++ b/tests/browser.js @@ -345,7 +345,7 @@ describe('Routing with async components', function() { }); beforeEach(function() { - mainWasInLoadingState = false; + mainWasInLoadingState = false; aboutWasInLoadingState = false; mainSeenPendingUpdate = false; @@ -553,6 +553,33 @@ describe('Contextual routers', function() { if (!historyAPI) return; + var SubSubCat = React.createClass({ + + render: function() { + return div(null, + Router.Locations({ref: 'router', contextual: true}, + Router.Location({ + path: '/', + handler: function(props) { return div(null, 'subcat/subsubcat/root') } + }), + Router.Location({ + path: '/back_to_parent', + ref: 'link', + handler: function(props) { + return Router.Link({href: '../'}, 'subcat/subsubcat/back_to_parent') + } + }), + Router.Location({ + path: '/back_to_root', + ref: 'link', + handler: function(props) { + return Router.Link({href: '../../__zuul'}, 'subcat/subsubcat/back_to_root') + } + }) + )); + } + }); + var SubCat = React.createClass({ render: function() { @@ -575,6 +602,18 @@ describe('Contextual routers', function() { handler: function(props) { return Router.Link({global: true, href: '/__zuul'}, 'subcat/escape') } + }), + Router.Location({ + path: '/back_to_parent', + ref: 'link', + handler: function(props) { + return Router.Link({href: '../__zuul'}, 'subcat/back_to_parent') + } + }), + Router.Location({ + path: '/subsubcat/*', + handler: SubSubCat, + ref: 'subsubcat' }) )); } @@ -652,6 +691,42 @@ describe('Contextual routers', function() { }); }); }); + + it('does navigate to root context from nested', function(done) { + assertRendered('mainpage'); + router.navigate('/__zuul/subcat/back_to_parent', function() { + assertRendered('subcat/back_to_parent'); + clickOn(router.refs.subcat.refs.router.refs.link); + delay(function() { + assertRendered('mainpage'); + done(); + }); + }); + }); + + it('does navigate to nested context from double nested', function(done) { + assertRendered('mainpage'); + router.navigate('/__zuul/subcat/subsubcat/back_to_parent', function() { + assertRendered('subcat/subsubcat/back_to_parent'); + clickOn(router.refs.subcat.refs.router.refs.subsubcat.refs.router.refs.link); + delay(function() { + assertRendered('subcat/root'); + done(); + }); + }); + }); + + it('does navigate to root context from double nested', function(done) { + assertRendered('mainpage'); + router.navigate('/__zuul/subcat/subsubcat/back_to_root', function() { + assertRendered('subcat/subsubcat/back_to_root'); + clickOn(router.refs.subcat.refs.router.refs.subsubcat.refs.router.refs.link); + delay(function() { + assertRendered('mainpage'); + done(); + }); + }); + }); }); describe('Multiple active routers', function() { @@ -833,6 +908,33 @@ describe('Hash routing', function() { describe('Contextual Hash routers', function() { + var SubSubCat = React.createClass({ + + render: function() { + return div(null, + Router.Locations({ref: 'router', contextual: true}, + Router.Location({ + path: '/', + handler: function(props) { return div(null, 'subcat/subsubcat/root') } + }), + Router.Location({ + path: '/back_to_parent', + ref: 'link', + handler: function(props) { + return Router.Link({href: '../'}, 'subcat/subsubcat/back_to_parent') + } + }), + Router.Location({ + path: '/back_to_root', + ref: 'link', + handler: function(props) { + return Router.Link({href: '../../'}, 'subcat/subsubcat/back_to_root') + } + }) + )); + } + }); + var SubCat = React.createClass({ render: function() { @@ -848,6 +950,18 @@ describe('Contextual Hash routers', function() { handler: function(props) { return Router.Link({globalHash: true, href: '/'}, 'subcat/escape'); } + }), + Router.Location({ + path: '/back_to_parent', + ref: 'link', + handler: function(props) { + return Router.Link({href: '../'}, 'subcat/back_to_parent') + } + }), + Router.Location({ + path: '/subsubcat/*', + handler: SubSubCat, + ref: 'subsubcat' }) )); } @@ -889,6 +1003,43 @@ describe('Contextual Hash routers', function() { }); }); + + it('does navigate to root context from nested', function(done) { + assertRendered('mainpage'); + router.navigate('/subcat/back_to_parent', function() { + assertRendered('subcat/back_to_parent'); + clickOn(router.refs.subcat.refs.router.refs.link); + delay(function() { + assertRendered('mainpage'); + done(); + }); + }); + }); + + it('does navigate to nested context from double nested', function(done) { + assertRendered('mainpage'); + router.navigate('/subcat/subsubcat/back_to_parent', function() { + assertRendered('subcat/subsubcat/back_to_parent'); + clickOn(router.refs.subcat.refs.router.refs.subsubcat.refs.router.refs.link); + delay(function() { + assertRendered('subcat/root'); + done(); + }); + }); + }); + + it('does navigate to root context from double nested', function(done) { + assertRendered('mainpage'); + router.navigate('/subcat/subsubcat/back_to_root', function() { + assertRendered('subcat/subsubcat/back_to_root'); + clickOn(router.refs.subcat.refs.router.refs.subsubcat.refs.router.refs.link); + delay(function() { + assertRendered('mainpage'); + done(); + }); + }); + }); + }); });