-
Notifications
You must be signed in to change notification settings - Fork 4
/
knockout.clear.js
127 lines (113 loc) · 4.31 KB
/
knockout.clear.js
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
(function() {
if ((typeof ko === "undefined") ||
(typeof ko.version !== "string") ||
(parseFloat(ko.version.split("-")[0]) < 3.3)) {
throw new Error("This library requires Knockout 3.3");
}
// Simple binding that we can use to keep a side-effecting pureComputed awake
ko.bindingHandlers.execute = {
init: function() {
return { 'controlsDescendantBindings': true };
},
update: function(element, valueAccessor) {
// Unwrap recursively - so binding can be to an array, etc.
ko.toJS(valueAccessor());
}
};
ko.virtualElements.allowedBindings.execute = true;
// Wrap ko.pureComputed to allow us to check if something was created by it
var pureComputedId = "__execute_isPureComputed__";
var originalPureComputed = ko.pureComputed.bind(ko);
ko.pureComputed = function(evaluatorFunctionOrOptions, evaluatorFunctionTarget) {
var pc = originalPureComputed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);
pc[pureComputedId] = true;
return pc;
};
ko.isPureComputed = function(obs) {
return !!(obs && obs[pureComputedId]);
}
// Fix throttle so it returns pureComputed
ko.extenders.throttle = function(target, timeout) {
target['throttleEvaluation'] = timeout;
var writeTimeoutInstance = null;
return ko.pureComputed({
'read': target,
'write': function(value) {
clearTimeout(writeTimeoutInstance);
writeTimeoutInstance = setTimeout(function() {
target(value);
}, timeout);
}
});
};
function ignore() {}
// Creates a computed that is not designed to have a return value, just
// side-effects. It must be given a pureComputed that keeps it awake.
ko.execute = function(pureComputed, evaluator, thisObj) {
if (!ko.isPureComputed(pureComputed)) {
throw new Error("ko.execute must be passed a ko.pureComputed");
}
var internalComputed = ko.pureComputed(evaluator, thisObj);
var disposable;
function wake() {
if (!disposable) {
disposable = internalComputed.subscribe(ignore);
}
}
// Should we start in the awake state?
if (pureComputed.getSubscriptionsCount("change") !== 0) {
wake();
}
pureComputed.subscribe(wake, null, "awake");
pureComputed.subscribe(function() {
if (disposable) {
disposable.dispose();
disposable = null;
}
}, null, "asleep");
return internalComputed;
}
// ko.unpromise:
//
// Returns a pureComputed, using an evaluator function that may return
// a promise (or thenable). The promise is unwrapped and supplies the
// value of the returned pureComputed.
//
// The second argument is optional, and may be an object containing any
// of these optional properties:
//
// initialValue - the value of the returned pureComputed prior to
// promise being resolved
//
// errorValue - the value of the returned pureComputed if the
// promise is rejected
//
// thisArg - the 'this' argument for the evaluator function
//
// If no errorValue is specified, initialValue is used instead. If no
// initialValue is specified, undefined is used instead.
ko.unpromise = function(evaluator, options) {
var latest = ko.observable(options && options.initialValue),
waitingOn = 0,
result = ko.pureComputed(latest),
errorValue = options && (options.errorValue || options.initialValue)
ko.execute(result, function() {
var p = evaluator.call(options && options.thisArg);
var w = ++waitingOn;
if (p && p.then) {
p.then(function(v) {
if (w === waitingOn) {
latest(v);
}
}, function() {
if (w === waitingOn) {
latest(errorValue);
}
});
} else {
latest(p);
}
});
return result;
}
}());