snappymail/vendors/knockout/src/subscribables/observableArray.js
djmaze fac36e828b Cleanup Squire and Knockout with help of Chromium Code Coverage
Bugfix: Squire inlineNodeNames the 'I' tag was missing
Improved: Squire style editing
2021-02-23 22:50:48 +01:00

78 lines
3.6 KiB
JavaScript

ko.observableArray = initialValues => {
initialValues = initialValues || [];
if (typeof initialValues != 'object' || !('length' in initialValues))
throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
var result = ko.observable(initialValues);
Object.setPrototypeOf(result, ko.observableArray['fn']);
return result.extend({'trackArrayChanges':true});
};
ko.observableArray['fn'] = {
'remove': function (valueOrPredicate) {
var underlyingArray = this.peek();
var removedValues = [];
var predicate = typeof valueOrPredicate == "function" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
var i = underlyingArray.length;
while (i--) {
var value = underlyingArray[i];
if (predicate(value)) {
if (removedValues.length === 0) {
this.valueWillMutate();
}
if (underlyingArray[i] !== value) {
throw Error("Array modified during remove; cannot remove item");
}
removedValues.push(value);
underlyingArray.splice(i, 1);
}
}
if (removedValues.length) {
this.valueHasMutated();
}
return removedValues;
}
};
// Note that for browsers that don't support proto assignment, the
// inheritance chain is created manually in the ko.observableArray constructor
Object.setPrototypeOf(ko.observableArray['fn'], ko.observable['fn']);
// Populate ko.observableArray.fn with native arrays functions
Object.getOwnPropertyNames(Array.prototype).forEach(methodName => {
// skip property length
if (typeof Array.prototype[methodName] === 'function' && 'constructor' != methodName) {
if (["copyWithin", "fill", "pop", "push", "reverse", "shift", "sort", "splice", "unshift"].includes(methodName)) {
// Mutator methods
// https://developer.mozilla.org/tr/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype#mutator_methods
// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
ko.observableArray['fn'][methodName] = function (...args) {
// Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
// (for consistency with mutating regular observables)
var underlyingArray = this.peek();
this.valueWillMutate();
this.cacheDiffForKnownOperation(underlyingArray, methodName, args);
var methodCallResult = underlyingArray[methodName](...args);
this.valueHasMutated();
// The native sort and reverse methods return a reference to the array, but it makes more sense to return the observable array instead.
return methodCallResult === underlyingArray ? this : methodCallResult;
};
} else {
// Accessor and Iteration methods
ko.observableArray['fn'][methodName] = function (...args) {
return this()[methodName](...args);
};
}
}
});
ko.isObservableArray = instance => {
return ko.isObservable(instance)
&& typeof instance["remove"] == "function"
&& typeof instance["push"] == "function";
};
ko.exportSymbol('observableArray', ko.observableArray);
ko.exportSymbol('isObservableArray', ko.isObservableArray);