@microsoft/fast-element 2.0.0-beta.1 → 2.0.0-beta.11
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 +348 -0
- package/CHANGELOG.md +114 -1
- package/dist/dts/components/attributes.d.ts +10 -0
- package/dist/dts/components/{controller.d.ts → element-controller.d.ts} +49 -25
- package/dist/dts/components/fast-definitions.d.ts +43 -9
- package/dist/dts/components/fast-element.d.ts +15 -21
- package/dist/dts/context.d.ts +157 -0
- package/dist/dts/di/di.d.ts +899 -0
- package/dist/dts/index.d.ts +2 -2
- package/dist/dts/interfaces.d.ts +45 -14
- package/dist/dts/metadata.d.ts +25 -0
- package/dist/dts/observation/arrays.d.ts +1 -1
- package/dist/dts/observation/observable.d.ts +101 -75
- package/dist/dts/pending-task.d.ts +20 -0
- package/dist/dts/platform.d.ts +7 -0
- package/dist/dts/polyfills.d.ts +1 -8
- 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 +10 -17
- package/dist/dts/styles/host.d.ts +68 -0
- package/dist/dts/templating/binding-signal.d.ts +21 -0
- package/dist/dts/templating/binding-two-way.d.ts +39 -0
- package/dist/dts/templating/binding.d.ts +69 -294
- package/dist/dts/templating/children.d.ts +1 -1
- package/dist/dts/templating/compiler.d.ts +1 -2
- package/dist/dts/templating/html-directive.d.ts +93 -35
- 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 +272 -0
- package/dist/dts/templating/repeat.d.ts +20 -75
- package/dist/dts/templating/slotted.d.ts +1 -1
- package/dist/dts/templating/template.d.ts +12 -61
- package/dist/dts/templating/view.d.ts +77 -12
- package/dist/dts/templating/when.d.ts +3 -3
- package/dist/dts/testing/exports.d.ts +3 -0
- package/dist/dts/testing/fakes.d.ts +4 -0
- package/dist/dts/testing/fixture.d.ts +84 -0
- package/dist/dts/testing/timeout.d.ts +7 -0
- package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +0 -0
- 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} +188 -109
- package/dist/esm/components/fast-definitions.js +38 -28
- package/dist/esm/components/fast-element.js +31 -12
- package/dist/esm/context.js +163 -0
- package/dist/esm/debug.js +36 -4
- package/dist/esm/di/di.js +1435 -0
- package/dist/esm/index.js +2 -1
- package/dist/esm/interfaces.js +4 -0
- package/dist/esm/metadata.js +60 -0
- package/dist/esm/observation/arrays.js +304 -3
- package/dist/esm/observation/observable.js +81 -87
- package/dist/esm/pending-task.js +16 -0
- package/dist/esm/platform.js +26 -1
- package/dist/esm/polyfills.js +1 -55
- 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/styles/element-styles.js +14 -33
- package/dist/esm/{observation/behavior.js → styles/host.js} +0 -0
- package/dist/esm/templating/binding-signal.js +83 -0
- package/dist/esm/templating/binding-two-way.js +103 -0
- package/dist/esm/templating/binding.js +134 -414
- package/dist/esm/templating/compiler.js +30 -7
- package/dist/esm/templating/html-directive.js +100 -28
- package/dist/esm/templating/node-observation.js +9 -8
- package/dist/esm/templating/ref.js +4 -12
- package/dist/esm/templating/render.js +391 -0
- package/dist/esm/templating/repeat.js +96 -72
- package/dist/esm/templating/template.js +11 -29
- package/dist/esm/templating/view.js +107 -29
- package/dist/esm/templating/when.js +5 -4
- package/dist/esm/testing/exports.js +3 -0
- package/dist/esm/testing/fakes.js +76 -0
- package/dist/esm/testing/fixture.js +86 -0
- package/dist/esm/testing/timeout.js +24 -0
- package/dist/esm/utilities.js +0 -95
- package/dist/fast-element.api.json +9278 -10745
- package/dist/fast-element.d.ts +707 -813
- package/dist/fast-element.debug.js +1229 -944
- package/dist/fast-element.debug.min.js +1 -1
- package/dist/fast-element.js +1191 -938
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +716 -824
- package/docs/api-report.md +265 -319
- package/package.json +39 -14
- package/dist/dts/hooks.d.ts +0 -20
- package/dist/dts/observation/behavior.d.ts +0 -19
- package/dist/dts/observation/splice-strategies.d.ts +0 -13
- package/dist/esm/hooks.js +0 -32
- package/dist/esm/observation/splice-strategies.js +0 -400
|
@@ -28,61 +28,6 @@ if (!globalThis.trustedTypes) {
|
|
|
28
28
|
createPolicy: (n, r) => r,
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
// ensure FAST global - duplicated in platform.ts
|
|
32
|
-
const propConfig$1 = {
|
|
33
|
-
configurable: false,
|
|
34
|
-
enumerable: false,
|
|
35
|
-
writable: false,
|
|
36
|
-
};
|
|
37
|
-
if (globalThis.FAST === void 0) {
|
|
38
|
-
Reflect.defineProperty(globalThis, "FAST", Object.assign({ value: Object.create(null) }, propConfig$1));
|
|
39
|
-
}
|
|
40
|
-
const FAST$2 = globalThis.FAST;
|
|
41
|
-
if (FAST$2.getById === void 0) {
|
|
42
|
-
const storage = Object.create(null);
|
|
43
|
-
Reflect.defineProperty(FAST$2, "getById", Object.assign({ value(id, initialize) {
|
|
44
|
-
let found = storage[id];
|
|
45
|
-
if (found === void 0) {
|
|
46
|
-
found = initialize ? (storage[id] = initialize()) : null;
|
|
47
|
-
}
|
|
48
|
-
return found;
|
|
49
|
-
} }, propConfig$1));
|
|
50
|
-
}
|
|
51
|
-
// duplicated from DOM
|
|
52
|
-
const supportsAdoptedStyleSheets = Array.isArray(document.adoptedStyleSheets) &&
|
|
53
|
-
"replace" in CSSStyleSheet.prototype;
|
|
54
|
-
function usableStyleTarget(target) {
|
|
55
|
-
return target === document ? document.body : target;
|
|
56
|
-
}
|
|
57
|
-
let id$1 = 0;
|
|
58
|
-
const nextStyleId = () => `fast-${++id$1}`;
|
|
59
|
-
class StyleElementStrategy {
|
|
60
|
-
constructor(styles) {
|
|
61
|
-
this.styles = styles;
|
|
62
|
-
this.styleClass = nextStyleId();
|
|
63
|
-
}
|
|
64
|
-
addStylesTo(target) {
|
|
65
|
-
target = usableStyleTarget(target);
|
|
66
|
-
const styles = this.styles;
|
|
67
|
-
const styleClass = this.styleClass;
|
|
68
|
-
for (let i = 0; i < styles.length; i++) {
|
|
69
|
-
const element = document.createElement("style");
|
|
70
|
-
element.innerHTML = styles[i];
|
|
71
|
-
element.className = styleClass;
|
|
72
|
-
target.append(element);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
removeStylesFrom(target) {
|
|
76
|
-
const styles = target.querySelectorAll(`.${this.styleClass}`);
|
|
77
|
-
target = usableStyleTarget(target);
|
|
78
|
-
for (let i = 0, ii = styles.length; i < ii; ++i) {
|
|
79
|
-
target.removeChild(styles[i]);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (!supportsAdoptedStyleSheets) {
|
|
84
|
-
FAST$2.getById(/* KernelServiceId.styleSheetStrategy */ 5, () => StyleElementStrategy);
|
|
85
|
-
}
|
|
86
31
|
|
|
87
32
|
if (globalThis.FAST === void 0) {
|
|
88
33
|
Reflect.defineProperty(globalThis, "FAST", {
|
|
@@ -97,19 +42,51 @@ const debugMessages = {
|
|
|
97
42
|
[1101 /* needsArrayObservation */]: "Must call enableArrayObservation before observing arrays.",
|
|
98
43
|
[1201 /* onlySetHTMLPolicyOnce */]: "The HTML policy can only be set once.",
|
|
99
44
|
[1202 /* bindingInnerHTMLRequiresTrustedTypes */]: "To bind innerHTML, you must use a TrustedTypesPolicy.",
|
|
45
|
+
[1203 /* twoWayBindingRequiresObservables */]: "View=>Model update skipped. To use twoWay binding, the target property must be observable.",
|
|
46
|
+
[1204 /* hostBindingWithoutHost */]: "No host element is present. Cannot bind host with ${name}.",
|
|
47
|
+
[1205 /* unsupportedBindingBehavior */]: "The requested binding behavior is not supported by the binding engine.",
|
|
100
48
|
[1401 /* missingElementDefinition */]: "Missing FASTElement definition.",
|
|
49
|
+
[1501 /* noRegistrationForContext */]: "No registration for Context/Interface '${name}'.",
|
|
50
|
+
[1502 /* noFactoryForResolver */]: "Dependency injection resolver for '${key}' returned a null factory.",
|
|
51
|
+
[1503 /* invalidResolverStrategy */]: "Invalid dependency injection resolver strategy specified '${strategy}'.",
|
|
52
|
+
[1504 /* cannotAutoregisterDependency */]: "Unable to autoregister dependency.",
|
|
53
|
+
[1505 /* cannotResolveKey */]: "Unable to resolve dependency injection key '${key}'.",
|
|
54
|
+
[1506 /* cannotConstructNativeFunction */]: "'${name}' is a native function and therefore cannot be safely constructed by DI. If this is intentional, please use a callback or cachedCallback resolver.",
|
|
55
|
+
[1507 /* cannotJITRegisterNonConstructor */]: "Attempted to jitRegister something that is not a constructor '${value}'. Did you forget to register this dependency?",
|
|
56
|
+
[1508 /* cannotJITRegisterIntrinsic */]: "Attempted to jitRegister an intrinsic type '${value}'. Did you forget to add @inject(Key)?",
|
|
57
|
+
[1509 /* cannotJITRegisterInterface */]: "Attempted to jitRegister an interface '${value}'.",
|
|
58
|
+
[1510 /* invalidResolver */]: "A valid resolver was not returned from the register method.",
|
|
59
|
+
[1511 /* invalidKey */]: "Key/value cannot be null or undefined. Are you trying to inject/register something that doesn't exist with DI?",
|
|
60
|
+
[1512 /* noDefaultResolver */]: "'${key}' not registered. Did you forget to add @singleton()?",
|
|
61
|
+
[1513 /* cyclicDependency */]: "Cyclic dependency found '${name}'.",
|
|
62
|
+
[1514 /* connectUpdateRequiresController */]: "Injected properties that are updated on changes to DOM connectivity require the target object to be an instance of FASTElement.",
|
|
101
63
|
};
|
|
64
|
+
const allPlaceholders = /(\$\{\w+?})/g;
|
|
65
|
+
const placeholder = /\$\{(\w+?)}/g;
|
|
66
|
+
const noValues = Object.freeze({});
|
|
67
|
+
function formatMessage(message, values) {
|
|
68
|
+
return message
|
|
69
|
+
.split(allPlaceholders)
|
|
70
|
+
.map(v => {
|
|
71
|
+
var _a;
|
|
72
|
+
const replaced = v.replace(placeholder, "$1");
|
|
73
|
+
return String((_a = values[replaced]) !== null && _a !== void 0 ? _a : v);
|
|
74
|
+
})
|
|
75
|
+
.join("");
|
|
76
|
+
}
|
|
102
77
|
Object.assign(FAST$1, {
|
|
103
78
|
addMessages(messages) {
|
|
104
79
|
Object.assign(debugMessages, messages);
|
|
105
80
|
},
|
|
106
|
-
warn(code,
|
|
81
|
+
warn(code, values = noValues) {
|
|
107
82
|
var _a;
|
|
108
|
-
|
|
83
|
+
const message = (_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Warning";
|
|
84
|
+
console.warn(formatMessage(message, values));
|
|
109
85
|
},
|
|
110
|
-
error(code,
|
|
86
|
+
error(code, values = noValues) {
|
|
111
87
|
var _a;
|
|
112
|
-
|
|
88
|
+
const message = (_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Error";
|
|
89
|
+
return new Error(formatMessage(message, values));
|
|
113
90
|
},
|
|
114
91
|
});
|
|
115
92
|
|
|
@@ -141,7 +118,7 @@ if (FAST.error === void 0) {
|
|
|
141
118
|
Object.assign(FAST, {
|
|
142
119
|
warn() { },
|
|
143
120
|
error(code) {
|
|
144
|
-
return new Error(`
|
|
121
|
+
return new Error(`Error ${code}`);
|
|
145
122
|
},
|
|
146
123
|
addMessages() { },
|
|
147
124
|
});
|
|
@@ -172,10 +149,34 @@ function createTypeRegistry() {
|
|
|
172
149
|
return typeToDefinition.get(key);
|
|
173
150
|
},
|
|
174
151
|
getForInstance(object) {
|
|
152
|
+
if (object === null || object === void 0) {
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
175
155
|
return typeToDefinition.get(object.constructor);
|
|
176
156
|
},
|
|
177
157
|
});
|
|
178
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Creates a function capable of locating metadata associated with a type.
|
|
161
|
+
* @returns A metadata locator function.
|
|
162
|
+
* @internal
|
|
163
|
+
*/
|
|
164
|
+
function createMetadataLocator() {
|
|
165
|
+
const metadataLookup = new WeakMap();
|
|
166
|
+
return function (target) {
|
|
167
|
+
let metadata = metadataLookup.get(target);
|
|
168
|
+
if (metadata === void 0) {
|
|
169
|
+
let currentTarget = Reflect.getPrototypeOf(target);
|
|
170
|
+
while (metadata === void 0 && currentTarget !== null) {
|
|
171
|
+
metadata = metadataLookup.get(currentTarget);
|
|
172
|
+
currentTarget = Reflect.getPrototypeOf(currentTarget);
|
|
173
|
+
}
|
|
174
|
+
metadata = metadata === void 0 ? [] : metadata.slice(0);
|
|
175
|
+
metadataLookup.set(target, metadata);
|
|
176
|
+
}
|
|
177
|
+
return metadata;
|
|
178
|
+
};
|
|
179
|
+
}
|
|
179
180
|
|
|
180
181
|
/**
|
|
181
182
|
* @internal
|
|
@@ -417,6 +418,21 @@ class PropertyChangeNotifier {
|
|
|
417
418
|
}
|
|
418
419
|
}
|
|
419
420
|
|
|
421
|
+
/**
|
|
422
|
+
* Describes how the source's lifetime relates to its controller's lifetime.
|
|
423
|
+
* @public
|
|
424
|
+
*/
|
|
425
|
+
const SourceLifetime = Object.freeze({
|
|
426
|
+
/**
|
|
427
|
+
* The source to controller lifetime relationship is unknown.
|
|
428
|
+
*/
|
|
429
|
+
unknown: void 0,
|
|
430
|
+
/**
|
|
431
|
+
* The source and controller lifetimes are coupled to one another.
|
|
432
|
+
* They can/will be GC'd together.
|
|
433
|
+
*/
|
|
434
|
+
coupled: 1,
|
|
435
|
+
});
|
|
420
436
|
/**
|
|
421
437
|
* Common Observable APIs.
|
|
422
438
|
* @public
|
|
@@ -425,7 +441,6 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
425
441
|
const queueUpdate = Updates.enqueue;
|
|
426
442
|
const volatileRegex = /(:|&&|\|\||if)/;
|
|
427
443
|
const notifierLookup = new WeakMap();
|
|
428
|
-
const accessorLookup = new WeakMap();
|
|
429
444
|
let watcher = void 0;
|
|
430
445
|
let createArrayObserver = (array) => {
|
|
431
446
|
throw FAST.error(1101 /* Message.needsArrayObservation */);
|
|
@@ -440,19 +455,7 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
440
455
|
}
|
|
441
456
|
return found;
|
|
442
457
|
}
|
|
443
|
-
|
|
444
|
-
let accessors = accessorLookup.get(target);
|
|
445
|
-
if (accessors === void 0) {
|
|
446
|
-
let currentTarget = Reflect.getPrototypeOf(target);
|
|
447
|
-
while (accessors === void 0 && currentTarget !== null) {
|
|
448
|
-
accessors = accessorLookup.get(currentTarget);
|
|
449
|
-
currentTarget = Reflect.getPrototypeOf(currentTarget);
|
|
450
|
-
}
|
|
451
|
-
accessors = accessors === void 0 ? [] : accessors.slice(0);
|
|
452
|
-
accessorLookup.set(target, accessors);
|
|
453
|
-
}
|
|
454
|
-
return accessors;
|
|
455
|
-
}
|
|
458
|
+
const getAccessors = createMetadataLocator();
|
|
456
459
|
class DefaultObservableAccessor {
|
|
457
460
|
constructor(name) {
|
|
458
461
|
this.name = name;
|
|
@@ -478,10 +481,10 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
478
481
|
}
|
|
479
482
|
}
|
|
480
483
|
}
|
|
481
|
-
class
|
|
482
|
-
constructor(
|
|
483
|
-
super(
|
|
484
|
-
this.
|
|
484
|
+
class ExpressionNotifierImplementation extends SubscriberSet {
|
|
485
|
+
constructor(expression, initialSubscriber, isVolatileBinding = false) {
|
|
486
|
+
super(expression, initialSubscriber);
|
|
487
|
+
this.expression = expression;
|
|
485
488
|
this.isVolatileBinding = isVolatileBinding;
|
|
486
489
|
this.needsRefresh = true;
|
|
487
490
|
this.needsQueue = true;
|
|
@@ -496,6 +499,22 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
496
499
|
setMode(isAsync) {
|
|
497
500
|
this.isAsync = this.needsQueue = isAsync;
|
|
498
501
|
}
|
|
502
|
+
bind(controller) {
|
|
503
|
+
this.controller = controller;
|
|
504
|
+
const value = this.observe(controller.source, controller.context);
|
|
505
|
+
if (!controller.isBound && this.requiresUnbind(controller)) {
|
|
506
|
+
controller.onUnbind(this);
|
|
507
|
+
}
|
|
508
|
+
return value;
|
|
509
|
+
}
|
|
510
|
+
requiresUnbind(controller) {
|
|
511
|
+
return (controller.sourceLifetime !== SourceLifetime.coupled ||
|
|
512
|
+
this.first !== this.last ||
|
|
513
|
+
this.first.propertySource !== controller.source);
|
|
514
|
+
}
|
|
515
|
+
unbind(controller) {
|
|
516
|
+
this.dispose();
|
|
517
|
+
}
|
|
499
518
|
observe(source, context) {
|
|
500
519
|
if (this.needsRefresh && this.last !== null) {
|
|
501
520
|
this.dispose();
|
|
@@ -503,10 +522,19 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
503
522
|
const previousWatcher = watcher;
|
|
504
523
|
watcher = this.needsRefresh ? this : void 0;
|
|
505
524
|
this.needsRefresh = this.isVolatileBinding;
|
|
506
|
-
|
|
507
|
-
|
|
525
|
+
let result;
|
|
526
|
+
try {
|
|
527
|
+
result = this.expression(source, context);
|
|
528
|
+
}
|
|
529
|
+
finally {
|
|
530
|
+
watcher = previousWatcher;
|
|
531
|
+
}
|
|
508
532
|
return result;
|
|
509
533
|
}
|
|
534
|
+
// backwards compat with v1 kernel
|
|
535
|
+
disconnect() {
|
|
536
|
+
this.dispose();
|
|
537
|
+
}
|
|
510
538
|
dispose() {
|
|
511
539
|
if (this.last !== null) {
|
|
512
540
|
let current = this.first;
|
|
@@ -633,22 +661,22 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
633
661
|
*/
|
|
634
662
|
getAccessors,
|
|
635
663
|
/**
|
|
636
|
-
* Creates a {@link
|
|
637
|
-
* provided {@link
|
|
638
|
-
* @param
|
|
664
|
+
* Creates a {@link ExpressionNotifier} that can watch the
|
|
665
|
+
* provided {@link Expression} for changes.
|
|
666
|
+
* @param expression - The binding to observe.
|
|
639
667
|
* @param initialSubscriber - An initial subscriber to changes in the binding value.
|
|
640
668
|
* @param isVolatileBinding - Indicates whether the binding's dependency list must be re-evaluated on every value evaluation.
|
|
641
669
|
*/
|
|
642
|
-
binding(
|
|
643
|
-
return new
|
|
670
|
+
binding(expression, initialSubscriber, isVolatileBinding = this.isVolatileBinding(expression)) {
|
|
671
|
+
return new ExpressionNotifierImplementation(expression, initialSubscriber, isVolatileBinding);
|
|
644
672
|
},
|
|
645
673
|
/**
|
|
646
674
|
* Determines whether a binding expression is volatile and needs to have its dependency list re-evaluated
|
|
647
675
|
* on every evaluation of the value.
|
|
648
|
-
* @param
|
|
676
|
+
* @param expression - The binding to inspect.
|
|
649
677
|
*/
|
|
650
|
-
isVolatileBinding(
|
|
651
|
-
return volatileRegex.test(
|
|
678
|
+
isVolatileBinding(expression) {
|
|
679
|
+
return volatileRegex.test(expression.toString());
|
|
652
680
|
},
|
|
653
681
|
});
|
|
654
682
|
});
|
|
@@ -687,73 +715,40 @@ const contextEvent = FAST.getById(3 /* KernelServiceId.contextEvent */, () => {
|
|
|
687
715
|
},
|
|
688
716
|
};
|
|
689
717
|
});
|
|
690
|
-
class DefaultExecutionContext {
|
|
691
|
-
constructor(parentSource = null, parentContext = null) {
|
|
692
|
-
this.index = 0;
|
|
693
|
-
this.length = 0;
|
|
694
|
-
this.parent = parentSource;
|
|
695
|
-
this.parentContext = parentContext;
|
|
696
|
-
}
|
|
697
|
-
get event() {
|
|
698
|
-
return contextEvent.get();
|
|
699
|
-
}
|
|
700
|
-
get isEven() {
|
|
701
|
-
return this.index % 2 === 0;
|
|
702
|
-
}
|
|
703
|
-
get isOdd() {
|
|
704
|
-
return this.index % 2 !== 0;
|
|
705
|
-
}
|
|
706
|
-
get isFirst() {
|
|
707
|
-
return this.index === 0;
|
|
708
|
-
}
|
|
709
|
-
get isInMiddle() {
|
|
710
|
-
return !this.isFirst && !this.isLast;
|
|
711
|
-
}
|
|
712
|
-
get isLast() {
|
|
713
|
-
return this.index === this.length - 1;
|
|
714
|
-
}
|
|
715
|
-
eventDetail() {
|
|
716
|
-
return this.event.detail;
|
|
717
|
-
}
|
|
718
|
-
eventTarget() {
|
|
719
|
-
return this.event.target;
|
|
720
|
-
}
|
|
721
|
-
updatePosition(index, length) {
|
|
722
|
-
this.index = index;
|
|
723
|
-
this.length = length;
|
|
724
|
-
}
|
|
725
|
-
createChildContext(parentSource) {
|
|
726
|
-
return new DefaultExecutionContext(parentSource, this);
|
|
727
|
-
}
|
|
728
|
-
createItemContext(index, length) {
|
|
729
|
-
const childContext = Object.create(this);
|
|
730
|
-
childContext.index = index;
|
|
731
|
-
childContext.length = length;
|
|
732
|
-
return childContext;
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
Observable.defineProperty(DefaultExecutionContext.prototype, "index");
|
|
736
|
-
Observable.defineProperty(DefaultExecutionContext.prototype, "length");
|
|
737
718
|
/**
|
|
738
|
-
*
|
|
719
|
+
* Provides additional contextual information available to behaviors and expressions.
|
|
739
720
|
* @public
|
|
740
721
|
*/
|
|
741
722
|
const ExecutionContext = Object.freeze({
|
|
742
|
-
default: new DefaultExecutionContext(),
|
|
743
723
|
/**
|
|
744
|
-
*
|
|
745
|
-
* @param event - The event to set.
|
|
746
|
-
* @internal
|
|
724
|
+
* A default execution context.
|
|
747
725
|
*/
|
|
748
|
-
|
|
749
|
-
|
|
726
|
+
default: {
|
|
727
|
+
index: 0,
|
|
728
|
+
length: 0,
|
|
729
|
+
get event() {
|
|
730
|
+
return ExecutionContext.getEvent();
|
|
731
|
+
},
|
|
732
|
+
eventDetail() {
|
|
733
|
+
return this.event.detail;
|
|
734
|
+
},
|
|
735
|
+
eventTarget() {
|
|
736
|
+
return this.event.target;
|
|
737
|
+
},
|
|
750
738
|
},
|
|
751
739
|
/**
|
|
752
|
-
*
|
|
753
|
-
* @returns
|
|
740
|
+
* Gets the current event.
|
|
741
|
+
* @returns An event object.
|
|
754
742
|
*/
|
|
755
|
-
|
|
756
|
-
return
|
|
743
|
+
getEvent() {
|
|
744
|
+
return contextEvent.get();
|
|
745
|
+
},
|
|
746
|
+
/**
|
|
747
|
+
* Sets the current event.
|
|
748
|
+
* @param event - An event object.
|
|
749
|
+
*/
|
|
750
|
+
setEvent(event) {
|
|
751
|
+
contextEvent.set(event);
|
|
757
752
|
},
|
|
758
753
|
});
|
|
759
754
|
|
|
@@ -822,10 +817,311 @@ const SpliceStrategySupport = Object.freeze({
|
|
|
822
817
|
const reset = new Splice(0, emptyArray, 0);
|
|
823
818
|
reset.reset = true;
|
|
824
819
|
const resetSplices = [reset];
|
|
820
|
+
// Note: This function is *based* on the computation of the Levenshtein
|
|
821
|
+
// "edit" distance. The one change is that "updates" are treated as two
|
|
822
|
+
// edits - not one. With Array splices, an update is really a delete
|
|
823
|
+
// followed by an add. By retaining this, we optimize for "keeping" the
|
|
824
|
+
// maximum array items in the original array. For example:
|
|
825
|
+
//
|
|
826
|
+
// 'xxxx123' to '123yyyy'
|
|
827
|
+
//
|
|
828
|
+
// With 1-edit updates, the shortest path would be just to update all seven
|
|
829
|
+
// characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
|
|
830
|
+
// leaves the substring '123' intact.
|
|
831
|
+
function calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd) {
|
|
832
|
+
// "Deletion" columns
|
|
833
|
+
const rowCount = oldEnd - oldStart + 1;
|
|
834
|
+
const columnCount = currentEnd - currentStart + 1;
|
|
835
|
+
const distances = new Array(rowCount);
|
|
836
|
+
let north;
|
|
837
|
+
let west;
|
|
838
|
+
// "Addition" rows. Initialize null column.
|
|
839
|
+
for (let i = 0; i < rowCount; ++i) {
|
|
840
|
+
distances[i] = new Array(columnCount);
|
|
841
|
+
distances[i][0] = i;
|
|
842
|
+
}
|
|
843
|
+
// Initialize null row
|
|
844
|
+
for (let j = 0; j < columnCount; ++j) {
|
|
845
|
+
distances[0][j] = j;
|
|
846
|
+
}
|
|
847
|
+
for (let i = 1; i < rowCount; ++i) {
|
|
848
|
+
for (let j = 1; j < columnCount; ++j) {
|
|
849
|
+
if (current[currentStart + j - 1] === old[oldStart + i - 1]) {
|
|
850
|
+
distances[i][j] = distances[i - 1][j - 1];
|
|
851
|
+
}
|
|
852
|
+
else {
|
|
853
|
+
north = distances[i - 1][j] + 1;
|
|
854
|
+
west = distances[i][j - 1] + 1;
|
|
855
|
+
distances[i][j] = north < west ? north : west;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
return distances;
|
|
860
|
+
}
|
|
861
|
+
// This starts at the final weight, and walks "backward" by finding
|
|
862
|
+
// the minimum previous weight recursively until the origin of the weight
|
|
863
|
+
// matrix.
|
|
864
|
+
function spliceOperationsFromEditDistances(distances) {
|
|
865
|
+
let i = distances.length - 1;
|
|
866
|
+
let j = distances[0].length - 1;
|
|
867
|
+
let current = distances[i][j];
|
|
868
|
+
const edits = [];
|
|
869
|
+
while (i > 0 || j > 0) {
|
|
870
|
+
if (i === 0) {
|
|
871
|
+
edits.push(2 /* Edit.add */);
|
|
872
|
+
j--;
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
if (j === 0) {
|
|
876
|
+
edits.push(3 /* Edit.delete */);
|
|
877
|
+
i--;
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
const northWest = distances[i - 1][j - 1];
|
|
881
|
+
const west = distances[i - 1][j];
|
|
882
|
+
const north = distances[i][j - 1];
|
|
883
|
+
let min;
|
|
884
|
+
if (west < north) {
|
|
885
|
+
min = west < northWest ? west : northWest;
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
min = north < northWest ? north : northWest;
|
|
889
|
+
}
|
|
890
|
+
if (min === northWest) {
|
|
891
|
+
if (northWest === current) {
|
|
892
|
+
edits.push(0 /* Edit.leave */);
|
|
893
|
+
}
|
|
894
|
+
else {
|
|
895
|
+
edits.push(1 /* Edit.update */);
|
|
896
|
+
current = northWest;
|
|
897
|
+
}
|
|
898
|
+
i--;
|
|
899
|
+
j--;
|
|
900
|
+
}
|
|
901
|
+
else if (min === west) {
|
|
902
|
+
edits.push(3 /* Edit.delete */);
|
|
903
|
+
i--;
|
|
904
|
+
current = west;
|
|
905
|
+
}
|
|
906
|
+
else {
|
|
907
|
+
edits.push(2 /* Edit.add */);
|
|
908
|
+
j--;
|
|
909
|
+
current = north;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
return edits.reverse();
|
|
913
|
+
}
|
|
914
|
+
function sharedPrefix(current, old, searchLength) {
|
|
915
|
+
for (let i = 0; i < searchLength; ++i) {
|
|
916
|
+
if (current[i] !== old[i]) {
|
|
917
|
+
return i;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
return searchLength;
|
|
921
|
+
}
|
|
922
|
+
function sharedSuffix(current, old, searchLength) {
|
|
923
|
+
let index1 = current.length;
|
|
924
|
+
let index2 = old.length;
|
|
925
|
+
let count = 0;
|
|
926
|
+
while (count < searchLength && current[--index1] === old[--index2]) {
|
|
927
|
+
count++;
|
|
928
|
+
}
|
|
929
|
+
return count;
|
|
930
|
+
}
|
|
931
|
+
function intersect(start1, end1, start2, end2) {
|
|
932
|
+
// Disjoint
|
|
933
|
+
if (end1 < start2 || end2 < start1) {
|
|
934
|
+
return -1;
|
|
935
|
+
}
|
|
936
|
+
// Adjacent
|
|
937
|
+
if (end1 === start2 || end2 === start1) {
|
|
938
|
+
return 0;
|
|
939
|
+
}
|
|
940
|
+
// Non-zero intersect, span1 first
|
|
941
|
+
if (start1 < start2) {
|
|
942
|
+
if (end1 < end2) {
|
|
943
|
+
return end1 - start2; // Overlap
|
|
944
|
+
}
|
|
945
|
+
return end2 - start2; // Contained
|
|
946
|
+
}
|
|
947
|
+
// Non-zero intersect, span2 first
|
|
948
|
+
if (end2 < end1) {
|
|
949
|
+
return end2 - start1; // Overlap
|
|
950
|
+
}
|
|
951
|
+
return end1 - start1; // Contained
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* @remarks
|
|
955
|
+
* Lacking individual splice mutation information, the minimal set of
|
|
956
|
+
* splices can be synthesized given the previous state and final state of an
|
|
957
|
+
* array. The basic approach is to calculate the edit distance matrix and
|
|
958
|
+
* choose the shortest path through it.
|
|
959
|
+
*
|
|
960
|
+
* Complexity: O(l * p)
|
|
961
|
+
* l: The length of the current array
|
|
962
|
+
* p: The length of the old array
|
|
963
|
+
*/
|
|
964
|
+
function calc(current, currentStart, currentEnd, old, oldStart, oldEnd) {
|
|
965
|
+
let prefixCount = 0;
|
|
966
|
+
let suffixCount = 0;
|
|
967
|
+
const minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
|
|
968
|
+
if (currentStart === 0 && oldStart === 0) {
|
|
969
|
+
prefixCount = sharedPrefix(current, old, minLength);
|
|
970
|
+
}
|
|
971
|
+
if (currentEnd === current.length && oldEnd === old.length) {
|
|
972
|
+
suffixCount = sharedSuffix(current, old, minLength - prefixCount);
|
|
973
|
+
}
|
|
974
|
+
currentStart += prefixCount;
|
|
975
|
+
oldStart += prefixCount;
|
|
976
|
+
currentEnd -= suffixCount;
|
|
977
|
+
oldEnd -= suffixCount;
|
|
978
|
+
if (currentEnd - currentStart === 0 && oldEnd - oldStart === 0) {
|
|
979
|
+
return emptyArray;
|
|
980
|
+
}
|
|
981
|
+
if (currentStart === currentEnd) {
|
|
982
|
+
const splice = new Splice(currentStart, [], 0);
|
|
983
|
+
while (oldStart < oldEnd) {
|
|
984
|
+
splice.removed.push(old[oldStart++]);
|
|
985
|
+
}
|
|
986
|
+
return [splice];
|
|
987
|
+
}
|
|
988
|
+
else if (oldStart === oldEnd) {
|
|
989
|
+
return [new Splice(currentStart, [], currentEnd - currentStart)];
|
|
990
|
+
}
|
|
991
|
+
const ops = spliceOperationsFromEditDistances(calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
|
|
992
|
+
const splices = [];
|
|
993
|
+
let splice = void 0;
|
|
994
|
+
let index = currentStart;
|
|
995
|
+
let oldIndex = oldStart;
|
|
996
|
+
for (let i = 0; i < ops.length; ++i) {
|
|
997
|
+
switch (ops[i]) {
|
|
998
|
+
case 0 /* Edit.leave */:
|
|
999
|
+
if (splice !== void 0) {
|
|
1000
|
+
splices.push(splice);
|
|
1001
|
+
splice = void 0;
|
|
1002
|
+
}
|
|
1003
|
+
index++;
|
|
1004
|
+
oldIndex++;
|
|
1005
|
+
break;
|
|
1006
|
+
case 1 /* Edit.update */:
|
|
1007
|
+
if (splice === void 0) {
|
|
1008
|
+
splice = new Splice(index, [], 0);
|
|
1009
|
+
}
|
|
1010
|
+
splice.addedCount++;
|
|
1011
|
+
index++;
|
|
1012
|
+
splice.removed.push(old[oldIndex]);
|
|
1013
|
+
oldIndex++;
|
|
1014
|
+
break;
|
|
1015
|
+
case 2 /* Edit.add */:
|
|
1016
|
+
if (splice === void 0) {
|
|
1017
|
+
splice = new Splice(index, [], 0);
|
|
1018
|
+
}
|
|
1019
|
+
splice.addedCount++;
|
|
1020
|
+
index++;
|
|
1021
|
+
break;
|
|
1022
|
+
case 3 /* Edit.delete */:
|
|
1023
|
+
if (splice === void 0) {
|
|
1024
|
+
splice = new Splice(index, [], 0);
|
|
1025
|
+
}
|
|
1026
|
+
splice.removed.push(old[oldIndex]);
|
|
1027
|
+
oldIndex++;
|
|
1028
|
+
break;
|
|
1029
|
+
// no default
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
if (splice !== void 0) {
|
|
1033
|
+
splices.push(splice);
|
|
1034
|
+
}
|
|
1035
|
+
return splices;
|
|
1036
|
+
}
|
|
1037
|
+
function merge(splice, splices) {
|
|
1038
|
+
let inserted = false;
|
|
1039
|
+
let insertionOffset = 0;
|
|
1040
|
+
for (let i = 0; i < splices.length; i++) {
|
|
1041
|
+
const current = splices[i];
|
|
1042
|
+
current.index += insertionOffset;
|
|
1043
|
+
if (inserted) {
|
|
1044
|
+
continue;
|
|
1045
|
+
}
|
|
1046
|
+
const intersectCount = intersect(splice.index, splice.index + splice.removed.length, current.index, current.index + current.addedCount);
|
|
1047
|
+
if (intersectCount >= 0) {
|
|
1048
|
+
// Merge the two splices
|
|
1049
|
+
splices.splice(i, 1);
|
|
1050
|
+
i--;
|
|
1051
|
+
insertionOffset -= current.addedCount - current.removed.length;
|
|
1052
|
+
splice.addedCount += current.addedCount - intersectCount;
|
|
1053
|
+
const deleteCount = splice.removed.length + current.removed.length - intersectCount;
|
|
1054
|
+
if (!splice.addedCount && !deleteCount) {
|
|
1055
|
+
// merged splice is a noop. discard.
|
|
1056
|
+
inserted = true;
|
|
1057
|
+
}
|
|
1058
|
+
else {
|
|
1059
|
+
let currentRemoved = current.removed;
|
|
1060
|
+
if (splice.index < current.index) {
|
|
1061
|
+
// some prefix of splice.removed is prepended to current.removed.
|
|
1062
|
+
const prepend = splice.removed.slice(0, current.index - splice.index);
|
|
1063
|
+
prepend.push(...currentRemoved);
|
|
1064
|
+
currentRemoved = prepend;
|
|
1065
|
+
}
|
|
1066
|
+
if (splice.index + splice.removed.length >
|
|
1067
|
+
current.index + current.addedCount) {
|
|
1068
|
+
// some suffix of splice.removed is appended to current.removed.
|
|
1069
|
+
const append = splice.removed.slice(current.index + current.addedCount - splice.index);
|
|
1070
|
+
currentRemoved.push(...append);
|
|
1071
|
+
}
|
|
1072
|
+
splice.removed = currentRemoved;
|
|
1073
|
+
if (current.index < splice.index) {
|
|
1074
|
+
splice.index = current.index;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
else if (splice.index < current.index) {
|
|
1079
|
+
// Insert splice here.
|
|
1080
|
+
inserted = true;
|
|
1081
|
+
splices.splice(i, 0, splice);
|
|
1082
|
+
i++;
|
|
1083
|
+
const offset = splice.addedCount - splice.removed.length;
|
|
1084
|
+
current.index += offset;
|
|
1085
|
+
insertionOffset += offset;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
if (!inserted) {
|
|
1089
|
+
splices.push(splice);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
function project(array, changes) {
|
|
1093
|
+
let splices = [];
|
|
1094
|
+
const initialSplices = [];
|
|
1095
|
+
for (let i = 0, ii = changes.length; i < ii; i++) {
|
|
1096
|
+
merge(changes[i], initialSplices);
|
|
1097
|
+
}
|
|
1098
|
+
for (let i = 0, ii = initialSplices.length; i < ii; ++i) {
|
|
1099
|
+
const splice = initialSplices[i];
|
|
1100
|
+
if (splice.addedCount === 1 && splice.removed.length === 1) {
|
|
1101
|
+
if (splice.removed[0] !== array[splice.index]) {
|
|
1102
|
+
splices.push(splice);
|
|
1103
|
+
}
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
splices = splices.concat(calc(array, splice.index, splice.index + splice.addedCount, splice.removed, 0, splice.removed.length));
|
|
1107
|
+
}
|
|
1108
|
+
return splices;
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* A SpliceStrategy that attempts to merge all splices into the minimal set of
|
|
1112
|
+
* splices needed to represent the change from the old array to the new array.
|
|
1113
|
+
* @public
|
|
1114
|
+
*/
|
|
825
1115
|
let defaultSpliceStrategy = Object.freeze({
|
|
826
|
-
support: SpliceStrategySupport.
|
|
1116
|
+
support: SpliceStrategySupport.optimized,
|
|
827
1117
|
normalize(previous, current, changes) {
|
|
828
|
-
|
|
1118
|
+
if (previous === void 0) {
|
|
1119
|
+
if (changes === void 0) {
|
|
1120
|
+
return emptyArray;
|
|
1121
|
+
}
|
|
1122
|
+
return changes.length > 1 ? project(current, changes) : changes;
|
|
1123
|
+
}
|
|
1124
|
+
return resetSplices;
|
|
829
1125
|
},
|
|
830
1126
|
pop(array, observer, pop, args) {
|
|
831
1127
|
const notEmpty = array.length > 0;
|
|
@@ -1010,7 +1306,7 @@ const ArrayObserver = Object.freeze({
|
|
|
1010
1306
|
* @returns The length of the array.
|
|
1011
1307
|
* @public
|
|
1012
1308
|
*/
|
|
1013
|
-
function
|
|
1309
|
+
function lengthOf(array) {
|
|
1014
1310
|
if (!array) {
|
|
1015
1311
|
return 0;
|
|
1016
1312
|
}
|
|
@@ -1023,7 +1319,6 @@ function length(array) {
|
|
|
1023
1319
|
return array.length;
|
|
1024
1320
|
}
|
|
1025
1321
|
|
|
1026
|
-
const styleSheetCache = new Map();
|
|
1027
1322
|
let DefaultStyleStrategy;
|
|
1028
1323
|
function reduceStyles(styles) {
|
|
1029
1324
|
return styles
|
|
@@ -1094,42 +1389,26 @@ class ElementStyles {
|
|
|
1094
1389
|
static setDefaultStrategy(Strategy) {
|
|
1095
1390
|
DefaultStyleStrategy = Strategy;
|
|
1096
1391
|
}
|
|
1392
|
+
/**
|
|
1393
|
+
* Normalizes a set of composable style options.
|
|
1394
|
+
* @param styles - The style options to normalize.
|
|
1395
|
+
* @returns A singular ElementStyles instance or undefined.
|
|
1396
|
+
*/
|
|
1397
|
+
static normalize(styles) {
|
|
1398
|
+
return styles === void 0
|
|
1399
|
+
? void 0
|
|
1400
|
+
: Array.isArray(styles)
|
|
1401
|
+
? new ElementStyles(styles)
|
|
1402
|
+
: styles instanceof ElementStyles
|
|
1403
|
+
? styles
|
|
1404
|
+
: new ElementStyles([styles]);
|
|
1405
|
+
}
|
|
1097
1406
|
}
|
|
1098
1407
|
/**
|
|
1099
1408
|
* Indicates whether the DOM supports the adoptedStyleSheets feature.
|
|
1100
1409
|
*/
|
|
1101
1410
|
ElementStyles.supportsAdoptedStyleSheets = Array.isArray(document.adoptedStyleSheets) &&
|
|
1102
1411
|
"replace" in CSSStyleSheet.prototype;
|
|
1103
|
-
/**
|
|
1104
|
-
* https://wicg.github.io/construct-stylesheets/
|
|
1105
|
-
* https://developers.google.com/web/updates/2019/02/constructable-stylesheets
|
|
1106
|
-
*
|
|
1107
|
-
* @internal
|
|
1108
|
-
*/
|
|
1109
|
-
class AdoptedStyleSheetsStrategy {
|
|
1110
|
-
constructor(styles) {
|
|
1111
|
-
this.sheets = styles.map((x) => {
|
|
1112
|
-
if (x instanceof CSSStyleSheet) {
|
|
1113
|
-
return x;
|
|
1114
|
-
}
|
|
1115
|
-
let sheet = styleSheetCache.get(x);
|
|
1116
|
-
if (sheet === void 0) {
|
|
1117
|
-
sheet = new CSSStyleSheet();
|
|
1118
|
-
sheet.replaceSync(x);
|
|
1119
|
-
styleSheetCache.set(x, sheet);
|
|
1120
|
-
}
|
|
1121
|
-
return sheet;
|
|
1122
|
-
});
|
|
1123
|
-
}
|
|
1124
|
-
addStylesTo(target) {
|
|
1125
|
-
target.adoptedStyleSheets = [...target.adoptedStyleSheets, ...this.sheets];
|
|
1126
|
-
}
|
|
1127
|
-
removeStylesFrom(target) {
|
|
1128
|
-
const sheets = this.sheets;
|
|
1129
|
-
target.adoptedStyleSheets = target.adoptedStyleSheets.filter((x) => sheets.indexOf(x) === -1);
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
ElementStyles.setDefaultStrategy(FAST.getById(5 /* KernelServiceId.styleSheetStrategy */, () => AdoptedStyleSheetsStrategy));
|
|
1133
1412
|
|
|
1134
1413
|
const registry$1 = createTypeRegistry();
|
|
1135
1414
|
/**
|
|
@@ -1238,11 +1517,11 @@ class CSSPartial {
|
|
|
1238
1517
|
}
|
|
1239
1518
|
return this.css;
|
|
1240
1519
|
}
|
|
1241
|
-
|
|
1242
|
-
|
|
1520
|
+
addedCallback(controller) {
|
|
1521
|
+
controller.addStyles(this.styles);
|
|
1243
1522
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1523
|
+
removedCallback(controller) {
|
|
1524
|
+
controller.removeStyles(this.styles);
|
|
1246
1525
|
}
|
|
1247
1526
|
}
|
|
1248
1527
|
CSSDirective.define(CSSPartial);
|
|
@@ -1309,9 +1588,9 @@ const marker = `fast-${Math.random().toString(36).substring(2, 8)}`;
|
|
|
1309
1588
|
const interpolationStart = `${marker}{`;
|
|
1310
1589
|
const interpolationEnd = `}${marker}`;
|
|
1311
1590
|
const interpolationEndLength = interpolationEnd.length;
|
|
1312
|
-
let id = 0;
|
|
1591
|
+
let id$1 = 0;
|
|
1313
1592
|
/** @internal */
|
|
1314
|
-
const nextId = () => `${marker}-${++id}`;
|
|
1593
|
+
const nextId = () => `${marker}-${++id$1}`;
|
|
1315
1594
|
/**
|
|
1316
1595
|
* Common APIs related to markup generation.
|
|
1317
1596
|
* @public
|
|
@@ -1381,6 +1660,67 @@ const Parser = Object.freeze({
|
|
|
1381
1660
|
},
|
|
1382
1661
|
});
|
|
1383
1662
|
|
|
1663
|
+
/**
|
|
1664
|
+
* Bridges between ViewBehaviors and HostBehaviors, enabling a host to
|
|
1665
|
+
* control ViewBehaviors.
|
|
1666
|
+
* @public
|
|
1667
|
+
*/
|
|
1668
|
+
const ViewBehaviorOrchestrator = Object.freeze({
|
|
1669
|
+
/**
|
|
1670
|
+
* Creates a ViewBehaviorOrchestrator.
|
|
1671
|
+
* @param source - The source to to associate behaviors with.
|
|
1672
|
+
* @returns A ViewBehaviorOrchestrator.
|
|
1673
|
+
*/
|
|
1674
|
+
create(source) {
|
|
1675
|
+
const behaviors = [];
|
|
1676
|
+
const targets = {};
|
|
1677
|
+
let unbindables = null;
|
|
1678
|
+
let isConnected = false;
|
|
1679
|
+
return {
|
|
1680
|
+
source,
|
|
1681
|
+
context: ExecutionContext.default,
|
|
1682
|
+
targets,
|
|
1683
|
+
get isBound() {
|
|
1684
|
+
return isConnected;
|
|
1685
|
+
},
|
|
1686
|
+
addBehaviorFactory(factory, target) {
|
|
1687
|
+
const nodeId = factory.nodeId || (factory.nodeId = nextId());
|
|
1688
|
+
factory.id || (factory.id = nextId());
|
|
1689
|
+
this.addTarget(nodeId, target);
|
|
1690
|
+
this.addBehavior(factory.createBehavior());
|
|
1691
|
+
},
|
|
1692
|
+
addTarget(nodeId, target) {
|
|
1693
|
+
targets[nodeId] = target;
|
|
1694
|
+
},
|
|
1695
|
+
addBehavior(behavior) {
|
|
1696
|
+
behaviors.push(behavior);
|
|
1697
|
+
if (isConnected) {
|
|
1698
|
+
behavior.bind(this);
|
|
1699
|
+
}
|
|
1700
|
+
},
|
|
1701
|
+
onUnbind(unbindable) {
|
|
1702
|
+
if (unbindables === null) {
|
|
1703
|
+
unbindables = [];
|
|
1704
|
+
}
|
|
1705
|
+
unbindables.push(unbindable);
|
|
1706
|
+
},
|
|
1707
|
+
connectedCallback(controller) {
|
|
1708
|
+
if (!isConnected) {
|
|
1709
|
+
isConnected = true;
|
|
1710
|
+
behaviors.forEach(x => x.bind(this));
|
|
1711
|
+
}
|
|
1712
|
+
},
|
|
1713
|
+
disconnectedCallback(controller) {
|
|
1714
|
+
if (isConnected) {
|
|
1715
|
+
isConnected = false;
|
|
1716
|
+
if (unbindables !== null) {
|
|
1717
|
+
unbindables.forEach(x => x.unbind(this));
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
},
|
|
1721
|
+
};
|
|
1722
|
+
},
|
|
1723
|
+
});
|
|
1384
1724
|
const registry = createTypeRegistry();
|
|
1385
1725
|
/**
|
|
1386
1726
|
* Instructs the template engine to apply behavior to a node.
|
|
@@ -1420,6 +1760,22 @@ function htmlDirective(options) {
|
|
|
1420
1760
|
HTMLDirective.define(type, options);
|
|
1421
1761
|
};
|
|
1422
1762
|
}
|
|
1763
|
+
/**
|
|
1764
|
+
* Captures a binding expression along with related information and capabilities.
|
|
1765
|
+
*
|
|
1766
|
+
* @public
|
|
1767
|
+
*/
|
|
1768
|
+
class Binding {
|
|
1769
|
+
/**
|
|
1770
|
+
* Creates a binding.
|
|
1771
|
+
* @param evaluate - Evaluates the binding.
|
|
1772
|
+
* @param isVolatile - Indicates whether the binding is volatile.
|
|
1773
|
+
*/
|
|
1774
|
+
constructor(evaluate, isVolatile = false) {
|
|
1775
|
+
this.evaluate = evaluate;
|
|
1776
|
+
this.isVolatile = isVolatile;
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1423
1779
|
/**
|
|
1424
1780
|
* The type of HTML aspect to target.
|
|
1425
1781
|
* @public
|
|
@@ -1457,26 +1813,22 @@ const Aspect = Object.freeze({
|
|
|
1457
1813
|
*
|
|
1458
1814
|
* @param directive - The directive to assign the aspect to.
|
|
1459
1815
|
* @param value - The value to base the aspect determination on.
|
|
1816
|
+
* @remarks
|
|
1817
|
+
* If a falsy value is provided, then the content aspect will be assigned.
|
|
1460
1818
|
*/
|
|
1461
1819
|
assign(directive, value) {
|
|
1462
|
-
directive.sourceAspect = value;
|
|
1463
1820
|
if (!value) {
|
|
1821
|
+
directive.aspectType = Aspect.content;
|
|
1464
1822
|
return;
|
|
1465
1823
|
}
|
|
1824
|
+
directive.sourceAspect = value;
|
|
1466
1825
|
switch (value[0]) {
|
|
1467
1826
|
case ":":
|
|
1468
1827
|
directive.targetAspect = value.substring(1);
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
case "classList":
|
|
1474
|
-
directive.aspectType = Aspect.tokenList;
|
|
1475
|
-
break;
|
|
1476
|
-
default:
|
|
1477
|
-
directive.aspectType = Aspect.property;
|
|
1478
|
-
break;
|
|
1479
|
-
}
|
|
1828
|
+
directive.aspectType =
|
|
1829
|
+
directive.targetAspect === "classList"
|
|
1830
|
+
? Aspect.tokenList
|
|
1831
|
+
: Aspect.property;
|
|
1480
1832
|
break;
|
|
1481
1833
|
case "?":
|
|
1482
1834
|
directive.targetAspect = value.substring(1);
|
|
@@ -1487,14 +1839,8 @@ const Aspect = Object.freeze({
|
|
|
1487
1839
|
directive.aspectType = Aspect.event;
|
|
1488
1840
|
break;
|
|
1489
1841
|
default:
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
directive.aspectType = Aspect.property;
|
|
1493
|
-
}
|
|
1494
|
-
else {
|
|
1495
|
-
directive.targetAspect = value;
|
|
1496
|
-
directive.aspectType = Aspect.attribute;
|
|
1497
|
-
}
|
|
1842
|
+
directive.targetAspect = value;
|
|
1843
|
+
directive.aspectType = Aspect.attribute;
|
|
1498
1844
|
break;
|
|
1499
1845
|
}
|
|
1500
1846
|
},
|
|
@@ -1510,13 +1856,10 @@ class StatelessAttachedAttributeDirective {
|
|
|
1510
1856
|
*/
|
|
1511
1857
|
constructor(options) {
|
|
1512
1858
|
this.options = options;
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
*/
|
|
1518
|
-
createBehavior(targets) {
|
|
1519
|
-
return this;
|
|
1859
|
+
/**
|
|
1860
|
+
* The unique id of the factory.
|
|
1861
|
+
*/
|
|
1862
|
+
this.id = nextId();
|
|
1520
1863
|
}
|
|
1521
1864
|
/**
|
|
1522
1865
|
* Creates a placeholder string based on the directive's index within the template.
|
|
@@ -1527,8 +1870,15 @@ class StatelessAttachedAttributeDirective {
|
|
|
1527
1870
|
createHTML(add) {
|
|
1528
1871
|
return Markup.attribute(add(this));
|
|
1529
1872
|
}
|
|
1530
|
-
|
|
1531
|
-
|
|
1873
|
+
/**
|
|
1874
|
+
* Creates a behavior.
|
|
1875
|
+
* @param targets - The targets available for behaviors to be attached to.
|
|
1876
|
+
*/
|
|
1877
|
+
createBehavior() {
|
|
1878
|
+
return this;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1532
1882
|
const createInnerHTMLBinding = globalThis.TrustedHTML
|
|
1533
1883
|
? (binding) => (s, c) => {
|
|
1534
1884
|
const value = binding(s, c);
|
|
@@ -1538,107 +1888,26 @@ const createInnerHTMLBinding = globalThis.TrustedHTML
|
|
|
1538
1888
|
throw FAST.error(1202 /* Message.bindingInnerHTMLRequiresTrustedTypes */);
|
|
1539
1889
|
}
|
|
1540
1890
|
: (binding) => binding;
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
*/
|
|
1545
|
-
const BindingMode = Object.freeze({
|
|
1546
|
-
/**
|
|
1547
|
-
* Creates a binding mode based on the supplied behavior types.
|
|
1548
|
-
* @param UpdateType - The base behavior type used to update aspects.
|
|
1549
|
-
* @param EventType - The base behavior type used to respond to events.
|
|
1550
|
-
* @returns A new binding mode.
|
|
1551
|
-
*/
|
|
1552
|
-
define(UpdateType, EventType = EventBinding) {
|
|
1553
|
-
return Object.freeze({
|
|
1554
|
-
[1]: d => new UpdateType(d, DOM.setAttribute),
|
|
1555
|
-
[2]: d => new UpdateType(d, DOM.setBooleanAttribute),
|
|
1556
|
-
[3]: d => new UpdateType(d, (t, a, v) => (t[a] = v)),
|
|
1557
|
-
[4]: d => new (createContentBinding(UpdateType))(d, updateContentTarget),
|
|
1558
|
-
[5]: d => new UpdateType(d, updateTokenListTarget),
|
|
1559
|
-
[6]: d => new EventType(d),
|
|
1560
|
-
});
|
|
1561
|
-
},
|
|
1562
|
-
});
|
|
1563
|
-
/**
|
|
1564
|
-
* Describes the configuration for a binding expression.
|
|
1565
|
-
* @public
|
|
1566
|
-
*/
|
|
1567
|
-
const BindingConfig = Object.freeze({
|
|
1568
|
-
/**
|
|
1569
|
-
* Creates a binding configuration based on the provided mode and options.
|
|
1570
|
-
* @param mode - The mode to use for the configuration.
|
|
1571
|
-
* @param defaultOptions - The default options to use for the configuration.
|
|
1572
|
-
* @returns A new binding configuration.
|
|
1573
|
-
*/
|
|
1574
|
-
define(mode, defaultOptions) {
|
|
1575
|
-
const config = (options) => {
|
|
1576
|
-
return {
|
|
1577
|
-
mode: config.mode,
|
|
1578
|
-
options: Object.assign({}, defaultOptions, options),
|
|
1579
|
-
};
|
|
1580
|
-
};
|
|
1581
|
-
config.options = defaultOptions;
|
|
1582
|
-
config.mode = mode;
|
|
1583
|
-
return config;
|
|
1584
|
-
},
|
|
1585
|
-
});
|
|
1586
|
-
/**
|
|
1587
|
-
* A base binding behavior for DOM updates.
|
|
1588
|
-
* @public
|
|
1589
|
-
*/
|
|
1590
|
-
class UpdateBinding {
|
|
1591
|
-
/**
|
|
1592
|
-
* Creates an instance of UpdateBinding.
|
|
1593
|
-
* @param directive - The directive that has the configuration for this behavior.
|
|
1594
|
-
* @param updateTarget - The function used to update the target with the latest value.
|
|
1595
|
-
*/
|
|
1596
|
-
constructor(directive, updateTarget) {
|
|
1597
|
-
this.directive = directive;
|
|
1598
|
-
this.updateTarget = updateTarget;
|
|
1891
|
+
class OnChangeBinding extends Binding {
|
|
1892
|
+
createObserver(_, subscriber) {
|
|
1893
|
+
return Observable.binding(this.evaluate, subscriber, this.isVolatile);
|
|
1599
1894
|
}
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
* @param context - The execution context that the binding is operating within.
|
|
1604
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1605
|
-
*/
|
|
1606
|
-
bind(source, context, targets) { }
|
|
1607
|
-
/**
|
|
1608
|
-
* Unbinds this behavior from the source.
|
|
1609
|
-
* @param source - The source to unbind from.
|
|
1610
|
-
* @param context - The execution context that the binding is operating within.
|
|
1611
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1612
|
-
*/
|
|
1613
|
-
unbind(source, context, targets) { }
|
|
1614
|
-
/**
|
|
1615
|
-
* Creates a behavior.
|
|
1616
|
-
* @param targets - The targets available for behaviors to be attached to.
|
|
1617
|
-
*/
|
|
1618
|
-
createBehavior(targets) {
|
|
1895
|
+
}
|
|
1896
|
+
class OneTimeBinding extends Binding {
|
|
1897
|
+
createObserver() {
|
|
1619
1898
|
return this;
|
|
1620
1899
|
}
|
|
1900
|
+
bind(controller) {
|
|
1901
|
+
return this.evaluate(controller.source, controller.context);
|
|
1902
|
+
}
|
|
1621
1903
|
}
|
|
1622
|
-
function
|
|
1623
|
-
return class extends Type {
|
|
1624
|
-
unbind(source, context, targets) {
|
|
1625
|
-
super.unbind(source, context, targets);
|
|
1626
|
-
const target = targets[this.directive.nodeId];
|
|
1627
|
-
const view = target.$fastView;
|
|
1628
|
-
if (view !== void 0 && view.isComposed) {
|
|
1629
|
-
view.unbind();
|
|
1630
|
-
view.needsBindOnly = true;
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
};
|
|
1634
|
-
}
|
|
1635
|
-
function updateContentTarget(target, aspect, value, source, context) {
|
|
1904
|
+
function updateContent(target, aspect, value, controller) {
|
|
1636
1905
|
// If there's no actual value, then this equates to the
|
|
1637
1906
|
// empty string for the purposes of content bindings.
|
|
1638
1907
|
if (value === null || value === undefined) {
|
|
1639
1908
|
value = "";
|
|
1640
1909
|
}
|
|
1641
|
-
// If the value has a "create" method, then it's a
|
|
1910
|
+
// If the value has a "create" method, then it's a ContentTemplate.
|
|
1642
1911
|
if (value.create) {
|
|
1643
1912
|
target.textContent = "";
|
|
1644
1913
|
let view = target.$fastView;
|
|
@@ -1664,14 +1933,14 @@ function updateContentTarget(target, aspect, value, source, context) {
|
|
|
1664
1933
|
// and that there's actually no need to compose it.
|
|
1665
1934
|
if (!view.isComposed) {
|
|
1666
1935
|
view.isComposed = true;
|
|
1667
|
-
view.bind(source, context);
|
|
1936
|
+
view.bind(controller.source, controller.context);
|
|
1668
1937
|
view.insertBefore(target);
|
|
1669
1938
|
target.$fastView = view;
|
|
1670
1939
|
target.$fastTemplate = value;
|
|
1671
1940
|
}
|
|
1672
1941
|
else if (view.needsBindOnly) {
|
|
1673
1942
|
view.needsBindOnly = false;
|
|
1674
|
-
view.bind(source, context);
|
|
1943
|
+
view.bind(controller.source, controller.context);
|
|
1675
1944
|
}
|
|
1676
1945
|
}
|
|
1677
1946
|
else {
|
|
@@ -1691,10 +1960,9 @@ function updateContentTarget(target, aspect, value, source, context) {
|
|
|
1691
1960
|
target.textContent = value;
|
|
1692
1961
|
}
|
|
1693
1962
|
}
|
|
1694
|
-
function
|
|
1963
|
+
function updateTokenList(target, aspect, value) {
|
|
1695
1964
|
var _a;
|
|
1696
|
-
const
|
|
1697
|
-
const lookup = `${directive.id}-t`;
|
|
1965
|
+
const lookup = `${this.id}-t`;
|
|
1698
1966
|
const state = (_a = target[lookup]) !== null && _a !== void 0 ? _a : (target[lookup] = { c: 0, v: Object.create(null) });
|
|
1699
1967
|
const versions = state.v;
|
|
1700
1968
|
let currentVersion = state.c;
|
|
@@ -1724,366 +1992,168 @@ function updateTokenListTarget(target, aspect, value) {
|
|
|
1724
1992
|
}
|
|
1725
1993
|
}
|
|
1726
1994
|
}
|
|
1995
|
+
const setProperty = (t, a, v) => (t[a] = v);
|
|
1996
|
+
const eventTarget = () => void 0;
|
|
1727
1997
|
/**
|
|
1728
|
-
* A
|
|
1998
|
+
* A directive that applies bindings.
|
|
1729
1999
|
* @public
|
|
1730
2000
|
*/
|
|
1731
|
-
class
|
|
2001
|
+
class HTMLBindingDirective {
|
|
1732
2002
|
/**
|
|
1733
|
-
*
|
|
1734
|
-
* @param
|
|
1735
|
-
* @param context - The execution context that the binding is operating within.
|
|
1736
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
2003
|
+
* Creates an instance of HTMLBindingDirective.
|
|
2004
|
+
* @param dataBinding - The binding configuration to apply.
|
|
1737
2005
|
*/
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
this.updateTarget
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
this.
|
|
2006
|
+
constructor(dataBinding) {
|
|
2007
|
+
this.dataBinding = dataBinding;
|
|
2008
|
+
this.updateTarget = null;
|
|
2009
|
+
/**
|
|
2010
|
+
* The unique id of the factory.
|
|
2011
|
+
*/
|
|
2012
|
+
this.id = nextId();
|
|
2013
|
+
/**
|
|
2014
|
+
* The type of aspect to target.
|
|
2015
|
+
*/
|
|
2016
|
+
this.aspectType = Aspect.content;
|
|
2017
|
+
/** @internal */
|
|
2018
|
+
this.bind = this.bindDefault;
|
|
2019
|
+
this.data = `${this.id}-d`;
|
|
1752
2020
|
}
|
|
1753
2021
|
/**
|
|
1754
|
-
*
|
|
1755
|
-
* @param
|
|
1756
|
-
* @param context - The execution context that the binding is operating within.
|
|
1757
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
2022
|
+
* Creates HTML to be used within a template.
|
|
2023
|
+
* @param add - Can be used to add behavior factories to a template.
|
|
1758
2024
|
*/
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
const target = targets[directive.nodeId];
|
|
1762
|
-
const signal = this.getSignal(source, context);
|
|
1763
|
-
const handler = (target[this.handlerProperty] = () => {
|
|
1764
|
-
this.updateTarget(target, directive.targetAspect, directive.binding(source, context), source, context);
|
|
1765
|
-
});
|
|
1766
|
-
handler();
|
|
1767
|
-
const found = signals[signal];
|
|
1768
|
-
if (found) {
|
|
1769
|
-
Array.isArray(found)
|
|
1770
|
-
? found.push(handler)
|
|
1771
|
-
: (signals[signal] = [found, handler]);
|
|
1772
|
-
}
|
|
1773
|
-
else {
|
|
1774
|
-
signals[signal] = handler;
|
|
1775
|
-
}
|
|
2025
|
+
createHTML(add) {
|
|
2026
|
+
return Markup.interpolation(add(this));
|
|
1776
2027
|
}
|
|
1777
2028
|
/**
|
|
1778
|
-
*
|
|
1779
|
-
* @param source - The source to unbind from.
|
|
1780
|
-
* @param context - The execution context that the binding is operating within.
|
|
1781
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
2029
|
+
* Creates a behavior.
|
|
1782
2030
|
*/
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
2031
|
+
createBehavior() {
|
|
2032
|
+
if (this.updateTarget === null) {
|
|
2033
|
+
if (this.targetAspect === "innerHTML") {
|
|
2034
|
+
this.dataBinding.evaluate = createInnerHTMLBinding(this.dataBinding.evaluate);
|
|
2035
|
+
}
|
|
2036
|
+
switch (this.aspectType) {
|
|
2037
|
+
case 1:
|
|
2038
|
+
this.updateTarget = DOM.setAttribute;
|
|
2039
|
+
break;
|
|
2040
|
+
case 2:
|
|
2041
|
+
this.updateTarget = DOM.setBooleanAttribute;
|
|
2042
|
+
break;
|
|
2043
|
+
case 3:
|
|
2044
|
+
this.updateTarget = setProperty;
|
|
2045
|
+
break;
|
|
2046
|
+
case 4:
|
|
2047
|
+
this.bind = this.bindContent;
|
|
2048
|
+
this.updateTarget = updateContent;
|
|
2049
|
+
break;
|
|
2050
|
+
case 5:
|
|
2051
|
+
this.updateTarget = updateTokenList;
|
|
2052
|
+
break;
|
|
2053
|
+
case 6:
|
|
2054
|
+
this.bind = this.bindEvent;
|
|
2055
|
+
this.updateTarget = eventTarget;
|
|
2056
|
+
break;
|
|
2057
|
+
default:
|
|
2058
|
+
throw FAST.error(1205 /* Message.unsupportedBindingBehavior */);
|
|
1793
2059
|
}
|
|
1794
2060
|
}
|
|
1795
|
-
|
|
1796
|
-
signals[signal] = void 0;
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
getSignal(source, context) {
|
|
1800
|
-
const options = this.directive.options;
|
|
1801
|
-
return isString(options) ? options : options(source, context);
|
|
1802
|
-
}
|
|
1803
|
-
/**
|
|
1804
|
-
* Sends the specified signal to signaled bindings.
|
|
1805
|
-
* @param signal - The signal to send.
|
|
1806
|
-
* @public
|
|
1807
|
-
*/
|
|
1808
|
-
static send(signal) {
|
|
1809
|
-
const found = signals[signal];
|
|
1810
|
-
if (found) {
|
|
1811
|
-
Array.isArray(found) ? found.forEach(x => x()) : found();
|
|
1812
|
-
}
|
|
1813
|
-
}
|
|
1814
|
-
}
|
|
1815
|
-
/**
|
|
1816
|
-
* A binding behavior for bindings that change.
|
|
1817
|
-
* @public
|
|
1818
|
-
*/
|
|
1819
|
-
class ChangeBinding extends UpdateBinding {
|
|
1820
|
-
/**
|
|
1821
|
-
* Creates an instance of ChangeBinding.
|
|
1822
|
-
* @param directive - The directive that has the configuration for this behavior.
|
|
1823
|
-
* @param updateTarget - The function used to update the target with the latest value.
|
|
1824
|
-
*/
|
|
1825
|
-
constructor(directive, updateTarget) {
|
|
1826
|
-
super(directive, updateTarget);
|
|
1827
|
-
this.isBindingVolatile = Observable.isVolatileBinding(directive.binding);
|
|
1828
|
-
this.observerProperty = `${directive.id}-o`;
|
|
2061
|
+
return this;
|
|
1829
2062
|
}
|
|
1830
|
-
/**
|
|
1831
|
-
|
|
1832
|
-
* @param target - The target node.
|
|
1833
|
-
* @returns A BindingObserver.
|
|
1834
|
-
*/
|
|
1835
|
-
getObserver(target) {
|
|
2063
|
+
/** @internal */
|
|
2064
|
+
bindDefault(controller) {
|
|
1836
2065
|
var _a;
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
/**
|
|
1840
|
-
* Bind this behavior to the source.
|
|
1841
|
-
* @param source - The source to bind to.
|
|
1842
|
-
* @param context - The execution context that the binding is operating within.
|
|
1843
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1844
|
-
*/
|
|
1845
|
-
bind(source, context, targets) {
|
|
1846
|
-
const directive = this.directive;
|
|
1847
|
-
const target = targets[directive.nodeId];
|
|
1848
|
-
const observer = this.getObserver(target);
|
|
2066
|
+
const target = controller.targets[this.nodeId];
|
|
2067
|
+
const observer = (_a = target[this.data]) !== null && _a !== void 0 ? _a : (target[this.data] = this.dataBinding.createObserver(this, this));
|
|
1849
2068
|
observer.target = target;
|
|
1850
|
-
observer.
|
|
1851
|
-
observer.
|
|
1852
|
-
this.updateTarget
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
* Unbinds this behavior from the source.
|
|
1856
|
-
* @param source - The source to unbind from.
|
|
1857
|
-
* @param context - The execution context that the binding is operating within.
|
|
1858
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1859
|
-
*/
|
|
1860
|
-
unbind(source, context, targets) {
|
|
1861
|
-
const target = targets[this.directive.nodeId];
|
|
1862
|
-
const observer = this.getObserver(target);
|
|
1863
|
-
observer.dispose();
|
|
1864
|
-
observer.target = null;
|
|
1865
|
-
observer.source = null;
|
|
1866
|
-
observer.context = null;
|
|
2069
|
+
observer.controller = controller;
|
|
2070
|
+
this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
|
|
2071
|
+
if (this.updateTarget === updateContent) {
|
|
2072
|
+
controller.onUnbind(this);
|
|
2073
|
+
}
|
|
1867
2074
|
}
|
|
1868
2075
|
/** @internal */
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
const context = observer.context;
|
|
1873
|
-
this.updateTarget(target, this.directive.targetAspect, observer.observe(source, context), source, context);
|
|
1874
|
-
}
|
|
1875
|
-
}
|
|
1876
|
-
/**
|
|
1877
|
-
* A binding behavior for handling events.
|
|
1878
|
-
* @public
|
|
1879
|
-
*/
|
|
1880
|
-
class EventBinding {
|
|
1881
|
-
/**
|
|
1882
|
-
* Creates an instance of EventBinding.
|
|
1883
|
-
* @param directive - The directive that has the configuration for this behavior.
|
|
1884
|
-
*/
|
|
1885
|
-
constructor(directive) {
|
|
1886
|
-
this.directive = directive;
|
|
1887
|
-
this.sourceProperty = `${directive.id}-s`;
|
|
1888
|
-
this.contextProperty = `${directive.id}-c`;
|
|
2076
|
+
bindContent(controller) {
|
|
2077
|
+
this.bindDefault(controller);
|
|
2078
|
+
controller.onUnbind(this);
|
|
1889
2079
|
}
|
|
1890
|
-
/**
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
*/
|
|
1896
|
-
bind(source, context, targets) {
|
|
1897
|
-
const directive = this.directive;
|
|
1898
|
-
const target = targets[directive.nodeId];
|
|
1899
|
-
target[this.sourceProperty] = source;
|
|
1900
|
-
target[this.contextProperty] = context;
|
|
1901
|
-
target.addEventListener(directive.targetAspect, this, directive.options);
|
|
1902
|
-
}
|
|
1903
|
-
/**
|
|
1904
|
-
* Unbinds this behavior from the source.
|
|
1905
|
-
* @param source - The source to unbind from.
|
|
1906
|
-
* @param context - The execution context that the binding is operating within.
|
|
1907
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1908
|
-
*/
|
|
1909
|
-
unbind(source, context, targets) {
|
|
1910
|
-
const directive = this.directive;
|
|
1911
|
-
const target = targets[directive.nodeId];
|
|
1912
|
-
target[this.sourceProperty] = target[this.contextProperty] = null;
|
|
1913
|
-
target.removeEventListener(directive.targetAspect, this, directive.options);
|
|
2080
|
+
/** @internal */
|
|
2081
|
+
bindEvent(controller) {
|
|
2082
|
+
const target = controller.targets[this.nodeId];
|
|
2083
|
+
target[this.data] = controller;
|
|
2084
|
+
target.addEventListener(this.targetAspect, this, this.dataBinding.options);
|
|
1914
2085
|
}
|
|
1915
|
-
/**
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
2086
|
+
/** @internal */
|
|
2087
|
+
unbind(controller) {
|
|
2088
|
+
const target = controller.targets[this.nodeId];
|
|
2089
|
+
const view = target.$fastView;
|
|
2090
|
+
if (view !== void 0 && view.isComposed) {
|
|
2091
|
+
view.unbind();
|
|
2092
|
+
view.needsBindOnly = true;
|
|
2093
|
+
}
|
|
1921
2094
|
}
|
|
1922
|
-
/**
|
|
1923
|
-
* @internal
|
|
1924
|
-
*/
|
|
2095
|
+
/** @internal */
|
|
1925
2096
|
handleEvent(event) {
|
|
1926
2097
|
const target = event.currentTarget;
|
|
1927
2098
|
ExecutionContext.setEvent(event);
|
|
1928
|
-
const
|
|
2099
|
+
const controller = target[this.data];
|
|
2100
|
+
const result = this.dataBinding.evaluate(controller.source, controller.context);
|
|
1929
2101
|
ExecutionContext.setEvent(null);
|
|
1930
2102
|
if (result !== true) {
|
|
1931
2103
|
event.preventDefault();
|
|
1932
2104
|
}
|
|
1933
2105
|
}
|
|
1934
|
-
}
|
|
1935
|
-
let twoWaySettings = {
|
|
1936
|
-
determineChangeEvent() {
|
|
1937
|
-
return "change";
|
|
1938
|
-
},
|
|
1939
|
-
};
|
|
1940
|
-
/**
|
|
1941
|
-
* A binding behavior for bindings that update in two directions.
|
|
1942
|
-
* @public
|
|
1943
|
-
*/
|
|
1944
|
-
class TwoWayBinding extends ChangeBinding {
|
|
1945
|
-
/**
|
|
1946
|
-
* Bind this behavior to the source.
|
|
1947
|
-
* @param source - The source to bind to.
|
|
1948
|
-
* @param context - The execution context that the binding is operating within.
|
|
1949
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1950
|
-
*/
|
|
1951
|
-
bind(source, context, targets) {
|
|
1952
|
-
var _a;
|
|
1953
|
-
super.bind(source, context, targets);
|
|
1954
|
-
const directive = this.directive;
|
|
1955
|
-
const target = targets[directive.nodeId];
|
|
1956
|
-
if (!this.changeEvent) {
|
|
1957
|
-
this.changeEvent =
|
|
1958
|
-
(_a = directive.options.changeEvent) !== null && _a !== void 0 ? _a : twoWaySettings.determineChangeEvent(directive, target);
|
|
1959
|
-
}
|
|
1960
|
-
target.addEventListener(this.changeEvent, this);
|
|
1961
|
-
}
|
|
1962
|
-
/**
|
|
1963
|
-
* Unbinds this behavior from the source.
|
|
1964
|
-
* @param source - The source to unbind from.
|
|
1965
|
-
* @param context - The execution context that the binding is operating within.
|
|
1966
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1967
|
-
*/
|
|
1968
|
-
unbind(source, context, targets) {
|
|
1969
|
-
super.unbind(source, context, targets);
|
|
1970
|
-
targets[this.directive.nodeId].removeEventListener(this.changeEvent, this);
|
|
1971
|
-
}
|
|
1972
2106
|
/** @internal */
|
|
1973
|
-
|
|
1974
|
-
const
|
|
1975
|
-
const
|
|
1976
|
-
|
|
1977
|
-
switch (directive.aspectType) {
|
|
1978
|
-
case 1:
|
|
1979
|
-
value = target.getAttribute(directive.targetAspect);
|
|
1980
|
-
break;
|
|
1981
|
-
case 2:
|
|
1982
|
-
value = target.hasAttribute(directive.targetAspect);
|
|
1983
|
-
break;
|
|
1984
|
-
case 4:
|
|
1985
|
-
value = target.innerText;
|
|
1986
|
-
break;
|
|
1987
|
-
default:
|
|
1988
|
-
value = target[directive.targetAspect];
|
|
1989
|
-
break;
|
|
1990
|
-
}
|
|
1991
|
-
const observer = this.getObserver(target);
|
|
1992
|
-
const last = observer.last; // using internal API!!!
|
|
1993
|
-
last.propertySource[last.propertyName] = directive.options.fromView(value);
|
|
1994
|
-
}
|
|
1995
|
-
/**
|
|
1996
|
-
* Configures two-way binding.
|
|
1997
|
-
* @param settings - The settings to use for the two-way binding system.
|
|
1998
|
-
*/
|
|
1999
|
-
static configure(settings) {
|
|
2000
|
-
twoWaySettings = settings;
|
|
2107
|
+
handleChange(binding, observer) {
|
|
2108
|
+
const target = observer.target;
|
|
2109
|
+
const controller = observer.controller;
|
|
2110
|
+
this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
|
|
2001
2111
|
}
|
|
2002
2112
|
}
|
|
2113
|
+
HTMLDirective.define(HTMLBindingDirective, { aspected: true });
|
|
2003
2114
|
/**
|
|
2004
|
-
*
|
|
2005
|
-
* @
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
/**
|
|
2009
|
-
* The default twoWay binding configuration.
|
|
2010
|
-
* @public
|
|
2011
|
-
*/
|
|
2012
|
-
const twoWay = BindingConfig.define(BindingMode.define(TwoWayBinding), {
|
|
2013
|
-
fromView: v => v,
|
|
2014
|
-
});
|
|
2015
|
-
/**
|
|
2016
|
-
* The default onTime binding configuration.
|
|
2115
|
+
* Creates an standard binding.
|
|
2116
|
+
* @param binding - The binding to refresh when changed.
|
|
2117
|
+
* @param isVolatile - Indicates whether the binding is volatile or not.
|
|
2118
|
+
* @returns A binding configuration.
|
|
2017
2119
|
* @public
|
|
2018
2120
|
*/
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
}
|
|
2022
|
-
const signalMode = BindingMode.define(SignalBinding);
|
|
2121
|
+
function bind(binding, isVolatile = Observable.isVolatileBinding(binding)) {
|
|
2122
|
+
return new OnChangeBinding(binding, isVolatile);
|
|
2123
|
+
}
|
|
2023
2124
|
/**
|
|
2024
|
-
* Creates a
|
|
2025
|
-
* @param
|
|
2125
|
+
* Creates a one time binding
|
|
2126
|
+
* @param binding - The binding to refresh when signaled.
|
|
2026
2127
|
* @returns A binding configuration.
|
|
2027
2128
|
* @public
|
|
2028
2129
|
*/
|
|
2029
|
-
|
|
2030
|
-
return
|
|
2031
|
-
}
|
|
2130
|
+
function oneTime(binding) {
|
|
2131
|
+
return new OneTimeBinding(binding);
|
|
2132
|
+
}
|
|
2032
2133
|
/**
|
|
2033
|
-
*
|
|
2134
|
+
* Creates an event listener binding.
|
|
2135
|
+
* @param binding - The binding to invoke when the event is raised.
|
|
2136
|
+
* @param options - Event listener options.
|
|
2137
|
+
* @returns A binding configuration.
|
|
2034
2138
|
* @public
|
|
2035
2139
|
*/
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
* @param mode - The binding mode to use when applying the binding.
|
|
2041
|
-
* @param options - The options to configure the binding with.
|
|
2042
|
-
*/
|
|
2043
|
-
constructor(binding, mode, options) {
|
|
2044
|
-
this.binding = binding;
|
|
2045
|
-
this.mode = mode;
|
|
2046
|
-
this.options = options;
|
|
2047
|
-
this.factory = null;
|
|
2048
|
-
/**
|
|
2049
|
-
* The type of aspect to target.
|
|
2050
|
-
*/
|
|
2051
|
-
this.aspectType = Aspect.content;
|
|
2052
|
-
}
|
|
2053
|
-
/**
|
|
2054
|
-
* Creates HTML to be used within a template.
|
|
2055
|
-
* @param add - Can be used to add behavior factories to a template.
|
|
2056
|
-
*/
|
|
2057
|
-
createHTML(add) {
|
|
2058
|
-
return Markup.interpolation(add(this));
|
|
2059
|
-
}
|
|
2060
|
-
/**
|
|
2061
|
-
* Creates a behavior.
|
|
2062
|
-
* @param targets - The targets available for behaviors to be attached to.
|
|
2063
|
-
*/
|
|
2064
|
-
createBehavior(targets) {
|
|
2065
|
-
if (this.factory == null) {
|
|
2066
|
-
if (this.targetAspect === "innerHTML") {
|
|
2067
|
-
this.binding = createInnerHTMLBinding(this.binding);
|
|
2068
|
-
}
|
|
2069
|
-
this.factory = this.mode[this.aspectType](this);
|
|
2070
|
-
}
|
|
2071
|
-
return this.factory.createBehavior(targets);
|
|
2072
|
-
}
|
|
2140
|
+
function listener(binding, options) {
|
|
2141
|
+
const config = new OnChangeBinding(binding, false);
|
|
2142
|
+
config.options = options;
|
|
2143
|
+
return config;
|
|
2073
2144
|
}
|
|
2074
|
-
HTMLDirective.define(HTMLBindingDirective, { aspected: true });
|
|
2075
2145
|
/**
|
|
2076
|
-
*
|
|
2077
|
-
* @param
|
|
2078
|
-
* @
|
|
2079
|
-
* @returns A binding directive.
|
|
2146
|
+
* Normalizes the input value into a binding.
|
|
2147
|
+
* @param value - The value to create the default binding for.
|
|
2148
|
+
* @returns A binding configuration for the provided value.
|
|
2080
2149
|
* @public
|
|
2081
2150
|
*/
|
|
2082
|
-
function
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2151
|
+
function normalizeBinding(value) {
|
|
2152
|
+
return isFunction(value)
|
|
2153
|
+
? bind(value)
|
|
2154
|
+
: value instanceof Binding
|
|
2155
|
+
? value
|
|
2156
|
+
: oneTime(() => value);
|
|
2087
2157
|
}
|
|
2088
2158
|
|
|
2089
2159
|
function removeNodeSequence(firstNode, lastNode) {
|
|
@@ -2107,21 +2177,91 @@ class HTMLView {
|
|
|
2107
2177
|
* @param fragment - The html fragment that contains the nodes for this view.
|
|
2108
2178
|
* @param behaviors - The behaviors to be applied to this view.
|
|
2109
2179
|
*/
|
|
2110
|
-
constructor(fragment, factories, targets) {
|
|
2111
|
-
this.fragment = fragment;
|
|
2112
|
-
this.factories = factories;
|
|
2113
|
-
this.targets = targets;
|
|
2114
|
-
this.behaviors = null;
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
this.
|
|
2124
|
-
|
|
2180
|
+
constructor(fragment, factories, targets) {
|
|
2181
|
+
this.fragment = fragment;
|
|
2182
|
+
this.factories = factories;
|
|
2183
|
+
this.targets = targets;
|
|
2184
|
+
this.behaviors = null;
|
|
2185
|
+
this.unbindables = [];
|
|
2186
|
+
/**
|
|
2187
|
+
* The data that the view is bound to.
|
|
2188
|
+
*/
|
|
2189
|
+
this.source = null;
|
|
2190
|
+
/**
|
|
2191
|
+
* Indicates whether the controller is bound.
|
|
2192
|
+
*/
|
|
2193
|
+
this.isBound = false;
|
|
2194
|
+
/**
|
|
2195
|
+
* Indicates how the source's lifetime relates to the controller's lifetime.
|
|
2196
|
+
*/
|
|
2197
|
+
this.sourceLifetime = SourceLifetime.unknown;
|
|
2198
|
+
/**
|
|
2199
|
+
* The execution context the view is running within.
|
|
2200
|
+
*/
|
|
2201
|
+
this.context = this;
|
|
2202
|
+
/**
|
|
2203
|
+
* The index of the current item within a repeat context.
|
|
2204
|
+
*/
|
|
2205
|
+
this.index = 0;
|
|
2206
|
+
/**
|
|
2207
|
+
* The length of the current collection within a repeat context.
|
|
2208
|
+
*/
|
|
2209
|
+
this.length = 0;
|
|
2210
|
+
this.firstChild = fragment.firstChild;
|
|
2211
|
+
this.lastChild = fragment.lastChild;
|
|
2212
|
+
}
|
|
2213
|
+
/**
|
|
2214
|
+
* The current event within an event handler.
|
|
2215
|
+
*/
|
|
2216
|
+
get event() {
|
|
2217
|
+
return ExecutionContext.getEvent();
|
|
2218
|
+
}
|
|
2219
|
+
/**
|
|
2220
|
+
* Indicates whether the current item within a repeat context
|
|
2221
|
+
* has an even index.
|
|
2222
|
+
*/
|
|
2223
|
+
get isEven() {
|
|
2224
|
+
return this.index % 2 === 0;
|
|
2225
|
+
}
|
|
2226
|
+
/**
|
|
2227
|
+
* Indicates whether the current item within a repeat context
|
|
2228
|
+
* has an odd index.
|
|
2229
|
+
*/
|
|
2230
|
+
get isOdd() {
|
|
2231
|
+
return this.index % 2 !== 0;
|
|
2232
|
+
}
|
|
2233
|
+
/**
|
|
2234
|
+
* Indicates whether the current item within a repeat context
|
|
2235
|
+
* is the first item in the collection.
|
|
2236
|
+
*/
|
|
2237
|
+
get isFirst() {
|
|
2238
|
+
return this.index === 0;
|
|
2239
|
+
}
|
|
2240
|
+
/**
|
|
2241
|
+
* Indicates whether the current item within a repeat context
|
|
2242
|
+
* is somewhere in the middle of the collection.
|
|
2243
|
+
*/
|
|
2244
|
+
get isInMiddle() {
|
|
2245
|
+
return !this.isFirst && !this.isLast;
|
|
2246
|
+
}
|
|
2247
|
+
/**
|
|
2248
|
+
* Indicates whether the current item within a repeat context
|
|
2249
|
+
* is the last item in the collection.
|
|
2250
|
+
*/
|
|
2251
|
+
get isLast() {
|
|
2252
|
+
return this.index === this.length - 1;
|
|
2253
|
+
}
|
|
2254
|
+
/**
|
|
2255
|
+
* Returns the typed event detail of a custom event.
|
|
2256
|
+
*/
|
|
2257
|
+
eventDetail() {
|
|
2258
|
+
return this.event.detail;
|
|
2259
|
+
}
|
|
2260
|
+
/**
|
|
2261
|
+
* Returns the typed event target of the event.
|
|
2262
|
+
*/
|
|
2263
|
+
eventTarget() {
|
|
2264
|
+
return this.event.target;
|
|
2125
2265
|
}
|
|
2126
2266
|
/**
|
|
2127
2267
|
* Appends the view's DOM nodes to the referenced node.
|
|
@@ -2139,8 +2279,10 @@ class HTMLView {
|
|
|
2139
2279
|
node.parentNode.insertBefore(this.fragment, node);
|
|
2140
2280
|
}
|
|
2141
2281
|
else {
|
|
2142
|
-
const parentNode = node.parentNode;
|
|
2143
2282
|
const end = this.lastChild;
|
|
2283
|
+
if (node.previousSibling === end)
|
|
2284
|
+
return;
|
|
2285
|
+
const parentNode = node.parentNode;
|
|
2144
2286
|
let current = this.firstChild;
|
|
2145
2287
|
let next;
|
|
2146
2288
|
while (current !== end) {
|
|
@@ -2175,58 +2317,61 @@ class HTMLView {
|
|
|
2175
2317
|
removeNodeSequence(this.firstChild, this.lastChild);
|
|
2176
2318
|
this.unbind();
|
|
2177
2319
|
}
|
|
2320
|
+
onUnbind(behavior) {
|
|
2321
|
+
this.unbindables.push(behavior);
|
|
2322
|
+
}
|
|
2178
2323
|
/**
|
|
2179
2324
|
* Binds a view's behaviors to its binding source.
|
|
2180
2325
|
* @param source - The binding source for the view's binding behaviors.
|
|
2181
2326
|
* @param context - The execution context to run the behaviors within.
|
|
2182
2327
|
*/
|
|
2183
|
-
bind(source, context) {
|
|
2184
|
-
|
|
2185
|
-
const oldSource = this.source;
|
|
2186
|
-
if (oldSource === source) {
|
|
2328
|
+
bind(source, context = this) {
|
|
2329
|
+
if (this.source === source) {
|
|
2187
2330
|
return;
|
|
2188
2331
|
}
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
2194
|
-
const current = behaviors[i];
|
|
2195
|
-
current.unbind(oldSource, context, targets);
|
|
2196
|
-
current.bind(source, context, targets);
|
|
2197
|
-
}
|
|
2198
|
-
}
|
|
2199
|
-
else if (behaviors === null) {
|
|
2332
|
+
let behaviors = this.behaviors;
|
|
2333
|
+
if (behaviors === null) {
|
|
2334
|
+
this.source = source;
|
|
2335
|
+
this.context = context;
|
|
2200
2336
|
this.behaviors = behaviors = new Array(this.factories.length);
|
|
2201
2337
|
const factories = this.factories;
|
|
2202
2338
|
for (let i = 0, ii = factories.length; i < ii; ++i) {
|
|
2203
|
-
const behavior = factories[i].createBehavior(
|
|
2204
|
-
behavior.bind(
|
|
2339
|
+
const behavior = factories[i].createBehavior();
|
|
2340
|
+
behavior.bind(this);
|
|
2205
2341
|
behaviors[i] = behavior;
|
|
2206
2342
|
}
|
|
2207
2343
|
}
|
|
2208
2344
|
else {
|
|
2345
|
+
if (this.source !== null) {
|
|
2346
|
+
this.evaluateUnbindables();
|
|
2347
|
+
}
|
|
2348
|
+
this.isBound = false;
|
|
2349
|
+
this.source = source;
|
|
2350
|
+
this.context = context;
|
|
2209
2351
|
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
2210
|
-
behaviors[i].bind(
|
|
2352
|
+
behaviors[i].bind(this);
|
|
2211
2353
|
}
|
|
2212
2354
|
}
|
|
2355
|
+
this.isBound = true;
|
|
2213
2356
|
}
|
|
2214
2357
|
/**
|
|
2215
2358
|
* Unbinds a view's behaviors from its binding source.
|
|
2216
2359
|
*/
|
|
2217
2360
|
unbind() {
|
|
2218
|
-
|
|
2219
|
-
if (oldSource === null) {
|
|
2361
|
+
if (!this.isBound || this.source === null) {
|
|
2220
2362
|
return;
|
|
2221
2363
|
}
|
|
2222
|
-
|
|
2223
|
-
const context = this.context;
|
|
2224
|
-
const behaviors = this.behaviors;
|
|
2225
|
-
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
2226
|
-
behaviors[i].unbind(oldSource, context, targets);
|
|
2227
|
-
}
|
|
2364
|
+
this.evaluateUnbindables();
|
|
2228
2365
|
this.source = null;
|
|
2229
|
-
this.context =
|
|
2366
|
+
this.context = this;
|
|
2367
|
+
this.isBound = false;
|
|
2368
|
+
}
|
|
2369
|
+
evaluateUnbindables() {
|
|
2370
|
+
const unbindables = this.unbindables;
|
|
2371
|
+
for (let i = 0, ii = unbindables.length; i < ii; ++i) {
|
|
2372
|
+
unbindables[i].unbind(this);
|
|
2373
|
+
}
|
|
2374
|
+
unbindables.length = 0;
|
|
2230
2375
|
}
|
|
2231
2376
|
/**
|
|
2232
2377
|
* Efficiently disposes of a contiguous range of synthetic view instances.
|
|
@@ -2242,6 +2387,8 @@ class HTMLView {
|
|
|
2242
2387
|
}
|
|
2243
2388
|
}
|
|
2244
2389
|
}
|
|
2390
|
+
Observable.defineProperty(HTMLView.prototype, "index");
|
|
2391
|
+
Observable.defineProperty(HTMLView.prototype, "length");
|
|
2245
2392
|
|
|
2246
2393
|
const targetIdFrom = (parentId, nodeIndex) => `${parentId}.${nodeIndex}`;
|
|
2247
2394
|
const descriptorCache = {};
|
|
@@ -2250,6 +2397,22 @@ const next = {
|
|
|
2250
2397
|
index: 0,
|
|
2251
2398
|
node: null,
|
|
2252
2399
|
};
|
|
2400
|
+
function tryWarn(name) {
|
|
2401
|
+
if (!name.startsWith("fast-")) {
|
|
2402
|
+
FAST.warn(1204 /* Message.hostBindingWithoutHost */, { name });
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
const warningHost = new Proxy(document.createElement("div"), {
|
|
2406
|
+
get(target, property) {
|
|
2407
|
+
tryWarn(property);
|
|
2408
|
+
const value = Reflect.get(target, property);
|
|
2409
|
+
return isFunction(value) ? value.bind(target) : value;
|
|
2410
|
+
},
|
|
2411
|
+
set(target, property, value) {
|
|
2412
|
+
tryWarn(property);
|
|
2413
|
+
return Reflect.set(target, property, value);
|
|
2414
|
+
},
|
|
2415
|
+
});
|
|
2253
2416
|
class CompilationContext {
|
|
2254
2417
|
constructor(fragment, directives) {
|
|
2255
2418
|
this.fragment = fragment;
|
|
@@ -2300,7 +2463,7 @@ class CompilationContext {
|
|
|
2300
2463
|
const fragment = this.fragment.cloneNode(true);
|
|
2301
2464
|
const targets = Object.create(this.proto);
|
|
2302
2465
|
targets.r = fragment;
|
|
2303
|
-
targets.h = hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget :
|
|
2466
|
+
targets.h = hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget : warningHost;
|
|
2304
2467
|
for (const id of this.nodeIds) {
|
|
2305
2468
|
targets[id]; // trigger locator
|
|
2306
2469
|
}
|
|
@@ -2317,7 +2480,7 @@ function compileAttributes(context, parentId, node, nodeId, nodeIndex, includeBa
|
|
|
2317
2480
|
let result = null;
|
|
2318
2481
|
if (parseResult === null) {
|
|
2319
2482
|
if (includeBasicValues) {
|
|
2320
|
-
result =
|
|
2483
|
+
result = new HTMLBindingDirective(oneTime(() => attrValue));
|
|
2321
2484
|
Aspect.assign(result, attr.name);
|
|
2322
2485
|
}
|
|
2323
2486
|
}
|
|
@@ -2354,6 +2517,7 @@ function compileContent(context, node, parentId, nodeId, nodeIndex) {
|
|
|
2354
2517
|
}
|
|
2355
2518
|
else {
|
|
2356
2519
|
currentNode.textContent = " ";
|
|
2520
|
+
Aspect.assign(currentPart);
|
|
2357
2521
|
context.addFactory(currentPart, parentId, nodeId, nodeIndex);
|
|
2358
2522
|
}
|
|
2359
2523
|
lastNode = currentNode;
|
|
@@ -2486,22 +2650,28 @@ const Compiler = {
|
|
|
2486
2650
|
return parts[0];
|
|
2487
2651
|
}
|
|
2488
2652
|
let sourceAspect;
|
|
2653
|
+
let binding;
|
|
2654
|
+
let isVolatile = false;
|
|
2489
2655
|
const partCount = parts.length;
|
|
2490
2656
|
const finalParts = parts.map((x) => {
|
|
2491
2657
|
if (isString(x)) {
|
|
2492
2658
|
return () => x;
|
|
2493
2659
|
}
|
|
2494
2660
|
sourceAspect = x.sourceAspect || sourceAspect;
|
|
2495
|
-
|
|
2661
|
+
binding = x.dataBinding || binding;
|
|
2662
|
+
isVolatile = isVolatile || x.dataBinding.isVolatile;
|
|
2663
|
+
return x.dataBinding.evaluate;
|
|
2496
2664
|
});
|
|
2497
|
-
const
|
|
2665
|
+
const expression = (scope, context) => {
|
|
2498
2666
|
let output = "";
|
|
2499
2667
|
for (let i = 0; i < partCount; ++i) {
|
|
2500
2668
|
output += finalParts[i](scope, context);
|
|
2501
2669
|
}
|
|
2502
2670
|
return output;
|
|
2503
2671
|
};
|
|
2504
|
-
|
|
2672
|
+
binding.evaluate = expression;
|
|
2673
|
+
binding.isVolatile = isVolatile;
|
|
2674
|
+
const directive = new HTMLBindingDirective(binding);
|
|
2505
2675
|
Aspect.assign(directive, sourceAspect);
|
|
2506
2676
|
return directive;
|
|
2507
2677
|
},
|
|
@@ -2539,9 +2709,9 @@ class ViewTemplate {
|
|
|
2539
2709
|
* @param hostBindingTarget - An HTML element to target the host bindings at if different from the
|
|
2540
2710
|
* host that the template is being attached to.
|
|
2541
2711
|
*/
|
|
2542
|
-
render(source, host, hostBindingTarget
|
|
2543
|
-
const view = this.create(hostBindingTarget
|
|
2544
|
-
view.bind(source
|
|
2712
|
+
render(source, host, hostBindingTarget) {
|
|
2713
|
+
const view = this.create(hostBindingTarget);
|
|
2714
|
+
view.bind(source);
|
|
2545
2715
|
view.appendTo(host);
|
|
2546
2716
|
return view;
|
|
2547
2717
|
}
|
|
@@ -2581,12 +2751,12 @@ function html(strings, ...values) {
|
|
|
2581
2751
|
let definition;
|
|
2582
2752
|
html += currentString;
|
|
2583
2753
|
if (isFunction(currentValue)) {
|
|
2584
|
-
html += createAspectedHTML(bind(currentValue), currentString, add);
|
|
2754
|
+
html += createAspectedHTML(new HTMLBindingDirective(bind(currentValue)), currentString, add);
|
|
2585
2755
|
}
|
|
2586
2756
|
else if (isString(currentValue)) {
|
|
2587
2757
|
const match = lastAttributeNameRegex.exec(currentString);
|
|
2588
2758
|
if (match !== null) {
|
|
2589
|
-
const directive =
|
|
2759
|
+
const directive = new HTMLBindingDirective(oneTime(() => currentValue));
|
|
2590
2760
|
Aspect.assign(directive, match[2]);
|
|
2591
2761
|
html += directive.createHTML(add);
|
|
2592
2762
|
}
|
|
@@ -2594,8 +2764,11 @@ function html(strings, ...values) {
|
|
|
2594
2764
|
html += currentValue;
|
|
2595
2765
|
}
|
|
2596
2766
|
}
|
|
2767
|
+
else if (currentValue instanceof Binding) {
|
|
2768
|
+
html += createAspectedHTML(new HTMLBindingDirective(currentValue), currentString, add);
|
|
2769
|
+
}
|
|
2597
2770
|
else if ((definition = HTMLDirective.getForInstance(currentValue)) === void 0) {
|
|
2598
|
-
html += createAspectedHTML(
|
|
2771
|
+
html += createAspectedHTML(new HTMLBindingDirective(oneTime(() => currentValue)), currentString, add);
|
|
2599
2772
|
}
|
|
2600
2773
|
else {
|
|
2601
2774
|
if (definition.aspected) {
|
|
@@ -2608,26 +2781,6 @@ function html(strings, ...values) {
|
|
|
2608
2781
|
}
|
|
2609
2782
|
return new ViewTemplate(html + strings[strings.length - 1], factories);
|
|
2610
2783
|
}
|
|
2611
|
-
/**
|
|
2612
|
-
* Transforms a template literal string into a ChildViewTemplate.
|
|
2613
|
-
* @param strings - The string fragments that are interpolated with the values.
|
|
2614
|
-
* @param values - The values that are interpolated with the string fragments.
|
|
2615
|
-
* @remarks
|
|
2616
|
-
* The html helper supports interpolation of strings, numbers, binding expressions,
|
|
2617
|
-
* other template instances, and Directive instances.
|
|
2618
|
-
* @public
|
|
2619
|
-
*/
|
|
2620
|
-
const child = html;
|
|
2621
|
-
/**
|
|
2622
|
-
* Transforms a template literal string into an ItemViewTemplate.
|
|
2623
|
-
* @param strings - The string fragments that are interpolated with the values.
|
|
2624
|
-
* @param values - The values that are interpolated with the string fragments.
|
|
2625
|
-
* @remarks
|
|
2626
|
-
* The html helper supports interpolation of strings, numbers, binding expressions,
|
|
2627
|
-
* other template instances, and Directive instances.
|
|
2628
|
-
* @public
|
|
2629
|
-
*/
|
|
2630
|
-
const item = html;
|
|
2631
2784
|
|
|
2632
2785
|
/**
|
|
2633
2786
|
* The runtime behavior for template references.
|
|
@@ -2635,20 +2788,12 @@ const item = html;
|
|
|
2635
2788
|
*/
|
|
2636
2789
|
class RefDirective extends StatelessAttachedAttributeDirective {
|
|
2637
2790
|
/**
|
|
2638
|
-
* Bind this behavior
|
|
2639
|
-
* @param
|
|
2640
|
-
* @param context - The execution context that the binding is operating within.
|
|
2641
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
2791
|
+
* Bind this behavior.
|
|
2792
|
+
* @param controller - The view controller that manages the lifecycle of this behavior.
|
|
2642
2793
|
*/
|
|
2643
|
-
bind(
|
|
2644
|
-
source[this.options] = targets[this.nodeId];
|
|
2794
|
+
bind(controller) {
|
|
2795
|
+
controller.source[this.options] = controller.targets[this.nodeId];
|
|
2645
2796
|
}
|
|
2646
|
-
/**
|
|
2647
|
-
* Unbinds this behavior from the source.
|
|
2648
|
-
* @param source - The source to unbind from.
|
|
2649
|
-
*/
|
|
2650
|
-
/* eslint-disable-next-line @typescript-eslint/no-empty-function */
|
|
2651
|
-
unbind() { }
|
|
2652
2797
|
}
|
|
2653
2798
|
HTMLDirective.define(RefDirective);
|
|
2654
2799
|
/**
|
|
@@ -2660,27 +2805,34 @@ const ref = (propertyName) => new RefDirective(propertyName);
|
|
|
2660
2805
|
|
|
2661
2806
|
/**
|
|
2662
2807
|
* A directive that enables basic conditional rendering in a template.
|
|
2663
|
-
* @param
|
|
2808
|
+
* @param condition - The condition to test for rendering.
|
|
2664
2809
|
* @param templateOrTemplateBinding - The template or a binding that gets
|
|
2665
2810
|
* the template to render when the condition is true.
|
|
2666
2811
|
* @public
|
|
2667
2812
|
*/
|
|
2668
|
-
function when(
|
|
2669
|
-
const
|
|
2813
|
+
function when(condition, templateOrTemplateBinding) {
|
|
2814
|
+
const dataBinding = isFunction(condition) ? condition : () => condition;
|
|
2815
|
+
const templateBinding = isFunction(templateOrTemplateBinding)
|
|
2670
2816
|
? templateOrTemplateBinding
|
|
2671
2817
|
: () => templateOrTemplateBinding;
|
|
2672
|
-
return (source, context) =>
|
|
2818
|
+
return (source, context) => dataBinding(source, context) ? templateBinding(source, context) : null;
|
|
2673
2819
|
}
|
|
2674
2820
|
|
|
2675
2821
|
const defaultRepeatOptions = Object.freeze({
|
|
2676
2822
|
positioning: false,
|
|
2677
2823
|
recycle: true,
|
|
2678
2824
|
});
|
|
2679
|
-
function bindWithoutPositioning(view, items, index,
|
|
2680
|
-
view.
|
|
2825
|
+
function bindWithoutPositioning(view, items, index, controller) {
|
|
2826
|
+
view.context.parent = controller.source;
|
|
2827
|
+
view.context.parentContext = controller.context;
|
|
2828
|
+
view.bind(items[index]);
|
|
2681
2829
|
}
|
|
2682
|
-
function bindWithPositioning(view, items, index,
|
|
2683
|
-
view.
|
|
2830
|
+
function bindWithPositioning(view, items, index, controller) {
|
|
2831
|
+
view.context.parent = controller.source;
|
|
2832
|
+
view.context.parentContext = controller.context;
|
|
2833
|
+
view.context.length = items.length;
|
|
2834
|
+
view.context.index = index;
|
|
2835
|
+
view.bind(items[index]);
|
|
2684
2836
|
}
|
|
2685
2837
|
/**
|
|
2686
2838
|
* A behavior that renders a template for each item in an array.
|
|
@@ -2690,57 +2842,45 @@ class RepeatBehavior {
|
|
|
2690
2842
|
/**
|
|
2691
2843
|
* Creates an instance of RepeatBehavior.
|
|
2692
2844
|
* @param location - The location in the DOM to render the repeat.
|
|
2693
|
-
* @param
|
|
2845
|
+
* @param dataBinding - The array to render.
|
|
2694
2846
|
* @param isItemsBindingVolatile - Indicates whether the items binding has volatile dependencies.
|
|
2695
2847
|
* @param templateBinding - The template to render for each item.
|
|
2696
2848
|
* @param isTemplateBindingVolatile - Indicates whether the template binding has volatile dependencies.
|
|
2697
2849
|
* @param options - Options used to turn on special repeat features.
|
|
2698
2850
|
*/
|
|
2699
|
-
constructor(
|
|
2700
|
-
this.
|
|
2701
|
-
this.itemsBinding = itemsBinding;
|
|
2702
|
-
this.templateBinding = templateBinding;
|
|
2703
|
-
this.options = options;
|
|
2704
|
-
this.source = null;
|
|
2851
|
+
constructor(directive) {
|
|
2852
|
+
this.directive = directive;
|
|
2705
2853
|
this.views = [];
|
|
2706
2854
|
this.items = null;
|
|
2707
2855
|
this.itemsObserver = null;
|
|
2708
|
-
this.context = void 0;
|
|
2709
|
-
this.childContext = void 0;
|
|
2710
2856
|
this.bindView = bindWithoutPositioning;
|
|
2711
|
-
this.itemsBindingObserver =
|
|
2712
|
-
this.templateBindingObserver =
|
|
2713
|
-
if (options.positioning) {
|
|
2857
|
+
this.itemsBindingObserver = directive.dataBinding.createObserver(directive, this);
|
|
2858
|
+
this.templateBindingObserver = directive.templateBinding.createObserver(directive, this);
|
|
2859
|
+
if (directive.options.positioning) {
|
|
2714
2860
|
this.bindView = bindWithPositioning;
|
|
2715
2861
|
}
|
|
2716
2862
|
}
|
|
2717
2863
|
/**
|
|
2718
|
-
* Bind this behavior
|
|
2719
|
-
* @param
|
|
2720
|
-
* @param context - The execution context that the binding is operating within.
|
|
2864
|
+
* Bind this behavior.
|
|
2865
|
+
* @param controller - The view controller that manages the lifecycle of this behavior.
|
|
2721
2866
|
*/
|
|
2722
|
-
bind(
|
|
2723
|
-
this.
|
|
2724
|
-
this.
|
|
2725
|
-
this.
|
|
2726
|
-
this.
|
|
2727
|
-
this.template = this.templateBindingObserver.observe(source, this.context);
|
|
2867
|
+
bind(controller) {
|
|
2868
|
+
this.location = controller.targets[this.directive.nodeId];
|
|
2869
|
+
this.controller = controller;
|
|
2870
|
+
this.items = this.itemsBindingObserver.bind(controller);
|
|
2871
|
+
this.template = this.templateBindingObserver.bind(controller);
|
|
2728
2872
|
this.observeItems(true);
|
|
2729
2873
|
this.refreshAllViews();
|
|
2874
|
+
controller.onUnbind(this);
|
|
2730
2875
|
}
|
|
2731
2876
|
/**
|
|
2732
|
-
* Unbinds this behavior
|
|
2733
|
-
* @param source - The source to unbind from.
|
|
2877
|
+
* Unbinds this behavior.
|
|
2734
2878
|
*/
|
|
2735
2879
|
unbind() {
|
|
2736
|
-
this.source = null;
|
|
2737
|
-
this.items = null;
|
|
2738
2880
|
if (this.itemsObserver !== null) {
|
|
2739
2881
|
this.itemsObserver.unsubscribe(this);
|
|
2740
2882
|
}
|
|
2741
2883
|
this.unbindAllViews();
|
|
2742
|
-
this.itemsBindingObserver.dispose();
|
|
2743
|
-
this.templateBindingObserver.dispose();
|
|
2744
2884
|
}
|
|
2745
2885
|
/**
|
|
2746
2886
|
* Handles changes in the array, its items, and the repeat template.
|
|
@@ -2748,15 +2888,18 @@ class RepeatBehavior {
|
|
|
2748
2888
|
* @param args - The details about what was changed.
|
|
2749
2889
|
*/
|
|
2750
2890
|
handleChange(source, args) {
|
|
2751
|
-
if (
|
|
2752
|
-
this.items = this.itemsBindingObserver.
|
|
2891
|
+
if (args === this.itemsBindingObserver) {
|
|
2892
|
+
this.items = this.itemsBindingObserver.bind(this.controller);
|
|
2753
2893
|
this.observeItems();
|
|
2754
2894
|
this.refreshAllViews();
|
|
2755
2895
|
}
|
|
2756
|
-
else if (
|
|
2757
|
-
this.template = this.templateBindingObserver.
|
|
2896
|
+
else if (args === this.templateBindingObserver) {
|
|
2897
|
+
this.template = this.templateBindingObserver.bind(this.controller);
|
|
2758
2898
|
this.refreshAllViews(true);
|
|
2759
2899
|
}
|
|
2900
|
+
else if (!args[0]) {
|
|
2901
|
+
return;
|
|
2902
|
+
}
|
|
2760
2903
|
else if (args[0].reset) {
|
|
2761
2904
|
this.refreshAllViews();
|
|
2762
2905
|
}
|
|
@@ -2781,39 +2924,57 @@ class RepeatBehavior {
|
|
|
2781
2924
|
}
|
|
2782
2925
|
updateViews(splices) {
|
|
2783
2926
|
const views = this.views;
|
|
2784
|
-
const childContext = this.childContext;
|
|
2785
|
-
const totalRemoved = [];
|
|
2786
2927
|
const bindView = this.bindView;
|
|
2787
|
-
let removeDelta = 0;
|
|
2788
|
-
for (let i = 0, ii = splices.length; i < ii; ++i) {
|
|
2789
|
-
const splice = splices[i];
|
|
2790
|
-
const removed = splice.removed;
|
|
2791
|
-
totalRemoved.push(...views.splice(splice.index + removeDelta, removed.length));
|
|
2792
|
-
removeDelta -= splice.addedCount;
|
|
2793
|
-
}
|
|
2794
2928
|
const items = this.items;
|
|
2795
2929
|
const template = this.template;
|
|
2930
|
+
const controller = this.controller;
|
|
2931
|
+
const recycle = this.directive.options.recycle;
|
|
2932
|
+
const leftoverViews = [];
|
|
2933
|
+
let leftoverIndex = 0;
|
|
2934
|
+
let availableViews = 0;
|
|
2796
2935
|
for (let i = 0, ii = splices.length; i < ii; ++i) {
|
|
2797
2936
|
const splice = splices[i];
|
|
2937
|
+
const removed = splice.removed;
|
|
2938
|
+
let removeIndex = 0;
|
|
2798
2939
|
let addIndex = splice.index;
|
|
2799
2940
|
const end = addIndex + splice.addedCount;
|
|
2941
|
+
const removedViews = views.splice(splice.index, removed.length);
|
|
2942
|
+
const totalAvailableViews = (availableViews =
|
|
2943
|
+
leftoverViews.length + removedViews.length);
|
|
2800
2944
|
for (; addIndex < end; ++addIndex) {
|
|
2801
2945
|
const neighbor = views[addIndex];
|
|
2802
2946
|
const location = neighbor ? neighbor.firstChild : this.location;
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2947
|
+
let view;
|
|
2948
|
+
if (recycle && availableViews > 0) {
|
|
2949
|
+
if (removeIndex <= totalAvailableViews && removedViews.length > 0) {
|
|
2950
|
+
view = removedViews[removeIndex];
|
|
2951
|
+
removeIndex++;
|
|
2952
|
+
}
|
|
2953
|
+
else {
|
|
2954
|
+
view = leftoverViews[leftoverIndex];
|
|
2955
|
+
leftoverIndex++;
|
|
2956
|
+
}
|
|
2957
|
+
availableViews--;
|
|
2958
|
+
}
|
|
2959
|
+
else {
|
|
2960
|
+
view = template.create();
|
|
2961
|
+
}
|
|
2806
2962
|
views.splice(addIndex, 0, view);
|
|
2807
|
-
bindView(view, items, addIndex,
|
|
2963
|
+
bindView(view, items, addIndex, controller);
|
|
2808
2964
|
view.insertBefore(location);
|
|
2809
2965
|
}
|
|
2966
|
+
if (removedViews[removeIndex]) {
|
|
2967
|
+
leftoverViews.push(...removedViews.slice(removeIndex));
|
|
2968
|
+
}
|
|
2810
2969
|
}
|
|
2811
|
-
for (let i =
|
|
2812
|
-
|
|
2970
|
+
for (let i = leftoverIndex, ii = leftoverViews.length; i < ii; ++i) {
|
|
2971
|
+
leftoverViews[i].dispose();
|
|
2813
2972
|
}
|
|
2814
|
-
if (this.options.positioning) {
|
|
2973
|
+
if (this.directive.options.positioning) {
|
|
2815
2974
|
for (let i = 0, ii = views.length; i < ii; ++i) {
|
|
2816
|
-
views[i].context
|
|
2975
|
+
const context = views[i].context;
|
|
2976
|
+
context.length = i;
|
|
2977
|
+
context.index = ii;
|
|
2817
2978
|
}
|
|
2818
2979
|
}
|
|
2819
2980
|
}
|
|
@@ -2822,11 +2983,11 @@ class RepeatBehavior {
|
|
|
2822
2983
|
const template = this.template;
|
|
2823
2984
|
const location = this.location;
|
|
2824
2985
|
const bindView = this.bindView;
|
|
2825
|
-
const
|
|
2986
|
+
const controller = this.controller;
|
|
2826
2987
|
let itemsLength = items.length;
|
|
2827
2988
|
let views = this.views;
|
|
2828
2989
|
let viewsLength = views.length;
|
|
2829
|
-
if (itemsLength === 0 || templateChanged) {
|
|
2990
|
+
if (itemsLength === 0 || templateChanged || !this.directive.options.recycle) {
|
|
2830
2991
|
// all views need to be removed
|
|
2831
2992
|
HTMLView.disposeContiguousBatch(views);
|
|
2832
2993
|
viewsLength = 0;
|
|
@@ -2836,7 +2997,7 @@ class RepeatBehavior {
|
|
|
2836
2997
|
this.views = views = new Array(itemsLength);
|
|
2837
2998
|
for (let i = 0; i < itemsLength; ++i) {
|
|
2838
2999
|
const view = template.create();
|
|
2839
|
-
bindView(view, items, i,
|
|
3000
|
+
bindView(view, items, i, controller);
|
|
2840
3001
|
views[i] = view;
|
|
2841
3002
|
view.insertBefore(location);
|
|
2842
3003
|
}
|
|
@@ -2847,11 +3008,11 @@ class RepeatBehavior {
|
|
|
2847
3008
|
for (; i < itemsLength; ++i) {
|
|
2848
3009
|
if (i < viewsLength) {
|
|
2849
3010
|
const view = views[i];
|
|
2850
|
-
bindView(view, items, i,
|
|
3011
|
+
bindView(view, items, i, controller);
|
|
2851
3012
|
}
|
|
2852
3013
|
else {
|
|
2853
3014
|
const view = template.create();
|
|
2854
|
-
bindView(view, items, i,
|
|
3015
|
+
bindView(view, items, i, controller);
|
|
2855
3016
|
views.push(view);
|
|
2856
3017
|
view.insertBefore(location);
|
|
2857
3018
|
}
|
|
@@ -2876,17 +3037,19 @@ class RepeatBehavior {
|
|
|
2876
3037
|
class RepeatDirective {
|
|
2877
3038
|
/**
|
|
2878
3039
|
* Creates an instance of RepeatDirective.
|
|
2879
|
-
* @param
|
|
3040
|
+
* @param dataBinding - The binding that provides the array to render.
|
|
2880
3041
|
* @param templateBinding - The template binding used to obtain a template to render for each item in the array.
|
|
2881
3042
|
* @param options - Options used to turn on special repeat features.
|
|
2882
3043
|
*/
|
|
2883
|
-
constructor(
|
|
2884
|
-
this.
|
|
3044
|
+
constructor(dataBinding, templateBinding, options) {
|
|
3045
|
+
this.dataBinding = dataBinding;
|
|
2885
3046
|
this.templateBinding = templateBinding;
|
|
2886
3047
|
this.options = options;
|
|
3048
|
+
/**
|
|
3049
|
+
* The unique id of the factory.
|
|
3050
|
+
*/
|
|
3051
|
+
this.id = nextId();
|
|
2887
3052
|
ArrayObserver.enable();
|
|
2888
|
-
this.isItemsBindingVolatile = Observable.isVolatileBinding(itemsBinding);
|
|
2889
|
-
this.isTemplateBindingVolatile = Observable.isVolatileBinding(templateBinding);
|
|
2890
3053
|
}
|
|
2891
3054
|
/**
|
|
2892
3055
|
* Creates a placeholder string based on the directive's index within the template.
|
|
@@ -2899,16 +3062,23 @@ class RepeatDirective {
|
|
|
2899
3062
|
* Creates a behavior for the provided target node.
|
|
2900
3063
|
* @param target - The node instance to create the behavior for.
|
|
2901
3064
|
*/
|
|
2902
|
-
createBehavior(
|
|
2903
|
-
return new RepeatBehavior(
|
|
3065
|
+
createBehavior() {
|
|
3066
|
+
return new RepeatBehavior(this);
|
|
2904
3067
|
}
|
|
2905
3068
|
}
|
|
2906
3069
|
HTMLDirective.define(RepeatDirective);
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
3070
|
+
/**
|
|
3071
|
+
* A directive that enables list rendering.
|
|
3072
|
+
* @param items - The array to render.
|
|
3073
|
+
* @param template - The template or a template binding used obtain a template
|
|
3074
|
+
* to render for each item in the array.
|
|
3075
|
+
* @param options - Options used to turn on special repeat features.
|
|
3076
|
+
* @public
|
|
3077
|
+
*/
|
|
3078
|
+
function repeat(items, template, options = defaultRepeatOptions) {
|
|
3079
|
+
const dataBinding = normalizeBinding(items);
|
|
3080
|
+
const templateBinding = normalizeBinding(template);
|
|
3081
|
+
return new RepeatDirective(dataBinding, templateBinding, Object.assign(Object.assign({}, defaultRepeatOptions), options));
|
|
2912
3082
|
}
|
|
2913
3083
|
|
|
2914
3084
|
const selectElements = (value) => value.nodeType === 1;
|
|
@@ -2937,11 +3107,12 @@ class NodeObservationDirective extends StatelessAttachedAttributeDirective {
|
|
|
2937
3107
|
* @param context - The execution context that the binding is operating within.
|
|
2938
3108
|
* @param targets - The targets that behaviors in a view can attach to.
|
|
2939
3109
|
*/
|
|
2940
|
-
bind(
|
|
2941
|
-
const target = targets[this.nodeId];
|
|
2942
|
-
target[this.sourceProperty] = source;
|
|
2943
|
-
this.updateTarget(source, this.computeNodes(target));
|
|
3110
|
+
bind(controller) {
|
|
3111
|
+
const target = controller.targets[this.nodeId];
|
|
3112
|
+
target[this.sourceProperty] = controller.source;
|
|
3113
|
+
this.updateTarget(controller.source, this.computeNodes(target));
|
|
2944
3114
|
this.observe(target);
|
|
3115
|
+
controller.onUnbind(this);
|
|
2945
3116
|
}
|
|
2946
3117
|
/**
|
|
2947
3118
|
* Unbinds this behavior from the source.
|
|
@@ -2949,9 +3120,9 @@ class NodeObservationDirective extends StatelessAttachedAttributeDirective {
|
|
|
2949
3120
|
* @param context - The execution context that the binding is operating within.
|
|
2950
3121
|
* @param targets - The targets that behaviors in a view can attach to.
|
|
2951
3122
|
*/
|
|
2952
|
-
unbind(
|
|
2953
|
-
const target = targets[this.nodeId];
|
|
2954
|
-
this.updateTarget(source, emptyArray);
|
|
3123
|
+
unbind(controller) {
|
|
3124
|
+
const target = controller.targets[this.nodeId];
|
|
3125
|
+
this.updateTarget(controller.source, emptyArray);
|
|
2955
3126
|
this.disconnect(target);
|
|
2956
3127
|
target[this.sourceProperty] = null;
|
|
2957
3128
|
}
|
|
@@ -3100,6 +3271,16 @@ function children(propertyOrOptions) {
|
|
|
3100
3271
|
|
|
3101
3272
|
const booleanMode = "boolean";
|
|
3102
3273
|
const reflectMode = "reflect";
|
|
3274
|
+
/**
|
|
3275
|
+
* Metadata used to configure a custom attribute's behavior.
|
|
3276
|
+
* @public
|
|
3277
|
+
*/
|
|
3278
|
+
const AttributeConfiguration = Object.freeze({
|
|
3279
|
+
/**
|
|
3280
|
+
* Locates all attribute configurations associated with a type.
|
|
3281
|
+
*/
|
|
3282
|
+
locate: createMetadataLocator(),
|
|
3283
|
+
});
|
|
3103
3284
|
/**
|
|
3104
3285
|
* A {@link ValueConverter} that converts to and from `boolean` values.
|
|
3105
3286
|
* @remarks
|
|
@@ -3237,7 +3418,7 @@ class AttributeDefinition {
|
|
|
3237
3418
|
*/
|
|
3238
3419
|
static collect(Owner, ...attributeLists) {
|
|
3239
3420
|
const attributes = [];
|
|
3240
|
-
attributeLists.push(Owner
|
|
3421
|
+
attributeLists.push(AttributeConfiguration.locate(Owner));
|
|
3241
3422
|
for (let i = 0, ii = attributeLists.length; i < ii; ++i) {
|
|
3242
3423
|
const list = attributeLists[i];
|
|
3243
3424
|
if (list === void 0) {
|
|
@@ -3267,9 +3448,7 @@ function attr(configOrTarget, prop) {
|
|
|
3267
3448
|
// - @attr({...opts})
|
|
3268
3449
|
config.property = $prop;
|
|
3269
3450
|
}
|
|
3270
|
-
|
|
3271
|
-
($target.constructor.attributes = []);
|
|
3272
|
-
attributes.push(config);
|
|
3451
|
+
AttributeConfiguration.locate($target.constructor).push(config);
|
|
3273
3452
|
}
|
|
3274
3453
|
if (arguments.length > 1) {
|
|
3275
3454
|
// Non invocation:
|
|
@@ -3287,25 +3466,24 @@ function attr(configOrTarget, prop) {
|
|
|
3287
3466
|
|
|
3288
3467
|
const defaultShadowOptions = { mode: "open" };
|
|
3289
3468
|
const defaultElementOptions = {};
|
|
3469
|
+
const fastElementBaseTypes = new Set();
|
|
3290
3470
|
const fastElementRegistry = FAST.getById(4 /* KernelServiceId.elementRegistry */, () => createTypeRegistry());
|
|
3291
3471
|
/**
|
|
3292
3472
|
* Defines metadata for a FASTElement.
|
|
3293
3473
|
* @public
|
|
3294
3474
|
*/
|
|
3295
3475
|
class FASTElementDefinition {
|
|
3296
|
-
/**
|
|
3297
|
-
* Creates an instance of FASTElementDefinition.
|
|
3298
|
-
* @param type - The type this definition is being created for.
|
|
3299
|
-
* @param nameOrConfig - The name of the element to define or a config object
|
|
3300
|
-
* that describes the element to define.
|
|
3301
|
-
*/
|
|
3302
3476
|
constructor(type, nameOrConfig = type.definition) {
|
|
3477
|
+
var _a;
|
|
3478
|
+
this.platformDefined = false;
|
|
3303
3479
|
if (isString(nameOrConfig)) {
|
|
3304
3480
|
nameOrConfig = { name: nameOrConfig };
|
|
3305
3481
|
}
|
|
3306
3482
|
this.type = type;
|
|
3307
3483
|
this.name = nameOrConfig.name;
|
|
3308
3484
|
this.template = nameOrConfig.template;
|
|
3485
|
+
this.registry = (_a = nameOrConfig.registry) !== null && _a !== void 0 ? _a : customElements;
|
|
3486
|
+
const proto = type.prototype;
|
|
3309
3487
|
const attributes = AttributeDefinition.collect(type, nameOrConfig.attributes);
|
|
3310
3488
|
const observedAttributes = new Array(attributes.length);
|
|
3311
3489
|
const propertyLookup = {};
|
|
@@ -3315,9 +3493,13 @@ class FASTElementDefinition {
|
|
|
3315
3493
|
observedAttributes[i] = current.attribute;
|
|
3316
3494
|
propertyLookup[current.name] = current;
|
|
3317
3495
|
attributeLookup[current.attribute] = current;
|
|
3496
|
+
Observable.defineProperty(proto, current);
|
|
3318
3497
|
}
|
|
3498
|
+
Reflect.defineProperty(type, "observedAttributes", {
|
|
3499
|
+
value: observedAttributes,
|
|
3500
|
+
enumerable: true,
|
|
3501
|
+
});
|
|
3319
3502
|
this.attributes = attributes;
|
|
3320
|
-
this.observedAttributes = observedAttributes;
|
|
3321
3503
|
this.propertyLookup = propertyLookup;
|
|
3322
3504
|
this.attributeLookup = attributeLookup;
|
|
3323
3505
|
this.shadowOptions =
|
|
@@ -3330,43 +3512,50 @@ class FASTElementDefinition {
|
|
|
3330
3512
|
nameOrConfig.elementOptions === void 0
|
|
3331
3513
|
? defaultElementOptions
|
|
3332
3514
|
: Object.assign(Object.assign({}, defaultElementOptions), nameOrConfig.elementOptions);
|
|
3333
|
-
this.styles =
|
|
3334
|
-
|
|
3335
|
-
? void 0
|
|
3336
|
-
: Array.isArray(nameOrConfig.styles)
|
|
3337
|
-
? new ElementStyles(nameOrConfig.styles)
|
|
3338
|
-
: nameOrConfig.styles instanceof ElementStyles
|
|
3339
|
-
? nameOrConfig.styles
|
|
3340
|
-
: new ElementStyles([nameOrConfig.styles]);
|
|
3515
|
+
this.styles = ElementStyles.normalize(nameOrConfig.styles);
|
|
3516
|
+
fastElementRegistry.register(this);
|
|
3341
3517
|
}
|
|
3342
3518
|
/**
|
|
3343
3519
|
* Indicates if this element has been defined in at least one registry.
|
|
3344
3520
|
*/
|
|
3345
3521
|
get isDefined() {
|
|
3346
|
-
return
|
|
3522
|
+
return this.platformDefined;
|
|
3347
3523
|
}
|
|
3348
3524
|
/**
|
|
3349
3525
|
* Defines a custom element based on this definition.
|
|
3350
3526
|
* @param registry - The element registry to define the element in.
|
|
3527
|
+
* @remarks
|
|
3528
|
+
* This operation is idempotent per registry.
|
|
3351
3529
|
*/
|
|
3352
|
-
define(registry =
|
|
3530
|
+
define(registry = this.registry) {
|
|
3353
3531
|
const type = this.type;
|
|
3354
|
-
if (fastElementRegistry.register(this)) {
|
|
3355
|
-
const attributes = this.attributes;
|
|
3356
|
-
const proto = type.prototype;
|
|
3357
|
-
for (let i = 0, ii = attributes.length; i < ii; ++i) {
|
|
3358
|
-
Observable.defineProperty(proto, attributes[i]);
|
|
3359
|
-
}
|
|
3360
|
-
Reflect.defineProperty(type, "observedAttributes", {
|
|
3361
|
-
value: this.observedAttributes,
|
|
3362
|
-
enumerable: true,
|
|
3363
|
-
});
|
|
3364
|
-
}
|
|
3365
3532
|
if (!registry.get(this.name)) {
|
|
3533
|
+
this.platformDefined = true;
|
|
3366
3534
|
registry.define(this.name, type, this.elementOptions);
|
|
3367
3535
|
}
|
|
3368
3536
|
return this;
|
|
3369
3537
|
}
|
|
3538
|
+
/**
|
|
3539
|
+
* Creates an instance of FASTElementDefinition.
|
|
3540
|
+
* @param type - The type this definition is being created for.
|
|
3541
|
+
* @param nameOrDef - The name of the element to define or a config object
|
|
3542
|
+
* that describes the element to define.
|
|
3543
|
+
*/
|
|
3544
|
+
static compose(type, nameOrDef) {
|
|
3545
|
+
if (fastElementBaseTypes.has(type) || fastElementRegistry.getByType(type)) {
|
|
3546
|
+
return new FASTElementDefinition(class extends type {
|
|
3547
|
+
}, nameOrDef);
|
|
3548
|
+
}
|
|
3549
|
+
return new FASTElementDefinition(type, nameOrDef);
|
|
3550
|
+
}
|
|
3551
|
+
/**
|
|
3552
|
+
* Registers a FASTElement base type.
|
|
3553
|
+
* @param type - The type to register as a base type.
|
|
3554
|
+
* @internal
|
|
3555
|
+
*/
|
|
3556
|
+
static registerBaseType(type) {
|
|
3557
|
+
fastElementBaseTypes.add(type);
|
|
3558
|
+
}
|
|
3370
3559
|
}
|
|
3371
3560
|
/**
|
|
3372
3561
|
* Gets the element definition associated with the specified type.
|
|
@@ -3379,22 +3568,22 @@ FASTElementDefinition.getByType = fastElementRegistry.getByType;
|
|
|
3379
3568
|
*/
|
|
3380
3569
|
FASTElementDefinition.getForInstance = fastElementRegistry.getForInstance;
|
|
3381
3570
|
|
|
3382
|
-
const shadowRoots = new WeakMap();
|
|
3383
3571
|
const defaultEventOptions = {
|
|
3384
3572
|
bubbles: true,
|
|
3385
3573
|
composed: true,
|
|
3386
3574
|
cancelable: true,
|
|
3387
3575
|
};
|
|
3576
|
+
const isConnectedPropertyName = "isConnected";
|
|
3577
|
+
const shadowRoots = new WeakMap();
|
|
3388
3578
|
function getShadowRoot(element) {
|
|
3389
3579
|
var _a, _b;
|
|
3390
3580
|
return (_b = (_a = element.shadowRoot) !== null && _a !== void 0 ? _a : shadowRoots.get(element)) !== null && _b !== void 0 ? _b : null;
|
|
3391
3581
|
}
|
|
3392
|
-
const isConnectedPropertyName = "isConnected";
|
|
3393
3582
|
/**
|
|
3394
3583
|
* Controls the lifecycle and rendering of a `FASTElement`.
|
|
3395
3584
|
* @public
|
|
3396
3585
|
*/
|
|
3397
|
-
class
|
|
3586
|
+
class ElementController extends PropertyChangeNotifier {
|
|
3398
3587
|
/**
|
|
3399
3588
|
* Creates a Controller to control the specified element.
|
|
3400
3589
|
* @param element - The element to be controlled by this controller.
|
|
@@ -3405,12 +3594,12 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3405
3594
|
constructor(element, definition) {
|
|
3406
3595
|
super(element);
|
|
3407
3596
|
this.boundObservables = null;
|
|
3408
|
-
this.behaviors = null;
|
|
3409
3597
|
this.needsInitialization = true;
|
|
3410
3598
|
this.hasExistingShadowRoot = false;
|
|
3411
3599
|
this._template = null;
|
|
3412
|
-
this._styles = null;
|
|
3413
3600
|
this._isConnected = false;
|
|
3601
|
+
this.behaviors = null;
|
|
3602
|
+
this._mainStyles = null;
|
|
3414
3603
|
/**
|
|
3415
3604
|
* This allows Observable.getNotifier(...) to return the Controller
|
|
3416
3605
|
* when the notifier for the Controller itself is being requested. The
|
|
@@ -3426,7 +3615,7 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3426
3615
|
* If `null` then the element is managing its own rendering.
|
|
3427
3616
|
*/
|
|
3428
3617
|
this.view = null;
|
|
3429
|
-
this.
|
|
3618
|
+
this.source = element;
|
|
3430
3619
|
this.definition = definition;
|
|
3431
3620
|
const shadowOptions = definition.shadowOptions;
|
|
3432
3621
|
if (shadowOptions !== void 0) {
|
|
@@ -3480,9 +3669,9 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3480
3669
|
// 1. Template overrides take top precedence.
|
|
3481
3670
|
if (this._template === null) {
|
|
3482
3671
|
const definition = this.definition;
|
|
3483
|
-
if (this.
|
|
3672
|
+
if (this.source.resolveTemplate) {
|
|
3484
3673
|
// 2. Allow for element instance overrides next.
|
|
3485
|
-
this._template = this.
|
|
3674
|
+
this._template = this.source.resolveTemplate();
|
|
3486
3675
|
}
|
|
3487
3676
|
else if (definition.template) {
|
|
3488
3677
|
// 3. Default to the static definition.
|
|
@@ -3501,56 +3690,102 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3501
3690
|
}
|
|
3502
3691
|
}
|
|
3503
3692
|
/**
|
|
3504
|
-
*
|
|
3505
|
-
*
|
|
3506
|
-
* This value can only be accurately read after connect but can be set at any time.
|
|
3693
|
+
* The main set of styles used for the component, independent
|
|
3694
|
+
* of any dynamically added styles.
|
|
3507
3695
|
*/
|
|
3508
|
-
get
|
|
3696
|
+
get mainStyles() {
|
|
3509
3697
|
var _a;
|
|
3510
3698
|
// 1. Styles overrides take top precedence.
|
|
3511
|
-
if (this.
|
|
3699
|
+
if (this._mainStyles === null) {
|
|
3512
3700
|
const definition = this.definition;
|
|
3513
|
-
if (this.
|
|
3701
|
+
if (this.source.resolveStyles) {
|
|
3514
3702
|
// 2. Allow for element instance overrides next.
|
|
3515
|
-
this.
|
|
3703
|
+
this._mainStyles = this.source.resolveStyles();
|
|
3516
3704
|
}
|
|
3517
3705
|
else if (definition.styles) {
|
|
3518
3706
|
// 3. Default to the static definition.
|
|
3519
|
-
this.
|
|
3707
|
+
this._mainStyles = (_a = definition.styles) !== null && _a !== void 0 ? _a : null;
|
|
3520
3708
|
}
|
|
3521
3709
|
}
|
|
3522
|
-
return this.
|
|
3710
|
+
return this._mainStyles;
|
|
3523
3711
|
}
|
|
3524
|
-
set
|
|
3525
|
-
if (this.
|
|
3712
|
+
set mainStyles(value) {
|
|
3713
|
+
if (this._mainStyles === value) {
|
|
3526
3714
|
return;
|
|
3527
3715
|
}
|
|
3528
|
-
if (this.
|
|
3529
|
-
this.removeStyles(this.
|
|
3716
|
+
if (this._mainStyles !== null) {
|
|
3717
|
+
this.removeStyles(this._mainStyles);
|
|
3530
3718
|
}
|
|
3531
|
-
this.
|
|
3719
|
+
this._mainStyles = value;
|
|
3532
3720
|
if (!this.needsInitialization) {
|
|
3533
3721
|
this.addStyles(value);
|
|
3534
3722
|
}
|
|
3535
3723
|
}
|
|
3724
|
+
/**
|
|
3725
|
+
* Adds the behavior to the component.
|
|
3726
|
+
* @param behavior - The behavior to add.
|
|
3727
|
+
*/
|
|
3728
|
+
addBehavior(behavior) {
|
|
3729
|
+
var _a, _b;
|
|
3730
|
+
const targetBehaviors = (_a = this.behaviors) !== null && _a !== void 0 ? _a : (this.behaviors = new Map());
|
|
3731
|
+
const count = (_b = targetBehaviors.get(behavior)) !== null && _b !== void 0 ? _b : 0;
|
|
3732
|
+
if (count === 0) {
|
|
3733
|
+
targetBehaviors.set(behavior, 1);
|
|
3734
|
+
behavior.addedCallback && behavior.addedCallback(this);
|
|
3735
|
+
if (behavior.connectedCallback && this.isConnected) {
|
|
3736
|
+
behavior.connectedCallback(this);
|
|
3737
|
+
}
|
|
3738
|
+
}
|
|
3739
|
+
else {
|
|
3740
|
+
targetBehaviors.set(behavior, count + 1);
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
/**
|
|
3744
|
+
* Removes the behavior from the component.
|
|
3745
|
+
* @param behavior - The behavior to remove.
|
|
3746
|
+
* @param force - Forces removal even if this behavior was added more than once.
|
|
3747
|
+
*/
|
|
3748
|
+
removeBehavior(behavior, force = false) {
|
|
3749
|
+
const targetBehaviors = this.behaviors;
|
|
3750
|
+
if (targetBehaviors === null) {
|
|
3751
|
+
return;
|
|
3752
|
+
}
|
|
3753
|
+
const count = targetBehaviors.get(behavior);
|
|
3754
|
+
if (count === void 0) {
|
|
3755
|
+
return;
|
|
3756
|
+
}
|
|
3757
|
+
if (count === 1 || force) {
|
|
3758
|
+
targetBehaviors.delete(behavior);
|
|
3759
|
+
if (behavior.disconnectedCallback && this.isConnected) {
|
|
3760
|
+
behavior.disconnectedCallback(this);
|
|
3761
|
+
}
|
|
3762
|
+
behavior.removedCallback && behavior.removedCallback(this);
|
|
3763
|
+
}
|
|
3764
|
+
else {
|
|
3765
|
+
targetBehaviors.set(behavior, count - 1);
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3536
3768
|
/**
|
|
3537
3769
|
* Adds styles to this element. Providing an HTMLStyleElement will attach the element instance to the shadowRoot.
|
|
3538
3770
|
* @param styles - The styles to add.
|
|
3539
3771
|
*/
|
|
3540
3772
|
addStyles(styles) {
|
|
3773
|
+
var _a;
|
|
3541
3774
|
if (!styles) {
|
|
3542
3775
|
return;
|
|
3543
3776
|
}
|
|
3544
|
-
const
|
|
3545
|
-
this.element.getRootNode();
|
|
3777
|
+
const source = this.source;
|
|
3546
3778
|
if (styles instanceof HTMLElement) {
|
|
3779
|
+
const target = (_a = getShadowRoot(source)) !== null && _a !== void 0 ? _a : this.source;
|
|
3547
3780
|
target.append(styles);
|
|
3548
3781
|
}
|
|
3549
|
-
else if (!styles.isAttachedTo(
|
|
3782
|
+
else if (!styles.isAttachedTo(source)) {
|
|
3550
3783
|
const sourceBehaviors = styles.behaviors;
|
|
3551
|
-
styles.addStylesTo(
|
|
3784
|
+
styles.addStylesTo(source);
|
|
3552
3785
|
if (sourceBehaviors !== null) {
|
|
3553
|
-
|
|
3786
|
+
for (let i = 0, ii = sourceBehaviors.length; i < ii; ++i) {
|
|
3787
|
+
this.addBehavior(sourceBehaviors[i]);
|
|
3788
|
+
}
|
|
3554
3789
|
}
|
|
3555
3790
|
}
|
|
3556
3791
|
}
|
|
@@ -3559,97 +3794,42 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3559
3794
|
* @param styles - the styles to remove.
|
|
3560
3795
|
*/
|
|
3561
3796
|
removeStyles(styles) {
|
|
3797
|
+
var _a;
|
|
3562
3798
|
if (!styles) {
|
|
3563
3799
|
return;
|
|
3564
3800
|
}
|
|
3565
|
-
const
|
|
3566
|
-
this.element.getRootNode();
|
|
3801
|
+
const source = this.source;
|
|
3567
3802
|
if (styles instanceof HTMLElement) {
|
|
3803
|
+
const target = (_a = getShadowRoot(source)) !== null && _a !== void 0 ? _a : source;
|
|
3568
3804
|
target.removeChild(styles);
|
|
3569
3805
|
}
|
|
3570
|
-
else if (styles.isAttachedTo(
|
|
3806
|
+
else if (styles.isAttachedTo(source)) {
|
|
3571
3807
|
const sourceBehaviors = styles.behaviors;
|
|
3572
|
-
styles.removeStylesFrom(
|
|
3808
|
+
styles.removeStylesFrom(source);
|
|
3573
3809
|
if (sourceBehaviors !== null) {
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
}
|
|
3578
|
-
/**
|
|
3579
|
-
* Adds behaviors to this element.
|
|
3580
|
-
* @param behaviors - The behaviors to add.
|
|
3581
|
-
*/
|
|
3582
|
-
addBehaviors(behaviors) {
|
|
3583
|
-
var _a;
|
|
3584
|
-
const targetBehaviors = (_a = this.behaviors) !== null && _a !== void 0 ? _a : (this.behaviors = new Map());
|
|
3585
|
-
const length = behaviors.length;
|
|
3586
|
-
const behaviorsToBind = [];
|
|
3587
|
-
for (let i = 0; i < length; ++i) {
|
|
3588
|
-
const behavior = behaviors[i];
|
|
3589
|
-
if (targetBehaviors.has(behavior)) {
|
|
3590
|
-
targetBehaviors.set(behavior, targetBehaviors.get(behavior) + 1);
|
|
3591
|
-
}
|
|
3592
|
-
else {
|
|
3593
|
-
targetBehaviors.set(behavior, 1);
|
|
3594
|
-
behaviorsToBind.push(behavior);
|
|
3595
|
-
}
|
|
3596
|
-
}
|
|
3597
|
-
if (this._isConnected) {
|
|
3598
|
-
const element = this.element;
|
|
3599
|
-
const context = ExecutionContext.default;
|
|
3600
|
-
for (let i = 0; i < behaviorsToBind.length; ++i) {
|
|
3601
|
-
behaviorsToBind[i].bind(element, context);
|
|
3602
|
-
}
|
|
3603
|
-
}
|
|
3604
|
-
}
|
|
3605
|
-
/**
|
|
3606
|
-
* Removes behaviors from this element.
|
|
3607
|
-
* @param behaviors - The behaviors to remove.
|
|
3608
|
-
* @param force - Forces unbinding of behaviors.
|
|
3609
|
-
*/
|
|
3610
|
-
removeBehaviors(behaviors, force = false) {
|
|
3611
|
-
const targetBehaviors = this.behaviors;
|
|
3612
|
-
if (targetBehaviors === null) {
|
|
3613
|
-
return;
|
|
3614
|
-
}
|
|
3615
|
-
const length = behaviors.length;
|
|
3616
|
-
const behaviorsToUnbind = [];
|
|
3617
|
-
for (let i = 0; i < length; ++i) {
|
|
3618
|
-
const behavior = behaviors[i];
|
|
3619
|
-
if (targetBehaviors.has(behavior)) {
|
|
3620
|
-
const count = targetBehaviors.get(behavior) - 1;
|
|
3621
|
-
count === 0 || force
|
|
3622
|
-
? targetBehaviors.delete(behavior) && behaviorsToUnbind.push(behavior)
|
|
3623
|
-
: targetBehaviors.set(behavior, count);
|
|
3624
|
-
}
|
|
3625
|
-
}
|
|
3626
|
-
if (this._isConnected) {
|
|
3627
|
-
const element = this.element;
|
|
3628
|
-
const context = ExecutionContext.default;
|
|
3629
|
-
for (let i = 0; i < behaviorsToUnbind.length; ++i) {
|
|
3630
|
-
behaviorsToUnbind[i].unbind(element, context);
|
|
3810
|
+
for (let i = 0, ii = sourceBehaviors.length; i < ii; ++i) {
|
|
3811
|
+
this.addBehavior(sourceBehaviors[i]);
|
|
3812
|
+
}
|
|
3631
3813
|
}
|
|
3632
3814
|
}
|
|
3633
3815
|
}
|
|
3634
3816
|
/**
|
|
3635
3817
|
* Runs connected lifecycle behavior on the associated element.
|
|
3636
3818
|
*/
|
|
3637
|
-
|
|
3819
|
+
connect() {
|
|
3638
3820
|
if (this._isConnected) {
|
|
3639
3821
|
return;
|
|
3640
3822
|
}
|
|
3641
|
-
const element = this.element;
|
|
3642
|
-
const context = ExecutionContext.default;
|
|
3643
3823
|
if (this.needsInitialization) {
|
|
3644
3824
|
this.finishInitialization();
|
|
3645
3825
|
}
|
|
3646
3826
|
else if (this.view !== null) {
|
|
3647
|
-
this.view.bind(
|
|
3827
|
+
this.view.bind(this.source);
|
|
3648
3828
|
}
|
|
3649
3829
|
const behaviors = this.behaviors;
|
|
3650
3830
|
if (behaviors !== null) {
|
|
3651
|
-
for (const
|
|
3652
|
-
|
|
3831
|
+
for (const key of behaviors.keys()) {
|
|
3832
|
+
key.connectedCallback && key.connectedCallback(this);
|
|
3653
3833
|
}
|
|
3654
3834
|
}
|
|
3655
3835
|
this.setIsConnected(true);
|
|
@@ -3657,21 +3837,18 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3657
3837
|
/**
|
|
3658
3838
|
* Runs disconnected lifecycle behavior on the associated element.
|
|
3659
3839
|
*/
|
|
3660
|
-
|
|
3840
|
+
disconnect() {
|
|
3661
3841
|
if (!this._isConnected) {
|
|
3662
3842
|
return;
|
|
3663
3843
|
}
|
|
3664
3844
|
this.setIsConnected(false);
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
view.unbind();
|
|
3845
|
+
if (this.view !== null) {
|
|
3846
|
+
this.view.unbind();
|
|
3668
3847
|
}
|
|
3669
3848
|
const behaviors = this.behaviors;
|
|
3670
3849
|
if (behaviors !== null) {
|
|
3671
|
-
const
|
|
3672
|
-
|
|
3673
|
-
for (const behavior of behaviors.keys()) {
|
|
3674
|
-
behavior.unbind(element, context);
|
|
3850
|
+
for (const key of behaviors.keys()) {
|
|
3851
|
+
key.disconnectedCallback && key.disconnectedCallback(this);
|
|
3675
3852
|
}
|
|
3676
3853
|
}
|
|
3677
3854
|
}
|
|
@@ -3684,7 +3861,7 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3684
3861
|
onAttributeChangedCallback(name, oldValue, newValue) {
|
|
3685
3862
|
const attrDef = this.definition.attributeLookup[name];
|
|
3686
3863
|
if (attrDef !== void 0) {
|
|
3687
|
-
attrDef.onAttributeChangedCallback(this.
|
|
3864
|
+
attrDef.onAttributeChangedCallback(this.source, newValue);
|
|
3688
3865
|
}
|
|
3689
3866
|
}
|
|
3690
3867
|
/**
|
|
@@ -3697,12 +3874,12 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3697
3874
|
*/
|
|
3698
3875
|
emit(type, detail, options) {
|
|
3699
3876
|
if (this._isConnected) {
|
|
3700
|
-
return this.
|
|
3877
|
+
return this.source.dispatchEvent(new CustomEvent(type, Object.assign(Object.assign({ detail }, defaultEventOptions), options)));
|
|
3701
3878
|
}
|
|
3702
3879
|
return false;
|
|
3703
3880
|
}
|
|
3704
3881
|
finishInitialization() {
|
|
3705
|
-
const element = this.
|
|
3882
|
+
const element = this.source;
|
|
3706
3883
|
const boundObservables = this.boundObservables;
|
|
3707
3884
|
// If we have any observables that were bound, re-apply their values.
|
|
3708
3885
|
if (boundObservables !== null) {
|
|
@@ -3714,15 +3891,15 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3714
3891
|
this.boundObservables = null;
|
|
3715
3892
|
}
|
|
3716
3893
|
this.renderTemplate(this.template);
|
|
3717
|
-
this.addStyles(this.
|
|
3894
|
+
this.addStyles(this.mainStyles);
|
|
3718
3895
|
this.needsInitialization = false;
|
|
3719
3896
|
}
|
|
3720
3897
|
renderTemplate(template) {
|
|
3721
3898
|
var _a;
|
|
3722
|
-
const element = this.element;
|
|
3723
3899
|
// When getting the host to render to, we start by looking
|
|
3724
3900
|
// up the shadow root. If there isn't one, then that means
|
|
3725
3901
|
// we're doing a Light DOM render to the element's direct children.
|
|
3902
|
+
const element = this.source;
|
|
3726
3903
|
const host = (_a = getShadowRoot(element)) !== null && _a !== void 0 ? _a : element;
|
|
3727
3904
|
if (this.view !== null) {
|
|
3728
3905
|
// If there's already a view, we need to unbind and remove through dispose.
|
|
@@ -3739,6 +3916,8 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3739
3916
|
if (template) {
|
|
3740
3917
|
// If a new template was provided, render it.
|
|
3741
3918
|
this.view = template.render(element, host, element);
|
|
3919
|
+
this.view.sourceLifetime =
|
|
3920
|
+
SourceLifetime.coupled;
|
|
3742
3921
|
}
|
|
3743
3922
|
}
|
|
3744
3923
|
/**
|
|
@@ -3758,31 +3937,136 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3758
3937
|
if (definition === void 0) {
|
|
3759
3938
|
throw FAST.error(1401 /* Message.missingElementDefinition */);
|
|
3760
3939
|
}
|
|
3761
|
-
return (element.$fastController = new
|
|
3940
|
+
return (element.$fastController = new ElementController(element, definition));
|
|
3941
|
+
}
|
|
3942
|
+
}
|
|
3943
|
+
/**
|
|
3944
|
+
* Converts a styleTarget into the operative target. When the provided target is an Element
|
|
3945
|
+
* that is a FASTElement, the function will return the ShadowRoot for that element. Otherwise,
|
|
3946
|
+
* it will return the root node for the element.
|
|
3947
|
+
* @param target
|
|
3948
|
+
* @returns
|
|
3949
|
+
*/
|
|
3950
|
+
function normalizeStyleTarget(target) {
|
|
3951
|
+
var _a;
|
|
3952
|
+
if ("adoptedStyleSheets" in target) {
|
|
3953
|
+
return target;
|
|
3954
|
+
}
|
|
3955
|
+
else {
|
|
3956
|
+
return ((_a = getShadowRoot(target)) !== null && _a !== void 0 ? _a : target.getRootNode());
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
// Default StyleStrategy implementations are defined in this module because they
|
|
3960
|
+
// require access to element shadowRoots, and we don't want to leak shadowRoot
|
|
3961
|
+
// objects out of this module.
|
|
3962
|
+
/**
|
|
3963
|
+
* https://wicg.github.io/construct-stylesheets/
|
|
3964
|
+
* https://developers.google.com/web/updates/2019/02/constructable-stylesheets
|
|
3965
|
+
*
|
|
3966
|
+
* @internal
|
|
3967
|
+
*/
|
|
3968
|
+
class AdoptedStyleSheetsStrategy {
|
|
3969
|
+
constructor(styles) {
|
|
3970
|
+
const styleSheetCache = AdoptedStyleSheetsStrategy.styleSheetCache;
|
|
3971
|
+
this.sheets = styles.map((x) => {
|
|
3972
|
+
if (x instanceof CSSStyleSheet) {
|
|
3973
|
+
return x;
|
|
3974
|
+
}
|
|
3975
|
+
let sheet = styleSheetCache.get(x);
|
|
3976
|
+
if (sheet === void 0) {
|
|
3977
|
+
sheet = new CSSStyleSheet();
|
|
3978
|
+
sheet.replaceSync(x);
|
|
3979
|
+
styleSheetCache.set(x, sheet);
|
|
3980
|
+
}
|
|
3981
|
+
return sheet;
|
|
3982
|
+
});
|
|
3983
|
+
}
|
|
3984
|
+
addStylesTo(target) {
|
|
3985
|
+
const t = normalizeStyleTarget(target);
|
|
3986
|
+
t.adoptedStyleSheets = [...t.adoptedStyleSheets, ...this.sheets];
|
|
3987
|
+
}
|
|
3988
|
+
removeStylesFrom(target) {
|
|
3989
|
+
const t = normalizeStyleTarget(target);
|
|
3990
|
+
const sheets = this.sheets;
|
|
3991
|
+
t.adoptedStyleSheets = t.adoptedStyleSheets.filter((x) => sheets.indexOf(x) === -1);
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3994
|
+
AdoptedStyleSheetsStrategy.styleSheetCache = new Map();
|
|
3995
|
+
let id = 0;
|
|
3996
|
+
const nextStyleId = () => `fast-${++id}`;
|
|
3997
|
+
function usableStyleTarget(target) {
|
|
3998
|
+
return target === document ? document.body : target;
|
|
3999
|
+
}
|
|
4000
|
+
/**
|
|
4001
|
+
* @internal
|
|
4002
|
+
*/
|
|
4003
|
+
class StyleElementStrategy {
|
|
4004
|
+
constructor(styles) {
|
|
4005
|
+
this.styles = styles;
|
|
4006
|
+
this.styleClass = nextStyleId();
|
|
4007
|
+
}
|
|
4008
|
+
addStylesTo(target) {
|
|
4009
|
+
target = usableStyleTarget(normalizeStyleTarget(target));
|
|
4010
|
+
const styles = this.styles;
|
|
4011
|
+
const styleClass = this.styleClass;
|
|
4012
|
+
for (let i = 0; i < styles.length; i++) {
|
|
4013
|
+
const element = document.createElement("style");
|
|
4014
|
+
element.innerHTML = styles[i];
|
|
4015
|
+
element.className = styleClass;
|
|
4016
|
+
target.append(element);
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
4019
|
+
removeStylesFrom(target) {
|
|
4020
|
+
target = usableStyleTarget(normalizeStyleTarget(target));
|
|
4021
|
+
const styles = target.querySelectorAll(`.${this.styleClass}`);
|
|
4022
|
+
styles[0].parentNode;
|
|
4023
|
+
for (let i = 0, ii = styles.length; i < ii; ++i) {
|
|
4024
|
+
target.removeChild(styles[i]);
|
|
4025
|
+
}
|
|
3762
4026
|
}
|
|
3763
4027
|
}
|
|
4028
|
+
ElementStyles.setDefaultStrategy(ElementStyles.supportsAdoptedStyleSheets
|
|
4029
|
+
? AdoptedStyleSheetsStrategy
|
|
4030
|
+
: StyleElementStrategy);
|
|
3764
4031
|
|
|
3765
4032
|
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
3766
4033
|
function createFASTElement(BaseType) {
|
|
3767
|
-
|
|
4034
|
+
const type = class extends BaseType {
|
|
3768
4035
|
constructor() {
|
|
3769
4036
|
/* eslint-disable-next-line */
|
|
3770
4037
|
super();
|
|
3771
|
-
|
|
4038
|
+
ElementController.forCustomElement(this);
|
|
3772
4039
|
}
|
|
3773
4040
|
$emit(type, detail, options) {
|
|
3774
4041
|
return this.$fastController.emit(type, detail, options);
|
|
3775
4042
|
}
|
|
3776
4043
|
connectedCallback() {
|
|
3777
|
-
this.$fastController.
|
|
4044
|
+
this.$fastController.connect();
|
|
3778
4045
|
}
|
|
3779
4046
|
disconnectedCallback() {
|
|
3780
|
-
this.$fastController.
|
|
4047
|
+
this.$fastController.disconnect();
|
|
3781
4048
|
}
|
|
3782
4049
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
3783
4050
|
this.$fastController.onAttributeChangedCallback(name, oldValue, newValue);
|
|
3784
4051
|
}
|
|
3785
4052
|
};
|
|
4053
|
+
FASTElementDefinition.registerBaseType(type);
|
|
4054
|
+
return type;
|
|
4055
|
+
}
|
|
4056
|
+
function compose(type, nameOrDef) {
|
|
4057
|
+
if (isFunction(type)) {
|
|
4058
|
+
return FASTElementDefinition.compose(type, nameOrDef);
|
|
4059
|
+
}
|
|
4060
|
+
return FASTElementDefinition.compose(this, type);
|
|
4061
|
+
}
|
|
4062
|
+
function define(type, nameOrDef) {
|
|
4063
|
+
if (isFunction(type)) {
|
|
4064
|
+
return FASTElementDefinition.compose(type, nameOrDef).define().type;
|
|
4065
|
+
}
|
|
4066
|
+
return FASTElementDefinition.compose(this, type).define().type;
|
|
4067
|
+
}
|
|
4068
|
+
function from(BaseType) {
|
|
4069
|
+
return createFASTElement(BaseType);
|
|
3786
4070
|
}
|
|
3787
4071
|
/**
|
|
3788
4072
|
* A minimal base class for FASTElements that also provides
|
|
@@ -3795,18 +4079,19 @@ const FASTElement = Object.assign(createFASTElement(HTMLElement), {
|
|
|
3795
4079
|
* provided base type.
|
|
3796
4080
|
* @param BaseType - The base element type to inherit from.
|
|
3797
4081
|
*/
|
|
3798
|
-
from
|
|
3799
|
-
return createFASTElement(BaseType);
|
|
3800
|
-
},
|
|
4082
|
+
from,
|
|
3801
4083
|
/**
|
|
3802
4084
|
* Defines a platform custom element based on the provided type and definition.
|
|
3803
4085
|
* @param type - The custom element type to define.
|
|
3804
4086
|
* @param nameOrDef - The name of the element to define or a definition object
|
|
3805
4087
|
* that describes the element to define.
|
|
3806
4088
|
*/
|
|
3807
|
-
define
|
|
3808
|
-
|
|
3809
|
-
|
|
4089
|
+
define,
|
|
4090
|
+
/**
|
|
4091
|
+
* Defines metadata for a FASTElement which can be used to later define the element.
|
|
4092
|
+
* @public
|
|
4093
|
+
*/
|
|
4094
|
+
compose,
|
|
3810
4095
|
});
|
|
3811
4096
|
/**
|
|
3812
4097
|
* Decorator: Defines a platform custom element based on `FASTElement`.
|
|
@@ -3817,8 +4102,8 @@ const FASTElement = Object.assign(createFASTElement(HTMLElement), {
|
|
|
3817
4102
|
function customElement(nameOrDef) {
|
|
3818
4103
|
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
3819
4104
|
return function (type) {
|
|
3820
|
-
|
|
4105
|
+
define(type, nameOrDef);
|
|
3821
4106
|
};
|
|
3822
4107
|
}
|
|
3823
4108
|
|
|
3824
|
-
export {
|
|
4109
|
+
export { ArrayObserver, Aspect, AttributeConfiguration, AttributeDefinition, Binding, CSSDirective, ChildrenDirective, Compiler, DOM, ElementController, ElementStyles, ExecutionContext, FAST, FASTElement, FASTElementDefinition, HTMLBindingDirective, HTMLDirective, HTMLView, Markup, NodeObservationDirective, Observable, Parser, PropertyChangeNotifier, RefDirective, RepeatBehavior, RepeatDirective, SlottedDirective, SourceLifetime, Splice, SpliceStrategy, SpliceStrategySupport, StatelessAttachedAttributeDirective, SubscriberSet, Updates, ViewBehaviorOrchestrator, ViewTemplate, attr, bind, booleanConverter, children, createMetadataLocator, createTypeRegistry, css, cssDirective, cssPartial, customElement, elements, emptyArray, html, htmlDirective, lengthOf, listener, normalizeBinding, nullableNumberConverter, observable, oneTime, ref, repeat, slotted, volatile, when };
|