@microsoft/fast-element 2.0.0-beta.5 → 2.0.0-beta.7
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/CHANGELOG.json +72 -0
- package/CHANGELOG.md +24 -1
- package/dist/dts/components/attributes.d.ts +10 -0
- package/dist/dts/components/{controller.d.ts → element-controller.d.ts} +24 -25
- package/dist/dts/components/fast-definitions.d.ts +28 -3
- package/dist/dts/components/fast-element.d.ts +2 -2
- package/dist/dts/di/di.d.ts +41 -0
- package/dist/dts/index.d.ts +2 -2
- package/dist/dts/interfaces.d.ts +4 -0
- package/dist/dts/observation/observable.d.ts +86 -47
- package/dist/dts/pending-task.d.ts +20 -0
- package/dist/dts/platform.d.ts +6 -0
- package/dist/dts/state/exports.d.ts +3 -0
- package/dist/dts/state/reactive.d.ts +8 -0
- package/dist/dts/state/state.d.ts +141 -0
- package/dist/dts/state/visitor.d.ts +6 -0
- package/dist/dts/state/watch.d.ts +10 -0
- package/dist/dts/styles/css-directive.d.ts +2 -2
- package/dist/dts/styles/element-styles.d.ts +3 -3
- package/dist/dts/styles/host.d.ts +68 -0
- package/dist/dts/templating/binding-signal.d.ts +2 -2
- package/dist/dts/templating/binding-two-way.d.ts +11 -3
- package/dist/dts/templating/binding.d.ts +21 -119
- package/dist/dts/templating/children.d.ts +1 -1
- package/dist/dts/templating/html-directive.d.ts +69 -39
- package/dist/dts/templating/node-observation.d.ts +4 -5
- package/dist/dts/templating/ref.d.ts +5 -13
- package/dist/dts/templating/render.d.ts +15 -20
- package/dist/dts/templating/repeat.d.ts +11 -16
- package/dist/dts/templating/slotted.d.ts +1 -1
- package/dist/dts/templating/template.d.ts +4 -4
- package/dist/dts/templating/view.d.ts +68 -9
- package/dist/dts/templating/when.d.ts +1 -1
- package/dist/dts/testing/exports.d.ts +1 -0
- package/dist/dts/testing/fakes.d.ts +4 -0
- package/dist/dts/testing/fixture.d.ts +0 -6
- package/dist/dts/utilities.d.ts +0 -18
- package/dist/esm/components/attributes.js +13 -4
- package/dist/esm/components/{controller.js → element-controller.js} +95 -105
- package/dist/esm/components/fast-definitions.js +3 -1
- package/dist/esm/components/fast-element.js +4 -4
- package/dist/esm/di/di.js +87 -3
- package/dist/esm/index.js +2 -1
- package/dist/esm/interfaces.js +4 -0
- package/dist/esm/observation/observable.js +59 -126
- package/dist/esm/pending-task.js +16 -0
- package/dist/esm/platform.js +21 -0
- package/dist/esm/state/exports.js +3 -0
- package/dist/esm/state/reactive.js +34 -0
- package/dist/esm/state/state.js +148 -0
- package/dist/esm/state/visitor.js +28 -0
- package/dist/esm/state/watch.js +36 -0
- package/dist/esm/styles/css.js +4 -4
- package/dist/esm/{observation/behavior.js → styles/host.js} +0 -0
- package/dist/esm/templating/binding-signal.js +21 -17
- package/dist/esm/templating/binding-two-way.js +32 -27
- package/dist/esm/templating/binding.js +73 -177
- package/dist/esm/templating/html-directive.js +78 -7
- package/dist/esm/templating/node-observation.js +9 -8
- package/dist/esm/templating/ref.js +4 -12
- package/dist/esm/templating/render.js +30 -31
- package/dist/esm/templating/repeat.js +37 -38
- package/dist/esm/templating/template.js +3 -4
- package/dist/esm/templating/view.js +96 -24
- package/dist/esm/testing/exports.js +1 -0
- package/dist/esm/testing/fakes.js +76 -0
- package/dist/esm/testing/fixture.js +1 -3
- package/dist/esm/utilities.js +0 -95
- package/dist/fast-element.api.json +5720 -5385
- package/dist/fast-element.d.ts +510 -399
- package/dist/fast-element.debug.js +492 -509
- package/dist/fast-element.debug.min.js +1 -1
- package/dist/fast-element.js +492 -509
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +519 -405
- package/docs/api-report.md +197 -129
- package/package.json +8 -4
- package/dist/dts/hooks.d.ts +0 -20
- package/dist/dts/observation/behavior.d.ts +0 -19
- package/dist/esm/hooks.js +0 -32
|
@@ -10,31 +10,43 @@ let twoWaySettings = {
|
|
|
10
10
|
return "change";
|
|
11
11
|
},
|
|
12
12
|
};
|
|
13
|
+
export const TwoWaySettings = Object.freeze({
|
|
14
|
+
/**
|
|
15
|
+
* Configures two-way binding.
|
|
16
|
+
* @param settings - The settings to use for the two-way binding system.
|
|
17
|
+
*/
|
|
18
|
+
configure(settings) {
|
|
19
|
+
twoWaySettings = settings;
|
|
20
|
+
},
|
|
21
|
+
});
|
|
13
22
|
class TwoWayObserver {
|
|
14
23
|
constructor(directive, subscriber, dataBinding) {
|
|
15
24
|
this.directive = directive;
|
|
16
25
|
this.subscriber = subscriber;
|
|
17
26
|
this.dataBinding = dataBinding;
|
|
27
|
+
this.isNotBound = true;
|
|
18
28
|
this.notifier = Observable.binding(dataBinding.evaluate, this, dataBinding.isVolatile);
|
|
19
29
|
}
|
|
20
|
-
|
|
30
|
+
bind(controller) {
|
|
21
31
|
var _a;
|
|
22
32
|
if (!this.changeEvent) {
|
|
23
33
|
this.changeEvent =
|
|
24
34
|
(_a = this.dataBinding.options.changeEvent) !== null && _a !== void 0 ? _a : twoWaySettings.determineChangeEvent(this.directive, this.target);
|
|
25
35
|
}
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
if (this.isNotBound) {
|
|
37
|
+
this.target.addEventListener(this.changeEvent, this);
|
|
38
|
+
controller.onUnbind(this);
|
|
39
|
+
this.isNotBound = false;
|
|
40
|
+
}
|
|
41
|
+
return this.notifier.bind(controller);
|
|
28
42
|
}
|
|
29
|
-
|
|
30
|
-
this.
|
|
43
|
+
unbind(controller) {
|
|
44
|
+
this.isNotBound = true;
|
|
31
45
|
this.target.removeEventListener(this.changeEvent, this);
|
|
32
46
|
}
|
|
33
|
-
/** @internal */
|
|
34
47
|
handleChange(subject, args) {
|
|
35
48
|
this.subscriber.handleChange(this.dataBinding.evaluate, this);
|
|
36
49
|
}
|
|
37
|
-
/** @internal */
|
|
38
50
|
handleEvent(event) {
|
|
39
51
|
const directive = this.directive;
|
|
40
52
|
const target = event.currentTarget;
|
|
@@ -63,36 +75,29 @@ class TwoWayObserver {
|
|
|
63
75
|
}
|
|
64
76
|
}
|
|
65
77
|
class TwoWayBinding extends Binding {
|
|
66
|
-
constructor(evaluate, isVolatile, options = defaultOptions) {
|
|
67
|
-
super();
|
|
68
|
-
this.evaluate = evaluate;
|
|
69
|
-
this.isVolatile = isVolatile;
|
|
70
|
-
this.options = options;
|
|
71
|
-
if (!options.fromView) {
|
|
72
|
-
options.fromView = defaultOptions.fromView;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
78
|
createObserver(directive, subscriber) {
|
|
76
79
|
return new TwoWayObserver(directive, subscriber, this);
|
|
77
80
|
}
|
|
78
|
-
/**
|
|
79
|
-
* Configures two-way binding.
|
|
80
|
-
* @param settings - The settings to use for the two-way binding system.
|
|
81
|
-
*/
|
|
82
|
-
static configure(settings) {
|
|
83
|
-
twoWaySettings = settings;
|
|
84
|
-
}
|
|
85
81
|
}
|
|
86
82
|
/**
|
|
87
83
|
* Creates a default binding.
|
|
88
|
-
* @param
|
|
84
|
+
* @param expression - The binding to refresh when changed.
|
|
85
|
+
* @param optionsOrChangeEvent - The binding options or the name of the change event to use.
|
|
89
86
|
* @param isBindingVolatile - Indicates whether the binding is volatile or not.
|
|
90
|
-
* @returns A binding
|
|
87
|
+
* @returns A binding.
|
|
91
88
|
* @public
|
|
92
89
|
*/
|
|
93
|
-
export function twoWay(
|
|
90
|
+
export function twoWay(expression, optionsOrChangeEvent, isBindingVolatile = Observable.isVolatileBinding(expression)) {
|
|
94
91
|
if (isString(optionsOrChangeEvent)) {
|
|
95
92
|
optionsOrChangeEvent = { changeEvent: optionsOrChangeEvent };
|
|
96
93
|
}
|
|
97
|
-
|
|
94
|
+
if (!optionsOrChangeEvent) {
|
|
95
|
+
optionsOrChangeEvent = defaultOptions;
|
|
96
|
+
}
|
|
97
|
+
else if (!optionsOrChangeEvent.fromView) {
|
|
98
|
+
optionsOrChangeEvent.fromView = defaultOptions.fromView;
|
|
99
|
+
}
|
|
100
|
+
const binding = new TwoWayBinding(expression, isBindingVolatile);
|
|
101
|
+
binding.options = optionsOrChangeEvent;
|
|
102
|
+
return binding;
|
|
98
103
|
}
|
|
@@ -14,29 +14,19 @@ const createInnerHTMLBinding = globalThis.TrustedHTML
|
|
|
14
14
|
}
|
|
15
15
|
: (binding) => binding;
|
|
16
16
|
class OnChangeBinding extends Binding {
|
|
17
|
-
constructor(evaluate, isVolatile) {
|
|
18
|
-
super();
|
|
19
|
-
this.evaluate = evaluate;
|
|
20
|
-
this.isVolatile = isVolatile;
|
|
21
|
-
}
|
|
22
17
|
createObserver(_, subscriber) {
|
|
23
18
|
return Observable.binding(this.evaluate, subscriber, this.isVolatile);
|
|
24
19
|
}
|
|
25
20
|
}
|
|
26
21
|
class OneTimeBinding extends Binding {
|
|
27
|
-
constructor(evaluate) {
|
|
28
|
-
super();
|
|
29
|
-
this.evaluate = evaluate;
|
|
30
|
-
}
|
|
31
22
|
createObserver() {
|
|
32
23
|
return this;
|
|
33
24
|
}
|
|
34
|
-
|
|
35
|
-
return this.evaluate(source, context);
|
|
25
|
+
bind(controller) {
|
|
26
|
+
return this.evaluate(controller.source, controller.context);
|
|
36
27
|
}
|
|
37
|
-
dispose() { }
|
|
38
28
|
}
|
|
39
|
-
function
|
|
29
|
+
function updateContent(target, aspect, value, controller) {
|
|
40
30
|
// If there's no actual value, then this equates to the
|
|
41
31
|
// empty string for the purposes of content bindings.
|
|
42
32
|
if (value === null || value === undefined) {
|
|
@@ -68,14 +58,14 @@ function updateContentTarget(target, aspect, value, source, context) {
|
|
|
68
58
|
// and that there's actually no need to compose it.
|
|
69
59
|
if (!view.isComposed) {
|
|
70
60
|
view.isComposed = true;
|
|
71
|
-
view.bind(source
|
|
61
|
+
view.bind(controller.source);
|
|
72
62
|
view.insertBefore(target);
|
|
73
63
|
target.$fastView = view;
|
|
74
64
|
target.$fastTemplate = value;
|
|
75
65
|
}
|
|
76
66
|
else if (view.needsBindOnly) {
|
|
77
67
|
view.needsBindOnly = false;
|
|
78
|
-
view.bind(source
|
|
68
|
+
view.bind(controller.source);
|
|
79
69
|
}
|
|
80
70
|
}
|
|
81
71
|
else {
|
|
@@ -95,10 +85,9 @@ function updateContentTarget(target, aspect, value, source, context) {
|
|
|
95
85
|
target.textContent = value;
|
|
96
86
|
}
|
|
97
87
|
}
|
|
98
|
-
function
|
|
88
|
+
function updateTokenList(target, aspect, value) {
|
|
99
89
|
var _a;
|
|
100
|
-
const
|
|
101
|
-
const lookup = `${directive.id}-t`;
|
|
90
|
+
const lookup = `${this.id}-t`;
|
|
102
91
|
const state = (_a = target[lookup]) !== null && _a !== void 0 ? _a : (target[lookup] = { c: 0, v: Object.create(null) });
|
|
103
92
|
const versions = state.v;
|
|
104
93
|
let currentVersion = state.c;
|
|
@@ -128,154 +117,8 @@ function updateTokenListTarget(target, aspect, value) {
|
|
|
128
117
|
}
|
|
129
118
|
}
|
|
130
119
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
* @public
|
|
134
|
-
*/
|
|
135
|
-
export class BindingBehavior {
|
|
136
|
-
/**
|
|
137
|
-
* Creates an instance of ChangeBinding.
|
|
138
|
-
* @param directive - The directive that has the configuration for this behavior.
|
|
139
|
-
* @param updateTarget - The function used to update the target with the latest value.
|
|
140
|
-
*/
|
|
141
|
-
constructor(directive, updateTarget) {
|
|
142
|
-
this.directive = directive;
|
|
143
|
-
this.updateTarget = updateTarget;
|
|
144
|
-
this.observerProperty = `${directive.id}-o`;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Bind this behavior to the source.
|
|
148
|
-
* @param source - The source to bind to.
|
|
149
|
-
* @param context - The execution context that the binding is operating within.
|
|
150
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
151
|
-
*/
|
|
152
|
-
bind(source, context, targets) {
|
|
153
|
-
const directive = this.directive;
|
|
154
|
-
const target = targets[directive.nodeId];
|
|
155
|
-
const observer = this.getObserver(target);
|
|
156
|
-
observer.target = target;
|
|
157
|
-
observer.source = source;
|
|
158
|
-
observer.context = context;
|
|
159
|
-
this.updateTarget(target, directive.targetAspect, observer.observe(source, context), source, context);
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Unbinds this behavior from the source.
|
|
163
|
-
* @param source - The source to unbind from.
|
|
164
|
-
* @param context - The execution context that the binding is operating within.
|
|
165
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
166
|
-
*/
|
|
167
|
-
unbind(source, context, targets) {
|
|
168
|
-
const target = targets[this.directive.nodeId];
|
|
169
|
-
const observer = this.getObserver(target);
|
|
170
|
-
observer.dispose();
|
|
171
|
-
observer.target = null;
|
|
172
|
-
observer.source = null;
|
|
173
|
-
observer.context = null;
|
|
174
|
-
}
|
|
175
|
-
/** @internal */
|
|
176
|
-
handleChange(binding, observer) {
|
|
177
|
-
const target = observer.target;
|
|
178
|
-
const source = observer.source;
|
|
179
|
-
const context = observer.context;
|
|
180
|
-
this.updateTarget(target, this.directive.targetAspect, observer.observe(source, context), source, context);
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Returns the binding observer used to update the node.
|
|
184
|
-
* @param target - The target node.
|
|
185
|
-
* @returns A BindingObserver.
|
|
186
|
-
*/
|
|
187
|
-
getObserver(target) {
|
|
188
|
-
var _a;
|
|
189
|
-
return ((_a = target[this.observerProperty]) !== null && _a !== void 0 ? _a : (target[this.observerProperty] = this.directive.dataBinding.createObserver(this.directive, this)));
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Creates a behavior.
|
|
193
|
-
* @param targets - The targets available for behaviors to be attached to.
|
|
194
|
-
*/
|
|
195
|
-
createBehavior(targets) {
|
|
196
|
-
return this;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* A special binding behavior that can bind node content.
|
|
201
|
-
* @public
|
|
202
|
-
*/
|
|
203
|
-
export class ContentBehavior extends BindingBehavior {
|
|
204
|
-
/**
|
|
205
|
-
* Unbinds this behavior from the source.
|
|
206
|
-
* @param source - The source to unbind from.
|
|
207
|
-
* @param context - The execution context that the binding is operating within.
|
|
208
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
209
|
-
*/
|
|
210
|
-
unbind(source, context, targets) {
|
|
211
|
-
super.unbind(source, context, targets);
|
|
212
|
-
const target = targets[this.directive.nodeId];
|
|
213
|
-
const view = target.$fastView;
|
|
214
|
-
if (view !== void 0 && view.isComposed) {
|
|
215
|
-
view.unbind();
|
|
216
|
-
view.needsBindOnly = true;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* A binding behavior for handling events.
|
|
222
|
-
* @public
|
|
223
|
-
*/
|
|
224
|
-
export class EventBehavior {
|
|
225
|
-
/**
|
|
226
|
-
* Creates an instance of EventBinding.
|
|
227
|
-
* @param directive - The directive that has the configuration for this behavior.
|
|
228
|
-
*/
|
|
229
|
-
constructor(directive) {
|
|
230
|
-
this.directive = directive;
|
|
231
|
-
this.sourceProperty = `${directive.id}-s`;
|
|
232
|
-
this.contextProperty = `${directive.id}-c`;
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Bind this behavior to the source.
|
|
236
|
-
* @param source - The source to bind to.
|
|
237
|
-
* @param context - The execution context that the binding is operating within.
|
|
238
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
239
|
-
*/
|
|
240
|
-
bind(source, context, targets) {
|
|
241
|
-
const directive = this.directive;
|
|
242
|
-
const target = targets[directive.nodeId];
|
|
243
|
-
target[this.sourceProperty] = source;
|
|
244
|
-
target[this.contextProperty] = context;
|
|
245
|
-
target.addEventListener(directive.targetAspect, this, directive.dataBinding.options);
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Unbinds this behavior from the source.
|
|
249
|
-
* @param source - The source to unbind from.
|
|
250
|
-
* @param context - The execution context that the binding is operating within.
|
|
251
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
252
|
-
*/
|
|
253
|
-
unbind(source, context, targets) {
|
|
254
|
-
const directive = this.directive;
|
|
255
|
-
const target = targets[directive.nodeId];
|
|
256
|
-
target[this.sourceProperty] = target[this.contextProperty] = null;
|
|
257
|
-
target.removeEventListener(directive.targetAspect, this, directive.dataBinding.options);
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Creates a behavior.
|
|
261
|
-
* @param targets - The targets available for behaviors to be attached to.
|
|
262
|
-
*/
|
|
263
|
-
createBehavior(targets) {
|
|
264
|
-
return this;
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* @internal
|
|
268
|
-
*/
|
|
269
|
-
handleEvent(event) {
|
|
270
|
-
const target = event.currentTarget;
|
|
271
|
-
ExecutionContext.setEvent(event);
|
|
272
|
-
const result = this.directive.dataBinding.evaluate(target[this.sourceProperty], target[this.contextProperty]);
|
|
273
|
-
ExecutionContext.setEvent(null);
|
|
274
|
-
if (result !== true) {
|
|
275
|
-
event.preventDefault();
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
120
|
+
const setProperty = (t, a, v) => (t[a] = v);
|
|
121
|
+
const eventTarget = () => void 0;
|
|
279
122
|
/**
|
|
280
123
|
* A directive that applies bindings.
|
|
281
124
|
* @public
|
|
@@ -287,7 +130,7 @@ export class HTMLBindingDirective {
|
|
|
287
130
|
*/
|
|
288
131
|
constructor(dataBinding) {
|
|
289
132
|
this.dataBinding = dataBinding;
|
|
290
|
-
this.
|
|
133
|
+
this.updateTarget = null;
|
|
291
134
|
/**
|
|
292
135
|
* The unique id of the factory.
|
|
293
136
|
*/
|
|
@@ -296,6 +139,9 @@ export class HTMLBindingDirective {
|
|
|
296
139
|
* The type of aspect to target.
|
|
297
140
|
*/
|
|
298
141
|
this.aspectType = Aspect.content;
|
|
142
|
+
/** @internal */
|
|
143
|
+
this.bind = this.bindDefault;
|
|
144
|
+
this.data = `${this.id}-d`;
|
|
299
145
|
}
|
|
300
146
|
/**
|
|
301
147
|
* Creates HTML to be used within a template.
|
|
@@ -306,37 +152,87 @@ export class HTMLBindingDirective {
|
|
|
306
152
|
}
|
|
307
153
|
/**
|
|
308
154
|
* Creates a behavior.
|
|
309
|
-
* @param targets - The targets available for behaviors to be attached to.
|
|
310
155
|
*/
|
|
311
|
-
createBehavior(
|
|
312
|
-
if (this.
|
|
156
|
+
createBehavior() {
|
|
157
|
+
if (this.updateTarget === null) {
|
|
313
158
|
if (this.targetAspect === "innerHTML") {
|
|
314
159
|
this.dataBinding.evaluate = createInnerHTMLBinding(this.dataBinding.evaluate);
|
|
315
160
|
}
|
|
316
161
|
switch (this.aspectType) {
|
|
317
162
|
case 1:
|
|
318
|
-
this.
|
|
163
|
+
this.updateTarget = DOM.setAttribute;
|
|
319
164
|
break;
|
|
320
165
|
case 2:
|
|
321
|
-
this.
|
|
166
|
+
this.updateTarget = DOM.setBooleanAttribute;
|
|
322
167
|
break;
|
|
323
168
|
case 3:
|
|
324
|
-
this.
|
|
169
|
+
this.updateTarget = setProperty;
|
|
325
170
|
break;
|
|
326
171
|
case 4:
|
|
327
|
-
this.
|
|
172
|
+
this.bind = this.bindContent;
|
|
173
|
+
this.updateTarget = updateContent;
|
|
328
174
|
break;
|
|
329
175
|
case 5:
|
|
330
|
-
this.
|
|
176
|
+
this.updateTarget = updateTokenList;
|
|
331
177
|
break;
|
|
332
178
|
case 6:
|
|
333
|
-
this.
|
|
179
|
+
this.bind = this.bindEvent;
|
|
180
|
+
this.updateTarget = eventTarget;
|
|
334
181
|
break;
|
|
335
182
|
default:
|
|
336
183
|
throw FAST.error(1205 /* Message.unsupportedBindingBehavior */);
|
|
337
184
|
}
|
|
338
185
|
}
|
|
339
|
-
return this
|
|
186
|
+
return this;
|
|
187
|
+
}
|
|
188
|
+
/** @internal */
|
|
189
|
+
bindDefault(controller) {
|
|
190
|
+
var _a;
|
|
191
|
+
const target = controller.targets[this.nodeId];
|
|
192
|
+
const observer = (_a = target[this.data]) !== null && _a !== void 0 ? _a : (target[this.data] = this.dataBinding.createObserver(this, this));
|
|
193
|
+
observer.target = target;
|
|
194
|
+
observer.controller = controller;
|
|
195
|
+
this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
|
|
196
|
+
if (this.updateTarget === updateContent) {
|
|
197
|
+
controller.onUnbind(this);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/** @internal */
|
|
201
|
+
bindContent(controller) {
|
|
202
|
+
this.bindDefault(controller);
|
|
203
|
+
controller.onUnbind(this);
|
|
204
|
+
}
|
|
205
|
+
/** @internal */
|
|
206
|
+
bindEvent(controller) {
|
|
207
|
+
const target = controller.targets[this.nodeId];
|
|
208
|
+
target[this.data] = controller;
|
|
209
|
+
target.addEventListener(this.targetAspect, this, this.dataBinding.options);
|
|
210
|
+
}
|
|
211
|
+
/** @internal */
|
|
212
|
+
unbind(controller) {
|
|
213
|
+
const target = controller.targets[this.nodeId];
|
|
214
|
+
const view = target.$fastView;
|
|
215
|
+
if (view !== void 0 && view.isComposed) {
|
|
216
|
+
view.unbind();
|
|
217
|
+
view.needsBindOnly = true;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/** @internal */
|
|
221
|
+
handleEvent(event) {
|
|
222
|
+
const target = event.currentTarget;
|
|
223
|
+
ExecutionContext.setEvent(event);
|
|
224
|
+
const controller = target[this.data];
|
|
225
|
+
const result = this.dataBinding.evaluate(controller.source, controller.context);
|
|
226
|
+
ExecutionContext.setEvent(null);
|
|
227
|
+
if (result !== true) {
|
|
228
|
+
event.preventDefault();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** @internal */
|
|
232
|
+
handleChange(binding, observer) {
|
|
233
|
+
const target = observer.target;
|
|
234
|
+
const controller = observer.controller;
|
|
235
|
+
this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
|
|
340
236
|
}
|
|
341
237
|
}
|
|
342
238
|
HTMLDirective.define(HTMLBindingDirective, { aspected: true });
|
|
@@ -1,5 +1,67 @@
|
|
|
1
|
+
import { ExecutionContext, } from "../observation/observable.js";
|
|
1
2
|
import { createTypeRegistry } from "../platform.js";
|
|
2
3
|
import { Markup, nextId } from "./markup.js";
|
|
4
|
+
/**
|
|
5
|
+
* Bridges between ViewBehaviors and HostBehaviors, enabling a host to
|
|
6
|
+
* control ViewBehaviors.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export const ViewBehaviorOrchestrator = Object.freeze({
|
|
10
|
+
/**
|
|
11
|
+
* Creates a ViewBehaviorOrchestrator.
|
|
12
|
+
* @param source - The source to to associate behaviors with.
|
|
13
|
+
* @returns A ViewBehaviorOrchestrator.
|
|
14
|
+
*/
|
|
15
|
+
create(source) {
|
|
16
|
+
const behaviors = [];
|
|
17
|
+
const targets = {};
|
|
18
|
+
let unbindables = null;
|
|
19
|
+
let isConnected = false;
|
|
20
|
+
return {
|
|
21
|
+
source,
|
|
22
|
+
context: ExecutionContext.default,
|
|
23
|
+
targets,
|
|
24
|
+
get isBound() {
|
|
25
|
+
return isConnected;
|
|
26
|
+
},
|
|
27
|
+
addBehaviorFactory(factory, target) {
|
|
28
|
+
const nodeId = factory.nodeId || (factory.nodeId = nextId());
|
|
29
|
+
factory.id || (factory.id = nextId());
|
|
30
|
+
this.addTarget(nodeId, target);
|
|
31
|
+
this.addBehavior(factory.createBehavior());
|
|
32
|
+
},
|
|
33
|
+
addTarget(nodeId, target) {
|
|
34
|
+
targets[nodeId] = target;
|
|
35
|
+
},
|
|
36
|
+
addBehavior(behavior) {
|
|
37
|
+
behaviors.push(behavior);
|
|
38
|
+
if (isConnected) {
|
|
39
|
+
behavior.bind(this);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
onUnbind(unbindable) {
|
|
43
|
+
if (unbindables === null) {
|
|
44
|
+
unbindables = [];
|
|
45
|
+
}
|
|
46
|
+
unbindables.push(unbindable);
|
|
47
|
+
},
|
|
48
|
+
connectedCallback(controller) {
|
|
49
|
+
if (!isConnected) {
|
|
50
|
+
isConnected = true;
|
|
51
|
+
behaviors.forEach(x => x.bind(this));
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
disconnectedCallback(controller) {
|
|
55
|
+
if (isConnected) {
|
|
56
|
+
isConnected = false;
|
|
57
|
+
if (unbindables !== null) {
|
|
58
|
+
unbindables.forEach(x => x.unbind(this));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
3
65
|
const registry = createTypeRegistry();
|
|
4
66
|
/**
|
|
5
67
|
* Instructs the template engine to apply behavior to a node.
|
|
@@ -45,6 +107,15 @@ export function htmlDirective(options) {
|
|
|
45
107
|
* @public
|
|
46
108
|
*/
|
|
47
109
|
export class Binding {
|
|
110
|
+
/**
|
|
111
|
+
* Creates a binding.
|
|
112
|
+
* @param evaluate - Evaluates the binding.
|
|
113
|
+
* @param isVolatile - Indicates whether the binding is volatile.
|
|
114
|
+
*/
|
|
115
|
+
constructor(evaluate, isVolatile = false) {
|
|
116
|
+
this.evaluate = evaluate;
|
|
117
|
+
this.isVolatile = isVolatile;
|
|
118
|
+
}
|
|
48
119
|
}
|
|
49
120
|
/**
|
|
50
121
|
* The type of HTML aspect to target.
|
|
@@ -144,13 +215,6 @@ export class StatelessAttachedAttributeDirective {
|
|
|
144
215
|
*/
|
|
145
216
|
this.id = nextId();
|
|
146
217
|
}
|
|
147
|
-
/**
|
|
148
|
-
* Creates a behavior.
|
|
149
|
-
* @param targets - The targets available for behaviors to be attached to.
|
|
150
|
-
*/
|
|
151
|
-
createBehavior(targets) {
|
|
152
|
-
return this;
|
|
153
|
-
}
|
|
154
218
|
/**
|
|
155
219
|
* Creates a placeholder string based on the directive's index within the template.
|
|
156
220
|
* @param index - The index of the directive within the template.
|
|
@@ -160,4 +224,11 @@ export class StatelessAttachedAttributeDirective {
|
|
|
160
224
|
createHTML(add) {
|
|
161
225
|
return Markup.attribute(add(this));
|
|
162
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Creates a behavior.
|
|
229
|
+
* @param targets - The targets available for behaviors to be attached to.
|
|
230
|
+
*/
|
|
231
|
+
createBehavior() {
|
|
232
|
+
return this;
|
|
233
|
+
}
|
|
163
234
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { emptyArray } from "../platform.js";
|
|
2
|
-
import { StatelessAttachedAttributeDirective
|
|
2
|
+
import { StatelessAttachedAttributeDirective } from "./html-directive.js";
|
|
3
3
|
const selectElements = (value) => value.nodeType === 1;
|
|
4
4
|
/**
|
|
5
5
|
* Creates a function that can be used to filter a Node array, selecting only elements.
|
|
@@ -26,11 +26,12 @@ export class NodeObservationDirective extends StatelessAttachedAttributeDirectiv
|
|
|
26
26
|
* @param context - The execution context that the binding is operating within.
|
|
27
27
|
* @param targets - The targets that behaviors in a view can attach to.
|
|
28
28
|
*/
|
|
29
|
-
bind(
|
|
30
|
-
const target = targets[this.nodeId];
|
|
31
|
-
target[this.sourceProperty] = source;
|
|
32
|
-
this.updateTarget(source, this.computeNodes(target));
|
|
29
|
+
bind(controller) {
|
|
30
|
+
const target = controller.targets[this.nodeId];
|
|
31
|
+
target[this.sourceProperty] = controller.source;
|
|
32
|
+
this.updateTarget(controller.source, this.computeNodes(target));
|
|
33
33
|
this.observe(target);
|
|
34
|
+
controller.onUnbind(this);
|
|
34
35
|
}
|
|
35
36
|
/**
|
|
36
37
|
* Unbinds this behavior from the source.
|
|
@@ -38,9 +39,9 @@ export class NodeObservationDirective extends StatelessAttachedAttributeDirectiv
|
|
|
38
39
|
* @param context - The execution context that the binding is operating within.
|
|
39
40
|
* @param targets - The targets that behaviors in a view can attach to.
|
|
40
41
|
*/
|
|
41
|
-
unbind(
|
|
42
|
-
const target = targets[this.nodeId];
|
|
43
|
-
this.updateTarget(source, emptyArray);
|
|
42
|
+
unbind(controller) {
|
|
43
|
+
const target = controller.targets[this.nodeId];
|
|
44
|
+
this.updateTarget(controller.source, emptyArray);
|
|
44
45
|
this.disconnect(target);
|
|
45
46
|
target[this.sourceProperty] = null;
|
|
46
47
|
}
|
|
@@ -5,20 +5,12 @@ import { HTMLDirective, StatelessAttachedAttributeDirective, } from "./html-dire
|
|
|
5
5
|
*/
|
|
6
6
|
export class RefDirective extends StatelessAttachedAttributeDirective {
|
|
7
7
|
/**
|
|
8
|
-
* Bind this behavior
|
|
9
|
-
* @param
|
|
10
|
-
* @param context - The execution context that the binding is operating within.
|
|
11
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
8
|
+
* Bind this behavior.
|
|
9
|
+
* @param controller - The view controller that manages the lifecycle of this behavior.
|
|
12
10
|
*/
|
|
13
|
-
bind(
|
|
14
|
-
source[this.options] = targets[this.nodeId];
|
|
11
|
+
bind(controller) {
|
|
12
|
+
controller.source[this.options] = controller.targets[this.nodeId];
|
|
15
13
|
}
|
|
16
|
-
/**
|
|
17
|
-
* Unbinds this behavior from the source.
|
|
18
|
-
* @param source - The source to unbind from.
|
|
19
|
-
*/
|
|
20
|
-
/* eslint-disable-next-line @typescript-eslint/no-empty-function */
|
|
21
|
-
unbind() { }
|
|
22
14
|
}
|
|
23
15
|
HTMLDirective.define(RefDirective);
|
|
24
16
|
/**
|