Skip to content

Commit

Permalink
feat: request component deactivation on route transition
Browse files Browse the repository at this point in the history
  • Loading branch information
troch committed Jul 2, 2015
1 parent 3776aad commit 78c1a51
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 36 deletions.
33 changes: 23 additions & 10 deletions dist/commonjs/router5.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ var Router5 = (function () {
if (!evt.state) return;
if (this.lastKnownState && areStatesEqual(evt.state, this.lastKnownState)) return;

this._transition(evt.state, this.lastKnownState);
this.lastKnownState = evt.state;
var canTransition = this._transition(evt.state, this.lastKnownState);
if (canTransition) this.lastKnownState = evt.state;
}
}, {
key: 'start',
Expand Down Expand Up @@ -106,6 +106,10 @@ var Router5 = (function () {
}, {
key: '_transition',
value: function _transition(toState, fromState) {
var _this2 = this;

var cannotDeactivate = false;

if (fromState) {
var i = undefined;
var fromStateIds = nameToIDs(fromState.name);
Expand All @@ -116,12 +120,19 @@ var Router5 = (function () {
if (fromStateIds[i] !== toStateIds[i]) break;
}

var segmentsToDeactivate = fromStateIds.slice(i);
cannotDeactivate = fromStateIds.slice(i).map(function (id) {
return _this2.activeComponents[id];
}).filter(function (comp) {
return comp && comp.canDeactivate;
}).some(function (comp) {
return !comp.canDeactivate(toState, fromState);
});

if (i > 0) this._invokeCallbacks(fromStateIds[i - 1], toState, fromState);
if (!cannotDeactivate && i > 0) this._invokeCallbacks(fromStateIds[i - 1], toState, fromState);
}

this._invokeCallbacks('', toState, fromState);
if (!cannotDeactivate) this._invokeCallbacks('', toState, fromState);
return !cannotDeactivate;
}
}, {
key: 'getState',
Expand Down Expand Up @@ -195,12 +206,14 @@ var Router5 = (function () {
if (sameStates && !opts.reload) return;
// Transition and amend history
if (!sameStates) {
this._transition(this.lastStateAttempt, this.lastKnownState);
window.history[opts.replace ? 'replaceState' : 'pushState'](this.lastStateAttempt, '', this.options.useHash ? '#' + path : path);
}
var canTransition = this._transition(this.lastStateAttempt, this.lastKnownState);

// Update lastKnowState
this.lastKnownState = this.lastStateAttempt;
if (canTransition) {
window.history[opts.replace ? 'replaceState' : 'pushState'](this.lastStateAttempt, '', this.options.useHash ? '#' + path : path);
// Update lastKnowState
this.lastKnownState = this.lastStateAttempt;
}
}
}
}]);

Expand Down
33 changes: 23 additions & 10 deletions dist/umd/router5.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@
if (!evt.state) return;
if (this.lastKnownState && areStatesEqual(evt.state, this.lastKnownState)) return;

this._transition(evt.state, this.lastKnownState);
this.lastKnownState = evt.state;
var canTransition = this._transition(evt.state, this.lastKnownState);
if (canTransition) this.lastKnownState = evt.state;
}
}, {
key: 'start',
Expand Down Expand Up @@ -113,6 +113,10 @@
}, {
key: '_transition',
value: function _transition(toState, fromState) {
var _this2 = this;

var cannotDeactivate = false;

if (fromState) {
var i = undefined;
var fromStateIds = nameToIDs(fromState.name);
Expand All @@ -123,12 +127,19 @@
if (fromStateIds[i] !== toStateIds[i]) break;
}

var segmentsToDeactivate = fromStateIds.slice(i);
cannotDeactivate = fromStateIds.slice(i).map(function (id) {
return _this2.activeComponents[id];
}).filter(function (comp) {
return comp && comp.canDeactivate;
}).some(function (comp) {
return !comp.canDeactivate(toState, fromState);
});

if (i > 0) this._invokeCallbacks(fromStateIds[i - 1], toState, fromState);
if (!cannotDeactivate && i > 0) this._invokeCallbacks(fromStateIds[i - 1], toState, fromState);
}

this._invokeCallbacks('', toState, fromState);
if (!cannotDeactivate) this._invokeCallbacks('', toState, fromState);
return !cannotDeactivate;
}
}, {
key: 'getState',
Expand Down Expand Up @@ -202,12 +213,14 @@
if (sameStates && !opts.reload) return;
// Transition and amend history
if (!sameStates) {
this._transition(this.lastStateAttempt, this.lastKnownState);
window.history[opts.replace ? 'replaceState' : 'pushState'](this.lastStateAttempt, '', this.options.useHash ? '#' + path : path);
}
var canTransition = this._transition(this.lastStateAttempt, this.lastKnownState);

// Update lastKnowState
this.lastKnownState = this.lastStateAttempt;
if (canTransition) {
window.history[opts.replace ? 'replaceState' : 'pushState'](this.lastStateAttempt, '', this.options.useHash ? '#' + path : path);
// Update lastKnowState
this.lastKnownState = this.lastStateAttempt;
}
}
}
}]);

