Skip to content

Commit

Permalink
feat: add support for onTransition middleware function
Browse files Browse the repository at this point in the history
  • Loading branch information
troch committed Jul 29, 2015
1 parent e17ed69 commit 259065f
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 15 deletions.
1 change: 1 addition & 0 deletions modules/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const constants = {
SAME_STATES : 'SAME_STATES',
CANNOT_DEACTIVATE : 'CANNOT_DEACTIVATE',
CANNOT_ACTIVATE : 'CANNOT_ACTIVATE',
TRANSITION_ERR : 'TRANSITION_ERR',
NODE_LISTENER_ERR : 'NODE_ERR',
TRANSITION_CANCELLED : 'CANCELLED'
}
Expand Down
12 changes: 11 additions & 1 deletion modules/router5.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ let makeState = (name, params, path) => ({name, params, path})
class Router5 {
constructor(routes, opts = {}) {
this.started = false
this._onTr = null
this._cbs = {}
this._cmps = {}
this._canAct = {}
Expand Down Expand Up @@ -52,6 +53,15 @@ class Router5 {
return this
}

/**
* Set a transition middleware function
* @param {Function} mware The middleware function
*/
onTransition(fn) {
this._onTr = fn
return this
}

/**
* Add a route to the router.
* @param {String} name The route name
Expand Down Expand Up @@ -103,7 +113,7 @@ class Router5 {
return this
}

if (args.length === 2) {
if (args.length > 0) {
if (typeof args[0] === 'string') startPath = args[0]
if (typeof args[0] === 'object') startState = args[0]
}
Expand Down
19 changes: 17 additions & 2 deletions modules/transition.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,31 @@ export default function transition(router, toState, fromState, callback) {
)
}

let middlewareFn = router._onTr
let middleware = (toState, fromState, cb) => {
let mwareFunction = [middlewareFn]

asyncProcess(
isCancelled, mwareFunction, toState, fromState,
err => cb(err ? constants.TRANSITION_ERR : null)
)
}

let nodeListenerFn = router._cbs['^' + intersection]
let nodeListener = (toState, fromState, cb) => {
let listeners = router._cbs['^' + intersection] || []
let listeners = nodeListenerFn
asyncProcess(
isCancelled, listeners, toState, fromState,
err => cb(err ? constants.NODE_LISTENER_ERR : null),
true
)
}

let pipeline = fromState ? [canDeactivate, canActivate, nodeListener] : [canActivate, nodeListener]
let pipeline = (fromState ? [canDeactivate] : [])
.concat(canActivate)
.concat(middlewareFn ? middleware : [])
.concat(nodeListenerFn && nodeListenerFn.length ? nodeListener : [])

asyncProcess(isCancelled, pipeline, toState, fromState, done)

return cancel
Expand Down
49 changes: 37 additions & 12 deletions tests/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ var listeners = {
},
node: function nodeListener(newState, oldState) {
// Do nothing
},
transition: function (fromState, toState, done) {
done(null);
},
transitionErr: function (fromState, toState, done) {
done(true);
}
};

Expand Down Expand Up @@ -73,9 +79,9 @@ function testRouter(useHash) {

it('should start with the start route if matched', function (done) {
router.stop();
window.history.replaceState({}, '', base + getExpectedPath(useHash, '/users'));
router.start(function () {
expect(getPath(useHash)).toBe(getExpectedPath(useHash, '/users'));
window.history.replaceState({}, '', base + getExpectedPath(useHash, '/users/view/123'));
router.start(function (err, state) {
expect(state).toEqual({name: 'users.view', params: {id: '123'}, path: '/users/view/123'});
done();
});
});
Expand Down Expand Up @@ -123,7 +129,7 @@ function testRouter(useHash) {
it('should start with the provided state', function (done) {
router.stop();
window.history.replaceState({}, '', base + getExpectedPath(useHash, '/home'));
spyOn(listeners, 'global');
spyOn(listeners, 'global').and.callThrough();
router.addListener('', listeners.global);
var homeState = {name: 'home', params: {}, path: '/home'};
router.start(homeState, function (err, state) {
Expand All @@ -149,7 +155,7 @@ function testRouter(useHash) {
router.stop();
router.setOption('defaultRoute', 'home');
window.history.replaceState({}, '', base);
spyOn(listeners, 'global');
spyOn(listeners, 'global').and.callThrough();
router.addNodeListener('', listeners.global);

router.start(function (err, state) {
Expand All @@ -176,8 +182,7 @@ function testRouter(useHash) {

router.navigate('home', {}, {}, function () {
var previousState = router.lastKnownState;

spyOn(listeners, 'global');
spyOn(listeners, 'global').and.callThrough();
router.addListener(listeners.global);

router.navigate('orders.pending', {}, {}, function () {
Expand All @@ -190,7 +195,7 @@ function testRouter(useHash) {
});

it('should invoke listeners on navigation to same state if reload is set to true', function (done) {
spyOn(listeners, 'global');
spyOn(listeners, 'global').and.callThrough();
router.addListener(listeners.global);

router.navigate('orders.pending', {}, {}, function () {
Expand Down Expand Up @@ -233,7 +238,7 @@ function testRouter(useHash) {

it('should be able to remove listeners', function (done) {
router.removeListener(listeners.global);
spyOn(listeners, 'global');
spyOn(listeners, 'global').and.callThrough();

router.navigate('orders.view', {id: 123}, {replace: true}, function () {
expect(listeners.global).not.toHaveBeenCalled();
Expand All @@ -242,7 +247,7 @@ function testRouter(useHash) {
});

it('should not invoke listeners if trying to navigate to the current route', function (done) {
spyOn(listeners, 'global');
spyOn(listeners, 'global').and.callThrough();
router.addListener(listeners.global);

router.navigate('orders.view', {id: 123}, {}, function () {
Expand Down Expand Up @@ -274,7 +279,7 @@ function testRouter(useHash) {

it('should invoke node listeners', function (done) {
router.navigate('users.list', {}, {}, function () {
spyOn(listeners, 'node');
spyOn(listeners, 'node').and.callThrough();
router.addNodeListener('users', listeners.node);
router.navigate('users.view', {id: 1}, {}, function () {
expect(listeners.node).toHaveBeenCalled();
Expand All @@ -298,7 +303,7 @@ function testRouter(useHash) {

it('should invoke route listeners', function (done) {
router.navigate('users.list', {}, {}, function () {
spyOn(listeners, 'node');
spyOn(listeners, 'node').and.callThrough();
router.addRouteListener('users', listeners.node);
router.navigate('users', {}, {}, function () {
expect(listeners.node).toHaveBeenCalled();
Expand Down Expand Up @@ -397,5 +402,25 @@ function testRouter(useHash) {
});
cancel();
});

it('should support a transition middleware', function (done) {
spyOn(listeners, 'transition').and.callThrough();
router.onTransition(listeners.transition);
router.navigate('users', {}, {}, function (err, state) {
expect(listeners.transition).toHaveBeenCalled();
expect(err).toBe(null);
done();
});
});

it('should fail transition if middleware returns an error', function (done) {
spyOn(listeners, 'transitionErr').and.callThrough();
router.onTransition(listeners.transitionErr);
router.navigate('home', {}, {}, function (err, state) {
expect(listeners.transitionErr).toHaveBeenCalled();
expect(err).toBe(Router5.ERR.TRANSITION_ERR);
done();
});
});
});
}

0 comments on commit 259065f

Please sign in to comment.