@microsoft/fast-element 1.10.1 → 2.0.0-beta.2
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/.eslintrc.json +1 -12
- package/CHANGELOG.json +432 -1
- package/CHANGELOG.md +74 -2
- package/README.md +2 -2
- package/dist/dts/components/attributes.d.ts +4 -1
- package/dist/dts/components/controller.d.ts +12 -11
- package/dist/dts/components/fast-definitions.d.ts +10 -2
- package/dist/dts/components/fast-element.d.ts +12 -5
- package/dist/dts/context.d.ts +157 -0
- package/dist/dts/debug.d.ts +1 -0
- package/dist/dts/hooks.d.ts +20 -0
- package/dist/dts/index.d.ts +16 -15
- package/dist/dts/index.debug.d.ts +2 -0
- package/dist/dts/index.rollup.d.ts +2 -0
- package/dist/dts/index.rollup.debug.d.ts +3 -0
- package/dist/dts/interfaces.d.ts +144 -0
- package/dist/dts/metadata.d.ts +25 -0
- package/dist/dts/observation/arrays.d.ts +207 -0
- package/dist/dts/observation/behavior.d.ts +4 -4
- package/dist/dts/observation/notifier.d.ts +18 -18
- package/dist/dts/observation/observable.d.ts +56 -18
- package/dist/dts/observation/splice-strategies.d.ts +13 -0
- package/dist/dts/observation/update-queue.d.ts +40 -0
- package/dist/dts/platform.d.ts +18 -67
- package/dist/dts/polyfills.d.ts +8 -0
- package/dist/dts/styles/css-directive.d.ts +43 -5
- package/dist/dts/styles/css.d.ts +19 -3
- package/dist/dts/styles/element-styles.d.ts +42 -62
- package/dist/dts/templating/binding-signal.d.ts +38 -0
- package/dist/dts/templating/binding-two-way.d.ts +56 -0
- package/dist/dts/templating/binding.d.ts +233 -65
- package/dist/dts/templating/children.d.ts +18 -15
- package/dist/dts/templating/compiler.d.ts +46 -28
- package/dist/dts/templating/dom.d.ts +41 -0
- package/dist/dts/templating/html-directive.d.ts +179 -43
- package/dist/dts/templating/markup.d.ts +48 -0
- package/dist/dts/templating/node-observation.d.ts +45 -29
- package/dist/dts/templating/ref.d.ts +6 -12
- package/dist/dts/templating/repeat.d.ts +26 -14
- package/dist/dts/templating/slotted.d.ts +13 -14
- package/dist/dts/templating/template.d.ts +27 -21
- package/dist/dts/templating/view.d.ts +15 -22
- package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +1 -1
- package/dist/dts/utilities.d.ts +40 -0
- package/dist/esm/components/attributes.js +25 -24
- package/dist/esm/components/controller.js +77 -57
- package/dist/esm/components/fast-definitions.js +16 -22
- package/dist/esm/components/fast-element.js +10 -2
- package/dist/esm/context.js +159 -0
- package/dist/esm/debug.js +29 -0
- package/dist/esm/hooks.js +32 -0
- package/dist/esm/index.debug.js +2 -0
- package/dist/esm/index.js +19 -14
- package/dist/esm/index.rollup.debug.js +3 -0
- package/dist/esm/index.rollup.js +2 -0
- package/dist/esm/interfaces.js +8 -1
- package/dist/esm/metadata.js +60 -0
- package/dist/esm/observation/arrays.js +269 -0
- package/dist/esm/observation/notifier.js +75 -83
- package/dist/esm/observation/observable.js +93 -68
- package/dist/esm/observation/{array-change-records.js → splice-strategies.js} +136 -62
- package/dist/esm/observation/update-queue.js +67 -0
- package/dist/esm/platform.js +36 -42
- package/dist/esm/polyfills.js +85 -0
- package/dist/esm/styles/css-directive.js +29 -13
- package/dist/esm/styles/css.js +27 -40
- package/dist/esm/styles/element-styles.js +65 -104
- package/dist/esm/templating/binding-signal.js +84 -0
- package/dist/esm/templating/binding-two-way.js +76 -0
- package/dist/esm/templating/binding.js +306 -153
- package/dist/esm/templating/children.js +33 -23
- package/dist/esm/templating/compiler.js +235 -152
- package/dist/esm/templating/dom.js +49 -0
- package/dist/esm/templating/html-directive.js +125 -40
- package/dist/esm/templating/markup.js +75 -0
- package/dist/esm/templating/node-observation.js +50 -45
- package/dist/esm/templating/ref.js +7 -16
- package/dist/esm/templating/repeat.js +39 -36
- package/dist/esm/templating/slotted.js +23 -20
- package/dist/esm/templating/template.js +51 -95
- package/dist/esm/templating/view.js +44 -43
- package/dist/esm/templating/when.js +2 -1
- package/dist/esm/utilities.js +139 -0
- package/dist/fast-element.api.json +11789 -5377
- package/dist/fast-element.d.ts +1177 -531
- package/dist/fast-element.debug.js +3717 -0
- package/dist/fast-element.debug.min.js +1 -0
- package/dist/fast-element.js +3466 -4022
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +2697 -0
- package/docs/api-report.md +472 -219
- package/docs/fast-element-2-changes.md +15 -0
- package/docs/guide/declaring-templates.md +5 -4
- package/docs/guide/defining-elements.md +3 -2
- package/docs/guide/leveraging-css.md +1 -0
- package/docs/guide/next-steps.md +3 -2
- package/docs/guide/observables-and-state.md +2 -1
- package/docs/guide/using-directives.md +2 -1
- package/docs/guide/working-with-shadow-dom.md +1 -0
- package/karma.conf.cjs +6 -17
- package/package.json +65 -15
- package/dist/dts/dom.d.ts +0 -112
- package/dist/dts/observation/array-change-records.d.ts +0 -48
- package/dist/dts/observation/array-observer.d.ts +0 -9
- package/dist/esm/dom.js +0 -207
- package/dist/esm/observation/array-observer.js +0 -173
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { emptyArray } from "./platform.js";
|
|
2
|
+
// Tiny polyfill for TypeScript's Reflect metadata API.
|
|
3
|
+
const metadataByTarget = new Map();
|
|
4
|
+
if (!("metadata" in Reflect)) {
|
|
5
|
+
Reflect.metadata = function (key, value) {
|
|
6
|
+
return function (target) {
|
|
7
|
+
Reflect.defineMetadata(key, value, target);
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
Reflect.defineMetadata = function (key, value, target) {
|
|
11
|
+
let metadata = metadataByTarget.get(target);
|
|
12
|
+
if (metadata === void 0) {
|
|
13
|
+
metadataByTarget.set(target, (metadata = new Map()));
|
|
14
|
+
}
|
|
15
|
+
metadata.set(key, value);
|
|
16
|
+
};
|
|
17
|
+
Reflect.getOwnMetadata = function (key, target) {
|
|
18
|
+
const metadata = metadataByTarget.get(target);
|
|
19
|
+
if (metadata !== void 0) {
|
|
20
|
+
return metadata.get(key);
|
|
21
|
+
}
|
|
22
|
+
return void 0;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Provides basic metadata capabilities used by Context and Dependency Injection.
|
|
27
|
+
*/
|
|
28
|
+
export const Metadata = Object.freeze({
|
|
29
|
+
/**
|
|
30
|
+
* Gets the "design:paramtypes" metadata for the specified type.
|
|
31
|
+
* @param Type - The type to get the metadata for.
|
|
32
|
+
* @returns The metadata array or a frozen empty array if no metadata is found.
|
|
33
|
+
*/
|
|
34
|
+
getDesignParamTypes: Type => {
|
|
35
|
+
var _a;
|
|
36
|
+
return (_a = Reflect.getOwnMetadata("design:paramtypes", Type)) !== null && _a !== void 0 ? _a : emptyArray;
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* Gets the "annotation:paramtypes" metadata for the specified type.
|
|
40
|
+
* @param Type - The type to get the metadata for.
|
|
41
|
+
* @returns The metadata array or a frozen empty array if no metadata is found.
|
|
42
|
+
*/
|
|
43
|
+
getAnnotationParamTypes: Type => {
|
|
44
|
+
var _a;
|
|
45
|
+
return (_a = Reflect.getOwnMetadata("annotation:paramtypes", Type)) !== null && _a !== void 0 ? _a : emptyArray;
|
|
46
|
+
},
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
* @param Type - Gets the "annotation:paramtypes" metadata for the specified type. If none is found,
|
|
50
|
+
* an empty, mutable metadata array is created and added.
|
|
51
|
+
* @returns The metadata array.
|
|
52
|
+
*/
|
|
53
|
+
getOrCreateAnnotationParamTypes(Type) {
|
|
54
|
+
let types = this.getAnnotationParamTypes(Type);
|
|
55
|
+
if (types === emptyArray) {
|
|
56
|
+
Reflect.defineMetadata("annotation:paramtypes", (types = []), Type);
|
|
57
|
+
}
|
|
58
|
+
return types;
|
|
59
|
+
},
|
|
60
|
+
});
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { emptyArray } from "../platform.js";
|
|
2
|
+
import { SubscriberSet } from "./notifier.js";
|
|
3
|
+
import { Observable } from "./observable.js";
|
|
4
|
+
import { Updates } from "./update-queue.js";
|
|
5
|
+
/**
|
|
6
|
+
* A splice map is a representation of how a previous array of items
|
|
7
|
+
* was transformed into a new array of items. Conceptually it is a list of
|
|
8
|
+
* tuples of
|
|
9
|
+
*
|
|
10
|
+
* (index, removed, addedCount)
|
|
11
|
+
*
|
|
12
|
+
* which are kept in ascending index order of. The tuple represents that at
|
|
13
|
+
* the |index|, |removed| sequence of items were removed, and counting forward
|
|
14
|
+
* from |index|, |addedCount| items were added.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export class Splice {
|
|
18
|
+
/**
|
|
19
|
+
* Creates a splice.
|
|
20
|
+
* @param index - The index that the splice occurs at.
|
|
21
|
+
* @param removed - The items that were removed.
|
|
22
|
+
* @param addedCount - The number of items that were added.
|
|
23
|
+
*/
|
|
24
|
+
constructor(index, removed, addedCount) {
|
|
25
|
+
this.index = index;
|
|
26
|
+
this.removed = removed;
|
|
27
|
+
this.addedCount = addedCount;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Adjusts the splice index based on the provided array.
|
|
31
|
+
* @param array - The array to adjust to.
|
|
32
|
+
* @returns The same splice, mutated based on the reference array.
|
|
33
|
+
*/
|
|
34
|
+
adjustTo(array) {
|
|
35
|
+
let index = this.index;
|
|
36
|
+
const arrayLength = array.length;
|
|
37
|
+
if (index > arrayLength) {
|
|
38
|
+
index = arrayLength - this.addedCount;
|
|
39
|
+
}
|
|
40
|
+
else if (index < 0) {
|
|
41
|
+
index = arrayLength + this.removed.length + index - this.addedCount;
|
|
42
|
+
}
|
|
43
|
+
this.index = index < 0 ? 0 : index;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Indicates what level of feature support the splice
|
|
49
|
+
* strategy provides.
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
export const SpliceStrategySupport = Object.freeze({
|
|
53
|
+
/**
|
|
54
|
+
* Only supports resets.
|
|
55
|
+
*/
|
|
56
|
+
reset: 1,
|
|
57
|
+
/**
|
|
58
|
+
* Supports tracking splices and resets.
|
|
59
|
+
*/
|
|
60
|
+
splice: 2,
|
|
61
|
+
/**
|
|
62
|
+
* Supports tracking splices and resets, while applying some form
|
|
63
|
+
* of optimization, such as merging, to the splices.
|
|
64
|
+
*/
|
|
65
|
+
optimized: 3,
|
|
66
|
+
});
|
|
67
|
+
const reset = new Splice(0, emptyArray, 0);
|
|
68
|
+
reset.reset = true;
|
|
69
|
+
const resetSplices = [reset];
|
|
70
|
+
let defaultSpliceStrategy = Object.freeze({
|
|
71
|
+
support: SpliceStrategySupport.splice,
|
|
72
|
+
normalize(previous, current, changes) {
|
|
73
|
+
return previous === void 0 ? changes !== null && changes !== void 0 ? changes : emptyArray : resetSplices;
|
|
74
|
+
},
|
|
75
|
+
pop(array, observer, pop, args) {
|
|
76
|
+
const notEmpty = array.length > 0;
|
|
77
|
+
const result = pop.apply(array, args);
|
|
78
|
+
if (notEmpty) {
|
|
79
|
+
observer.addSplice(new Splice(array.length, [result], 0));
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
},
|
|
83
|
+
push(array, observer, push, args) {
|
|
84
|
+
const result = push.apply(array, args);
|
|
85
|
+
observer.addSplice(new Splice(array.length - args.length, [], args.length).adjustTo(array));
|
|
86
|
+
return result;
|
|
87
|
+
},
|
|
88
|
+
reverse(array, observer, reverse, args) {
|
|
89
|
+
const result = reverse.apply(array, args);
|
|
90
|
+
observer.reset(array);
|
|
91
|
+
return result;
|
|
92
|
+
},
|
|
93
|
+
shift(array, observer, shift, args) {
|
|
94
|
+
const notEmpty = array.length > 0;
|
|
95
|
+
const result = shift.apply(array, args);
|
|
96
|
+
if (notEmpty) {
|
|
97
|
+
observer.addSplice(new Splice(0, [result], 0));
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
},
|
|
101
|
+
sort(array, observer, sort, args) {
|
|
102
|
+
const result = sort.apply(array, args);
|
|
103
|
+
observer.reset(array);
|
|
104
|
+
return result;
|
|
105
|
+
},
|
|
106
|
+
splice(array, observer, splice, args) {
|
|
107
|
+
const result = splice.apply(array, args);
|
|
108
|
+
observer.addSplice(new Splice(+args[0], result, args.length > 2 ? args.length - 2 : 0).adjustTo(array));
|
|
109
|
+
return result;
|
|
110
|
+
},
|
|
111
|
+
unshift(array, observer, unshift, args) {
|
|
112
|
+
const result = unshift.apply(array, args);
|
|
113
|
+
observer.addSplice(new Splice(0, [], args.length).adjustTo(array));
|
|
114
|
+
return result;
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
/**
|
|
118
|
+
* Functionality related to tracking changes in arrays.
|
|
119
|
+
* @public
|
|
120
|
+
*/
|
|
121
|
+
export const SpliceStrategy = Object.freeze({
|
|
122
|
+
/**
|
|
123
|
+
* A set of changes that represent a full array reset.
|
|
124
|
+
*/
|
|
125
|
+
reset: resetSplices,
|
|
126
|
+
/**
|
|
127
|
+
* Sets the default strategy to use for array observers.
|
|
128
|
+
* @param strategy - The splice strategy to use.
|
|
129
|
+
*/
|
|
130
|
+
setDefaultStrategy(strategy) {
|
|
131
|
+
defaultSpliceStrategy = strategy;
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
function setNonEnumerable(target, property, value) {
|
|
135
|
+
Reflect.defineProperty(target, property, {
|
|
136
|
+
value,
|
|
137
|
+
enumerable: false,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
class DefaultArrayObserver extends SubscriberSet {
|
|
141
|
+
constructor(subject) {
|
|
142
|
+
super(subject);
|
|
143
|
+
this.oldCollection = void 0;
|
|
144
|
+
this.splices = void 0;
|
|
145
|
+
this.needsQueue = true;
|
|
146
|
+
this._strategy = null;
|
|
147
|
+
this._lengthObserver = void 0;
|
|
148
|
+
this.call = this.flush;
|
|
149
|
+
setNonEnumerable(subject, "$fastController", this);
|
|
150
|
+
}
|
|
151
|
+
get strategy() {
|
|
152
|
+
return this._strategy;
|
|
153
|
+
}
|
|
154
|
+
set strategy(value) {
|
|
155
|
+
this._strategy = value;
|
|
156
|
+
}
|
|
157
|
+
get lengthObserver() {
|
|
158
|
+
let observer = this._lengthObserver;
|
|
159
|
+
if (observer === void 0) {
|
|
160
|
+
const array = this.subject;
|
|
161
|
+
this._lengthObserver = observer = {
|
|
162
|
+
length: array.length,
|
|
163
|
+
handleChange() {
|
|
164
|
+
if (this.length !== array.length) {
|
|
165
|
+
this.length = array.length;
|
|
166
|
+
Observable.notify(observer, "length");
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
this.subscribe(observer);
|
|
171
|
+
}
|
|
172
|
+
return observer;
|
|
173
|
+
}
|
|
174
|
+
subscribe(subscriber) {
|
|
175
|
+
this.flush();
|
|
176
|
+
super.subscribe(subscriber);
|
|
177
|
+
}
|
|
178
|
+
addSplice(splice) {
|
|
179
|
+
if (this.splices === void 0) {
|
|
180
|
+
this.splices = [splice];
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
this.splices.push(splice);
|
|
184
|
+
}
|
|
185
|
+
this.enqueue();
|
|
186
|
+
}
|
|
187
|
+
reset(oldCollection) {
|
|
188
|
+
this.oldCollection = oldCollection;
|
|
189
|
+
this.enqueue();
|
|
190
|
+
}
|
|
191
|
+
flush() {
|
|
192
|
+
var _a;
|
|
193
|
+
const splices = this.splices;
|
|
194
|
+
const oldCollection = this.oldCollection;
|
|
195
|
+
if (splices === void 0 && oldCollection === void 0) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
this.needsQueue = true;
|
|
199
|
+
this.splices = void 0;
|
|
200
|
+
this.oldCollection = void 0;
|
|
201
|
+
this.notify(((_a = this._strategy) !== null && _a !== void 0 ? _a : defaultSpliceStrategy).normalize(oldCollection, this.subject, splices));
|
|
202
|
+
}
|
|
203
|
+
enqueue() {
|
|
204
|
+
if (this.needsQueue) {
|
|
205
|
+
this.needsQueue = false;
|
|
206
|
+
Updates.enqueue(this);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
let enabled = false;
|
|
211
|
+
/**
|
|
212
|
+
* An observer for arrays.
|
|
213
|
+
* @public
|
|
214
|
+
*/
|
|
215
|
+
export const ArrayObserver = Object.freeze({
|
|
216
|
+
/**
|
|
217
|
+
* Enables the array observation mechanism.
|
|
218
|
+
* @remarks
|
|
219
|
+
* Array observation is enabled automatically when using the
|
|
220
|
+
* {@link RepeatDirective}, so calling this API manually is
|
|
221
|
+
* not typically necessary.
|
|
222
|
+
*/
|
|
223
|
+
enable() {
|
|
224
|
+
if (enabled) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
enabled = true;
|
|
228
|
+
Observable.setArrayObserverFactory((collection) => new DefaultArrayObserver(collection));
|
|
229
|
+
const proto = Array.prototype;
|
|
230
|
+
if (!proto.$fastPatch) {
|
|
231
|
+
setNonEnumerable(proto, "$fastPatch", 1);
|
|
232
|
+
[
|
|
233
|
+
proto.pop,
|
|
234
|
+
proto.push,
|
|
235
|
+
proto.reverse,
|
|
236
|
+
proto.shift,
|
|
237
|
+
proto.sort,
|
|
238
|
+
proto.splice,
|
|
239
|
+
proto.unshift,
|
|
240
|
+
].forEach(method => {
|
|
241
|
+
proto[method.name] = function (...args) {
|
|
242
|
+
var _a;
|
|
243
|
+
const o = this.$fastController;
|
|
244
|
+
return o === void 0
|
|
245
|
+
? method.apply(this, args)
|
|
246
|
+
: ((_a = o.strategy) !== null && _a !== void 0 ? _a : defaultSpliceStrategy)[method.name](this, o, method, args);
|
|
247
|
+
};
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
/**
|
|
253
|
+
* Enables observing the length of an array.
|
|
254
|
+
* @param array - The array to observe the length of.
|
|
255
|
+
* @returns The length of the array.
|
|
256
|
+
* @public
|
|
257
|
+
*/
|
|
258
|
+
export function lengthOf(array) {
|
|
259
|
+
if (!array) {
|
|
260
|
+
return 0;
|
|
261
|
+
}
|
|
262
|
+
let arrayObserver = array.$fastController;
|
|
263
|
+
if (arrayObserver === void 0) {
|
|
264
|
+
ArrayObserver.enable();
|
|
265
|
+
arrayObserver = Observable.getNotifier(array);
|
|
266
|
+
}
|
|
267
|
+
Observable.track(arrayObserver.lengthObserver, "length");
|
|
268
|
+
return array.length;
|
|
269
|
+
}
|
|
@@ -1,31 +1,7 @@
|
|
|
1
|
-
function spilloverSubscribe(subscriber) {
|
|
2
|
-
const spillover = this.spillover;
|
|
3
|
-
const index = spillover.indexOf(subscriber);
|
|
4
|
-
if (index === -1) {
|
|
5
|
-
spillover.push(subscriber);
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
function spilloverUnsubscribe(subscriber) {
|
|
9
|
-
const spillover = this.spillover;
|
|
10
|
-
const index = spillover.indexOf(subscriber);
|
|
11
|
-
if (index !== -1) {
|
|
12
|
-
spillover.splice(index, 1);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
function spilloverNotifySubscribers(args) {
|
|
16
|
-
const spillover = this.spillover;
|
|
17
|
-
const source = this.source;
|
|
18
|
-
for (let i = 0, ii = spillover.length; i < ii; ++i) {
|
|
19
|
-
spillover[i].handleChange(source, args);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function spilloverHas(subscriber) {
|
|
23
|
-
return this.spillover.indexOf(subscriber) !== -1;
|
|
24
|
-
}
|
|
25
1
|
/**
|
|
26
2
|
* An implementation of {@link Notifier} that efficiently keeps track of
|
|
27
3
|
* subscribers interested in a specific change notification on an
|
|
28
|
-
* observable
|
|
4
|
+
* observable subject.
|
|
29
5
|
*
|
|
30
6
|
* @remarks
|
|
31
7
|
* This set is optimized for the most common scenario of 1 or 2 subscribers.
|
|
@@ -35,15 +11,15 @@ function spilloverHas(subscriber) {
|
|
|
35
11
|
*/
|
|
36
12
|
export class SubscriberSet {
|
|
37
13
|
/**
|
|
38
|
-
* Creates an instance of SubscriberSet for the specified
|
|
39
|
-
* @param
|
|
14
|
+
* Creates an instance of SubscriberSet for the specified subject.
|
|
15
|
+
* @param subject - The subject that subscribers will receive notifications from.
|
|
40
16
|
* @param initialSubscriber - An initial subscriber to changes.
|
|
41
17
|
*/
|
|
42
|
-
constructor(
|
|
18
|
+
constructor(subject, initialSubscriber) {
|
|
43
19
|
this.sub1 = void 0;
|
|
44
20
|
this.sub2 = void 0;
|
|
45
21
|
this.spillover = void 0;
|
|
46
|
-
this.
|
|
22
|
+
this.subject = subject;
|
|
47
23
|
this.sub1 = initialSubscriber;
|
|
48
24
|
}
|
|
49
25
|
/**
|
|
@@ -51,42 +27,58 @@ export class SubscriberSet {
|
|
|
51
27
|
* @param subscriber - The subscriber to test for inclusion in this set.
|
|
52
28
|
*/
|
|
53
29
|
has(subscriber) {
|
|
54
|
-
return this.
|
|
30
|
+
return this.spillover === void 0
|
|
31
|
+
? this.sub1 === subscriber || this.sub2 === subscriber
|
|
32
|
+
: this.spillover.indexOf(subscriber) !== -1;
|
|
55
33
|
}
|
|
56
34
|
/**
|
|
57
35
|
* Subscribes to notification of changes in an object's state.
|
|
58
36
|
* @param subscriber - The object that is subscribing for change notification.
|
|
59
37
|
*/
|
|
60
38
|
subscribe(subscriber) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
39
|
+
const spillover = this.spillover;
|
|
40
|
+
if (spillover === void 0) {
|
|
41
|
+
if (this.has(subscriber)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (this.sub1 === void 0) {
|
|
45
|
+
this.sub1 = subscriber;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (this.sub2 === void 0) {
|
|
49
|
+
this.sub2 = subscriber;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.spillover = [this.sub1, this.sub2, subscriber];
|
|
53
|
+
this.sub1 = void 0;
|
|
54
|
+
this.sub2 = void 0;
|
|
67
55
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
else {
|
|
57
|
+
const index = spillover.indexOf(subscriber);
|
|
58
|
+
if (index === -1) {
|
|
59
|
+
spillover.push(subscriber);
|
|
60
|
+
}
|
|
71
61
|
}
|
|
72
|
-
this.spillover = [this.sub1, this.sub2, subscriber];
|
|
73
|
-
this.subscribe = spilloverSubscribe;
|
|
74
|
-
this.unsubscribe = spilloverUnsubscribe;
|
|
75
|
-
this.notify = spilloverNotifySubscribers;
|
|
76
|
-
this.has = spilloverHas;
|
|
77
|
-
this.sub1 = void 0;
|
|
78
|
-
this.sub2 = void 0;
|
|
79
62
|
}
|
|
80
63
|
/**
|
|
81
64
|
* Unsubscribes from notification of changes in an object's state.
|
|
82
65
|
* @param subscriber - The object that is unsubscribing from change notification.
|
|
83
66
|
*/
|
|
84
67
|
unsubscribe(subscriber) {
|
|
85
|
-
|
|
86
|
-
|
|
68
|
+
const spillover = this.spillover;
|
|
69
|
+
if (spillover === void 0) {
|
|
70
|
+
if (this.sub1 === subscriber) {
|
|
71
|
+
this.sub1 = void 0;
|
|
72
|
+
}
|
|
73
|
+
else if (this.sub2 === subscriber) {
|
|
74
|
+
this.sub2 = void 0;
|
|
75
|
+
}
|
|
87
76
|
}
|
|
88
|
-
else
|
|
89
|
-
|
|
77
|
+
else {
|
|
78
|
+
const index = spillover.indexOf(subscriber);
|
|
79
|
+
if (index !== -1) {
|
|
80
|
+
spillover.splice(index, 1);
|
|
81
|
+
}
|
|
90
82
|
}
|
|
91
83
|
}
|
|
92
84
|
/**
|
|
@@ -94,14 +86,22 @@ export class SubscriberSet {
|
|
|
94
86
|
* @param args - Data passed along to subscribers during notification.
|
|
95
87
|
*/
|
|
96
88
|
notify(args) {
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
89
|
+
const spillover = this.spillover;
|
|
90
|
+
const subject = this.subject;
|
|
91
|
+
if (spillover === void 0) {
|
|
92
|
+
const sub1 = this.sub1;
|
|
93
|
+
const sub2 = this.sub2;
|
|
94
|
+
if (sub1 !== void 0) {
|
|
95
|
+
sub1.handleChange(subject, args);
|
|
96
|
+
}
|
|
97
|
+
if (sub2 !== void 0) {
|
|
98
|
+
sub2.handleChange(subject, args);
|
|
99
|
+
}
|
|
102
100
|
}
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
else {
|
|
102
|
+
for (let i = 0, ii = spillover.length; i < ii; ++i) {
|
|
103
|
+
spillover[i].handleChange(subject, args);
|
|
104
|
+
}
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
}
|
|
@@ -112,25 +112,22 @@ export class SubscriberSet {
|
|
|
112
112
|
*/
|
|
113
113
|
export class PropertyChangeNotifier {
|
|
114
114
|
/**
|
|
115
|
-
* Creates an instance of PropertyChangeNotifier for the specified
|
|
116
|
-
* @param
|
|
115
|
+
* Creates an instance of PropertyChangeNotifier for the specified subject.
|
|
116
|
+
* @param subject - The object that subscribers will receive notifications for.
|
|
117
117
|
*/
|
|
118
|
-
constructor(
|
|
118
|
+
constructor(subject) {
|
|
119
119
|
this.subscribers = {};
|
|
120
|
-
this.
|
|
121
|
-
this.
|
|
120
|
+
this.subjectSubscribers = null;
|
|
121
|
+
this.subject = subject;
|
|
122
122
|
}
|
|
123
123
|
/**
|
|
124
124
|
* Notifies all subscribers, based on the specified property.
|
|
125
125
|
* @param propertyName - The property name, passed along to subscribers during notification.
|
|
126
126
|
*/
|
|
127
127
|
notify(propertyName) {
|
|
128
|
-
var _a;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
subscribers.notify(propertyName);
|
|
132
|
-
}
|
|
133
|
-
(_a = this.sourceSubscribers) === null || _a === void 0 ? void 0 : _a.notify(propertyName);
|
|
128
|
+
var _a, _b;
|
|
129
|
+
(_a = this.subscribers[propertyName]) === null || _a === void 0 ? void 0 : _a.notify(propertyName);
|
|
130
|
+
(_b = this.subjectSubscribers) === null || _b === void 0 ? void 0 : _b.notify(propertyName);
|
|
134
131
|
}
|
|
135
132
|
/**
|
|
136
133
|
* Subscribes to notification of changes in an object's state.
|
|
@@ -138,19 +135,17 @@ export class PropertyChangeNotifier {
|
|
|
138
135
|
* @param propertyToWatch - The name of the property that the subscriber is interested in watching for changes.
|
|
139
136
|
*/
|
|
140
137
|
subscribe(subscriber, propertyToWatch) {
|
|
141
|
-
var _a;
|
|
138
|
+
var _a, _b;
|
|
139
|
+
let subscribers;
|
|
142
140
|
if (propertyToWatch) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
this.subscribers[propertyToWatch] = subscribers = new SubscriberSet(this.source);
|
|
146
|
-
}
|
|
147
|
-
subscribers.subscribe(subscriber);
|
|
141
|
+
subscribers =
|
|
142
|
+
(_a = this.subscribers[propertyToWatch]) !== null && _a !== void 0 ? _a : (this.subscribers[propertyToWatch] = new SubscriberSet(this.subject));
|
|
148
143
|
}
|
|
149
144
|
else {
|
|
150
|
-
|
|
151
|
-
(
|
|
152
|
-
this.sourceSubscribers.subscribe(subscriber);
|
|
145
|
+
subscribers =
|
|
146
|
+
(_b = this.subjectSubscribers) !== null && _b !== void 0 ? _b : (this.subjectSubscribers = new SubscriberSet(this.subject));
|
|
153
147
|
}
|
|
148
|
+
subscribers.subscribe(subscriber);
|
|
154
149
|
}
|
|
155
150
|
/**
|
|
156
151
|
* Unsubscribes from notification of changes in an object's state.
|
|
@@ -158,15 +153,12 @@ export class PropertyChangeNotifier {
|
|
|
158
153
|
* @param propertyToUnwatch - The name of the property that the subscriber is no longer interested in watching.
|
|
159
154
|
*/
|
|
160
155
|
unsubscribe(subscriber, propertyToUnwatch) {
|
|
161
|
-
var _a;
|
|
156
|
+
var _a, _b;
|
|
162
157
|
if (propertyToUnwatch) {
|
|
163
|
-
|
|
164
|
-
if (subscribers !== void 0) {
|
|
165
|
-
subscribers.unsubscribe(subscriber);
|
|
166
|
-
}
|
|
158
|
+
(_a = this.subscribers[propertyToUnwatch]) === null || _a === void 0 ? void 0 : _a.unsubscribe(subscriber);
|
|
167
159
|
}
|
|
168
160
|
else {
|
|
169
|
-
(
|
|
161
|
+
(_b = this.subjectSubscribers) === null || _b === void 0 ? void 0 : _b.unsubscribe(subscriber);
|
|
170
162
|
}
|
|
171
163
|
}
|
|
172
164
|
}
|