diff options
Diffstat (limited to 'packages/kadira-flow-router/client/triggers.js')
-rw-r--r-- | packages/kadira-flow-router/client/triggers.js | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/packages/kadira-flow-router/client/triggers.js b/packages/kadira-flow-router/client/triggers.js new file mode 100644 index 00000000..7733332c --- /dev/null +++ b/packages/kadira-flow-router/client/triggers.js @@ -0,0 +1,112 @@ +// a set of utility functions for triggers + +Triggers = {}; + +// Apply filters for a set of triggers +// @triggers - a set of triggers +// @filter - filter with array fileds with `only` and `except` +// support only either `only` or `except`, but not both +Triggers.applyFilters = function(triggers, filter) { + if(!(triggers instanceof Array)) { + triggers = [triggers]; + } + + if(!filter) { + return triggers; + } + + if(filter.only && filter.except) { + throw new Error("Triggers don't support only and except filters at once"); + } + + if(filter.only && !(filter.only instanceof Array)) { + throw new Error("only filters needs to be an array"); + } + + if(filter.except && !(filter.except instanceof Array)) { + throw new Error("except filters needs to be an array"); + } + + if(filter.only) { + return Triggers.createRouteBoundTriggers(triggers, filter.only); + } + + if(filter.except) { + return Triggers.createRouteBoundTriggers(triggers, filter.except, true); + } + + throw new Error("Provided a filter but not supported"); +}; + +// create triggers by bounding them to a set of route names +// @triggers - a set of triggers +// @names - list of route names to be bound (trigger runs only for these names) +// @negate - negate the result (triggers won't run for above names) +Triggers.createRouteBoundTriggers = function(triggers, names, negate) { + var namesMap = {}; + _.each(names, function(name) { + namesMap[name] = true; + }); + + var filteredTriggers = _.map(triggers, function(originalTrigger) { + var modifiedTrigger = function(context, next) { + var routeName = context.route.name; + var matched = (namesMap[routeName])? 1: -1; + matched = (negate)? matched * -1 : matched; + + if(matched === 1) { + originalTrigger(context, next); + } + }; + return modifiedTrigger; + }); + + return filteredTriggers; +}; + +// run triggers and abort if redirected or callback stopped +// @triggers - a set of triggers +// @context - context we need to pass (it must have the route) +// @redirectFn - function which used to redirect +// @after - called after if only all the triggers runs +Triggers.runTriggers = function(triggers, context, redirectFn, after) { + var abort = false; + var inCurrentLoop = true; + var alreadyRedirected = false; + + for(var lc=0; lc<triggers.length; lc++) { + var trigger = triggers[lc]; + trigger(context, doRedirect, doStop); + + if(abort) { + return; + } + } + + // mark that, we've exceeds the currentEventloop for + // this set of triggers. + inCurrentLoop = false; + after(); + + function doRedirect(url, params, queryParams) { + if(alreadyRedirected) { + throw new Error("already redirected"); + } + + if(!inCurrentLoop) { + throw new Error("redirect needs to be done in sync"); + } + + if(!url) { + throw new Error("trigger redirect requires an URL"); + } + + abort = true; + alreadyRedirected = true; + redirectFn(url, params, queryParams); + } + + function doStop() { + abort = true; + } +};
\ No newline at end of file |