grainjs 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -71
- package/dist/cjs/index.js +5 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/PriorityQueue.d.ts +1 -1
- package/dist/cjs/lib/_computed_queue.js +3 -3
- package/dist/cjs/lib/_computed_queue.js.map +1 -1
- package/dist/cjs/lib/binding.d.ts +11 -4
- package/dist/cjs/lib/binding.js +5 -5
- package/dist/cjs/lib/binding.js.map +1 -1
- package/dist/cjs/lib/computed.d.ts +49 -28
- package/dist/cjs/lib/computed.js +38 -52
- package/dist/cjs/lib/computed.js.map +1 -1
- package/dist/cjs/lib/dispose.d.ts +109 -96
- package/dist/cjs/lib/dispose.js +106 -80
- package/dist/cjs/lib/dispose.js.map +1 -1
- package/dist/cjs/lib/dom.d.ts +38 -18
- package/dist/cjs/lib/dom.js +44 -20
- package/dist/cjs/lib/dom.js.map +1 -1
- package/dist/cjs/lib/domComponent.d.ts +56 -48
- package/dist/cjs/lib/domComponent.js +66 -1
- package/dist/cjs/lib/domComponent.js.map +1 -1
- package/dist/cjs/lib/domComputed.d.ts +31 -21
- package/dist/cjs/lib/domComputed.js +14 -11
- package/dist/cjs/lib/domComputed.js.map +1 -1
- package/dist/cjs/lib/domDispose.d.ts +27 -12
- package/dist/cjs/lib/domDispose.js +26 -11
- package/dist/cjs/lib/domDispose.js.map +1 -1
- package/dist/cjs/lib/domForEach.d.ts +4 -3
- package/dist/cjs/lib/domForEach.js +10 -9
- package/dist/cjs/lib/domForEach.js.map +1 -1
- package/dist/cjs/lib/domImpl.d.ts +33 -10
- package/dist/cjs/lib/domImpl.js +28 -9
- package/dist/cjs/lib/domImpl.js.map +1 -1
- package/dist/cjs/lib/domMethods.d.ts +93 -47
- package/dist/cjs/lib/domMethods.js +88 -46
- package/dist/cjs/lib/domMethods.js.map +1 -1
- package/dist/cjs/lib/domevent.d.ts +87 -62
- package/dist/cjs/lib/domevent.js +84 -59
- package/dist/cjs/lib/domevent.js.map +1 -1
- package/dist/cjs/lib/emit.d.ts +62 -32
- package/dist/cjs/lib/emit.js +67 -53
- package/dist/cjs/lib/emit.js.map +1 -1
- package/dist/cjs/lib/kowrap.d.ts +6 -3
- package/dist/cjs/lib/kowrap.js +6 -3
- package/dist/cjs/lib/kowrap.js.map +1 -1
- package/dist/cjs/lib/obsArray.d.ts +91 -53
- package/dist/cjs/lib/obsArray.js +87 -55
- package/dist/cjs/lib/obsArray.js.map +1 -1
- package/dist/cjs/lib/observable.d.ts +25 -15
- package/dist/cjs/lib/observable.js +29 -18
- package/dist/cjs/lib/observable.js.map +1 -1
- package/dist/cjs/lib/pureComputed.d.ts +12 -15
- package/dist/cjs/lib/pureComputed.js +15 -18
- package/dist/cjs/lib/pureComputed.js.map +1 -1
- package/dist/cjs/lib/styled.d.ts +78 -61
- package/dist/cjs/lib/styled.js +26 -79
- package/dist/cjs/lib/styled.js.map +1 -1
- package/dist/cjs/lib/subscribe.d.ts +41 -37
- package/dist/cjs/lib/subscribe.js +31 -40
- package/dist/cjs/lib/subscribe.js.map +1 -1
- package/dist/cjs/lib/util.js +1 -0
- package/dist/cjs/lib/util.js.map +1 -1
- package/dist/cjs/lib/widgets/input.d.ts +3 -1
- package/dist/cjs/lib/widgets/input.js +6 -4
- package/dist/cjs/lib/widgets/input.js.map +1 -1
- package/dist/cjs/lib/widgets/select.d.ts +4 -2
- package/dist/cjs/lib/widgets/select.js +7 -5
- package/dist/cjs/lib/widgets/select.js.map +1 -1
- package/dist/esm/lib/_computed_queue.js +3 -3
- package/dist/esm/lib/_computed_queue.js.map +1 -1
- package/dist/esm/lib/binding.js +2 -2
- package/dist/esm/lib/binding.js.map +1 -1
- package/dist/esm/lib/computed.js +36 -50
- package/dist/esm/lib/computed.js.map +1 -1
- package/dist/esm/lib/dispose.js +104 -78
- package/dist/esm/lib/dispose.js.map +1 -1
- package/dist/esm/lib/dom.js +38 -18
- package/dist/esm/lib/dom.js.map +1 -1
- package/dist/esm/lib/domComponent.js +65 -0
- package/dist/esm/lib/domComponent.js.map +1 -1
- package/dist/esm/lib/domComputed.js +10 -7
- package/dist/esm/lib/domComputed.js.map +1 -1
- package/dist/esm/lib/domDispose.js +26 -11
- package/dist/esm/lib/domDispose.js.map +1 -1
- package/dist/esm/lib/domForEach.js +3 -2
- package/dist/esm/lib/domForEach.js.map +1 -1
- package/dist/esm/lib/domImpl.js +26 -7
- package/dist/esm/lib/domImpl.js.map +1 -1
- package/dist/esm/lib/domMethods.js +77 -35
- package/dist/esm/lib/domMethods.js.map +1 -1
- package/dist/esm/lib/domevent.js +84 -59
- package/dist/esm/lib/domevent.js.map +1 -1
- package/dist/esm/lib/emit.js +67 -53
- package/dist/esm/lib/emit.js.map +1 -1
- package/dist/esm/lib/kowrap.js +5 -2
- package/dist/esm/lib/kowrap.js.map +1 -1
- package/dist/esm/lib/obsArray.js +82 -50
- package/dist/esm/lib/obsArray.js.map +1 -1
- package/dist/esm/lib/observable.js +26 -15
- package/dist/esm/lib/observable.js.map +1 -1
- package/dist/esm/lib/pureComputed.js +15 -18
- package/dist/esm/lib/pureComputed.js.map +1 -1
- package/dist/esm/lib/styled.js +24 -77
- package/dist/esm/lib/styled.js.map +1 -1
- package/dist/esm/lib/subscribe.js +27 -36
- package/dist/esm/lib/subscribe.js.map +1 -1
- package/dist/esm/lib/util.js +1 -0
- package/dist/esm/lib/util.js.map +1 -1
- package/dist/esm/lib/widgets/input.js +3 -1
- package/dist/esm/lib/widgets/input.js.map +1 -1
- package/dist/esm/lib/widgets/select.js +3 -1
- package/dist/esm/lib/widgets/select.js.map +1 -1
- package/dist/grain-full.debug.js +2146 -3062
- package/dist/grain-full.debug.js.map +7 -0
- package/dist/grain-full.min.js +6 -2
- package/dist/grain-full.min.js.map +7 -1
- package/lib/binding.ts +9 -2
- package/lib/computed.ts +56 -56
- package/lib/dispose.ts +110 -85
- package/lib/dom.ts +39 -20
- package/lib/domComponent.ts +66 -57
- package/lib/domComputed.ts +29 -19
- package/lib/domDispose.ts +28 -11
- package/lib/domForEach.ts +7 -3
- package/lib/domImpl.ts +30 -7
- package/lib/domMethods.ts +101 -46
- package/lib/domevent.ts +85 -60
- package/lib/emit.ts +64 -50
- package/lib/kowrap.ts +5 -2
- package/lib/obsArray.ts +89 -54
- package/lib/observable.ts +26 -15
- package/lib/pureComputed.ts +16 -22
- package/lib/styled.ts +85 -71
- package/lib/subscribe.ts +41 -45
- package/lib/util.ts +1 -0
- package/lib/widgets/input.ts +3 -1
- package/lib/widgets/select.ts +3 -1
- package/package.json +38 -27
package/lib/kowrap.ts
CHANGED
|
@@ -65,10 +65,10 @@ export function fromKo<KObs extends IKnockoutObservable<any>>(koObs: KObs): Obse
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
* An Observable that wraps a Knockout observable, created via fromKo()
|
|
68
|
+
* An Observable that wraps a Knockout observable, created via `fromKo()`. It keeps minimal overhead
|
|
69
69
|
* when unused by only subscribing to the wrapped observable while it itself has subscriptions.
|
|
70
70
|
*
|
|
71
|
-
* This way, when unused, the only reference is from the wrapper to the wrapped object. KoWrapObs
|
|
71
|
+
* This way, when unused, the only reference is from the wrapper to the wrapped object. `KoWrapObs`
|
|
72
72
|
* should not be disposed; its lifetime is tied to that of the wrapped object.
|
|
73
73
|
*/
|
|
74
74
|
export class KoWrapObs<T> extends Observable<T> {
|
|
@@ -88,8 +88,11 @@ export class KoWrapObs<T> extends Observable<T> {
|
|
|
88
88
|
}
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
|
+
/** @override */
|
|
91
92
|
public get(): T { return this._koObs.peek(); }
|
|
93
|
+
/** @override */
|
|
92
94
|
public set(value: T): void { bundleChanges(() => this._koObs(value)); }
|
|
95
|
+
/** @override */
|
|
93
96
|
public dispose(): void { throw new Error("KoWrapObs should not be disposed"); }
|
|
94
97
|
}
|
|
95
98
|
|
package/lib/obsArray.ts
CHANGED
|
@@ -1,36 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ObsArray extends a plain Observable to allow for more efficient observation of array changes.
|
|
3
|
-
*
|
|
4
|
-
* As for any array-valued Observable, when the contents of the observed array changes, the
|
|
5
|
-
* listeners get called with new and previous values which are the same array. For simple changes,
|
|
6
|
-
* such as those made with .push() and .splice() methods, ObsArray allows for more efficient
|
|
7
|
-
* handling of the change by calling listeners with splice info in the third argument.
|
|
8
|
-
*
|
|
9
|
-
* This module also provides computedArray(), which allows mapping each item of an ObsArray
|
|
10
|
-
* through a function, passing through splice info for efficient handling of small changes. It
|
|
11
|
-
* also allows mapping an observable or a computed whose value is an ObsArray.
|
|
12
|
-
*
|
|
13
|
-
* There is no need or benefit in using computedArray() if you have a computed() that returns a
|
|
14
|
-
* plain array. It is specifically for the case when you want to preserve the efficiency of
|
|
15
|
-
* ObsArray when you map its values.
|
|
16
|
-
*
|
|
17
|
-
* Both ObsArray and ComputedArray may be used with disposable elements as their owners. E.g.
|
|
18
|
-
*
|
|
19
|
-
* const arr = obsArray<D>();
|
|
20
|
-
* arr.push(D.create(arr, "x"), D.create(arr, "y"));
|
|
21
|
-
* arr.pop(); // Element "y" gets disposed.
|
|
22
|
-
* arr.dispose(); // Element "x" gets disposed.
|
|
23
|
-
*
|
|
24
|
-
* const values = obsArray<string>();
|
|
25
|
-
* const compArr = computedArray<D>(values, (val, i, compArr) => D.create(compArr, val));
|
|
26
|
-
* values.push("foo", "bar"); // D("foo") and D("bar") get created
|
|
27
|
-
* values.pop(); // D("bar") gets disposed.
|
|
28
|
-
* compArr.dispose(); // D("foo") gets disposed.
|
|
29
|
-
*
|
|
30
|
-
* Note that only the pattern above works: obsArray (or compArray) may only be used to take
|
|
31
|
-
* ownership of those disposables that are added to it as array elements.
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
1
|
import {IDisposable, IDisposableOwnerT, setDisposeOwner} from './dispose';
|
|
35
2
|
import {Listener} from './emit';
|
|
36
3
|
import {BaseObservable, Observable} from './observable';
|
|
@@ -48,7 +15,7 @@ export type MaybeObsArray<T> = BaseObservable<T[]> | T[];
|
|
|
48
15
|
* completely.
|
|
49
16
|
*/
|
|
50
17
|
export interface IObsArraySplice<T> {
|
|
51
|
-
start: number;
|
|
18
|
+
start: number; /** asdf */
|
|
52
19
|
numAdded: number;
|
|
53
20
|
deleted: T[];
|
|
54
21
|
}
|
|
@@ -56,24 +23,50 @@ export interface IObsArraySplice<T> {
|
|
|
56
23
|
export type ISpliceListener<T, C> = (this: C, val: T[], prev: T[], change?: IObsArraySplice<T>) => void;
|
|
57
24
|
|
|
58
25
|
/**
|
|
59
|
-
* ObsArray<T
|
|
26
|
+
* `ObsArray<T>` is essentially an array-valued observable. It extends a plain Observable to allow
|
|
27
|
+
* for more efficient observation of array changes. It also may be
|
|
60
28
|
* used as an owner for disposable array elements.
|
|
29
|
+
*
|
|
30
|
+
* As for any array-valued `Observable`, when the contents of the observed array changes, the
|
|
31
|
+
* listeners get called with new and previous values which are the same array. For simple changes,
|
|
32
|
+
* such as those made with `.push()` and `.splice()` methods, `ObsArray` allows for more efficient
|
|
33
|
+
* handling of the change by calling listeners with splice info in the third argument.
|
|
34
|
+
*
|
|
35
|
+
* `ObsArray` may be used with disposable elements as their owner. E.g.
|
|
36
|
+
* ```ts
|
|
37
|
+
* const arr = obsArray<D>();
|
|
38
|
+
* arr.push(D.create(arr, "x"), D.create(arr, "y"));
|
|
39
|
+
* arr.pop(); // Element "y" gets disposed.
|
|
40
|
+
* arr.dispose(); // Element "x" gets disposed.
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* Note that only the pattern above works: `obsArray` may only be used to take
|
|
44
|
+
* ownership of those disposables that are added to it as array elements.
|
|
61
45
|
*/
|
|
62
46
|
export class ObsArray<T> extends BaseObservable<T[]> {
|
|
63
47
|
private _ownedItems?: Set<T & IDisposable> = undefined;
|
|
64
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Adds a callback to listen to changes in the observable. In case of `ObsArray`, the listener
|
|
51
|
+
* gets additional information.
|
|
52
|
+
*/
|
|
65
53
|
public addListener(callback: ISpliceListener<T, void>): Listener;
|
|
66
54
|
public addListener<C>(callback: ISpliceListener<T, C>, context: C): Listener;
|
|
67
55
|
public addListener(callback: ISpliceListener<T, any>, optContext?: any): Listener {
|
|
68
56
|
return super.addListener(callback, optContext);
|
|
69
57
|
}
|
|
70
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Take ownership of an item added to this array. This should _only_ be used for array elements,
|
|
61
|
+
* not any unrelated items.
|
|
62
|
+
*/
|
|
71
63
|
public autoDispose(value: T & IDisposable): T & IDisposable {
|
|
72
64
|
if (!this._ownedItems) { this._ownedItems = new Set<T & IDisposable>(); }
|
|
73
65
|
this._ownedItems.add(value);
|
|
74
66
|
return value;
|
|
75
67
|
}
|
|
76
68
|
|
|
69
|
+
/** @override */
|
|
77
70
|
public dispose(): void {
|
|
78
71
|
if (this._ownedItems) {
|
|
79
72
|
for (const item of this.get() as Array<T & IDisposable>) {
|
|
@@ -86,10 +79,12 @@ export class ObsArray<T> extends BaseObservable<T[]> {
|
|
|
86
79
|
super.dispose();
|
|
87
80
|
}
|
|
88
81
|
|
|
82
|
+
/** @internal */
|
|
89
83
|
protected _setWithSplice(value: T[], splice: IObsArraySplice<T>): void {
|
|
90
84
|
return this._setWithArg(value, splice);
|
|
91
85
|
}
|
|
92
86
|
|
|
87
|
+
/** @internal */
|
|
93
88
|
protected _disposeOwned(splice?: IObsArraySplice<T>): void {
|
|
94
89
|
if (!this._ownedItems) { return; }
|
|
95
90
|
if (splice) {
|
|
@@ -117,10 +112,11 @@ export class ObsArray<T> extends BaseObservable<T[]> {
|
|
|
117
112
|
}
|
|
118
113
|
|
|
119
114
|
/**
|
|
120
|
-
* MutableObsArray<T
|
|
121
|
-
* allow more efficient processing of such changes. It is created with obsArray<T>()
|
|
115
|
+
* `MutableObsArray<T>` adds array-like mutation methods which emit events with splice info, to
|
|
116
|
+
* allow more efficient processing of such changes. It is created with `obsArray<T>()`.
|
|
122
117
|
*/
|
|
123
118
|
export class MutableObsArray<T> extends ObsArray<T> {
|
|
119
|
+
/** Appends elements to the end and returns the new length (like `Array#push`). */
|
|
124
120
|
public push(...args: T[]): number {
|
|
125
121
|
const value = this.get();
|
|
126
122
|
const start = value.length;
|
|
@@ -129,6 +125,7 @@ export class MutableObsArray<T> extends ObsArray<T> {
|
|
|
129
125
|
return newLen;
|
|
130
126
|
}
|
|
131
127
|
|
|
128
|
+
/** Removes and returns the last element (like `Array#pop`). */
|
|
132
129
|
public pop(): T|undefined {
|
|
133
130
|
const value = this.get();
|
|
134
131
|
if (value.length === 0) { return undefined; }
|
|
@@ -137,6 +134,7 @@ export class MutableObsArray<T> extends ObsArray<T> {
|
|
|
137
134
|
return ret;
|
|
138
135
|
}
|
|
139
136
|
|
|
137
|
+
/** Prepends elements to the start and returns the new length (like `Array#unshift`). */
|
|
140
138
|
public unshift(...args: T[]) {
|
|
141
139
|
const value = this.get();
|
|
142
140
|
const newLen = value.unshift(...args);
|
|
@@ -144,6 +142,7 @@ export class MutableObsArray<T> extends ObsArray<T> {
|
|
|
144
142
|
return newLen;
|
|
145
143
|
}
|
|
146
144
|
|
|
145
|
+
/** Removes and returns the first element (like `Array#shift`). */
|
|
147
146
|
public shift(): T|undefined {
|
|
148
147
|
const value = this.get();
|
|
149
148
|
if (value.length === 0) { return undefined; }
|
|
@@ -152,6 +151,10 @@ export class MutableObsArray<T> extends ObsArray<T> {
|
|
|
152
151
|
return ret;
|
|
153
152
|
}
|
|
154
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Removes and/or inserts elements at a given index and returns the removed elements (like
|
|
156
|
+
* `Array#splice`).
|
|
157
|
+
*/
|
|
155
158
|
public splice(start: number, deleteCount: number = Infinity, ...newValues: T[]) {
|
|
156
159
|
const value = this.get();
|
|
157
160
|
const len = value.length;
|
|
@@ -164,7 +167,7 @@ export class MutableObsArray<T> extends ObsArray<T> {
|
|
|
164
167
|
|
|
165
168
|
/**
|
|
166
169
|
* Creates a new MutableObsArray with an optional initial value, defaulting to the empty array.
|
|
167
|
-
* It is essentially the same as observable<T[]
|
|
170
|
+
* It is essentially the same as `observable<T[]>`, but with array-like mutation methods.
|
|
168
171
|
*/
|
|
169
172
|
export function obsArray<T>(value: T[] = []): MutableObsArray<T> {
|
|
170
173
|
return new MutableObsArray<T>(value);
|
|
@@ -178,7 +181,7 @@ function isObsArray(val: BaseObservable<any>): val is BaseObservable<any[]> {
|
|
|
178
181
|
}
|
|
179
182
|
|
|
180
183
|
/**
|
|
181
|
-
* See computedArray()
|
|
184
|
+
* See [`computedArray()`](#computedArray) for documentation.
|
|
182
185
|
*/
|
|
183
186
|
export class ComputedArray<T, U> extends ObsArray<U> {
|
|
184
187
|
private _sub: Subscription;
|
|
@@ -196,6 +199,7 @@ export class ComputedArray<T, U> extends ObsArray<U> {
|
|
|
196
199
|
subscribe(obsArr, (use, obsArrayValue) => { use(obsArrayValue); return this._syncMap(obsArrayValue); });
|
|
197
200
|
}
|
|
198
201
|
|
|
202
|
+
/** @internal */
|
|
199
203
|
public dispose() {
|
|
200
204
|
this._unsync();
|
|
201
205
|
this._sub.dispose();
|
|
@@ -254,25 +258,43 @@ export class ComputedArray<T, U> extends ObsArray<U> {
|
|
|
254
258
|
}
|
|
255
259
|
|
|
256
260
|
/**
|
|
257
|
-
* Returns an ObsArray that maps all elements of the passed-in ObsArray through a mapper
|
|
258
|
-
* Also accepts an observable (e.g. a computed) whose value is an ObsArray
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
* The result is entirely analogous to:
|
|
261
|
+
* Returns an `ObsArray` that maps all elements of the passed-in `ObsArray` through a mapper
|
|
262
|
+
* function. Also accepts an observable (e.g. a computed) whose value is an `ObsArray`.
|
|
263
|
+
* ```ts
|
|
264
|
+
* computedArray(obsArray, mapper)
|
|
265
|
+
* ```
|
|
263
266
|
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
267
|
+
* The result is analogous to:
|
|
268
|
+
* ```ts
|
|
269
|
+
* computed((use) => use(obsArray).map(mapper)) // for ObsArray
|
|
270
|
+
* computed((use) => use(use(obsArray)).map(mapper)) // for Observable<ObsArray>
|
|
271
|
+
* ```
|
|
266
272
|
*
|
|
267
|
-
* The benefit of computedArray() is that a small change to the source array (e.g. one item
|
|
273
|
+
* The benefit of `computedArray()` is that a small change to the source array (e.g. one item
|
|
268
274
|
* added or removed), causes a small change to the mapped array, rather than a full rebuild.
|
|
269
275
|
*
|
|
270
|
-
* This is useful with an ObsArray or with an observable whose value is an ObsArray
|
|
271
|
-
* when the computed array
|
|
276
|
+
* This is useful with an `ObsArray` or with an observable whose value is an `ObsArray`, and also
|
|
277
|
+
* when the computed array's items are disposable and it owns them.
|
|
272
278
|
*
|
|
273
|
-
*
|
|
274
|
-
* array.
|
|
279
|
+
* There is no need or benefit to using `computedArray()` if you have a `computed()` that returns
|
|
280
|
+
* a plain array. It is specifically for the case when you want to preserve the efficiency of
|
|
281
|
+
* `ObsArray` when you map its values.
|
|
282
|
+
*
|
|
283
|
+
* Note that the mapper function is called with `(item, index, array)` as for a standard
|
|
284
|
+
* `array.map()`, but that the index is only accurate at the time of the call, and will stop
|
|
275
285
|
* reflecting the true index if more items are inserted into the array later.
|
|
286
|
+
*
|
|
287
|
+
* As with `ObsArray`, a `ComputedArray` may be used with disposable elements as their owners. E.g.
|
|
288
|
+
* ```ts
|
|
289
|
+
* const values = obsArray<string>();
|
|
290
|
+
* const compArr = computedArray<D>(values, (val, i, compArr) => D.create(compArr, val));
|
|
291
|
+
* values.push("foo", "bar"); // D("foo") and D("bar") get created
|
|
292
|
+
* values.pop(); // D("bar") gets disposed.
|
|
293
|
+
* compArr.dispose(); // D("foo") gets disposed.
|
|
294
|
+
* ```
|
|
295
|
+
*
|
|
296
|
+
* Note that only the pattern above works: obsArray (or compArray) may only be used to take
|
|
297
|
+
* ownership of those disposables that are added to it as array elements.
|
|
276
298
|
*/
|
|
277
299
|
export function computedArray<T, U>(
|
|
278
300
|
obsArr: BaseObservable<T[]> | Observable<BaseObservable<T[]>>,
|
|
@@ -296,6 +318,9 @@ export function makeLiveIndex<T>(owner: IDisposableOwnerT<LiveIndex>|null, obsAr
|
|
|
296
318
|
return setDisposeOwner(owner, new LiveIndex(obsArr, initialIndex));
|
|
297
319
|
}
|
|
298
320
|
|
|
321
|
+
/**
|
|
322
|
+
* An Observable that represents an index into an `ObsArray`, clamped to be in the valid range.
|
|
323
|
+
*/
|
|
299
324
|
export class LiveIndex extends Observable<number|null> {
|
|
300
325
|
private _listener: Listener;
|
|
301
326
|
private _isLive: boolean = true;
|
|
@@ -306,18 +331,28 @@ export class LiveIndex extends Observable<number|null> {
|
|
|
306
331
|
this._listener = _obsArray.addListener(this._onArrayChange, this);
|
|
307
332
|
}
|
|
308
333
|
|
|
334
|
+
/**
|
|
335
|
+
* Set the index, clamping it to a valid value.
|
|
336
|
+
*/
|
|
309
337
|
public set(index: number|null) {
|
|
310
338
|
// Clamp to [0, len) range of the observable array.
|
|
311
339
|
const len = this._obsArray.get().length;
|
|
312
340
|
super.set(len === 0 ? null : Math.max(0, Math.min(len - 1, index || 0)));
|
|
313
341
|
}
|
|
314
342
|
|
|
315
|
-
|
|
316
|
-
|
|
343
|
+
/**
|
|
344
|
+
* Turn "liveness" on or off. While set to false, the observable will not be adjusted as the
|
|
345
|
+
* array changes, except to keep it valid.
|
|
346
|
+
*
|
|
347
|
+
* @privateRemarks
|
|
348
|
+
* Note that this feature comes from a rather obscure need, and it would be better if something
|
|
349
|
+
* similar were possible without making it an explicit feature.
|
|
350
|
+
*/
|
|
317
351
|
public setLive(value: boolean): void {
|
|
318
352
|
this._isLive = value;
|
|
319
353
|
}
|
|
320
354
|
|
|
355
|
+
/** @override */
|
|
321
356
|
public dispose() {
|
|
322
357
|
this._listener.dispose();
|
|
323
358
|
super.dispose();
|
package/lib/observable.ts
CHANGED
|
@@ -27,13 +27,14 @@ import {Emitter, Listener} from './emit';
|
|
|
27
27
|
|
|
28
28
|
export {bundleChanges} from './_computed_queue';
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Base class for several variants of observable values.
|
|
32
|
+
*/
|
|
30
33
|
export class BaseObservable<T> {
|
|
31
34
|
private _onChange: Emitter;
|
|
32
35
|
private _value: T;
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
* Internal constructor for an Observable. You should use observable() function instead.
|
|
36
|
-
*/
|
|
37
|
+
// Internal constructor for an Observable. You should use observable() function instead.
|
|
37
38
|
constructor(value: T) {
|
|
38
39
|
this._onChange = new Emitter();
|
|
39
40
|
this._value = value;
|
|
@@ -42,14 +43,14 @@ export class BaseObservable<T> {
|
|
|
42
43
|
/**
|
|
43
44
|
* Returns the value of the observable. It is fast and does not create a subscription.
|
|
44
45
|
* (It is similar to knockout's peek()).
|
|
45
|
-
* @returns
|
|
46
|
+
* @returns The current value of the observable.
|
|
46
47
|
*/
|
|
47
48
|
public get(): T { return this._value; }
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* Sets the value of the observable. If the value differs from the previously set one, then
|
|
51
52
|
* listeners to this observable will get called with (newValue, oldValue) as arguments.
|
|
52
|
-
* @param
|
|
53
|
+
* @param value - The new value to set.
|
|
53
54
|
*/
|
|
54
55
|
public set(value: T): void {
|
|
55
56
|
if (value !== this._value) {
|
|
@@ -70,9 +71,9 @@ export class BaseObservable<T> {
|
|
|
70
71
|
|
|
71
72
|
/**
|
|
72
73
|
* Adds a callback to listen to changes in the observable.
|
|
73
|
-
* @param
|
|
74
|
-
* @param
|
|
75
|
-
* @returns
|
|
74
|
+
* @param callback - Function, called on changes with (newValue, oldValue) arguments.
|
|
75
|
+
* @param optContext - Context for the function.
|
|
76
|
+
* @returns Listener object. Its dispose() method removes the callback.
|
|
76
77
|
*/
|
|
77
78
|
public addListener(callback: (val: T, prev: T) => void, optContext?: object): Listener {
|
|
78
79
|
return this._onChange.addListener(callback, optContext);
|
|
@@ -88,7 +89,7 @@ export class BaseObservable<T> {
|
|
|
88
89
|
/**
|
|
89
90
|
* Sets a single callback to be called when a listener is added or removed. It overwrites any
|
|
90
91
|
* previously-set such callback.
|
|
91
|
-
* @param
|
|
92
|
+
* @param changeCB - Function to call after a listener is added or
|
|
92
93
|
* removed. It's called with a boolean indicating whether this observable has any listeners.
|
|
93
94
|
* Pass in `null` to unset the callback. Note that it can be called multiple times in a row
|
|
94
95
|
* with hasListeners `true`.
|
|
@@ -100,6 +101,7 @@ export class BaseObservable<T> {
|
|
|
100
101
|
/**
|
|
101
102
|
* Used by subscriptions to keep track of dependencies. An observable that has dependnecies,
|
|
102
103
|
* such as a computed observable, would override this method.
|
|
104
|
+
* @internal
|
|
103
105
|
*/
|
|
104
106
|
public _getDepItem(): DepItem|null {
|
|
105
107
|
return null;
|
|
@@ -121,11 +123,13 @@ export class BaseObservable<T> {
|
|
|
121
123
|
return this._onChange.isDisposed();
|
|
122
124
|
}
|
|
123
125
|
|
|
126
|
+
/** @internal */
|
|
124
127
|
protected _disposeOwned(arg?: any) { /* noop */ }
|
|
125
128
|
|
|
126
129
|
/**
|
|
127
130
|
* Allow derived classes to emit change events with an additional third argument describing the
|
|
128
131
|
* change. It always emits the event without checking for value equality.
|
|
132
|
+
* @internal
|
|
129
133
|
*/
|
|
130
134
|
protected _setWithArg(value: T, arg: any) {
|
|
131
135
|
const prev = this._value;
|
|
@@ -136,7 +140,11 @@ export class BaseObservable<T> {
|
|
|
136
140
|
}
|
|
137
141
|
}
|
|
138
142
|
|
|
143
|
+
/**
|
|
144
|
+
* An Observable holds a value and allows subscribing to changes.
|
|
145
|
+
*/
|
|
139
146
|
export class Observable<T> extends BaseObservable<T> implements IDisposableOwnerT<T & IDisposable> {
|
|
147
|
+
/** @internal */
|
|
140
148
|
// See module-level holder() function below for documentation.
|
|
141
149
|
public static holder<T>(value: T & IDisposable): Observable<T> {
|
|
142
150
|
const obs = new Observable<T>(value);
|
|
@@ -168,6 +176,7 @@ export class Observable<T> extends BaseObservable<T> implements IDisposableOwner
|
|
|
168
176
|
return value;
|
|
169
177
|
}
|
|
170
178
|
|
|
179
|
+
/** @internal */
|
|
171
180
|
protected _disposeOwned() {
|
|
172
181
|
if (this._owned) {
|
|
173
182
|
this._owned.dispose();
|
|
@@ -178,8 +187,8 @@ export class Observable<T> extends BaseObservable<T> implements IDisposableOwner
|
|
|
178
187
|
|
|
179
188
|
/**
|
|
180
189
|
* Creates a new Observable with the initial value of optValue if given or undefined if omitted.
|
|
181
|
-
* @param
|
|
182
|
-
* @returns
|
|
190
|
+
* @param optValue - The initial value to set.
|
|
191
|
+
* @returns The newly created observable.
|
|
183
192
|
*/
|
|
184
193
|
export function observable<T>(value: T): Observable<T> {
|
|
185
194
|
return new Observable<T>(value);
|
|
@@ -187,16 +196,18 @@ export function observable<T>(value: T): Observable<T> {
|
|
|
187
196
|
|
|
188
197
|
/**
|
|
189
198
|
* Creates a new Observable with an initial disposable value owned by this observable, e.g.
|
|
190
|
-
*
|
|
199
|
+
* ```
|
|
191
200
|
* const obs = obsHolder<D>(D.create(null, ...args));
|
|
201
|
+
* ```
|
|
192
202
|
*
|
|
193
|
-
* This is needed because using simply observable<D>(value) would not cause the observable to take
|
|
203
|
+
* This is needed because using simply `observable<D>(value)` would not cause the observable to take
|
|
194
204
|
* ownership of value (i.e. to dispose it later). This function is a less hacky equivalent to:
|
|
195
|
-
*
|
|
205
|
+
* ```
|
|
196
206
|
* const obs = observable<D>(null as any);
|
|
197
207
|
* D.create(obs, ...args);
|
|
208
|
+
* ```
|
|
198
209
|
*
|
|
199
|
-
* To allow nulls, use observable<D|null>(null)
|
|
210
|
+
* To allow nulls, use `observable<D|null>(null)`; then the obsHolder() constructor is not needed.
|
|
200
211
|
*/
|
|
201
212
|
export function obsHolder<T>(value: T & IDisposable): Observable<T> {
|
|
202
213
|
return Observable.holder<T>(value);
|
package/lib/pureComputed.ts
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* pureComputed.js implements a variant of computed() suitable for use with a pure read function
|
|
3
|
-
* (free of side-effects). A pureComputed is only subscribed to its dependencies when something is
|
|
4
|
-
* subscribed to it. At other times, it is not subscribed to anything, and calls to `get()` will
|
|
5
|
-
* recompute its value each time by calling its read() function.
|
|
6
|
-
*
|
|
7
|
-
* Its syntax and usage are otherwise exactly as for a computed.
|
|
8
|
-
*
|
|
9
|
-
* In addition to being cheaper when unused, a pureComputed() also avoids leaking memory when
|
|
10
|
-
* unused (since it's not registered with dependencies), so it is not necessary to dispose it.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
1
|
import {DepItem} from './_computed_queue';
|
|
14
2
|
import {IKnockoutReadObservable} from './kowrap';
|
|
15
3
|
import {BaseObservable, Observable} from './observable';
|
|
@@ -26,6 +14,17 @@ function _useFunc<T>(obs: BaseObservable<T>|IKnockoutReadObservable<T>): T {
|
|
|
26
14
|
// Constant empty array, which we use to avoid allocating new read-only empty arrays.
|
|
27
15
|
const emptyArray: ReadonlyArray<any> = [];
|
|
28
16
|
|
|
17
|
+
/**
|
|
18
|
+
* `PureComputed` is a variant of `Computed` suitable for use with a pure read function
|
|
19
|
+
* (free of side-effects). A `PureComputed` is only subscribed to its dependencies when something is
|
|
20
|
+
* subscribed to it. At other times, it is not subscribed to anything, and calls to `get()` will
|
|
21
|
+
* recompute its value each time by calling its `read()` function.
|
|
22
|
+
*
|
|
23
|
+
* Its syntax and usage are otherwise exactly as for a `Computed`.
|
|
24
|
+
*
|
|
25
|
+
* In addition to being cheaper when unused, a `PureComputed` also avoids leaking memory when
|
|
26
|
+
* unused (since it's not registered with dependencies), so it is not necessary to dispose it.
|
|
27
|
+
*/
|
|
29
28
|
export class PureComputed<T> extends Observable<T> {
|
|
30
29
|
private _callback: (use: UseCB, ...args: any[]) => T;
|
|
31
30
|
private _write: (value: T) => void;
|
|
@@ -33,9 +32,7 @@ export class PureComputed<T> extends Observable<T> {
|
|
|
33
32
|
private readonly _dependencies: ReadonlyArray<ISubscribableObs>;
|
|
34
33
|
private _inCall: boolean;
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
* Internal constructor for a PureComputed. You should use pureComputed() function instead.
|
|
38
|
-
*/
|
|
35
|
+
// Internal constructor for a PureComputed. You should use pureComputed() function instead.
|
|
39
36
|
constructor(callback: (use: UseCB, ...args: any[]) => T, dependencies: ReadonlyArray<ISubscribable>) {
|
|
40
37
|
// At initialization we force an undefined value even though it's not of type T: it's not
|
|
41
38
|
// actually used as get() is overridden.
|
|
@@ -48,11 +45,13 @@ export class PureComputed<T> extends Observable<T> {
|
|
|
48
45
|
this.setListenerChangeCB(this._onListenerChange, this);
|
|
49
46
|
}
|
|
50
47
|
|
|
48
|
+
/** @internal */
|
|
51
49
|
public _getDepItem(): DepItem {
|
|
52
50
|
this._activate();
|
|
53
51
|
return this._sub!._getDepItem();
|
|
54
52
|
}
|
|
55
53
|
|
|
54
|
+
/** @override */
|
|
56
55
|
public get(): T {
|
|
57
56
|
if (!this._sub && !this._inCall) {
|
|
58
57
|
// _inCall member prevents infinite recursion.
|
|
@@ -74,7 +73,7 @@ export class PureComputed<T> extends Observable<T> {
|
|
|
74
73
|
/**
|
|
75
74
|
* "Sets" the value of the pure computed by calling the write() callback if one was provided in
|
|
76
75
|
* the constructor. Throws an error if there was no such callback (not a "writable" computed).
|
|
77
|
-
* @param
|
|
76
|
+
* @param value - The value to pass to the write() callback.
|
|
78
77
|
*/
|
|
79
78
|
public set(value: T): void { this._write(value); }
|
|
80
79
|
|
|
@@ -121,9 +120,7 @@ export class PureComputed<T> extends Observable<T> {
|
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
/**
|
|
124
|
-
*
|
|
125
|
-
* type-checking when using it. We can only support a fixed number of argumnets (explicit
|
|
126
|
-
* dependencies), but 5 should almost always be enough.
|
|
123
|
+
* Creates and returns a new PureComputed. The interface is identical to that of a Computed.
|
|
127
124
|
*/
|
|
128
125
|
export function pureComputed<T>(cb: (use: UseCB) => T): PureComputed<T>;
|
|
129
126
|
|
|
@@ -147,9 +144,6 @@ export function pureComputed<A, B, C, D, E, T>(
|
|
|
147
144
|
a: Observable<A>, b: Observable<B>, c: Observable<C>, d: Observable<D>, e: Observable<E>,
|
|
148
145
|
cb: (use: UseCB, a: A, b: B, c: C, d: D, e: E) => T): PureComputed<T>;
|
|
149
146
|
|
|
150
|
-
/**
|
|
151
|
-
* Creates and returns a new PureComputed. The interface is identical to that of a Computed.
|
|
152
|
-
*/
|
|
153
147
|
export function pureComputed(...args: any[]): PureComputed<any> {
|
|
154
148
|
const readCb = args.pop();
|
|
155
149
|
// The cast helps ensure that Observable is compatible with ISubscribable abstraction that we use.
|