1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
var observableLatestValue = ko.utils.createSymbolOrString('_latestValue');
ko.observable = function (initialValue) {
function observable() {
if (arguments.length > 0) {
// Write
// Ignore writes if the value hasn't changed
if (observable.isDifferent(observable[observableLatestValue], arguments[0])) {
observable.valueWillMutate();
observable[observableLatestValue] = arguments[0];
observable.valueHasMutated();
}
return this; // Permits chained assignments
}
else {
// Read
ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
return observable[observableLatestValue];
}
}
observable[observableLatestValue] = initialValue;
// Inherit from 'subscribable'
if (!ko.utils.canSetPrototype) {
// 'subscribable' won't be on the prototype chain unless we put it there directly
ko.utils.extend(observable, ko.subscribable['fn']);
}
ko.subscribable['fn'].init(observable);
// Inherit from 'observable'
ko.utils.setPrototypeOfOrExtend(observable, observableFn);
if (ko.options['deferUpdates']) {
ko.extenders['deferred'](observable, true);
}
return observable;
}
// Define prototype for observables
var observableFn = {
'equalityComparer': valuesArePrimitiveAndEqual,
peek: function() { return this[observableLatestValue]; },
valueHasMutated: function () {
this['notifySubscribers'](this[observableLatestValue], 'spectate');
this['notifySubscribers'](this[observableLatestValue]);
},
valueWillMutate: function () { this['notifySubscribers'](this[observableLatestValue], 'beforeChange'); }
};
// Note that for browsers that don't support proto assignment, the
// inheritance chain is created manually in the ko.observable constructor
if (ko.utils.canSetPrototype) {
ko.utils.setPrototypeOf(observableFn, ko.subscribable['fn']);
}
var protoProperty = ko.observable.protoProperty = '__ko_proto__';
observableFn[protoProperty] = ko.observable;
ko.isObservable = function (instance) {
var proto = typeof instance == 'function' && instance[protoProperty];
if (proto && proto !== observableFn[protoProperty] && proto !== ko.computed['fn'][protoProperty]) {
throw Error("Invalid object that looks like an observable; possibly from another Knockout instance");
}
return !!proto;
};
ko.isWriteableObservable = function (instance) {
return (typeof instance == 'function' && (
(instance[protoProperty] === observableFn[protoProperty]) || // Observable
(instance[protoProperty] === ko.computed['fn'][protoProperty] && instance.hasWriteFunction))); // Writable computed observable
};
ko.exportSymbol('observable', ko.observable);
ko.exportSymbol('isObservable', ko.isObservable);
ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
ko.exportSymbol('isWritableObservable', ko.isWriteableObservable);
ko.exportSymbol('observable.fn', observableFn);
ko.exportProperty(observableFn, 'peek', observableFn.peek);
ko.exportProperty(observableFn, 'valueHasMutated', observableFn.valueHasMutated);
ko.exportProperty(observableFn, 'valueWillMutate', observableFn.valueWillMutate);
|