@microsoft/fast-element 1.10.2 → 2.0.0-beta.1
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 +321 -1
- package/CHANGELOG.md +52 -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 +8 -2
- package/dist/dts/components/fast-element.d.ts +5 -4
- 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/observation/arrays.d.ts +207 -0
- package/dist/dts/observation/behavior.d.ts +5 -5
- package/dist/dts/observation/notifier.d.ts +18 -18
- package/dist/dts/observation/observable.d.ts +86 -29
- 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.d.ts +320 -64
- package/dist/dts/templating/children.d.ts +18 -15
- package/dist/dts/templating/compiler.d.ts +47 -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 +72 -14
- package/dist/dts/templating/slotted.d.ts +13 -14
- package/dist/dts/templating/template.d.ts +78 -23
- package/dist/dts/templating/view.d.ts +16 -23
- 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 +14 -22
- 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/observation/arrays.js +269 -0
- package/dist/esm/observation/notifier.js +27 -35
- package/dist/esm/observation/observable.js +80 -107
- 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.js +465 -155
- 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 +38 -43
- package/dist/esm/templating/slotted.js +23 -20
- package/dist/esm/templating/template.js +71 -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 +13633 -5266
- package/dist/fast-element.d.ts +1434 -578
- package/dist/fast-element.debug.js +3824 -0
- package/dist/fast-element.debug.min.js +1 -0
- package/dist/fast-element.js +3574 -4020
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +2908 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/docs/api-report.md +590 -231
- package/docs/fast-element-2-changes.md +15 -0
- package/docs/guide/declaring-templates.md +4 -4
- package/docs/guide/defining-elements.md +2 -2
- package/docs/guide/next-steps.md +2 -2
- package/docs/guide/observables-and-state.md +1 -1
- package/docs/guide/using-directives.md +1 -1
- package/karma.conf.cjs +6 -17
- package/package.json +46 -14
- 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 -177
|
@@ -1,46 +1,113 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isString } from "../interfaces.js";
|
|
2
2
|
import { ExecutionContext, Observable, } from "../observation/observable.js";
|
|
3
|
-
import {
|
|
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
|
-
|
|
3
|
+
import { FAST } from "../platform.js";
|
|
4
|
+
import { DOM } from "./dom.js";
|
|
5
|
+
import { Aspect, HTMLDirective, } from "./html-directive.js";
|
|
6
|
+
import { Markup } from "./markup.js";
|
|
7
|
+
const createInnerHTMLBinding = globalThis.TrustedHTML
|
|
8
|
+
? (binding) => (s, c) => {
|
|
9
|
+
const value = binding(s, c);
|
|
10
|
+
if (value instanceof TrustedHTML) {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
throw FAST.error(1202 /* Message.bindingInnerHTMLRequiresTrustedTypes */);
|
|
14
|
+
}
|
|
15
|
+
: (binding) => binding;
|
|
16
|
+
/**
|
|
17
|
+
* Describes how aspects of an HTML element will be affected by bindings.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
export const BindingMode = Object.freeze({
|
|
21
|
+
/**
|
|
22
|
+
* Creates a binding mode based on the supplied behavior types.
|
|
23
|
+
* @param UpdateType - The base behavior type used to update aspects.
|
|
24
|
+
* @param EventType - The base behavior type used to respond to events.
|
|
25
|
+
* @returns A new binding mode.
|
|
26
|
+
*/
|
|
27
|
+
define(UpdateType, EventType = EventBinding) {
|
|
28
|
+
return Object.freeze({
|
|
29
|
+
[1]: d => new UpdateType(d, DOM.setAttribute),
|
|
30
|
+
[2]: d => new UpdateType(d, DOM.setBooleanAttribute),
|
|
31
|
+
[3]: d => new UpdateType(d, (t, a, v) => (t[a] = v)),
|
|
32
|
+
[4]: d => new (createContentBinding(UpdateType))(d, updateContentTarget),
|
|
33
|
+
[5]: d => new UpdateType(d, updateTokenListTarget),
|
|
34
|
+
[6]: d => new EventType(d),
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* Describes the configuration for a binding expression.
|
|
40
|
+
* @public
|
|
41
|
+
*/
|
|
42
|
+
export const BindingConfig = Object.freeze({
|
|
43
|
+
/**
|
|
44
|
+
* Creates a binding configuration based on the provided mode and options.
|
|
45
|
+
* @param mode - The mode to use for the configuration.
|
|
46
|
+
* @param defaultOptions - The default options to use for the configuration.
|
|
47
|
+
* @returns A new binding configuration.
|
|
48
|
+
*/
|
|
49
|
+
define(mode, defaultOptions) {
|
|
50
|
+
const config = (options) => {
|
|
51
|
+
return {
|
|
52
|
+
mode: config.mode,
|
|
53
|
+
options: Object.assign({}, defaultOptions, options),
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
config.options = defaultOptions;
|
|
57
|
+
config.mode = mode;
|
|
58
|
+
return config;
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
/**
|
|
62
|
+
* A base binding behavior for DOM updates.
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export class UpdateBinding {
|
|
66
|
+
/**
|
|
67
|
+
* Creates an instance of UpdateBinding.
|
|
68
|
+
* @param directive - The directive that has the configuration for this behavior.
|
|
69
|
+
* @param updateTarget - The function used to update the target with the latest value.
|
|
70
|
+
*/
|
|
71
|
+
constructor(directive, updateTarget) {
|
|
72
|
+
this.directive = directive;
|
|
73
|
+
this.updateTarget = updateTarget;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Bind this behavior to the source.
|
|
77
|
+
* @param source - The source to bind to.
|
|
78
|
+
* @param context - The execution context that the binding is operating within.
|
|
79
|
+
* @param targets - The targets that behaviors in a view can attach to.
|
|
80
|
+
*/
|
|
81
|
+
bind(source, context, targets) { }
|
|
82
|
+
/**
|
|
83
|
+
* Unbinds this behavior from the source.
|
|
84
|
+
* @param source - The source to unbind from.
|
|
85
|
+
* @param context - The execution context that the binding is operating within.
|
|
86
|
+
* @param targets - The targets that behaviors in a view can attach to.
|
|
87
|
+
*/
|
|
88
|
+
unbind(source, context, targets) { }
|
|
89
|
+
/**
|
|
90
|
+
* Creates a behavior.
|
|
91
|
+
* @param targets - The targets available for behaviors to be attached to.
|
|
92
|
+
*/
|
|
93
|
+
createBehavior(targets) {
|
|
94
|
+
return this;
|
|
30
95
|
}
|
|
31
96
|
}
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
97
|
+
function createContentBinding(Type) {
|
|
98
|
+
return class extends Type {
|
|
99
|
+
unbind(source, context, targets) {
|
|
100
|
+
super.unbind(source, context, targets);
|
|
101
|
+
const target = targets[this.directive.nodeId];
|
|
102
|
+
const view = target.$fastView;
|
|
103
|
+
if (view !== void 0 && view.isComposed) {
|
|
104
|
+
view.unbind();
|
|
105
|
+
view.needsBindOnly = true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
42
109
|
}
|
|
43
|
-
function updateContentTarget(value) {
|
|
110
|
+
function updateContentTarget(target, aspect, value, source, context) {
|
|
44
111
|
// If there's no actual value, then this equates to the
|
|
45
112
|
// empty string for the purposes of content bindings.
|
|
46
113
|
if (value === null || value === undefined) {
|
|
@@ -48,8 +115,8 @@ function updateContentTarget(value) {
|
|
|
48
115
|
}
|
|
49
116
|
// If the value has a "create" method, then it's a template-like.
|
|
50
117
|
if (value.create) {
|
|
51
|
-
|
|
52
|
-
let view =
|
|
118
|
+
target.textContent = "";
|
|
119
|
+
let view = target.$fastView;
|
|
53
120
|
// If there's no previous view that we might be able to
|
|
54
121
|
// reuse then create a new view from the template.
|
|
55
122
|
if (view === void 0) {
|
|
@@ -60,7 +127,7 @@ function updateContentTarget(value) {
|
|
|
60
127
|
// from the same template as the new value, then we
|
|
61
128
|
// need to remove the old view if it's still in the DOM
|
|
62
129
|
// and create a new view from the template.
|
|
63
|
-
if (
|
|
130
|
+
if (target.$fastTemplate !== value) {
|
|
64
131
|
if (view.isComposed) {
|
|
65
132
|
view.remove();
|
|
66
133
|
view.unbind();
|
|
@@ -72,18 +139,18 @@ function updateContentTarget(value) {
|
|
|
72
139
|
// and that there's actually no need to compose it.
|
|
73
140
|
if (!view.isComposed) {
|
|
74
141
|
view.isComposed = true;
|
|
75
|
-
view.bind(
|
|
76
|
-
view.insertBefore(
|
|
77
|
-
|
|
78
|
-
|
|
142
|
+
view.bind(source, context);
|
|
143
|
+
view.insertBefore(target);
|
|
144
|
+
target.$fastView = view;
|
|
145
|
+
target.$fastTemplate = value;
|
|
79
146
|
}
|
|
80
147
|
else if (view.needsBindOnly) {
|
|
81
148
|
view.needsBindOnly = false;
|
|
82
|
-
view.bind(
|
|
149
|
+
view.bind(source, context);
|
|
83
150
|
}
|
|
84
151
|
}
|
|
85
152
|
else {
|
|
86
|
-
const view =
|
|
153
|
+
const view = target.$fastView;
|
|
87
154
|
// If there is a view and it's currently composed into
|
|
88
155
|
// the DOM, then we need to remove it.
|
|
89
156
|
if (view !== void 0 && view.isComposed) {
|
|
@@ -96,16 +163,17 @@ function updateContentTarget(value) {
|
|
|
96
163
|
view.unbind();
|
|
97
164
|
}
|
|
98
165
|
}
|
|
99
|
-
|
|
166
|
+
target.textContent = value;
|
|
100
167
|
}
|
|
101
168
|
}
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
let
|
|
169
|
+
function updateTokenListTarget(target, aspect, value) {
|
|
170
|
+
var _a;
|
|
171
|
+
const directive = this.directive;
|
|
172
|
+
const lookup = `${directive.id}-t`;
|
|
173
|
+
const state = (_a = target[lookup]) !== null && _a !== void 0 ? _a : (target[lookup] = { c: 0, v: Object.create(null) });
|
|
174
|
+
const versions = state.v;
|
|
175
|
+
let currentVersion = state.c;
|
|
176
|
+
const tokenList = target[aspect];
|
|
109
177
|
// Add the classes, tracking the version at which they were added.
|
|
110
178
|
if (value !== null && value !== undefined && value.length) {
|
|
111
179
|
const names = value.split(/\s+/);
|
|
@@ -114,139 +182,381 @@ function updateClassTarget(value) {
|
|
|
114
182
|
if (currentName === "") {
|
|
115
183
|
continue;
|
|
116
184
|
}
|
|
117
|
-
|
|
118
|
-
|
|
185
|
+
versions[currentName] = currentVersion;
|
|
186
|
+
tokenList.add(currentName);
|
|
119
187
|
}
|
|
120
188
|
}
|
|
121
|
-
|
|
122
|
-
this.version = version + 1;
|
|
189
|
+
state.v = currentVersion + 1;
|
|
123
190
|
// If this is the first call to add classes, there's no need to remove old ones.
|
|
124
|
-
if (
|
|
191
|
+
if (currentVersion === 0) {
|
|
125
192
|
return;
|
|
126
193
|
}
|
|
127
194
|
// Remove classes from the previous version.
|
|
128
|
-
|
|
129
|
-
for (const name in
|
|
130
|
-
if (
|
|
131
|
-
|
|
195
|
+
currentVersion -= 1;
|
|
196
|
+
for (const name in versions) {
|
|
197
|
+
if (versions[name] === currentVersion) {
|
|
198
|
+
tokenList.remove(name);
|
|
132
199
|
}
|
|
133
200
|
}
|
|
134
201
|
}
|
|
135
202
|
/**
|
|
136
|
-
* A
|
|
203
|
+
* A binding behavior for one-time bindings.
|
|
137
204
|
* @public
|
|
138
205
|
*/
|
|
139
|
-
export class
|
|
206
|
+
export class OneTimeBinding extends UpdateBinding {
|
|
140
207
|
/**
|
|
141
|
-
*
|
|
142
|
-
* @param
|
|
208
|
+
* Bind this behavior to the source.
|
|
209
|
+
* @param source - The source to bind to.
|
|
210
|
+
* @param context - The execution context that the binding is operating within.
|
|
211
|
+
* @param targets - The targets that behaviors in a view can attach to.
|
|
143
212
|
*/
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
this.binding
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
break;
|
|
182
|
-
default:
|
|
183
|
-
this.cleanedTargetName = value;
|
|
184
|
-
if (value === "class") {
|
|
185
|
-
this.updateTarget = updateClassTarget;
|
|
186
|
-
}
|
|
187
|
-
break;
|
|
213
|
+
bind(source, context, targets) {
|
|
214
|
+
const directive = this.directive;
|
|
215
|
+
this.updateTarget(targets[directive.nodeId], directive.targetAspect, directive.binding(source, context), source, context);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const signals = Object.create(null);
|
|
219
|
+
/**
|
|
220
|
+
* A binding behavior for signal bindings.
|
|
221
|
+
* @public
|
|
222
|
+
*/
|
|
223
|
+
export class SignalBinding extends UpdateBinding {
|
|
224
|
+
constructor() {
|
|
225
|
+
super(...arguments);
|
|
226
|
+
this.handlerProperty = `${this.directive.id}-h`;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Bind this behavior to the source.
|
|
230
|
+
* @param source - The source to bind to.
|
|
231
|
+
* @param context - The execution context that the binding is operating within.
|
|
232
|
+
* @param targets - The targets that behaviors in a view can attach to.
|
|
233
|
+
*/
|
|
234
|
+
bind(source, context, targets) {
|
|
235
|
+
const directive = this.directive;
|
|
236
|
+
const target = targets[directive.nodeId];
|
|
237
|
+
const signal = this.getSignal(source, context);
|
|
238
|
+
const handler = (target[this.handlerProperty] = () => {
|
|
239
|
+
this.updateTarget(target, directive.targetAspect, directive.binding(source, context), source, context);
|
|
240
|
+
});
|
|
241
|
+
handler();
|
|
242
|
+
const found = signals[signal];
|
|
243
|
+
if (found) {
|
|
244
|
+
Array.isArray(found)
|
|
245
|
+
? found.push(handler)
|
|
246
|
+
: (signals[signal] = [found, handler]);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
signals[signal] = handler;
|
|
188
250
|
}
|
|
189
251
|
}
|
|
190
252
|
/**
|
|
191
|
-
*
|
|
192
|
-
*
|
|
253
|
+
* Unbinds this behavior from the source.
|
|
254
|
+
* @param source - The source to unbind from.
|
|
255
|
+
* @param context - The execution context that the binding is operating within.
|
|
256
|
+
* @param targets - The targets that behaviors in a view can attach to.
|
|
193
257
|
*/
|
|
194
|
-
|
|
195
|
-
this.
|
|
196
|
-
|
|
258
|
+
unbind(source, context, targets) {
|
|
259
|
+
const signal = this.getSignal(source, context);
|
|
260
|
+
const found = signals[signal];
|
|
261
|
+
if (found && Array.isArray(found)) {
|
|
262
|
+
const directive = this.directive;
|
|
263
|
+
const target = targets[directive.nodeId];
|
|
264
|
+
const handler = target[this.handlerProperty];
|
|
265
|
+
const index = found.indexOf(handler);
|
|
266
|
+
if (index !== -1) {
|
|
267
|
+
found.splice(index, 1);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
signals[signal] = void 0;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
getSignal(source, context) {
|
|
275
|
+
const options = this.directive.options;
|
|
276
|
+
return isString(options) ? options : options(source, context);
|
|
197
277
|
}
|
|
198
278
|
/**
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
* @
|
|
279
|
+
* Sends the specified signal to signaled bindings.
|
|
280
|
+
* @param signal - The signal to send.
|
|
281
|
+
* @public
|
|
202
282
|
*/
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
283
|
+
static send(signal) {
|
|
284
|
+
const found = signals[signal];
|
|
285
|
+
if (found) {
|
|
286
|
+
Array.isArray(found) ? found.forEach(x => x()) : found();
|
|
287
|
+
}
|
|
206
288
|
}
|
|
207
289
|
}
|
|
208
290
|
/**
|
|
209
|
-
* A behavior
|
|
210
|
-
* BindingDirective.
|
|
291
|
+
* A binding behavior for bindings that change.
|
|
211
292
|
* @public
|
|
212
293
|
*/
|
|
213
|
-
export class
|
|
214
|
-
/**
|
|
215
|
-
* Creates an instance of
|
|
216
|
-
* @param
|
|
217
|
-
* @param
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
*/
|
|
224
|
-
constructor(target, binding, isBindingVolatile, bind, unbind, updateTarget, targetName) {
|
|
225
|
-
/** @internal */
|
|
226
|
-
this.source = null;
|
|
227
|
-
/** @internal */
|
|
228
|
-
this.context = null;
|
|
229
|
-
/** @internal */
|
|
230
|
-
this.bindingObserver = null;
|
|
231
|
-
this.target = target;
|
|
232
|
-
this.binding = binding;
|
|
233
|
-
this.isBindingVolatile = isBindingVolatile;
|
|
234
|
-
this.bind = bind;
|
|
235
|
-
this.unbind = unbind;
|
|
236
|
-
this.updateTarget = updateTarget;
|
|
237
|
-
this.targetName = targetName;
|
|
294
|
+
export class ChangeBinding extends UpdateBinding {
|
|
295
|
+
/**
|
|
296
|
+
* Creates an instance of ChangeBinding.
|
|
297
|
+
* @param directive - The directive that has the configuration for this behavior.
|
|
298
|
+
* @param updateTarget - The function used to update the target with the latest value.
|
|
299
|
+
*/
|
|
300
|
+
constructor(directive, updateTarget) {
|
|
301
|
+
super(directive, updateTarget);
|
|
302
|
+
this.isBindingVolatile = Observable.isVolatileBinding(directive.binding);
|
|
303
|
+
this.observerProperty = `${directive.id}-o`;
|
|
238
304
|
}
|
|
239
|
-
/**
|
|
240
|
-
|
|
241
|
-
|
|
305
|
+
/**
|
|
306
|
+
* Returns the binding observer used to update the node.
|
|
307
|
+
* @param target - The target node.
|
|
308
|
+
* @returns A BindingObserver.
|
|
309
|
+
*/
|
|
310
|
+
getObserver(target) {
|
|
311
|
+
var _a;
|
|
312
|
+
return ((_a = target[this.observerProperty]) !== null && _a !== void 0 ? _a : (target[this.observerProperty] = Observable.binding(this.directive.binding, this, this.isBindingVolatile)));
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Bind this behavior to the source.
|
|
316
|
+
* @param source - The source to bind to.
|
|
317
|
+
* @param context - The execution context that the binding is operating within.
|
|
318
|
+
* @param targets - The targets that behaviors in a view can attach to.
|
|
319
|
+
*/
|
|
320
|
+
bind(source, context, targets) {
|
|
321
|
+
const directive = this.directive;
|
|
322
|
+
const target = targets[directive.nodeId];
|
|
323
|
+
const observer = this.getObserver(target);
|
|
324
|
+
observer.target = target;
|
|
325
|
+
observer.source = source;
|
|
326
|
+
observer.context = context;
|
|
327
|
+
this.updateTarget(target, directive.targetAspect, observer.observe(source, context), source, context);
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Unbinds this behavior from the source.
|
|
331
|
+
* @param source - The source to unbind from.
|
|
332
|
+
* @param context - The execution context that the binding is operating within.
|
|
333
|
+
* @param targets - The targets that behaviors in a view can attach to.
|
|
334
|
+
*/
|
|
335
|
+
unbind(source, context, targets) {
|
|
336
|
+
const target = targets[this.directive.nodeId];
|
|
337
|
+
const observer = this.getObserver(target);
|
|
338
|
+
observer.dispose();
|
|
339
|
+
observer.target = null;
|
|
340
|
+
observer.source = null;
|
|
341
|
+
observer.context = null;
|
|
242
342
|
}
|
|
243
343
|
/** @internal */
|
|
344
|
+
handleChange(binding, observer) {
|
|
345
|
+
const target = observer.target;
|
|
346
|
+
const source = observer.source;
|
|
347
|
+
const context = observer.context;
|
|
348
|
+
this.updateTarget(target, this.directive.targetAspect, observer.observe(source, context), source, context);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* A binding behavior for handling events.
|
|
353
|
+
* @public
|
|
354
|
+
*/
|
|
355
|
+
export class EventBinding {
|
|
356
|
+
/**
|
|
357
|
+
* Creates an instance of EventBinding.
|
|
358
|
+
* @param directive - The directive that has the configuration for this behavior.
|
|
359
|
+
*/
|
|
360
|
+
constructor(directive) {
|
|
361
|
+
this.directive = directive;
|
|
362
|
+
this.sourceProperty = `${directive.id}-s`;
|
|
363
|
+
this.contextProperty = `${directive.id}-c`;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Bind this behavior to the source.
|
|
367
|
+
* @param source - The source to bind to.
|
|
368
|
+
* @param context - The execution context that the binding is operating within.
|
|
369
|
+
* @param targets - The targets that behaviors in a view can attach to.
|
|
370
|
+
*/
|
|
371
|
+
bind(source, context, targets) {
|
|
372
|
+
const directive = this.directive;
|
|
373
|
+
const target = targets[directive.nodeId];
|
|
374
|
+
target[this.sourceProperty] = source;
|
|
375
|
+
target[this.contextProperty] = context;
|
|
376
|
+
target.addEventListener(directive.targetAspect, this, directive.options);
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Unbinds this behavior from the source.
|
|
380
|
+
* @param source - The source to unbind from.
|
|
381
|
+
* @param context - The execution context that the binding is operating within.
|
|
382
|
+
* @param targets - The targets that behaviors in a view can attach to.
|
|
383
|
+
*/
|
|
384
|
+
unbind(source, context, targets) {
|
|
385
|
+
const directive = this.directive;
|
|
386
|
+
const target = targets[directive.nodeId];
|
|
387
|
+
target[this.sourceProperty] = target[this.contextProperty] = null;
|
|
388
|
+
target.removeEventListener(directive.targetAspect, this, directive.options);
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Creates a behavior.
|
|
392
|
+
* @param targets - The targets available for behaviors to be attached to.
|
|
393
|
+
*/
|
|
394
|
+
createBehavior(targets) {
|
|
395
|
+
return this;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* @internal
|
|
399
|
+
*/
|
|
244
400
|
handleEvent(event) {
|
|
401
|
+
const target = event.currentTarget;
|
|
245
402
|
ExecutionContext.setEvent(event);
|
|
246
|
-
const result = this.binding(this.
|
|
403
|
+
const result = this.directive.binding(target[this.sourceProperty], target[this.contextProperty]);
|
|
247
404
|
ExecutionContext.setEvent(null);
|
|
248
405
|
if (result !== true) {
|
|
249
406
|
event.preventDefault();
|
|
250
407
|
}
|
|
251
408
|
}
|
|
252
409
|
}
|
|
410
|
+
let twoWaySettings = {
|
|
411
|
+
determineChangeEvent() {
|
|
412
|
+
return "change";
|
|
413
|
+
},
|
|
414
|
+
};
|
|
415
|
+
/**
|
|
416
|
+
* A binding behavior for bindings that update in two directions.
|
|
417
|
+
* @public
|
|
418
|
+
*/
|
|
419
|
+
export class TwoWayBinding extends ChangeBinding {
|
|
420
|
+
/**
|
|
421
|
+
* Bind this behavior to the source.
|
|
422
|
+
* @param source - The source to bind to.
|
|
423
|
+
* @param context - The execution context that the binding is operating within.
|
|
424
|
+
* @param targets - The targets that behaviors in a view can attach to.
|
|
425
|
+
*/
|
|
426
|
+
bind(source, context, targets) {
|
|
427
|
+
var _a;
|
|
428
|
+
super.bind(source, context, targets);
|
|
429
|
+
const directive = this.directive;
|
|
430
|
+
const target = targets[directive.nodeId];
|
|
431
|
+
if (!this.changeEvent) {
|
|
432
|
+
this.changeEvent =
|
|
433
|
+
(_a = directive.options.changeEvent) !== null && _a !== void 0 ? _a : twoWaySettings.determineChangeEvent(directive, target);
|
|
434
|
+
}
|
|
435
|
+
target.addEventListener(this.changeEvent, this);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Unbinds this behavior from the source.
|
|
439
|
+
* @param source - The source to unbind from.
|
|
440
|
+
* @param context - The execution context that the binding is operating within.
|
|
441
|
+
* @param targets - The targets that behaviors in a view can attach to.
|
|
442
|
+
*/
|
|
443
|
+
unbind(source, context, targets) {
|
|
444
|
+
super.unbind(source, context, targets);
|
|
445
|
+
targets[this.directive.nodeId].removeEventListener(this.changeEvent, this);
|
|
446
|
+
}
|
|
447
|
+
/** @internal */
|
|
448
|
+
handleEvent(event) {
|
|
449
|
+
const directive = this.directive;
|
|
450
|
+
const target = event.currentTarget;
|
|
451
|
+
let value;
|
|
452
|
+
switch (directive.aspectType) {
|
|
453
|
+
case 1:
|
|
454
|
+
value = target.getAttribute(directive.targetAspect);
|
|
455
|
+
break;
|
|
456
|
+
case 2:
|
|
457
|
+
value = target.hasAttribute(directive.targetAspect);
|
|
458
|
+
break;
|
|
459
|
+
case 4:
|
|
460
|
+
value = target.innerText;
|
|
461
|
+
break;
|
|
462
|
+
default:
|
|
463
|
+
value = target[directive.targetAspect];
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
const observer = this.getObserver(target);
|
|
467
|
+
const last = observer.last; // using internal API!!!
|
|
468
|
+
last.propertySource[last.propertyName] = directive.options.fromView(value);
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Configures two-way binding.
|
|
472
|
+
* @param settings - The settings to use for the two-way binding system.
|
|
473
|
+
*/
|
|
474
|
+
static configure(settings) {
|
|
475
|
+
twoWaySettings = settings;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* The default onChange binding configuration.
|
|
480
|
+
* @public
|
|
481
|
+
*/
|
|
482
|
+
export const onChange = BindingConfig.define(BindingMode.define(ChangeBinding), {});
|
|
483
|
+
/**
|
|
484
|
+
* The default twoWay binding configuration.
|
|
485
|
+
* @public
|
|
486
|
+
*/
|
|
487
|
+
export const twoWay = BindingConfig.define(BindingMode.define(TwoWayBinding), {
|
|
488
|
+
fromView: v => v,
|
|
489
|
+
});
|
|
490
|
+
/**
|
|
491
|
+
* The default onTime binding configuration.
|
|
492
|
+
* @public
|
|
493
|
+
*/
|
|
494
|
+
export const oneTime = BindingConfig.define(BindingMode.define(OneTimeBinding), {
|
|
495
|
+
once: true,
|
|
496
|
+
});
|
|
497
|
+
const signalMode = BindingMode.define(SignalBinding);
|
|
498
|
+
/**
|
|
499
|
+
* Creates a signal binding configuration with the supplied options.
|
|
500
|
+
* @param options - The signal name or a binding to use to retrieve the signal name.
|
|
501
|
+
* @returns A binding configuration.
|
|
502
|
+
* @public
|
|
503
|
+
*/
|
|
504
|
+
export const signal = (options) => {
|
|
505
|
+
return { mode: signalMode, options };
|
|
506
|
+
};
|
|
507
|
+
/**
|
|
508
|
+
* A directive that applies bindings.
|
|
509
|
+
* @public
|
|
510
|
+
*/
|
|
511
|
+
export class HTMLBindingDirective {
|
|
512
|
+
/**
|
|
513
|
+
* Creates an instance of HTMLBindingDirective.
|
|
514
|
+
* @param binding - The binding to apply.
|
|
515
|
+
* @param mode - The binding mode to use when applying the binding.
|
|
516
|
+
* @param options - The options to configure the binding with.
|
|
517
|
+
*/
|
|
518
|
+
constructor(binding, mode, options) {
|
|
519
|
+
this.binding = binding;
|
|
520
|
+
this.mode = mode;
|
|
521
|
+
this.options = options;
|
|
522
|
+
this.factory = null;
|
|
523
|
+
/**
|
|
524
|
+
* The type of aspect to target.
|
|
525
|
+
*/
|
|
526
|
+
this.aspectType = Aspect.content;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Creates HTML to be used within a template.
|
|
530
|
+
* @param add - Can be used to add behavior factories to a template.
|
|
531
|
+
*/
|
|
532
|
+
createHTML(add) {
|
|
533
|
+
return Markup.interpolation(add(this));
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Creates a behavior.
|
|
537
|
+
* @param targets - The targets available for behaviors to be attached to.
|
|
538
|
+
*/
|
|
539
|
+
createBehavior(targets) {
|
|
540
|
+
if (this.factory == null) {
|
|
541
|
+
if (this.targetAspect === "innerHTML") {
|
|
542
|
+
this.binding = createInnerHTMLBinding(this.binding);
|
|
543
|
+
}
|
|
544
|
+
this.factory = this.mode[this.aspectType](this);
|
|
545
|
+
}
|
|
546
|
+
return this.factory.createBehavior(targets);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
HTMLDirective.define(HTMLBindingDirective, { aspected: true });
|
|
550
|
+
/**
|
|
551
|
+
* Creates a binding directive with the specified configuration.
|
|
552
|
+
* @param binding - The binding expression.
|
|
553
|
+
* @param config - The binding configuration.
|
|
554
|
+
* @returns A binding directive.
|
|
555
|
+
* @public
|
|
556
|
+
*/
|
|
557
|
+
export function bind(binding, config = onChange) {
|
|
558
|
+
if (!("mode" in config)) {
|
|
559
|
+
config = onChange(config);
|
|
560
|
+
}
|
|
561
|
+
return new HTMLBindingDirective(binding, config.mode, config.options);
|
|
562
|
+
}
|