-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
reactive-var.js
103 lines (91 loc) · 3.64 KB
/
reactive-var.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
// CHANGE FOR NPM:
import {Tracker} from './tracker';
let ReactiveVar;
/*
* ## [new] ReactiveVar(initialValue, [equalsFunc])
*
* A ReactiveVar holds a single value that can be get and set,
* such that calling `set` will invalidate any Computations that
* called `get`, according to the usual contract for reactive
* data sources.
*
* A ReactiveVar is much like a Session variable -- compare `foo.get()`
* to `Session.get("foo")` -- but it doesn't have a global name and isn't
* automatically migrated across hot code pushes. Also, while Session
* variables can only hold JSON or EJSON, ReactiveVars can hold any value.
*
* An important property of ReactiveVars, which is sometimes the reason
* to use one, is that setting the value to the same value as before has
* no effect, meaning ReactiveVars can be used to absorb extra
* invalidations that wouldn't serve a purpose. However, by default,
* ReactiveVars are extremely conservative about what changes they
* absorb. Calling `set` with an object argument will *always* trigger
* invalidations, because even if the new value is `===` the old value,
* the object may have been mutated. You can change the default behavior
* by passing a function of two arguments, `oldValue` and `newValue`,
* to the constructor as `equalsFunc`.
*
* This class is extremely basic right now, but the idea is to evolve
* it into the ReactiveVar of Geoff's Lickable Forms proposal.
*/
/**
* @class
* @instanceName reactiveVar
* @summary Constructor for a ReactiveVar, which represents a single reactive variable.
* @locus Client
* @param {Any} initialValue The initial value to set. `equalsFunc` is ignored when setting the initial value.
* @param {Function} [equalsFunc] Optional. A function of two arguments, called on the old value and the new value whenever the ReactiveVar is set. If it returns true, no set is performed. If omitted, the default `equalsFunc` returns true if its arguments are `===` and are of type number, boolean, string, undefined, or null.
*/
ReactiveVar = function (initialValue, equalsFunc) {
if (! (this instanceof ReactiveVar))
// called without `new`
return new ReactiveVar(initialValue, equalsFunc);
this.curValue = initialValue;
this.equalsFunc = equalsFunc;
this.dep = new Tracker.Dependency;
};
ReactiveVar._isEqual = function (oldValue, newValue) {
var a = oldValue, b = newValue;
// Two values are "equal" here if they are `===` and are
// number, boolean, string, undefined, or null.
if (a !== b)
return false;
else
return ((!a) || (typeof a === 'number') || (typeof a === 'boolean') ||
(typeof a === 'string'));
};
/**
* @summary Returns the current value of the ReactiveVar, establishing a reactive dependency.
* @locus Client
*/
ReactiveVar.prototype.get = function () {
if (Tracker.active)
this.dep.depend();
return this.curValue;
};
/**
* @summary Sets the current value of the ReactiveVar, invalidating the Computations that called `get` if `newValue` is different from the old value.
* @locus Client
* @param {Any} newValue
*/
ReactiveVar.prototype.set = function (newValue) {
var oldValue = this.curValue;
if ((this.equalsFunc || ReactiveVar._isEqual)(oldValue, newValue))
// value is same as last time
return;
this.curValue = newValue;
this.dep.changed();
};
ReactiveVar.prototype.toString = function () {
return 'ReactiveVar{' + this.get() + '}';
};
ReactiveVar.prototype._numListeners = function() {
// Tests want to know.
// Accesses a private field of Tracker.Dependency.
var count = 0;
for (var id in this.dep._dependentsById)
count++;
return count;
};
// CHANGE FOR NPM:
export {ReactiveVar};