/
settable.js
157 lines (143 loc) · 4.06 KB
/
settable.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"use strict";
var canReflect = require("can-reflect");
var ObservationRecorder = require("can-observation-recorder");
var SimpleObservable = require("../can-simple-observable");
var Observation = require("can-observation");
var queues = require("can-queues");
var log = require("../log");
var valueEventBindings = require("can-event-queue/value/value");
var peek = ObservationRecorder.ignore(canReflect.getValue.bind(canReflect));
// This supports an "internal" settable value that the `fn` can derive its value from.
// It's useful to `can-define`.
// ```
// new SettableObservable(function(lastSet){
// return lastSet * 5;
// }, null, 5)
// ```
function SettableObservable(fn, context, initialValue) {
this.lastSetValue = new SimpleObservable(initialValue);
function observe() {
return fn.call(context, this.lastSetValue.get());
}
this.handler = this.handler.bind(this);
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
canReflect.assignSymbols(this, {
"can.getName": function() {
return (
canReflect.getName(this.constructor) +
"<" +
canReflect.getName(fn) +
">"
);
}
});
Object.defineProperty(this.handler, "name", {
value: canReflect.getName(this) + ".handler"
});
Object.defineProperty(observe, "name", {
value: canReflect.getName(fn) + "::" + canReflect.getName(this.constructor)
});
}
//!steal-remove-end
this.observation = new Observation(observe, this);
}
valueEventBindings(SettableObservable.prototype);
canReflect.assignMap(SettableObservable.prototype, {
// call `obs.log()` to log observable changes to the browser console
// The observable has to be bound for `.log` to be called
log: log,
constructor: SettableObservable,
handler: function(newVal) {
var old = this._value;
this._value = newVal;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (typeof this._log === "function") {
this._log(old, newVal);
}
}
//!steal-remove-end
// adds callback handlers to be called w/i their respective queue.
queues.enqueueByQueue(
this.handlers.getNode([]),
this,
[newVal, old],
function() {
return {};
}
);
},
onBound: function() {
// onBound can be called by `.get` and then later called through
// a keyTree binding.
if(!this.bound) {
this.bound = true;
this.activate();
}
},
activate: function(){
canReflect.onValue(this.observation, this.handler, "notify");
this._value = peek(this.observation);
},
onUnbound: function() {
this.bound = false;
canReflect.offValue(this.observation, this.handler, "notify");
},
set: function(newVal) {
var oldVal = this.lastSetValue.get();
if (
canReflect.isObservableLike(oldVal) &&
canReflect.isValueLike(oldVal) &&
!canReflect.isObservableLike(newVal)
) {
canReflect.setValue(oldVal, newVal);
} else {
if (newVal !== oldVal) {
this.lastSetValue.set(newVal);
}
}
},
get: function() {
if (ObservationRecorder.isRecording()) {
ObservationRecorder.add(this);
if (!this.bound) {
// proactively setup bindings
this.onBound();
}
}
if (this.bound === true) {
return this._value;
} else {
return this.observation.get();
}
},
hasDependencies: function() {
return canReflect.valueHasDependencies(this.observation);
},
getValueDependencies: function() {
return canReflect.getValueDependencies(this.observation);
}
});
Object.defineProperty(SettableObservable.prototype,"value",{
set: function(value){
return this.set(value);
},
get: function(){
return this.get();
}
});
canReflect.assignSymbols(SettableObservable.prototype, {
"can.getValue": SettableObservable.prototype.get,
"can.setValue": SettableObservable.prototype.set,
"can.isMapLike": false,
"can.getPriority": function() {
return canReflect.getPriority(this.observation);
},
"can.setPriority": function(newPriority) {
canReflect.setPriority(this.observation, newPriority);
},
"can.valueHasDependencies": SettableObservable.prototype.hasDependencies,
"can.getValueDependencies": SettableObservable.prototype.getValueDependencies
});
module.exports = SettableObservable;