reflux-core
Version:
A simple library for uni-directional dataflow application architecture inspired by ReactJS Flux
127 lines (113 loc) • 4.36 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.staticJoinCreator = staticJoinCreator;
exports.instanceJoinCreator = instanceJoinCreator;
var _createStore = require("./createStore");
var _utils = require("./utils");
var _ = _interopRequireWildcard(_utils);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
/**
* Internal module used to create static and instance join methods
*/
var slice = Array.prototype.slice,
strategyMethodNames = {
strict: "joinStrict",
first: "joinLeading",
last: "joinTrailing",
all: "joinConcat"
};
/**
* Used in `index.js` to create the static join methods
* @param {String} strategy Which strategy to use when tracking listenable trigger arguments
* @returns {Function} A static function which returns a store with a join listen on the given listenables using the given strategy
*/
function staticJoinCreator(strategy) {
return function () /* listenables... */{
var listenables = slice.call(arguments);
return (0, _createStore.createStore)({
init: function init() {
this[strategyMethodNames[strategy]].apply(this, listenables.concat("triggerAsync"));
}
});
};
}
/**
* 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
*/
function instanceJoinCreator(strategy) {
return function () /* listenables..., callback*/{
_.throwIf(arguments.length < 2, "Cannot create a join with less than 2 listenables!");
var listenables = slice.call(arguments),
callback = listenables.pop(),
numberOfListenables = listenables.length,
join = {
numberOfListenables: numberOfListenables,
callback: this[callback] || callback,
listener: this,
strategy: strategy
},
i,
cancels = [],
subobj;
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);
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);
}
;