Expand Down
28 changes: 19 additions & 9 deletions modules/Router5.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export default class Router5 {
if (!evt.state) return
if (this.lastKnownState && areStatesEqual(evt.state, this.lastKnownState)) return

this._transition(evt.state, this.lastKnownState)
this.lastKnownState = evt.state
let canTransition = this._transition(evt.state, this.lastKnownState)
if (canTransition) this.lastKnownState = evt.state
}

start() {
Expand Down Expand Up @@ -77,6 +77,8 @@ export default class Router5 {
}

_transition(toState, fromState) {
let cannotDeactivate = false

if (fromState) {
let i
let fromStateIds = nameToIDs(fromState.name)
Expand All @@ -87,12 +89,17 @@ export default class Router5 {
if (fromStateIds[i] !== toStateIds[i]) break
}

let segmentsToDeactivate = fromStateIds.slice(i)
cannotDeactivate =
fromStateIds.slice(i)
.map(id => this.activeComponents[id])
.filter(comp => comp && comp.canDeactivate)
.some(comp => !comp.canDeactivate(toState, fromState))

if (i > 0) this._invokeCallbacks(fromStateIds[i - 1], toState, fromState)
if (!cannotDeactivate && i > 0) this._invokeCallbacks(fromStateIds[i - 1], toState, fromState)
}

this._invokeCallbacks('', toState, fromState)
if (!cannotDeactivate) this._invokeCallbacks('', toState, fromState)
return !cannotDeactivate
}

getState() {
Expand Down Expand Up @@ -152,11 +159,14 @@ export default class Router5 {
if (sameStates && !opts.reload) return
// Transition and amend history
if (!sameStates) {
this._transition(this.lastStateAttempt, this.lastKnownState)
window.history[opts.replace ? 'replaceState' : 'pushState'](this.lastStateAttempt, '', this.options.useHash ? `#${path}` : path)
let canTransition = this._transition(this.lastStateAttempt, this.lastKnownState)

if (canTransition) {
window.history[opts.replace ? 'replaceState' : 'pushState'](this.lastStateAttempt, '', this.options.useHash ? `#${path}` : path)
// Update lastKnowState
this.lastKnownState = this.lastStateAttempt
}
}

// Update lastKnowState
this.lastKnownState = this.lastStateAttempt
}
}
33 changes: 26 additions & 7 deletions tests/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,27 +142,46 @@ describe('router5', function () {
});

it('should be able to register components', function () {
router.registerComponent('users.view', {
router.registerComponent('users.view', {});
expect(Object.keys(router.activeComponents).length).toBe(1);

router.registerComponent('users.list', {});
expect(Object.keys(router.activeComponents).length).toBe(2);

router.deregisterComponent('users.list');
expect(Object.keys(router.activeComponents).length).toBe(1);

router.deregisterComponent('users.view');
expect(Object.keys(router.activeComponents).length).toBe(0);
});

it('should block navigation if a component refuses deactivation', function () {
router.navigate('users.list');

// Cannot deactivate
router.registerComponent('users.list', {
canDeactivate: function () {
return true;
return false;
}
});
expect(Object.keys(router.activeComponents).length).toBe(1);
router.navigate('users');
expect(window.location.hash).toBe('#/users/list');

// Can deactivate
router.deregisterComponent('users.list');
router.registerComponent('users.list', {
canDeactivate: function () {
return true;
}
});
expect(Object.keys(router.activeComponents).length).toBe(2);

router.deregisterComponent('users.list');
expect(Object.keys(router.activeComponents).length).toBe(1);
router.navigate('users');
expect(window.location.hash).toBe('#/users');
});

it('should warn when trying to register a component twice', function () {
spyOn(console, 'warn');
router.registerComponent('users.view', {});
router.registerComponent('users.view', {});
expect(console.warn).toHaveBeenCalled();
});
});
Expand Down

0 comments on commit 78c1a51

Please sign in to comment.