UNPKG

fluo

Version:

A prototype-based fork of the Reflux data flow library similar to Facebook Flux

90 lines (76 loc) 2.89 kB
var _ = require("./utils"); var slice = Array.prototype.slice; /** * Used in `ListenerMethods.js` to create the instance join methods * @param {String} strategy Which strategy to use when tracking listenable trigger arguments * @returns {Function} An instance method which sets up a join listen on the given listenables using the given strategy */ module.exports = function instanceJoinCreator(strategy) { return function(/* listenables..., callback*/) { _.throwIf(arguments.length < 3, 'Cannot create a join with less than 2 listenables!'); var listenables = slice.call(arguments); var callback = listenables.pop(); var numberOfListenables = listenables.length; var join = { numberOfListenables: numberOfListenables, callback: this[callback] || callback, listener: this, strategy: strategy }; var cancels = []; var i; for (i = 0; i < numberOfListenables; ++i) { _.throwIf(this.validateListening(listenables[i])); } for (i = 0; i < numberOfListenables; ++i) { cancels.push(listenables[i].listen(newListener(i,join), this)); } reset(join); var subobj = { listenable: listenables }; subobj.stop = makeStopper(subobj,cancels,this); this.subscriptions = (this.subscriptions || []).concat(subobj); return subobj; }; }; // ---- internal join functions ---- function makeStopper(subobj,cancels,context){ return function() { var i, subs = context.subscriptions, index = (subs ? subs.indexOf(subobj) : -1); _.throwIf(index === -1,'Tried to remove join already gone from subscriptions list!'); for(i=0;i < cancels.length; ++i){ cancels[i](); } subs.splice(index, 1); }; } function reset(join) { join.listenablesEmitted = new Array(join.numberOfListenables); join.args = new Array(join.numberOfListenables); } function newListener(i,join) { return function() { var callargs = slice.call(arguments); if (join.listenablesEmitted[i]){ switch(join.strategy){ case "strict": throw new Error("Strict join failed because listener triggered twice."); case "last": join.args[i] = callargs; break; case "all": join.args[i].push(callargs); } } else { join.listenablesEmitted[i] = true; join.args[i] = (join.strategy==="all"?[callargs]:callargs); } emitIfAllListenablesEmitted(join); }; } function emitIfAllListenablesEmitted(join) { for (var i = 0; i < join.numberOfListenables; ++i) { if (!join.listenablesEmitted[i]) { return; } } join.callback.apply(join.listener,join.args); reset(join); }