abstract-state-router
Advanced tools
Comparing version 2.0.0 to 3.0.0
222
index.js
@@ -12,2 +12,4 @@ var StateState = require('./state-state') | ||
var combine = require('combine-arrays') | ||
var buildPath = require('page-path-builder') | ||
var StateTransitionManager = require('./state-transition-manager') | ||
@@ -18,3 +20,5 @@ module.exports = function StateProvider(renderer, rootElement, hashRouter) { | ||
var stateProviderEmitter = new EventEmitter() | ||
StateTransitionManager(stateProviderEmitter) | ||
hashRouter = hashRouter || newHashBrownRouter() | ||
current.set('', {}) | ||
@@ -24,11 +28,18 @@ var destroyDom = Promise.denodeify(renderer.destroy) | ||
var renderDom = Promise.denodeify(renderer.render) | ||
var resetDom = Promise.denodeify(renderer.reset) | ||
var activeDomApis = {} | ||
var activeStateResolveContent = {} | ||
var activeEmitters = {} | ||
function handleError(e) { | ||
console.log(e.stack || e) | ||
stateProviderEmitter.emit('error', e) | ||
function handleError(event, err) { | ||
if (!stateProviderEmitter.emit(event, err)) { | ||
console.error(err) | ||
} | ||
} | ||
function destroyStateName(stateName) { | ||
activeEmitters[stateName]('destroy') | ||
delete activeEmitters[stateName] | ||
delete activeStateResolveContent[stateName] | ||
return destroyDom(activeDomApis[stateName]).then(function() { | ||
@@ -39,2 +50,9 @@ delete activeDomApis[stateName] | ||
function resetStateName(stateName) { | ||
activeEmitters[stateName]('destroy') | ||
delete activeEmitters[stateName] | ||
delete activeStateResolveContent[stateName] | ||
return resetDom(activeDomApis[stateName]) | ||
} | ||
function getChildElementForStateName(stateName) { | ||
@@ -57,2 +75,5 @@ return new Promise(function(resolve) { | ||
return renderDom(childElement, state.template) | ||
}).then(function(domApi) { | ||
activeDomApis[stateName] = domApi | ||
return domApi | ||
}) | ||
@@ -62,16 +83,12 @@ } | ||
function renderAll(stateNames) { | ||
return series(stateNames, renderStateName).then(function(domApis) { | ||
combine({ | ||
name: stateNames, | ||
domApi: domApis | ||
}).forEach(function(stateAndChild) { | ||
activeDomApis[stateAndChild.name] = stateAndChild.domApi | ||
}) | ||
}) | ||
return series(stateNames, renderStateName) | ||
} | ||
current.set('', {}) | ||
function onRouteChange(state, parameters) { | ||
function stateGo(transition) { | ||
var fullStateName = prototypalStateHolder.applyDefaultChildStates(state.name) | ||
attemptStateChange(fullStateName, parameters, transition) | ||
} | ||
function onRouteChange(state, parameters) { | ||
stateProviderEmitter.go(state.name, parameters) | ||
stateProviderEmitter.emit('stateChangeAttempt', stateGo) | ||
} | ||
@@ -82,3 +99,3 @@ | ||
var route = buildRoute(prototypalStateHolder, state.name) | ||
var route = prototypalStateHolder.buildFullStateRoute(state.name) | ||
@@ -88,31 +105,127 @@ hashRouter.add(route, onRouteChange.bind(null, state)) | ||
stateProviderEmitter.addState = addState | ||
stateProviderEmitter.go = function go(newStateName, parameters) { | ||
stateProviderEmitter.emit('state change started', newStateName) | ||
var stateComparisonResults = StateComparison(prototypalStateHolder)(current.get().name, current.get().parameters, newStateName, parameters) | ||
var stateChanges = stateChangeLogic(stateComparisonResults) | ||
// { destroy, change, create } | ||
function emit() { | ||
var args = Array.prototype.slice.apply(arguments) | ||
return function() { | ||
return stateProviderEmitter.emit.apply(stateProviderEmitter, args) | ||
} | ||
} | ||
var statesToResolve = stateChanges.change.concat(stateChanges.create).map(prototypalStateHolder.get) | ||
function getStatesToResolve(stateChanges) { | ||
return stateChanges.change.concat(stateChanges.create).map(prototypalStateHolder.get) | ||
} | ||
resolveStates(statesToResolve, parameters).then(function afterResolves(stateResolveResultsObject) { | ||
return series(reverse(stateChanges.destroy), destroyStateName).then(function() { | ||
return renderAll(stateChanges.create).then(function() { | ||
function attemptStateChange(newStateName, parameters, transition) { | ||
function ifNotCancelled(fn) { | ||
return function() { | ||
if (transition.cancelled) { | ||
var err = new Error('The transition to ' + newStateName + 'was cancelled') | ||
err.wasCancelledBySomeoneElse = true | ||
throw err | ||
} else { | ||
return fn.apply(null, arguments) | ||
} | ||
} | ||
} | ||
return prototypalStateHolder.guaranteeAllStatesExist(newStateName) | ||
.then(function applyDefaultParameters() { | ||
var state = prototypalStateHolder.get(newStateName) | ||
var defaultParams = state.defaultQuerystringParameters || {} | ||
var needToApplyDefaults = Object.keys(defaultParams).some(function missingParameterValue(param) { | ||
return !parameters[param] | ||
}) | ||
if (needToApplyDefaults) { | ||
throw redirector(newStateName, extend({}, defaultParams, parameters)) | ||
} | ||
}).then(ifNotCancelled(emit('stateChangeStart', newStateName, parameters))) | ||
.then(function getStateChanges() { | ||
var stateComparisonResults = StateComparison(prototypalStateHolder)(current.get().name, current.get().parameters, newStateName, parameters) | ||
return stateChangeLogic(stateComparisonResults) // { destroy, change, create } | ||
}).then(ifNotCancelled(function resolveDestroyAndActivateStates(stateChanges) { | ||
return resolveStates(getStatesToResolve(stateChanges), parameters).catch(function onResolveError(e) { | ||
e.stateChangeError = true | ||
throw e | ||
}).then(ifNotCancelled(function destroyAndActivate(stateResolveResultsObject) { | ||
transition.cancellable = false | ||
function activateAll() { | ||
var statesToActivate = stateChanges.change.concat(stateChanges.create) | ||
statesToActivate.map(prototypalStateHolder.get).forEach(function(state) { | ||
try { | ||
state.activate(activeDomApis[state.name], state.data, parameters, getContentObject(stateResolveResultsObject, state.name)) | ||
} catch (e) { | ||
handleError(e) | ||
} | ||
return activateStates(statesToActivate) | ||
} | ||
extend(activeStateResolveContent, stateResolveResultsObject) | ||
return series(reverse(stateChanges.destroy), destroyStateName).then(function() { | ||
return series(reverse(stateChanges.change), resetStateName) | ||
}).then(function() { | ||
return renderAll(stateChanges.create).then(activateAll) | ||
}) | ||
})) | ||
function activateStates(stateNames) { | ||
return stateNames.map(prototypalStateHolder.get).forEach(function(state) { | ||
var context = new EventEmitter() | ||
extend(context, { | ||
domApi: activeDomApis[state.name], | ||
data: state.data, | ||
parameters: parameters, | ||
content: getContentObject(activeStateResolveContent, state.name) | ||
}) | ||
activeEmitters[state.name] = function emit() { | ||
context.emit.apply(context, arguments) | ||
} | ||
try { | ||
state.activate(context) | ||
} catch (e) { | ||
console.error(e) | ||
} | ||
}) | ||
}).then(function() { | ||
stateProviderEmitter.emit('state change finished') | ||
}).catch(handleError) | ||
} | ||
})).then(function stateChangeComplete() { | ||
current.set(newStateName, parameters) | ||
try { | ||
stateProviderEmitter.emit('stateChangeEnd', newStateName, parameters) | ||
} catch (e) { | ||
handleError('error', e) | ||
} | ||
}).catch(ifNotCancelled(function handleStateChangeError(err) { | ||
if (err && err.redirectTo) { | ||
stateProviderEmitter.emit('stateChangeCancelled', err) | ||
return stateProviderEmitter.go(err.redirectTo.name, err.redirectTo.params, { replace: true }) | ||
} else if (err) { | ||
handleError('stateChangeError', err) | ||
} | ||
})).catch(function handleCancellation(err) { | ||
if (err && err.wasCancelledBySomeoneElse) { | ||
// we don't care, the state transition manager has already emitted the stateChangeCancelled for us | ||
} else { | ||
throw new Error("This probably shouldn't happen, maybe file an issue or something " + err) | ||
} | ||
}) | ||
} | ||
function getDestinationUrl(stateName, parameters) { | ||
return prototypalStateHolder.guaranteeAllStatesExist(stateName).then(function() { | ||
var route = prototypalStateHolder.buildFullStateRoute(stateName) | ||
return buildPath(route, parameters || {}) | ||
}) | ||
} | ||
var defaultOptions = { | ||
replace: false | ||
} | ||
stateProviderEmitter.addState = addState | ||
stateProviderEmitter.go = function go(newStateName, parameters, options) { | ||
options = extend({}, defaultOptions, options) | ||
var goFunction = options.replace ? hashRouter.replace : hashRouter.go | ||
return getDestinationUrl(newStateName, parameters).then(goFunction, handleError.bind(null, 'stateChangeError')) | ||
} | ||
return stateProviderEmitter | ||
@@ -131,2 +244,11 @@ } | ||
function redirector(newStateName, parameters) { | ||
return { | ||
redirectTo: { | ||
name: newStateName, | ||
params: parameters | ||
} | ||
} | ||
} | ||
// { [stateName]: resolveResult } | ||
@@ -137,3 +259,16 @@ function resolveStates(states, parameters) { | ||
var resolves = Promise.all(statesWithResolveFunctions.map(function(state) { | ||
return Promise.denodeify(state.resolve)(state.data, parameters) | ||
return new Promise(function (resolve, reject) { | ||
function resolveCb(err, content) { | ||
err ? reject(err) : resolve(content) | ||
} | ||
resolveCb.redirect = function redirect(newStateName, parameters) { | ||
reject(redirector(newStateName, parameters)) | ||
} | ||
var res = state.resolve(state.data, parameters, resolveCb) | ||
if (res && (typeof res === 'object' || typeof res === 'function') && typeof res.then === 'function') { | ||
resolve(res) | ||
} | ||
}) | ||
})) | ||
@@ -158,2 +293,6 @@ | ||
function reverse(ary) { | ||
return ary.slice().reverse() | ||
} | ||
function isFunction(property) { | ||
@@ -164,14 +303,1 @@ return function(obj) { | ||
} | ||
function buildRoute(prototypalStateHolder, stateName) { | ||
return prototypalStateHolder.getHierarchy(stateName).reduce(function(route, state) { | ||
if (route && route[route.length - 1] !== '/' && state.route[0] !== '/') { | ||
route = route + '/' | ||
} | ||
return route + state.route | ||
}, '') | ||
} | ||
function reverse(ary) { | ||
return [].concat(ary) | ||
} |
{ | ||
"name": "abstract-state-router", | ||
"version": "2.0.0", | ||
"version": "3.0.0", | ||
"description": "The basics of a client-side state router ala the AngularJS ui-router, but without any DOM interactions", | ||
@@ -26,4 +26,5 @@ "main": "index.js", | ||
"combine-arrays": "^1.0.0", | ||
"extend": "^2.0.0", | ||
"hash-brown-router": "^1.3.0", | ||
"path-to-regexp": "^1.0.1", | ||
"page-path-builder": "^1.0.1", | ||
"promise": "^6.0.1", | ||
@@ -33,6 +34,4 @@ "promise-map-series": "^0.2.0" | ||
"devDependencies": { | ||
"extend": "^2.0.0", | ||
"page": "^1.3.7", | ||
"tape": "^2.14.0" | ||
} | ||
} |
@@ -7,5 +7,7 @@ To manage webapp states so that you don't have to deal with url paths or anything. | ||
var createStateRouter = require('abstract-state-router') | ||
```js | ||
var createStateRouter = require('abstract-state-router') | ||
var stateRouter = createStateRouter(renderer, rootElement, router) | ||
var stateRouter = createStateRouter(renderer, rootElement, router) | ||
``` | ||
@@ -18,3 +20,3 @@ The renderer should be an object with four properties: render, destroy, getChildElement, and reset. Still needs to be documented, see test/support/renderer-mock.js for an implementation. | ||
# stateRouter.addState({name, route, data, template, resolve, activate}) | ||
# stateRouter.addState({name, route, defaultChild, data, template, resolve, activate, querystringParameters}) | ||
@@ -27,5 +29,7 @@ The addState function takes a single object of options. | ||
`defaultChild` is a string (or a function that returns a string) of the default child's name. If you attempt to go directly to a state that has a default child, you will be directed to the default child. (E.g. if 'contacts' has the defaultChild 'list', then doing `state.go('contacts')` will actually do `state.go('contacts.list')`.) | ||
`data` is an object that can hold whatever you want - it will be passed in to the resolve and callback functions. | ||
`template` is a template string/object/whatever to be interpreted by the render function | ||
`template` is a template string/object/whatever to be interpreted by the render function. | ||
@@ -36,4 +40,6 @@ `resolve` is a function called when the selected state begins to be transitioned to, allowing you to accomplish the same objective as you would with ui-router's [resolve](https://github.com/angular-ui/ui-router/wiki#resolve). | ||
## resolve(data, parameters, callback(err, content), redirectCallback(stateName, params)) | ||
`querystringParameters` is an array of query string parameters that will be watched by this state. | ||
## resolve(data, parameters, callback(err, content).redirect(stateName, params)) | ||
The first argument is the data object you passed to the addState call. The second argument is an object containing the parameters that were parsed out of the route params and the query string. | ||
@@ -43,12 +49,19 @@ | ||
If you call `redirectCallback(stateName, params)`, the state router will begin transitioning to that state instead. The current destination will never become active, and will not show up in the browser history. | ||
If you call `callback.redirect(stateName, params)`, the state router will begin transitioning to that state instead. The current destination will never become active, and will not show up in the browser history. | ||
## activate(domApi, data, parameters, content) | ||
## activate(context) | ||
The activate function is called when the state becomes active. It is passed the DOM API from the rendering function, the data object from the addState call, the route/querystring parameters, and the content object passed into the resolveFunction's callback. | ||
The activate function is called when the state becomes active. It is passed an event emitter named `context` with four properties: | ||
This is the point where you display the view for the current state! | ||
- `domApi`: the DOM API returned by the renderer | ||
- `data`: the data object given to the addState call | ||
- `parameters`: the route/querystring parameters | ||
- `content`: the object passed into the resolveFunction's callback | ||
# stateRouter.go(stateName, parameters, [options]) | ||
###events | ||
- 'destroy': emitted when the state is destroyed | ||
# stateRouter.go(stateName, [parameters, [options]]) | ||
Browses to the given state, with the current parameters. Changes the url to match. | ||
@@ -58,17 +71,25 @@ | ||
If a state change is triggered during a state transition, it is queued and applied once the current state change is done. | ||
# State change flow | ||
- emit StateChangeStarted | ||
- emit StateChangeStart | ||
- call all resolve functions | ||
- resolve functions return | ||
= NO LONGER AT PREVIOUS STATE | ||
- destroy existing dom elements | ||
- call all render functions | ||
- call all controller functions | ||
- **NO LONGER AT PREVIOUS STATE** | ||
- destroy the contexts of all "destroy" and "change" states | ||
- destroy appropriate dom elements | ||
- reset "change"ing dom elements - still needs implemented | ||
- call render functions for "create"ed states | ||
- call all activate functions | ||
- emit StateChangeEnd | ||
# Every state change does this to states | ||
- destroy: states that are no longer active at all. The contexts are destroyed, and the DOM elements are destroyed. | ||
- change: states that remain around, but with different parameter values - the DOM sticks around, but the contexts are destroyed and resolve/activate are called again. | ||
- create: states that weren't active at all before. The DOM elements are rendered, and resolve/activate are called. | ||
# TODO | ||
- "redirect somewhere else instead" function in the resolve | ||
- "redirect somewhere else instead" function during activation | ||
- emitting errors when trying to navigate to an invalid state | ||
- the ability to set an "error" state to go to on errors | ||
@@ -81,1 +102,2 @@ | ||
[![Build Status](https://travis-ci.org/TehShrike/abstract-state-router.svg?branch=master)](https://travis-ci.org/TehShrike/abstract-state-router) |
var stateStringParser = require('./state-string-parser') | ||
var Promise = require('promise') | ||
var parse = require('./state-string-parser') | ||
@@ -27,4 +29,5 @@ module.exports = function StateState() { | ||
if (names.length > 1) { | ||
names.pop() | ||
return names.join('') | ||
var secondToLast = names.length - 2 | ||
return names[secondToLast] | ||
} else { | ||
@@ -35,2 +38,47 @@ return null | ||
function guaranteeAllStatesExist(newStateName) { | ||
return new Promise(function(resolve) { | ||
var stateNames = parse(newStateName) | ||
var statesThatDontExist = stateNames.filter(function(name) { | ||
return !states[name] | ||
}) | ||
if (statesThatDontExist.length > 0) { | ||
throw new Error('State ' + statesThatDontExist[statesThatDontExist.length - 1] + ' does not exist') | ||
} | ||
resolve() | ||
}) | ||
} | ||
function buildFullStateRoute(stateName) { | ||
return getHierarchy(stateName).reduce(function(route, state) { | ||
if (route && route[route.length - 1] !== '/' && state.route[0] !== '/') { | ||
route = route + '/' | ||
} | ||
return route + (state.route || '') | ||
}, '') | ||
} | ||
function applyDefaultChildStates(stateName) { | ||
var state = states[stateName] | ||
function getDefaultChildStateName() { | ||
return state && (typeof state.defaultChild === 'function' | ||
? state.defaultChild() | ||
: state.defaultChild) | ||
} | ||
var defaultChildStateName = getDefaultChildStateName() | ||
if (!defaultChildStateName) { | ||
return stateName | ||
} | ||
var fullStateName = stateName + '.' + defaultChildStateName | ||
return applyDefaultChildStates(fullStateName) | ||
} | ||
return { | ||
@@ -41,8 +89,11 @@ add: function(name, state) { | ||
get: function(name) { | ||
return states[name] | ||
return name && states[name] | ||
}, | ||
getHierarchy: getHierarchy, | ||
getParent: getParent, | ||
getParentName: getParentName | ||
getParentName: getParentName, | ||
guaranteeAllStatesExist: guaranteeAllStatesExist, | ||
buildFullStateRoute: buildFullStateRoute, | ||
applyDefaultChildStates: applyDefaultChildStates | ||
} | ||
} |
@@ -203,1 +203,24 @@ var test = require('tape') | ||
}) | ||
test('changing from app.main.tab1 to just main', function(t) { | ||
var results = setup()('app.main.tab1', { main1: 'wut' }, 'app', {}) | ||
compareAllElements(t, [{ | ||
stateNameChanged: false, | ||
stateParametersChanged: false, | ||
nameBefore: 'app', | ||
nameAfter: 'app' | ||
}, { | ||
stateNameChanged: true, | ||
stateParametersChanged: false, | ||
nameBefore: 'app.main', | ||
nameAfter: undefined | ||
}, { | ||
stateNameChanged: true, | ||
stateParametersChanged: false, | ||
nameBefore: 'app.main.tab1', | ||
nameAfter: undefined | ||
}], results) | ||
t.end() | ||
}) |
273
test/test.js
@@ -1,57 +0,5 @@ | ||
/* Don't forget to test | ||
- calling go with replace=true, and then having that state also call replace, or just error out the state transition | ||
*/ | ||
var test = require('tape') | ||
var hashRouterFactory = require('hash-brown-router') | ||
var hashLocationMockFactory = require('hash-brown-router/hash-location-mock') | ||
var stateRouterFactory = require('../') | ||
var mockRenderFn = require('./support/renderer-mock') | ||
var assertingRendererFactory = require('./helpers/asserting-renderer-factory') | ||
var getTestState = require('./helpers/test-state-factory') | ||
function getTestState(t, renderFn) { | ||
var hashRouter = hashRouterFactory(hashLocationMockFactory()) | ||
var stateRouter = stateRouterFactory(renderFn || mockRenderFn, 'body', hashRouter) | ||
hashRouter.setDefault(function noop() {}) | ||
stateRouter.addState({ | ||
name: 'dummy', | ||
route: '/dummy', | ||
data: {}, | ||
render: t.fail.bind(t, 'dummy route was called') | ||
}) | ||
return { | ||
hashRouter: hashRouter, | ||
stateRouter: stateRouter | ||
} | ||
} | ||
function assertingRenderFunctionFactory(t, expectedTemplates) { | ||
return { | ||
render: function render(element, template, cb) { | ||
t.ok(expectedTemplates.length, 'The render function hasn\'t been called too many times yet') | ||
var expected = expectedTemplates.shift() | ||
t.equal(expected, template, 'The expected template was sent to the render function') | ||
process.nextTick(function() { | ||
cb(null, { | ||
template: template | ||
}) | ||
}) | ||
}, | ||
reset: function reset(renderedTemplateApi, cb) { | ||
setTimeout(cb, 100) | ||
}, | ||
destroy: function destroy(renderedTemplateApi, cb) { | ||
setTimeout(cb, 100) | ||
}, | ||
getChildElement: function getChildElement(renderedTemplateApi, cb) { | ||
setTimeout(function() { | ||
cb(null, 'dummy child element') | ||
}, 100) | ||
} | ||
} | ||
} | ||
test('normal, error-less state activation flow for two states', function(t) { | ||
@@ -70,9 +18,9 @@ function basicTest(t) { | ||
var state = getTestState(t, assertingRenderFunctionFactory(t, [parentTemplate, childTemplate])) | ||
var renderer = assertingRendererFactory(t, [parentTemplate, childTemplate]) | ||
var state = getTestState(t, renderer) | ||
var stateRouter = state.stateRouter | ||
var assertsBelow = 18 | ||
var renderAsserts = 4 | ||
var renderAsserts = renderer.expectedAssertions | ||
t.plan(assertsBelow + renderAsserts) | ||
console.log('Plan for', assertsBelow + renderAsserts) | ||
@@ -83,3 +31,2 @@ var parentResolveFinished = false | ||
stateRouter.addState({ | ||
@@ -99,3 +46,8 @@ name: 'rofl', | ||
querystringParameters: ['wat'], | ||
activate: function(domApi, data, parameters, content) { | ||
activate: function(context) { | ||
var domApi = context.domApi | ||
var data = context.data | ||
var parameters = context.parameters | ||
var content = context.content | ||
t.notOk(parentStateActivated, 'parent state hasn\'t been activated before') | ||
@@ -127,3 +79,8 @@ parentStateActivated = true | ||
}, | ||
activate: function(domApi, data, parameters, content) { | ||
activate: function(context) { | ||
var domApi = context.domApi | ||
var data = context.data | ||
var parameters = context.parameters | ||
var content = context.content | ||
t.ok(parentStateActivated, 'Parent state was activated before the child state was') | ||
@@ -157,88 +114,138 @@ t.ok(childResolveFinished, 'Child resolve was completed before the activate') | ||
// test('calls resolve callback, passes results to the render callback', function(t) { | ||
// var state = getTestState(t) | ||
test('undefined data, querystring, and resolve function', function(t) { | ||
function basicTest(t) { | ||
var parentTemplate = {} | ||
// t.plan(3) | ||
var renderer = assertingRendererFactory(t, [parentTemplate]) | ||
var state = getTestState(t, renderer) | ||
var assertsBelow = 3 | ||
// var resolveData = {} | ||
// var originalData = {} | ||
t.plan(assertsBelow + renderer.expectedAssertions) | ||
// function resolve(data, parameters, cb) { | ||
// t.pass('resolve function called') | ||
// t.equal(parameters.wat, 'wut', 'received the parameter from the url') | ||
// process.nextTick(function() { | ||
// cb(null, resolveData) | ||
// }) | ||
// } | ||
state.stateRouter.addState({ | ||
name: 'rofl', | ||
route: '/routeButt', | ||
template: parentTemplate, | ||
activate: function(context) { | ||
var data = context.data | ||
var parameters = context.parameters | ||
var content = context.content | ||
// function render(data, parameters, content) { | ||
// t.equal(content, resolveData, 'received the object from the resolve function') | ||
// t.end() | ||
// } | ||
t.equal(typeof data, 'undefined', 'data is undefined') | ||
t.equal(parameters.wat, 'wut', 'got the parameter value') | ||
t.equal(Object.keys(content).length, 0, 'No keys on the content object') | ||
t.end() | ||
} | ||
}) | ||
// stateRouter.addState({ | ||
// name: 'someRoute', | ||
// route: '/routeButt', | ||
// data: originalData, | ||
// querystringParameters: ['wat'], | ||
// resolve: resolve, | ||
// render: render | ||
// }) | ||
return state | ||
} | ||
// state.hashRouter.go('/routeButt?wat=wut') | ||
// }) | ||
t.test('triggered with go()', function(t) { | ||
var stateRouter = basicTest(t).stateRouter | ||
stateRouter.go('rofl', { wat: 'wut' }) | ||
}) | ||
// test('activates both parent and child state', function(t) { | ||
// var state = getTestState(t) | ||
t.test('triggered by the router', function(t) { | ||
var hashRouter = basicTest(t).hashRouter | ||
hashRouter.go('/routeButt?wat=wut') | ||
}) | ||
}) | ||
// t.plan(12) | ||
test('normal, error-less state activation flow for two states', function(t) { | ||
var parentData = {} | ||
var child1Data = {} | ||
var child2Data = {} | ||
var parentTemplate = {} | ||
var child1Template = {} | ||
var child2Template = {} | ||
var parentResolveContent = { | ||
parentProperty: 'some string' | ||
} | ||
var child1ResolveContent = { | ||
child1Property: 'a different string' | ||
} | ||
var child2ResolveContent = { | ||
child2Property: 'whatever man' | ||
} | ||
// var parentData = {} | ||
// var childData = {} | ||
// var calledResolveFunctionForParent = false | ||
// var calledResolveFunctionForChild = false | ||
var renderer = assertingRendererFactory(t, [parentTemplate, child1Template, child2Template]) | ||
var state = getTestState(t, renderer) | ||
var stateRouter = state.stateRouter | ||
var assertsBelow = 11 | ||
// var activatedParent = false | ||
// var activatedChild = false | ||
t.plan(assertsBelow + renderer.expectedAssertions) | ||
// state.stateRouter.addState({ | ||
// name: 'parent', | ||
// route: '/routeParent', | ||
// data: parentData, | ||
// resolve: function(cb) { | ||
// t.notOk(calledResolveFunctionForParent, 'Called the parent\'s resolve function for the first time') | ||
// t.notOk(activatedParent, 'Called the resolve function before the render function') | ||
// calledResolveFunctionForParent = true | ||
// }, | ||
// render: function(data, parameters, content) { | ||
// t.equal(data, parentData, 'got back the parent data object') | ||
// t.notOk(parameters.wat, 'wut', 'got the right parameter') | ||
// t.notOk(activatedParent, 'have not activated the parent before') | ||
// t.notOk(activatedChild, 'have not activated the child yet') | ||
// activatedParent = true | ||
// } | ||
// }) | ||
var parentResolveCalled = false | ||
var parentStateActivated = false | ||
var child1ResolveCalled = false | ||
var child1Activated = false | ||
// state.stateRouter.addState({ | ||
// name: 'parent.child', | ||
// route: '/routeChild', | ||
// querystringParameters: ['wat'], | ||
// data: childData, | ||
// resolve: function(cb) { | ||
// t.notOk(calledResolveFunctionForChild, 'Called the child\'s resolve function for the first time') | ||
// t.notOk(activatedChild, 'Called the resolve function before the render function') | ||
// calledResolveFunctionForChild = true | ||
// }, | ||
// render: function(data, parameters, content) { | ||
// t.equal(data, childData, 'got back the child data object') | ||
// t.equal(parameters.wat, 'wut', 'got the right parameter') | ||
// t.ok(activatedParent, 'have already activated the parent') | ||
// t.notOk(activatedChild, 'have not activated the child before') | ||
// activatedChild = true | ||
// t.end() | ||
// } | ||
// }) | ||
stateRouter.addState({ | ||
name: 'parent', | ||
route: '/parent', | ||
data: parentData, | ||
template: parentTemplate, | ||
resolve: function(data, parameters, cb) { | ||
t.notOk(parentResolveCalled, 'parent resolve function hasn\'t been called before') | ||
parentResolveCalled = true | ||
setTimeout(function() { | ||
cb(null, parentResolveContent) | ||
}, 50) | ||
}, | ||
querystringParameters: ['wat'], | ||
activate: function(context) { | ||
t.notOk(parentStateActivated, 'parent state hasn\'t been activated before') | ||
parentStateActivated = true | ||
} | ||
}) | ||
// state.hashRouter.go('/routeParent/routeChild?wat=wut') | ||
// }) | ||
stateRouter.addState({ | ||
name: 'parent.child1', | ||
route: '/child1', | ||
data: child1Data, | ||
template: child1Template, | ||
resolve: function(data, parameters, cb) { | ||
t.notOk(child1ResolveCalled, 'child1 resolve function hasn\'t been called before') | ||
child1ResolveCalled = true | ||
setTimeout(function() { | ||
cb(null, child1ResolveContent) | ||
}, 50) | ||
}, | ||
activate: function(context) { | ||
t.notOk(child1Activated, 'child1 hasn\'t been activated before') | ||
setTimeout(function() { | ||
stateRouter.go('parent.child2', { wat: 'some value' }) | ||
}) | ||
} | ||
}) | ||
stateRouter.addState({ | ||
name: 'parent.child2', | ||
route: '/child2', | ||
data: child2Data, | ||
template: child2Template, | ||
resolve: function(data, parameters, cb) { | ||
t.equal(data, child2Data, 'got back the correct child2 data object in the child2 resolve function') | ||
t.equal(parameters.wat, 'some value', 'got the parent\'s querystring value in the child2 resolve function') | ||
setTimeout(function() { | ||
cb(null, child2ResolveContent) | ||
}, 50) | ||
}, | ||
activate: function(context) { | ||
t.equal(context.domApi.template, child2Template, 'got back the correct DOM API') | ||
t.equal(context.data, child2Data, 'Got back the correct data object') | ||
t.equal(context.content.parentProperty, parentResolveContent.parentProperty, 'The child2 activate function got the parent property from the resolve function object') | ||
t.equal(context.content.child2Property, child2ResolveContent.child2Property, 'The child2 activate function got the child2 property from the resolve function') | ||
t.equal(context.parameters.wat, 'some value', 'got the the parent\'s parameter value in the child2\'s activate function') | ||
t.end() | ||
} | ||
}) | ||
stateRouter.go('parent.child1', { wat: 'some value' }) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
68694
1
26
2052
97
6
1
+ Addedextend@^2.0.0
+ Addedpage-path-builder@^1.0.1
+ Addedextend@2.0.2(transitive)
+ Addedobject-assign@4.1.1(transitive)
+ Addedpage-path-builder@1.0.4(transitive)
+ Addedquery-string@4.3.4(transitive)
+ Addedstrict-uri-encode@1.1.0(transitive)
- Removedpath-to-regexp@^1.0.1
- Removedpath-to-regexp@1.9.0(transitive)