@danielkalen/simplybind
Version:
Magically simple, framework-less one-way/two-way data binding for frontend/backend in ~5kb.
173 lines (165 loc) • 4.59 kB
JavaScript
function addSubscriber(context, callable) {
if (this.hasSubscriber(context, callable)) {
return false;
}
if (!this._context0) {
this._context0 = context;
this._callable0 = callable;
return true;
}
if (!this._context1) {
this._context1 = context;
this._callable1 = callable;
return true;
}
if (!this._context2) {
this._context2 = context;
this._callable2 = callable;
return true;
}
if (!this._contextsRest) {
this._contextsRest = [context];
this._callablesRest = [callable];
return true;
}
this._contextsRest.push(context);
this._callablesRest.push(callable);
return true;
}
function removeSubscriber(context, callable) {
if (this._context0 === context && this._callable0 === callable) {
this._context0 = null;
this._callable0 = null;
return true;
}
if (this._context1 === context && this._callable1 === callable) {
this._context1 = null;
this._callable1 = null;
return true;
}
if (this._context2 === context && this._callable2 === callable) {
this._context2 = null;
this._callable2 = null;
return true;
}
let rest = this._contextsRest;
let index;
if (!rest || !rest.length || (index = rest.indexOf(context)) === -1 || this._callablesRest[index] !== callable) { // eslint-disable-line no-cond-assign
return false;
}
rest.splice(index, 1);
this._callablesRest.splice(index, 1);
return true;
}
let arrayPool1 = [];
let arrayPool2 = [];
let poolUtilization = [];
function callSubscribers(newValue, oldValue) {
let context0 = this._context0;
let callable0 = this._callable0;
let context1 = this._context1;
let callable1 = this._callable1;
let context2 = this._context2;
let callable2 = this._callable2;
let length = this._contextsRest ? this._contextsRest.length : 0;
let contextsRest;
let callablesRest;
let poolIndex;
let i;
if (length) {
// grab temp arrays from the pool.
poolIndex = poolUtilization.length;
while (poolIndex-- && poolUtilization[poolIndex]) {
// Do nothing
}
if (poolIndex < 0) {
poolIndex = poolUtilization.length;
contextsRest = [];
callablesRest = [];
poolUtilization.push(true);
arrayPool1.push(contextsRest);
arrayPool2.push(callablesRest);
} else {
poolUtilization[poolIndex] = true;
contextsRest = arrayPool1[poolIndex];
callablesRest = arrayPool2[poolIndex];
}
// copy the contents of the "rest" arrays.
i = length;
while (i--) {
contextsRest[i] = this._contextsRest[i];
callablesRest[i] = this._callablesRest[i];
}
}
if (context0) {
if (callable0) {
callable0.call(context0, newValue, oldValue);
} else {
context0(newValue, oldValue);
}
}
if (context1) {
if (callable1) {
callable1.call(context1, newValue, oldValue);
} else {
context1(newValue, oldValue);
}
}
if (context2) {
if (callable2) {
callable2.call(context2, newValue, oldValue);
} else {
context2(newValue, oldValue);
}
}
if (length) {
for (i = 0; i < length; i++) {
let callable = callablesRest[i];
let context = contextsRest[i];
if (callable) {
callable.call(context, newValue, oldValue);
} else {
context(newValue, oldValue);
}
contextsRest[i] = null;
callablesRest[i] = null;
}
poolUtilization[poolIndex] = false;
}
}
function hasSubscribers() {
return !!(
this._context0
|| this._context1
|| this._context2
|| this._contextsRest && this._contextsRest.length);
}
function hasSubscriber(context, callable) {
let has = this._context0 === context && this._callable0 === callable
|| this._context1 === context && this._callable1 === callable
|| this._context2 === context && this._callable2 === callable;
if (has) {
return true;
}
let index;
let contexts = this._contextsRest;
if (!contexts || (index = contexts.length) === 0) { // eslint-disable-line no-cond-assign
return false;
}
let callables = this._callablesRest;
while (index--) {
if (contexts[index] === context && callables[index] === callable) {
return true;
}
}
return false;
}
export function subscriberCollection() {
return function(target) {
target.prototype.addSubscriber = addSubscriber;
target.prototype.removeSubscriber = removeSubscriber;
target.prototype.callSubscribers = callSubscribers;
target.prototype.hasSubscribers = hasSubscribers;
target.prototype.hasSubscriber = hasSubscriber;
};
}