export {Observable, ObservableList}
/**
* Represents the Observable interface
* @interface Observable interface
* @typedef {Object} Observable
* @param {*} value the observed value
* @returns {object} returns the API
* @constructor
*/
const Observable = value => {
const listeners = [];
return {
onChange: callback => {
listeners.push(callback);
callback(value, value);
},
getValue: () => value,
setValue: newValue => {
if (value === newValue) return;
const oldValue = value;
value = newValue;
listeners.forEach(callback => callback(value, oldValue));
}
}
};
/**
*
* @param list of classes that implement the Observable interface
* @see {@link Observable} for more information
* @returns {object} returns the API
* @constructor
*/
const ObservableList = list => {
const addListeners = [];
const delListeners = [];
const removeAt = array => index => array.splice(index, 1);
const removeItem = array => item => { const i = array.indexOf(item); if (i>=0) removeAt(array)(i); };
const listRemoveItem = removeItem(list);
const delListenersRemove = removeAt(delListeners);
return {
onAdd: listener => addListeners.push(listener),
onDel: listener => delListeners.push(listener),
add: item => {
list.push(item);
addListeners.forEach( listener => listener(item))
},
del: item => {
listRemoveItem(item);
const safeIterate = [...delListeners]; // shallow copy as we might change listeners array while iterating
safeIterate.forEach( (listener, index) => listener(item, () => delListenersRemove(index) ));
},
removeDeleteListener: removeItem(delListeners),
count: () => list.length,
countIf: pred => list.reduce( (sum, item) => pred(item) ? sum + 1 : sum, 0)
}
};