@microsoft/fast-element 2.0.0-beta.2 → 2.0.0-beta.21
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 +509 -0
- package/CHANGELOG.md +189 -1
- package/dist/dts/components/attributes.d.ts +15 -0
- package/dist/dts/components/{controller.d.ts → element-controller.d.ts} +74 -28
- package/dist/dts/components/fast-definitions.d.ts +41 -9
- package/dist/dts/components/fast-element.d.ts +14 -26
- package/dist/dts/components/hydration.d.ts +14 -0
- package/dist/{esm/observation/behavior.js → dts/components/install-hydration.d.ts} +0 -0
- package/dist/dts/context.d.ts +7 -7
- package/dist/dts/di/di.d.ts +894 -0
- package/dist/dts/dom-policy.d.ts +83 -0
- package/dist/dts/dom.d.ts +100 -0
- package/dist/dts/index.d.ts +5 -4
- package/dist/dts/index.rollup.d.ts +0 -1
- package/dist/dts/index.rollup.debug.d.ts +0 -1
- package/dist/dts/interfaces.d.ts +62 -80
- package/dist/dts/metadata.d.ts +5 -5
- package/dist/dts/observation/observable.d.ts +99 -54
- package/dist/dts/pending-task.d.ts +32 -0
- package/dist/dts/platform.d.ts +8 -1
- package/dist/dts/polyfills.d.ts +0 -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/css.d.ts +0 -5
- package/dist/dts/styles/element-styles.d.ts +10 -17
- package/dist/dts/styles/host.d.ts +68 -0
- package/dist/dts/styles/style-strategy.d.ts +42 -0
- package/dist/dts/templating/binding-signal.d.ts +12 -27
- package/dist/dts/templating/binding-two-way.d.ts +22 -37
- package/dist/dts/templating/binding.d.ts +76 -208
- package/dist/dts/templating/children.d.ts +1 -1
- package/dist/dts/templating/compiler.d.ts +11 -13
- package/dist/dts/templating/html-directive.d.ts +91 -97
- package/dist/dts/templating/node-observation.d.ts +15 -6
- package/dist/dts/templating/ref.d.ts +7 -11
- package/dist/dts/templating/render.d.ts +296 -0
- package/dist/dts/templating/repeat.d.ts +23 -34
- package/dist/dts/templating/slotted.d.ts +1 -1
- package/dist/dts/templating/template.d.ts +92 -14
- package/dist/dts/templating/view.d.ts +81 -11
- 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 +14 -0
- package/dist/dts/testing/fixture.d.ts +84 -0
- package/dist/dts/testing/timeout.d.ts +7 -0
- package/dist/dts/utilities.d.ts +55 -19
- package/dist/esm/components/attributes.js +28 -5
- package/dist/esm/components/{controller.js → element-controller.js} +238 -137
- package/dist/esm/components/fast-definitions.js +38 -30
- package/dist/esm/components/fast-element.js +27 -16
- package/dist/esm/components/hydration.js +35 -0
- package/dist/esm/components/install-hydration.js +2 -0
- package/dist/esm/context.js +7 -3
- package/dist/esm/debug.js +41 -5
- package/dist/esm/di/di.js +1430 -0
- package/dist/esm/dom-policy.js +345 -0
- package/dist/esm/dom.js +101 -0
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.rollup.debug.js +3 -1
- package/dist/esm/index.rollup.js +3 -1
- package/dist/esm/interfaces.js +52 -0
- package/dist/esm/metadata.js +9 -8
- package/dist/esm/observation/arrays.js +303 -2
- package/dist/esm/observation/observable.js +88 -142
- package/dist/esm/observation/update-queue.js +2 -2
- package/dist/esm/pending-task.js +28 -0
- package/dist/esm/platform.js +28 -3
- package/dist/esm/polyfills.js +3 -61
- 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 -9
- package/dist/esm/styles/element-styles.js +14 -33
- package/dist/esm/styles/host.js +1 -0
- package/dist/esm/styles/style-strategy.js +1 -0
- package/dist/esm/templating/binding-signal.js +67 -62
- package/dist/esm/templating/binding-two-way.js +72 -39
- package/dist/esm/templating/binding.js +142 -286
- package/dist/esm/templating/children.js +8 -4
- package/dist/esm/templating/compiler.js +59 -43
- package/dist/esm/templating/html-directive.js +56 -75
- package/dist/esm/templating/node-observation.js +20 -13
- package/dist/esm/templating/ref.js +4 -12
- package/dist/esm/templating/render.js +402 -0
- package/dist/esm/templating/repeat.js +88 -75
- package/dist/esm/templating/template.js +132 -60
- package/dist/esm/templating/view.js +113 -29
- package/dist/esm/templating/when.js +5 -4
- package/dist/esm/testing/exports.js +3 -0
- package/dist/esm/testing/fakes.js +107 -0
- package/dist/esm/testing/fixture.js +86 -0
- package/dist/esm/testing/timeout.js +24 -0
- package/dist/esm/utilities.js +97 -96
- package/dist/fast-element.api.json +9741 -8201
- package/dist/fast-element.d.ts +889 -646
- package/dist/fast-element.debug.js +2001 -1167
- package/dist/fast-element.debug.min.js +1 -1
- package/dist/fast-element.js +1907 -1109
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +913 -703
- package/docs/api-report.md +331 -258
- package/package.json +38 -16
- 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/dts/templating/dom.d.ts +0 -41
- package/dist/esm/hooks.js +0 -32
- package/dist/esm/observation/splice-strategies.js +0 -400
- package/dist/esm/templating/dom.js +0 -49
|
@@ -1,10 +1,138 @@
|
|
|
1
|
+
if (globalThis.FAST === void 0) {
|
|
2
|
+
Reflect.defineProperty(globalThis, "FAST", {
|
|
3
|
+
value: Object.create(null),
|
|
4
|
+
configurable: false,
|
|
5
|
+
enumerable: false,
|
|
6
|
+
writable: false,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
const FAST$1 = globalThis.FAST;
|
|
10
|
+
const debugMessages = {
|
|
11
|
+
[1101 /* needsArrayObservation */]: "Must call enableArrayObservation before observing arrays.",
|
|
12
|
+
[1201 /* onlySetDOMPolicyOnce */]: "The DOM Policy can only be set once.",
|
|
13
|
+
[1202 /* bindingInnerHTMLRequiresTrustedTypes */]: "To bind innerHTML, you must use a TrustedTypesPolicy.",
|
|
14
|
+
[1203 /* twoWayBindingRequiresObservables */]: "View=>Model update skipped. To use twoWay binding, the target property must be observable.",
|
|
15
|
+
[1204 /* hostBindingWithoutHost */]: "No host element is present. Cannot bind host with ${name}.",
|
|
16
|
+
[1205 /* unsupportedBindingBehavior */]: "The requested binding behavior is not supported by the binding engine.",
|
|
17
|
+
[1206 /* directCallToHTMLTagNotAllowed */]: "Calling html`` as a normal function invalidates the security guarantees provided by FAST.",
|
|
18
|
+
[1207 /* onlySetTemplatePolicyOnce */]: "The DOM Policy for an HTML template can only be set once.",
|
|
19
|
+
[1208 /* cannotSetTemplatePolicyAfterCompilation */]: "The DOM Policy cannot be set after a template is compiled.",
|
|
20
|
+
[1209 /* blockedByDOMPolicy */]: "'${aspectName}' on '${tagName}' is blocked by the current DOMPolicy.",
|
|
21
|
+
[1401 /* missingElementDefinition */]: "Missing FASTElement definition.",
|
|
22
|
+
[1501 /* noRegistrationForContext */]: "No registration for Context/Interface '${name}'.",
|
|
23
|
+
[1502 /* noFactoryForResolver */]: "Dependency injection resolver for '${key}' returned a null factory.",
|
|
24
|
+
[1503 /* invalidResolverStrategy */]: "Invalid dependency injection resolver strategy specified '${strategy}'.",
|
|
25
|
+
[1504 /* cannotAutoregisterDependency */]: "Unable to autoregister dependency.",
|
|
26
|
+
[1505 /* cannotResolveKey */]: "Unable to resolve dependency injection key '${key}'.",
|
|
27
|
+
[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.",
|
|
28
|
+
[1507 /* cannotJITRegisterNonConstructor */]: "Attempted to jitRegister something that is not a constructor '${value}'. Did you forget to register this dependency?",
|
|
29
|
+
[1508 /* cannotJITRegisterIntrinsic */]: "Attempted to jitRegister an intrinsic type '${value}'. Did you forget to add @inject(Key)?",
|
|
30
|
+
[1509 /* cannotJITRegisterInterface */]: "Attempted to jitRegister an interface '${value}'.",
|
|
31
|
+
[1510 /* invalidResolver */]: "A valid resolver was not returned from the register method.",
|
|
32
|
+
[1511 /* invalidKey */]: "Key/value cannot be null or undefined. Are you trying to inject/register something that doesn't exist with DI?",
|
|
33
|
+
[1512 /* noDefaultResolver */]: "'${key}' not registered. Did you forget to add @singleton()?",
|
|
34
|
+
[1513 /* cyclicDependency */]: "Cyclic dependency found '${name}'.",
|
|
35
|
+
[1514 /* connectUpdateRequiresController */]: "Injected properties that are updated on changes to DOM connectivity require the target object to be an instance of FASTElement.",
|
|
36
|
+
};
|
|
37
|
+
const allPlaceholders = /(\$\{\w+?})/g;
|
|
38
|
+
const placeholder = /\$\{(\w+?)}/g;
|
|
39
|
+
const noValues = Object.freeze({});
|
|
40
|
+
function formatMessage(message, values) {
|
|
41
|
+
return message
|
|
42
|
+
.split(allPlaceholders)
|
|
43
|
+
.map(v => {
|
|
44
|
+
var _a;
|
|
45
|
+
const replaced = v.replace(placeholder, "$1");
|
|
46
|
+
return String((_a = values[replaced]) !== null && _a !== void 0 ? _a : v);
|
|
47
|
+
})
|
|
48
|
+
.join("");
|
|
49
|
+
}
|
|
50
|
+
Object.assign(FAST$1, {
|
|
51
|
+
addMessages(messages) {
|
|
52
|
+
Object.assign(debugMessages, messages);
|
|
53
|
+
},
|
|
54
|
+
warn(code, values = noValues) {
|
|
55
|
+
var _a;
|
|
56
|
+
const message = (_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Warning";
|
|
57
|
+
console.warn(formatMessage(message, values));
|
|
58
|
+
},
|
|
59
|
+
error(code, values = noValues) {
|
|
60
|
+
var _a;
|
|
61
|
+
const message = (_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Error";
|
|
62
|
+
return new Error(formatMessage(message, values));
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
let kernelMode;
|
|
67
|
+
const kernelAttr = "fast-kernel";
|
|
68
|
+
try {
|
|
69
|
+
if (document.currentScript) {
|
|
70
|
+
kernelMode = document.currentScript.getAttribute(kernelAttr);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const scripts = document.getElementsByTagName("script");
|
|
74
|
+
const currentScript = scripts[scripts.length - 1];
|
|
75
|
+
kernelMode = currentScript.getAttribute(kernelAttr);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
kernelMode = "isolate";
|
|
80
|
+
}
|
|
81
|
+
let KernelServiceId;
|
|
82
|
+
switch (kernelMode) {
|
|
83
|
+
case "share": // share the kernel across major versions
|
|
84
|
+
KernelServiceId = Object.freeze({
|
|
85
|
+
updateQueue: 1,
|
|
86
|
+
observable: 2,
|
|
87
|
+
contextEvent: 3,
|
|
88
|
+
elementRegistry: 4,
|
|
89
|
+
});
|
|
90
|
+
break;
|
|
91
|
+
case "share-v2": // only share the kernel with other v2 instances
|
|
92
|
+
KernelServiceId = Object.freeze({
|
|
93
|
+
updateQueue: 1.2,
|
|
94
|
+
observable: 2.2,
|
|
95
|
+
contextEvent: 3.2,
|
|
96
|
+
elementRegistry: 4.2,
|
|
97
|
+
});
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
// fully isolate the kernel from all other FAST instances
|
|
101
|
+
const postfix = `-${Math.random().toString(36).substring(2, 8)}`;
|
|
102
|
+
KernelServiceId = Object.freeze({
|
|
103
|
+
updateQueue: `1.2${postfix}`,
|
|
104
|
+
observable: `2.2${postfix}`,
|
|
105
|
+
contextEvent: `3.2${postfix}`,
|
|
106
|
+
elementRegistry: `4.2${postfix}`,
|
|
107
|
+
});
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Determines whether or not an object is a function.
|
|
112
|
+
* @internal
|
|
113
|
+
*/
|
|
114
|
+
const isFunction = (object) => typeof object === "function";
|
|
115
|
+
/**
|
|
116
|
+
* Determines whether or not an object is a string.
|
|
117
|
+
* @internal
|
|
118
|
+
*/
|
|
119
|
+
const isString = (object) => typeof object === "string";
|
|
120
|
+
/**
|
|
121
|
+
* A function which does nothing.
|
|
122
|
+
* @internal
|
|
123
|
+
*/
|
|
124
|
+
const noop = () => void 0;
|
|
125
|
+
|
|
126
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
1
127
|
(function ensureGlobalThis() {
|
|
2
128
|
if (typeof globalThis !== "undefined") {
|
|
3
129
|
// We're running in a modern environment.
|
|
4
130
|
return;
|
|
5
131
|
}
|
|
132
|
+
// @ts-ignore
|
|
6
133
|
if (typeof global !== "undefined") {
|
|
7
134
|
// We're running in NodeJS
|
|
135
|
+
// @ts-ignore
|
|
8
136
|
global.globalThis = global;
|
|
9
137
|
}
|
|
10
138
|
else if (typeof self !== "undefined") {
|
|
@@ -22,98 +150,8 @@
|
|
|
22
150
|
result.globalThis = result;
|
|
23
151
|
}
|
|
24
152
|
})();
|
|
25
|
-
// API-only Polyfill for trustedTypes
|
|
26
|
-
if (!globalThis.trustedTypes) {
|
|
27
|
-
globalThis.trustedTypes = {
|
|
28
|
-
createPolicy: (n, r) => r,
|
|
29
|
-
};
|
|
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
|
-
|
|
87
|
-
if (globalThis.FAST === void 0) {
|
|
88
|
-
Reflect.defineProperty(globalThis, "FAST", {
|
|
89
|
-
value: Object.create(null),
|
|
90
|
-
configurable: false,
|
|
91
|
-
enumerable: false,
|
|
92
|
-
writable: false,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
const FAST$1 = globalThis.FAST;
|
|
96
|
-
const debugMessages = {
|
|
97
|
-
[1101 /* needsArrayObservation */]: "Must call enableArrayObservation before observing arrays.",
|
|
98
|
-
[1201 /* onlySetHTMLPolicyOnce */]: "The HTML policy can only be set once.",
|
|
99
|
-
[1202 /* bindingInnerHTMLRequiresTrustedTypes */]: "To bind innerHTML, you must use a TrustedTypesPolicy.",
|
|
100
|
-
[1401 /* missingElementDefinition */]: "Missing FASTElement definition.",
|
|
101
|
-
};
|
|
102
|
-
Object.assign(FAST$1, {
|
|
103
|
-
addMessages(messages) {
|
|
104
|
-
Object.assign(debugMessages, messages);
|
|
105
|
-
},
|
|
106
|
-
warn(code, ...args) {
|
|
107
|
-
var _a;
|
|
108
|
-
console.warn((_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Warning");
|
|
109
|
-
},
|
|
110
|
-
error(code, ...args) {
|
|
111
|
-
var _a;
|
|
112
|
-
return new Error((_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Error");
|
|
113
|
-
},
|
|
114
|
-
});
|
|
115
153
|
|
|
116
|
-
// ensure FAST global - duplicated
|
|
154
|
+
// ensure FAST global - duplicated debug.ts
|
|
117
155
|
const propConfig = {
|
|
118
156
|
configurable: false,
|
|
119
157
|
enumerable: false,
|
|
@@ -124,7 +162,7 @@ if (globalThis.FAST === void 0) {
|
|
|
124
162
|
}
|
|
125
163
|
/**
|
|
126
164
|
* The FAST global.
|
|
127
|
-
* @
|
|
165
|
+
* @public
|
|
128
166
|
*/
|
|
129
167
|
const FAST = globalThis.FAST;
|
|
130
168
|
if (FAST.getById === void 0) {
|
|
@@ -141,7 +179,7 @@ if (FAST.error === void 0) {
|
|
|
141
179
|
Object.assign(FAST, {
|
|
142
180
|
warn() { },
|
|
143
181
|
error(code) {
|
|
144
|
-
return new Error(`
|
|
182
|
+
return new Error(`Error ${code}`);
|
|
145
183
|
},
|
|
146
184
|
addMessages() { },
|
|
147
185
|
});
|
|
@@ -172,25 +210,482 @@ function createTypeRegistry() {
|
|
|
172
210
|
return typeToDefinition.get(key);
|
|
173
211
|
},
|
|
174
212
|
getForInstance(object) {
|
|
213
|
+
if (object === null || object === void 0) {
|
|
214
|
+
return void 0;
|
|
215
|
+
}
|
|
175
216
|
return typeToDefinition.get(object.constructor);
|
|
176
217
|
},
|
|
177
218
|
});
|
|
178
219
|
}
|
|
179
|
-
|
|
180
220
|
/**
|
|
221
|
+
* Creates a function capable of locating metadata associated with a type.
|
|
222
|
+
* @returns A metadata locator function.
|
|
181
223
|
* @internal
|
|
182
224
|
*/
|
|
183
|
-
|
|
225
|
+
function createMetadataLocator() {
|
|
226
|
+
const metadataLookup = new WeakMap();
|
|
227
|
+
return function (target) {
|
|
228
|
+
let metadata = metadataLookup.get(target);
|
|
229
|
+
if (metadata === void 0) {
|
|
230
|
+
let currentTarget = Reflect.getPrototypeOf(target);
|
|
231
|
+
while (metadata === void 0 && currentTarget !== null) {
|
|
232
|
+
metadata = metadataLookup.get(currentTarget);
|
|
233
|
+
currentTarget = Reflect.getPrototypeOf(currentTarget);
|
|
234
|
+
}
|
|
235
|
+
metadata = metadata === void 0 ? [] : metadata.slice(0);
|
|
236
|
+
metadataLookup.set(target, metadata);
|
|
237
|
+
}
|
|
238
|
+
return metadata;
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
184
242
|
/**
|
|
185
|
-
*
|
|
243
|
+
* The type of HTML aspect to target.
|
|
244
|
+
* @public
|
|
186
245
|
*/
|
|
187
|
-
const
|
|
246
|
+
const DOMAspect = Object.freeze({
|
|
247
|
+
/**
|
|
248
|
+
* Not aspected.
|
|
249
|
+
*/
|
|
250
|
+
none: 0,
|
|
251
|
+
/**
|
|
252
|
+
* An attribute.
|
|
253
|
+
*/
|
|
254
|
+
attribute: 1,
|
|
255
|
+
/**
|
|
256
|
+
* A boolean attribute.
|
|
257
|
+
*/
|
|
258
|
+
booleanAttribute: 2,
|
|
259
|
+
/**
|
|
260
|
+
* A property.
|
|
261
|
+
*/
|
|
262
|
+
property: 3,
|
|
263
|
+
/**
|
|
264
|
+
* Content
|
|
265
|
+
*/
|
|
266
|
+
content: 4,
|
|
267
|
+
/**
|
|
268
|
+
* A token list.
|
|
269
|
+
*/
|
|
270
|
+
tokenList: 5,
|
|
271
|
+
/**
|
|
272
|
+
* An event.
|
|
273
|
+
*/
|
|
274
|
+
event: 6,
|
|
275
|
+
});
|
|
276
|
+
const createHTML$1 = html => html;
|
|
277
|
+
const fastTrustedType = globalThis.trustedTypes
|
|
278
|
+
? globalThis.trustedTypes.createPolicy("fast-html", { createHTML: createHTML$1 })
|
|
279
|
+
: { createHTML: createHTML$1 };
|
|
280
|
+
let defaultPolicy = Object.freeze({
|
|
281
|
+
createHTML(value) {
|
|
282
|
+
return fastTrustedType.createHTML(value);
|
|
283
|
+
},
|
|
284
|
+
protect(tagName, aspect, aspectName, sink) {
|
|
285
|
+
return sink;
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
const fastPolicy = defaultPolicy;
|
|
289
|
+
/**
|
|
290
|
+
* Common DOM APIs.
|
|
291
|
+
* @public
|
|
292
|
+
*/
|
|
293
|
+
const DOM = Object.freeze({
|
|
294
|
+
/**
|
|
295
|
+
* Gets the dom policy used by the templating system.
|
|
296
|
+
*/
|
|
297
|
+
get policy() {
|
|
298
|
+
return defaultPolicy;
|
|
299
|
+
},
|
|
300
|
+
/**
|
|
301
|
+
* Sets the dom policy used by the templating system.
|
|
302
|
+
* @param policy - The policy to set.
|
|
303
|
+
* @remarks
|
|
304
|
+
* This API can only be called once, for security reasons. It should be
|
|
305
|
+
* called by the application developer at the start of their program.
|
|
306
|
+
*/
|
|
307
|
+
setPolicy(value) {
|
|
308
|
+
if (defaultPolicy !== fastPolicy) {
|
|
309
|
+
throw FAST.error(1201 /* Message.onlySetDOMPolicyOnce */);
|
|
310
|
+
}
|
|
311
|
+
defaultPolicy = value;
|
|
312
|
+
},
|
|
313
|
+
/**
|
|
314
|
+
* Sets an attribute value on an element.
|
|
315
|
+
* @param element - The element to set the attribute value on.
|
|
316
|
+
* @param attributeName - The attribute name to set.
|
|
317
|
+
* @param value - The value of the attribute to set.
|
|
318
|
+
* @remarks
|
|
319
|
+
* If the value is `null` or `undefined`, the attribute is removed, otherwise
|
|
320
|
+
* it is set to the provided value using the standard `setAttribute` API.
|
|
321
|
+
*/
|
|
322
|
+
setAttribute(element, attributeName, value) {
|
|
323
|
+
value === null || value === undefined
|
|
324
|
+
? element.removeAttribute(attributeName)
|
|
325
|
+
: element.setAttribute(attributeName, value);
|
|
326
|
+
},
|
|
327
|
+
/**
|
|
328
|
+
* Sets a boolean attribute value.
|
|
329
|
+
* @param element - The element to set the boolean attribute value on.
|
|
330
|
+
* @param attributeName - The attribute name to set.
|
|
331
|
+
* @param value - The value of the attribute to set.
|
|
332
|
+
* @remarks
|
|
333
|
+
* If the value is true, the attribute is added; otherwise it is removed.
|
|
334
|
+
*/
|
|
335
|
+
setBooleanAttribute(element, attributeName, value) {
|
|
336
|
+
value
|
|
337
|
+
? element.setAttribute(attributeName, "")
|
|
338
|
+
: element.removeAttribute(attributeName);
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
function safeURL(tagName, aspect, aspectName, sink) {
|
|
343
|
+
return (target, name, value, ...rest) => {
|
|
344
|
+
if (isString(value)) {
|
|
345
|
+
value = value.replace("javascript:", "");
|
|
346
|
+
}
|
|
347
|
+
sink(target, name, value, ...rest);
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function block(tagName, aspect, aspectName, sink) {
|
|
351
|
+
throw FAST.error(1209 /* Message.blockedByDOMPolicy */, {
|
|
352
|
+
aspectName,
|
|
353
|
+
tagName: tagName !== null && tagName !== void 0 ? tagName : "text",
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
const defaultDOMElementGuards = {
|
|
357
|
+
a: {
|
|
358
|
+
[DOMAspect.attribute]: {
|
|
359
|
+
href: safeURL,
|
|
360
|
+
},
|
|
361
|
+
[DOMAspect.property]: {
|
|
362
|
+
href: safeURL,
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
area: {
|
|
366
|
+
[DOMAspect.attribute]: {
|
|
367
|
+
href: safeURL,
|
|
368
|
+
},
|
|
369
|
+
[DOMAspect.property]: {
|
|
370
|
+
href: safeURL,
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
button: {
|
|
374
|
+
[DOMAspect.attribute]: {
|
|
375
|
+
formaction: safeURL,
|
|
376
|
+
},
|
|
377
|
+
[DOMAspect.property]: {
|
|
378
|
+
formAction: safeURL,
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
embed: {
|
|
382
|
+
[DOMAspect.attribute]: {
|
|
383
|
+
src: block,
|
|
384
|
+
},
|
|
385
|
+
[DOMAspect.property]: {
|
|
386
|
+
src: block,
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
form: {
|
|
390
|
+
[DOMAspect.attribute]: {
|
|
391
|
+
action: safeURL,
|
|
392
|
+
},
|
|
393
|
+
[DOMAspect.property]: {
|
|
394
|
+
action: safeURL,
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
frame: {
|
|
398
|
+
[DOMAspect.attribute]: {
|
|
399
|
+
src: safeURL,
|
|
400
|
+
},
|
|
401
|
+
[DOMAspect.property]: {
|
|
402
|
+
src: safeURL,
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
iframe: {
|
|
406
|
+
[DOMAspect.attribute]: {
|
|
407
|
+
src: safeURL,
|
|
408
|
+
},
|
|
409
|
+
[DOMAspect.property]: {
|
|
410
|
+
src: safeURL,
|
|
411
|
+
srcdoc: block,
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
input: {
|
|
415
|
+
[DOMAspect.attribute]: {
|
|
416
|
+
formaction: safeURL,
|
|
417
|
+
},
|
|
418
|
+
[DOMAspect.property]: {
|
|
419
|
+
formAction: safeURL,
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
link: {
|
|
423
|
+
[DOMAspect.attribute]: {
|
|
424
|
+
href: block,
|
|
425
|
+
},
|
|
426
|
+
[DOMAspect.property]: {
|
|
427
|
+
href: block,
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
object: {
|
|
431
|
+
[DOMAspect.attribute]: {
|
|
432
|
+
codebase: block,
|
|
433
|
+
data: block,
|
|
434
|
+
},
|
|
435
|
+
[DOMAspect.property]: {
|
|
436
|
+
codeBase: block,
|
|
437
|
+
data: block,
|
|
438
|
+
},
|
|
439
|
+
},
|
|
440
|
+
script: {
|
|
441
|
+
[DOMAspect.attribute]: {
|
|
442
|
+
src: block,
|
|
443
|
+
text: block,
|
|
444
|
+
},
|
|
445
|
+
[DOMAspect.property]: {
|
|
446
|
+
src: block,
|
|
447
|
+
text: block,
|
|
448
|
+
innerText: block,
|
|
449
|
+
textContent: block,
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
style: {
|
|
453
|
+
[DOMAspect.property]: {
|
|
454
|
+
innerText: block,
|
|
455
|
+
textContent: block,
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
};
|
|
459
|
+
const blockedEvents = {
|
|
460
|
+
onabort: block,
|
|
461
|
+
onauxclick: block,
|
|
462
|
+
onbeforeinput: block,
|
|
463
|
+
onbeforematch: block,
|
|
464
|
+
onblur: block,
|
|
465
|
+
oncancel: block,
|
|
466
|
+
oncanplay: block,
|
|
467
|
+
oncanplaythrough: block,
|
|
468
|
+
onchange: block,
|
|
469
|
+
onclick: block,
|
|
470
|
+
onclose: block,
|
|
471
|
+
oncontextlost: block,
|
|
472
|
+
oncontextmenu: block,
|
|
473
|
+
oncontextrestored: block,
|
|
474
|
+
oncopy: block,
|
|
475
|
+
oncuechange: block,
|
|
476
|
+
oncut: block,
|
|
477
|
+
ondblclick: block,
|
|
478
|
+
ondrag: block,
|
|
479
|
+
ondragend: block,
|
|
480
|
+
ondragenter: block,
|
|
481
|
+
ondragleave: block,
|
|
482
|
+
ondragover: block,
|
|
483
|
+
ondragstart: block,
|
|
484
|
+
ondrop: block,
|
|
485
|
+
ondurationchange: block,
|
|
486
|
+
onemptied: block,
|
|
487
|
+
onended: block,
|
|
488
|
+
onerror: block,
|
|
489
|
+
onfocus: block,
|
|
490
|
+
onformdata: block,
|
|
491
|
+
oninput: block,
|
|
492
|
+
oninvalid: block,
|
|
493
|
+
onkeydown: block,
|
|
494
|
+
onkeypress: block,
|
|
495
|
+
onkeyup: block,
|
|
496
|
+
onload: block,
|
|
497
|
+
onloadeddata: block,
|
|
498
|
+
onloadedmetadata: block,
|
|
499
|
+
onloadstart: block,
|
|
500
|
+
onmousedown: block,
|
|
501
|
+
onmouseenter: block,
|
|
502
|
+
onmouseleave: block,
|
|
503
|
+
onmousemove: block,
|
|
504
|
+
onmouseout: block,
|
|
505
|
+
onmouseover: block,
|
|
506
|
+
onmouseup: block,
|
|
507
|
+
onpaste: block,
|
|
508
|
+
onpause: block,
|
|
509
|
+
onplay: block,
|
|
510
|
+
onplaying: block,
|
|
511
|
+
onprogress: block,
|
|
512
|
+
onratechange: block,
|
|
513
|
+
onreset: block,
|
|
514
|
+
onresize: block,
|
|
515
|
+
onscroll: block,
|
|
516
|
+
onsecuritypolicyviolation: block,
|
|
517
|
+
onseeked: block,
|
|
518
|
+
onseeking: block,
|
|
519
|
+
onselect: block,
|
|
520
|
+
onslotchange: block,
|
|
521
|
+
onstalled: block,
|
|
522
|
+
onsubmit: block,
|
|
523
|
+
onsuspend: block,
|
|
524
|
+
ontimeupdate: block,
|
|
525
|
+
ontoggle: block,
|
|
526
|
+
onvolumechange: block,
|
|
527
|
+
onwaiting: block,
|
|
528
|
+
onwebkitanimationend: block,
|
|
529
|
+
onwebkitanimationiteration: block,
|
|
530
|
+
onwebkitanimationstart: block,
|
|
531
|
+
onwebkittransitionend: block,
|
|
532
|
+
onwheel: block,
|
|
533
|
+
};
|
|
534
|
+
const defaultDOMGuards = {
|
|
535
|
+
elements: defaultDOMElementGuards,
|
|
536
|
+
aspects: {
|
|
537
|
+
[DOMAspect.attribute]: Object.assign({}, blockedEvents),
|
|
538
|
+
[DOMAspect.property]: Object.assign({ innerHTML: block }, blockedEvents),
|
|
539
|
+
[DOMAspect.event]: Object.assign({}, blockedEvents),
|
|
540
|
+
},
|
|
541
|
+
};
|
|
542
|
+
function createDomSinkGuards(config, defaults) {
|
|
543
|
+
const result = {};
|
|
544
|
+
for (const name in defaults) {
|
|
545
|
+
const overrideValue = config[name];
|
|
546
|
+
const defaultValue = defaults[name];
|
|
547
|
+
switch (overrideValue) {
|
|
548
|
+
case null:
|
|
549
|
+
// remove the default
|
|
550
|
+
break;
|
|
551
|
+
case undefined:
|
|
552
|
+
// keep the default
|
|
553
|
+
result[name] = defaultValue;
|
|
554
|
+
break;
|
|
555
|
+
default:
|
|
556
|
+
// override the default
|
|
557
|
+
result[name] = overrideValue;
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
// add any new sinks that were not overrides
|
|
562
|
+
for (const name in config) {
|
|
563
|
+
if (!(name in result)) {
|
|
564
|
+
result[name] = config[name];
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return Object.freeze(result);
|
|
568
|
+
}
|
|
569
|
+
function createDOMAspectGuards(config, defaults) {
|
|
570
|
+
const result = {};
|
|
571
|
+
for (const aspect in defaults) {
|
|
572
|
+
const overrideValue = config[aspect];
|
|
573
|
+
const defaultValue = defaults[aspect];
|
|
574
|
+
switch (overrideValue) {
|
|
575
|
+
case null:
|
|
576
|
+
// remove the default
|
|
577
|
+
break;
|
|
578
|
+
case undefined:
|
|
579
|
+
// keep the default
|
|
580
|
+
result[aspect] = createDomSinkGuards(defaultValue, {});
|
|
581
|
+
break;
|
|
582
|
+
default:
|
|
583
|
+
// override the default
|
|
584
|
+
result[aspect] = createDomSinkGuards(overrideValue, defaultValue);
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
// add any new aspect guards that were not overrides
|
|
589
|
+
for (const aspect in config) {
|
|
590
|
+
if (!(aspect in result)) {
|
|
591
|
+
result[aspect] = createDomSinkGuards(config[aspect], {});
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return Object.freeze(result);
|
|
595
|
+
}
|
|
596
|
+
function createElementGuards(config, defaults) {
|
|
597
|
+
const result = {};
|
|
598
|
+
for (const tag in defaults) {
|
|
599
|
+
const overrideValue = config[tag];
|
|
600
|
+
const defaultValue = defaults[tag];
|
|
601
|
+
switch (overrideValue) {
|
|
602
|
+
case null:
|
|
603
|
+
// remove the default
|
|
604
|
+
break;
|
|
605
|
+
case undefined:
|
|
606
|
+
// keep the default
|
|
607
|
+
result[tag] = createDOMAspectGuards(overrideValue, {});
|
|
608
|
+
break;
|
|
609
|
+
default:
|
|
610
|
+
// override the default aspects
|
|
611
|
+
result[tag] = createDOMAspectGuards(overrideValue, defaultValue);
|
|
612
|
+
break;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
// Add any new element guards that were not overrides
|
|
616
|
+
for (const tag in config) {
|
|
617
|
+
if (!(tag in result)) {
|
|
618
|
+
result[tag] = createDOMAspectGuards(config[tag], {});
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return Object.freeze(result);
|
|
622
|
+
}
|
|
623
|
+
function createDOMGuards(config, defaults) {
|
|
624
|
+
return Object.freeze({
|
|
625
|
+
elements: config.elements
|
|
626
|
+
? createElementGuards(config.elements, defaults.elements)
|
|
627
|
+
: defaults.elements,
|
|
628
|
+
aspects: config.aspects
|
|
629
|
+
? createDOMAspectGuards(config.aspects, defaults.aspects)
|
|
630
|
+
: defaults.aspects,
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
function createTrustedType() {
|
|
634
|
+
const createHTML = html => html;
|
|
635
|
+
return globalThis.trustedTypes
|
|
636
|
+
? globalThis.trustedTypes.createPolicy("fast-html", { createHTML })
|
|
637
|
+
: { createHTML };
|
|
638
|
+
}
|
|
639
|
+
function tryGuard(aspectGuards, tagName, aspect, aspectName, sink) {
|
|
640
|
+
const sinkGuards = aspectGuards[aspect];
|
|
641
|
+
if (sinkGuards) {
|
|
642
|
+
const guard = sinkGuards[aspectName];
|
|
643
|
+
if (guard) {
|
|
644
|
+
return guard(tagName, aspect, aspectName, sink);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* A helper for creating DOM policies.
|
|
650
|
+
* @public
|
|
651
|
+
*/
|
|
652
|
+
const DOMPolicy = Object.freeze({
|
|
653
|
+
/**
|
|
654
|
+
* Creates a new DOM Policy object.
|
|
655
|
+
* @param options The options to use in creating the policy.
|
|
656
|
+
* @returns The newly created DOMPolicy.
|
|
657
|
+
*/
|
|
658
|
+
create(options = {}) {
|
|
659
|
+
var _a, _b;
|
|
660
|
+
const trustedType = (_a = options.trustedType) !== null && _a !== void 0 ? _a : createTrustedType();
|
|
661
|
+
const guards = createDOMGuards((_b = options.guards) !== null && _b !== void 0 ? _b : {}, defaultDOMGuards);
|
|
662
|
+
return Object.freeze({
|
|
663
|
+
createHTML(value) {
|
|
664
|
+
return trustedType.createHTML(value);
|
|
665
|
+
},
|
|
666
|
+
protect(tagName, aspect, aspectName, sink) {
|
|
667
|
+
var _a;
|
|
668
|
+
// Check for element-specific guards.
|
|
669
|
+
const key = (tagName !== null && tagName !== void 0 ? tagName : "").toLowerCase();
|
|
670
|
+
const elementGuards = guards.elements[key];
|
|
671
|
+
if (elementGuards) {
|
|
672
|
+
const guard = tryGuard(elementGuards, tagName, aspect, aspectName, sink);
|
|
673
|
+
if (guard) {
|
|
674
|
+
return guard;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
// Check for guards applicable to all nodes.
|
|
678
|
+
return ((_a = tryGuard(guards.aspects, tagName, aspect, aspectName, sink)) !== null && _a !== void 0 ? _a : sink);
|
|
679
|
+
},
|
|
680
|
+
});
|
|
681
|
+
},
|
|
682
|
+
});
|
|
188
683
|
|
|
189
684
|
/**
|
|
190
685
|
* The default UpdateQueue.
|
|
191
686
|
* @public
|
|
192
687
|
*/
|
|
193
|
-
const Updates = FAST.getById(
|
|
688
|
+
const Updates = FAST.getById(KernelServiceId.updateQueue, () => {
|
|
194
689
|
const tasks = [];
|
|
195
690
|
const pendingErrors = [];
|
|
196
691
|
const rAF = globalThis.requestAnimationFrame;
|
|
@@ -417,15 +912,29 @@ class PropertyChangeNotifier {
|
|
|
417
912
|
}
|
|
418
913
|
}
|
|
419
914
|
|
|
915
|
+
/**
|
|
916
|
+
* Describes how the source's lifetime relates to its controller's lifetime.
|
|
917
|
+
* @public
|
|
918
|
+
*/
|
|
919
|
+
const SourceLifetime = Object.freeze({
|
|
920
|
+
/**
|
|
921
|
+
* The source to controller lifetime relationship is unknown.
|
|
922
|
+
*/
|
|
923
|
+
unknown: void 0,
|
|
924
|
+
/**
|
|
925
|
+
* The source and controller lifetimes are coupled to one another.
|
|
926
|
+
* They can/will be GC'd together.
|
|
927
|
+
*/
|
|
928
|
+
coupled: 1,
|
|
929
|
+
});
|
|
420
930
|
/**
|
|
421
931
|
* Common Observable APIs.
|
|
422
932
|
* @public
|
|
423
933
|
*/
|
|
424
|
-
const Observable = FAST.getById(
|
|
934
|
+
const Observable = FAST.getById(KernelServiceId.observable, () => {
|
|
425
935
|
const queueUpdate = Updates.enqueue;
|
|
426
936
|
const volatileRegex = /(:|&&|\|\||if)/;
|
|
427
937
|
const notifierLookup = new WeakMap();
|
|
428
|
-
const accessorLookup = new WeakMap();
|
|
429
938
|
let watcher = void 0;
|
|
430
939
|
let createArrayObserver = (array) => {
|
|
431
940
|
throw FAST.error(1101 /* Message.needsArrayObservation */);
|
|
@@ -440,19 +949,7 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
440
949
|
}
|
|
441
950
|
return found;
|
|
442
951
|
}
|
|
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
|
-
}
|
|
952
|
+
const getAccessors = createMetadataLocator();
|
|
456
953
|
class DefaultObservableAccessor {
|
|
457
954
|
constructor(name) {
|
|
458
955
|
this.name = name;
|
|
@@ -478,10 +975,10 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
478
975
|
}
|
|
479
976
|
}
|
|
480
977
|
}
|
|
481
|
-
class
|
|
482
|
-
constructor(
|
|
483
|
-
super(
|
|
484
|
-
this.
|
|
978
|
+
class ExpressionNotifierImplementation extends SubscriberSet {
|
|
979
|
+
constructor(expression, initialSubscriber, isVolatileBinding = false) {
|
|
980
|
+
super(expression, initialSubscriber);
|
|
981
|
+
this.expression = expression;
|
|
485
982
|
this.isVolatileBinding = isVolatileBinding;
|
|
486
983
|
this.needsRefresh = true;
|
|
487
984
|
this.needsQueue = true;
|
|
@@ -492,10 +989,30 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
492
989
|
this.propertyName = void 0;
|
|
493
990
|
this.notifier = void 0;
|
|
494
991
|
this.next = void 0;
|
|
992
|
+
/**
|
|
993
|
+
* Opts out of JSON stringification.
|
|
994
|
+
*/
|
|
995
|
+
this.toJSON = noop;
|
|
495
996
|
}
|
|
496
997
|
setMode(isAsync) {
|
|
497
998
|
this.isAsync = this.needsQueue = isAsync;
|
|
498
999
|
}
|
|
1000
|
+
bind(controller) {
|
|
1001
|
+
this.controller = controller;
|
|
1002
|
+
const value = this.observe(controller.source, controller.context);
|
|
1003
|
+
if (!controller.isBound && this.requiresUnbind(controller)) {
|
|
1004
|
+
controller.onUnbind(this);
|
|
1005
|
+
}
|
|
1006
|
+
return value;
|
|
1007
|
+
}
|
|
1008
|
+
requiresUnbind(controller) {
|
|
1009
|
+
return (controller.sourceLifetime !== SourceLifetime.coupled ||
|
|
1010
|
+
this.first !== this.last ||
|
|
1011
|
+
this.first.propertySource !== controller.source);
|
|
1012
|
+
}
|
|
1013
|
+
unbind(controller) {
|
|
1014
|
+
this.dispose();
|
|
1015
|
+
}
|
|
499
1016
|
observe(source, context) {
|
|
500
1017
|
if (this.needsRefresh && this.last !== null) {
|
|
501
1018
|
this.dispose();
|
|
@@ -503,10 +1020,19 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
503
1020
|
const previousWatcher = watcher;
|
|
504
1021
|
watcher = this.needsRefresh ? this : void 0;
|
|
505
1022
|
this.needsRefresh = this.isVolatileBinding;
|
|
506
|
-
|
|
507
|
-
|
|
1023
|
+
let result;
|
|
1024
|
+
try {
|
|
1025
|
+
result = this.expression(source, context);
|
|
1026
|
+
}
|
|
1027
|
+
finally {
|
|
1028
|
+
watcher = previousWatcher;
|
|
1029
|
+
}
|
|
508
1030
|
return result;
|
|
509
1031
|
}
|
|
1032
|
+
// backwards compat with v1 kernel
|
|
1033
|
+
disconnect() {
|
|
1034
|
+
this.dispose();
|
|
1035
|
+
}
|
|
510
1036
|
dispose() {
|
|
511
1037
|
if (this.last !== null) {
|
|
512
1038
|
let current = this.first;
|
|
@@ -633,22 +1159,22 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
633
1159
|
*/
|
|
634
1160
|
getAccessors,
|
|
635
1161
|
/**
|
|
636
|
-
* Creates a {@link
|
|
637
|
-
* provided {@link
|
|
638
|
-
* @param
|
|
1162
|
+
* Creates a {@link ExpressionNotifier} that can watch the
|
|
1163
|
+
* provided {@link Expression} for changes.
|
|
1164
|
+
* @param expression - The binding to observe.
|
|
639
1165
|
* @param initialSubscriber - An initial subscriber to changes in the binding value.
|
|
640
1166
|
* @param isVolatileBinding - Indicates whether the binding's dependency list must be re-evaluated on every value evaluation.
|
|
641
1167
|
*/
|
|
642
|
-
binding(
|
|
643
|
-
return new
|
|
1168
|
+
binding(expression, initialSubscriber, isVolatileBinding = this.isVolatileBinding(expression)) {
|
|
1169
|
+
return new ExpressionNotifierImplementation(expression, initialSubscriber, isVolatileBinding);
|
|
644
1170
|
},
|
|
645
1171
|
/**
|
|
646
1172
|
* Determines whether a binding expression is volatile and needs to have its dependency list re-evaluated
|
|
647
1173
|
* on every evaluation of the value.
|
|
648
|
-
* @param
|
|
1174
|
+
* @param expression - The binding to inspect.
|
|
649
1175
|
*/
|
|
650
|
-
isVolatileBinding(
|
|
651
|
-
return volatileRegex.test(
|
|
1176
|
+
isVolatileBinding(expression) {
|
|
1177
|
+
return volatileRegex.test(expression.toString());
|
|
652
1178
|
},
|
|
653
1179
|
});
|
|
654
1180
|
});
|
|
@@ -676,7 +1202,7 @@ function volatile(target, name, descriptor) {
|
|
|
676
1202
|
},
|
|
677
1203
|
});
|
|
678
1204
|
}
|
|
679
|
-
const contextEvent = FAST.getById(
|
|
1205
|
+
const contextEvent = FAST.getById(KernelServiceId.contextEvent, () => {
|
|
680
1206
|
let current = null;
|
|
681
1207
|
return {
|
|
682
1208
|
get() {
|
|
@@ -691,123 +1217,38 @@ const contextEvent = FAST.getById(3 /* KernelServiceId.contextEvent */, () => {
|
|
|
691
1217
|
* Provides additional contextual information available to behaviors and expressions.
|
|
692
1218
|
* @public
|
|
693
1219
|
*/
|
|
694
|
-
|
|
695
|
-
constructor(parentSource = null, parentContext = null) {
|
|
696
|
-
/**
|
|
697
|
-
* The index of the current item within a repeat context.
|
|
698
|
-
*/
|
|
699
|
-
this.index = 0;
|
|
700
|
-
/**
|
|
701
|
-
* The length of the current collection within a repeat context.
|
|
702
|
-
*/
|
|
703
|
-
this.length = 0;
|
|
704
|
-
this.parent = parentSource;
|
|
705
|
-
this.parentContext = parentContext;
|
|
706
|
-
}
|
|
707
|
-
/**
|
|
708
|
-
* The current event within an event handler.
|
|
709
|
-
*/
|
|
710
|
-
get event() {
|
|
711
|
-
return contextEvent.get();
|
|
712
|
-
}
|
|
713
|
-
/**
|
|
714
|
-
* Indicates whether the current item within a repeat context
|
|
715
|
-
* has an even index.
|
|
716
|
-
*/
|
|
717
|
-
get isEven() {
|
|
718
|
-
return this.index % 2 === 0;
|
|
719
|
-
}
|
|
720
|
-
/**
|
|
721
|
-
* Indicates whether the current item within a repeat context
|
|
722
|
-
* has an odd index.
|
|
723
|
-
*/
|
|
724
|
-
get isOdd() {
|
|
725
|
-
return this.index % 2 !== 0;
|
|
726
|
-
}
|
|
727
|
-
/**
|
|
728
|
-
* Indicates whether the current item within a repeat context
|
|
729
|
-
* is the first item in the collection.
|
|
730
|
-
*/
|
|
731
|
-
get isFirst() {
|
|
732
|
-
return this.index === 0;
|
|
733
|
-
}
|
|
734
|
-
/**
|
|
735
|
-
* Indicates whether the current item within a repeat context
|
|
736
|
-
* is somewhere in the middle of the collection.
|
|
737
|
-
*/
|
|
738
|
-
get isInMiddle() {
|
|
739
|
-
return !this.isFirst && !this.isLast;
|
|
740
|
-
}
|
|
741
|
-
/**
|
|
742
|
-
* Indicates whether the current item within a repeat context
|
|
743
|
-
* is the last item in the collection.
|
|
744
|
-
*/
|
|
745
|
-
get isLast() {
|
|
746
|
-
return this.index === this.length - 1;
|
|
747
|
-
}
|
|
748
|
-
/**
|
|
749
|
-
* Returns the typed event detail of a custom event.
|
|
750
|
-
*/
|
|
751
|
-
eventDetail() {
|
|
752
|
-
return this.event.detail;
|
|
753
|
-
}
|
|
754
|
-
/**
|
|
755
|
-
* Returns the typed event target of the event.
|
|
756
|
-
*/
|
|
757
|
-
eventTarget() {
|
|
758
|
-
return this.event.target;
|
|
759
|
-
}
|
|
760
|
-
/**
|
|
761
|
-
* Updates the position/size on a context associated with a list item.
|
|
762
|
-
* @param index - The new index of the item.
|
|
763
|
-
* @param length - The new length of the list.
|
|
764
|
-
*/
|
|
765
|
-
updatePosition(index, length) {
|
|
766
|
-
this.index = index;
|
|
767
|
-
this.length = length;
|
|
768
|
-
}
|
|
1220
|
+
const ExecutionContext = Object.freeze({
|
|
769
1221
|
/**
|
|
770
|
-
*
|
|
771
|
-
* @param source - The source for the context if different than the parent.
|
|
772
|
-
* @returns A child execution context.
|
|
1222
|
+
* A default execution context.
|
|
773
1223
|
*/
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
1224
|
+
default: {
|
|
1225
|
+
index: 0,
|
|
1226
|
+
length: 0,
|
|
1227
|
+
get event() {
|
|
1228
|
+
return ExecutionContext.getEvent();
|
|
1229
|
+
},
|
|
1230
|
+
eventDetail() {
|
|
1231
|
+
return this.event.detail;
|
|
1232
|
+
},
|
|
1233
|
+
eventTarget() {
|
|
1234
|
+
return this.event.target;
|
|
1235
|
+
},
|
|
1236
|
+
},
|
|
777
1237
|
/**
|
|
778
|
-
*
|
|
779
|
-
* @
|
|
780
|
-
* @param index - The index of the item in the list.
|
|
781
|
-
* @param length - The length of the list.
|
|
1238
|
+
* Gets the current event.
|
|
1239
|
+
* @returns An event object.
|
|
782
1240
|
*/
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
childContext.length = length;
|
|
787
|
-
return childContext;
|
|
788
|
-
}
|
|
1241
|
+
getEvent() {
|
|
1242
|
+
return contextEvent.get();
|
|
1243
|
+
},
|
|
789
1244
|
/**
|
|
790
|
-
* Sets the
|
|
791
|
-
* @param event -
|
|
792
|
-
* @internal
|
|
1245
|
+
* Sets the current event.
|
|
1246
|
+
* @param event - An event object.
|
|
793
1247
|
*/
|
|
794
|
-
|
|
1248
|
+
setEvent(event) {
|
|
795
1249
|
contextEvent.set(event);
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
* Creates a new root execution context.
|
|
799
|
-
* @returns A new execution context.
|
|
800
|
-
*/
|
|
801
|
-
static create() {
|
|
802
|
-
return new ExecutionContext();
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
/**
|
|
806
|
-
* The default execution context.
|
|
807
|
-
*/
|
|
808
|
-
ExecutionContext.default = new ExecutionContext();
|
|
809
|
-
Observable.defineProperty(ExecutionContext.prototype, "index");
|
|
810
|
-
Observable.defineProperty(ExecutionContext.prototype, "length");
|
|
1250
|
+
},
|
|
1251
|
+
});
|
|
811
1252
|
|
|
812
1253
|
/**
|
|
813
1254
|
* A splice map is a representation of how a previous array of items
|
|
@@ -874,10 +1315,311 @@ const SpliceStrategySupport = Object.freeze({
|
|
|
874
1315
|
const reset = new Splice(0, emptyArray, 0);
|
|
875
1316
|
reset.reset = true;
|
|
876
1317
|
const resetSplices = [reset];
|
|
1318
|
+
// Note: This function is *based* on the computation of the Levenshtein
|
|
1319
|
+
// "edit" distance. The one change is that "updates" are treated as two
|
|
1320
|
+
// edits - not one. With Array splices, an update is really a delete
|
|
1321
|
+
// followed by an add. By retaining this, we optimize for "keeping" the
|
|
1322
|
+
// maximum array items in the original array. For example:
|
|
1323
|
+
//
|
|
1324
|
+
// 'xxxx123' to '123yyyy'
|
|
1325
|
+
//
|
|
1326
|
+
// With 1-edit updates, the shortest path would be just to update all seven
|
|
1327
|
+
// characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
|
|
1328
|
+
// leaves the substring '123' intact.
|
|
1329
|
+
function calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd) {
|
|
1330
|
+
// "Deletion" columns
|
|
1331
|
+
const rowCount = oldEnd - oldStart + 1;
|
|
1332
|
+
const columnCount = currentEnd - currentStart + 1;
|
|
1333
|
+
const distances = new Array(rowCount);
|
|
1334
|
+
let north;
|
|
1335
|
+
let west;
|
|
1336
|
+
// "Addition" rows. Initialize null column.
|
|
1337
|
+
for (let i = 0; i < rowCount; ++i) {
|
|
1338
|
+
distances[i] = new Array(columnCount);
|
|
1339
|
+
distances[i][0] = i;
|
|
1340
|
+
}
|
|
1341
|
+
// Initialize null row
|
|
1342
|
+
for (let j = 0; j < columnCount; ++j) {
|
|
1343
|
+
distances[0][j] = j;
|
|
1344
|
+
}
|
|
1345
|
+
for (let i = 1; i < rowCount; ++i) {
|
|
1346
|
+
for (let j = 1; j < columnCount; ++j) {
|
|
1347
|
+
if (current[currentStart + j - 1] === old[oldStart + i - 1]) {
|
|
1348
|
+
distances[i][j] = distances[i - 1][j - 1];
|
|
1349
|
+
}
|
|
1350
|
+
else {
|
|
1351
|
+
north = distances[i - 1][j] + 1;
|
|
1352
|
+
west = distances[i][j - 1] + 1;
|
|
1353
|
+
distances[i][j] = north < west ? north : west;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
return distances;
|
|
1358
|
+
}
|
|
1359
|
+
// This starts at the final weight, and walks "backward" by finding
|
|
1360
|
+
// the minimum previous weight recursively until the origin of the weight
|
|
1361
|
+
// matrix.
|
|
1362
|
+
function spliceOperationsFromEditDistances(distances) {
|
|
1363
|
+
let i = distances.length - 1;
|
|
1364
|
+
let j = distances[0].length - 1;
|
|
1365
|
+
let current = distances[i][j];
|
|
1366
|
+
const edits = [];
|
|
1367
|
+
while (i > 0 || j > 0) {
|
|
1368
|
+
if (i === 0) {
|
|
1369
|
+
edits.push(2 /* Edit.add */);
|
|
1370
|
+
j--;
|
|
1371
|
+
continue;
|
|
1372
|
+
}
|
|
1373
|
+
if (j === 0) {
|
|
1374
|
+
edits.push(3 /* Edit.delete */);
|
|
1375
|
+
i--;
|
|
1376
|
+
continue;
|
|
1377
|
+
}
|
|
1378
|
+
const northWest = distances[i - 1][j - 1];
|
|
1379
|
+
const west = distances[i - 1][j];
|
|
1380
|
+
const north = distances[i][j - 1];
|
|
1381
|
+
let min;
|
|
1382
|
+
if (west < north) {
|
|
1383
|
+
min = west < northWest ? west : northWest;
|
|
1384
|
+
}
|
|
1385
|
+
else {
|
|
1386
|
+
min = north < northWest ? north : northWest;
|
|
1387
|
+
}
|
|
1388
|
+
if (min === northWest) {
|
|
1389
|
+
if (northWest === current) {
|
|
1390
|
+
edits.push(0 /* Edit.leave */);
|
|
1391
|
+
}
|
|
1392
|
+
else {
|
|
1393
|
+
edits.push(1 /* Edit.update */);
|
|
1394
|
+
current = northWest;
|
|
1395
|
+
}
|
|
1396
|
+
i--;
|
|
1397
|
+
j--;
|
|
1398
|
+
}
|
|
1399
|
+
else if (min === west) {
|
|
1400
|
+
edits.push(3 /* Edit.delete */);
|
|
1401
|
+
i--;
|
|
1402
|
+
current = west;
|
|
1403
|
+
}
|
|
1404
|
+
else {
|
|
1405
|
+
edits.push(2 /* Edit.add */);
|
|
1406
|
+
j--;
|
|
1407
|
+
current = north;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
return edits.reverse();
|
|
1411
|
+
}
|
|
1412
|
+
function sharedPrefix(current, old, searchLength) {
|
|
1413
|
+
for (let i = 0; i < searchLength; ++i) {
|
|
1414
|
+
if (current[i] !== old[i]) {
|
|
1415
|
+
return i;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
return searchLength;
|
|
1419
|
+
}
|
|
1420
|
+
function sharedSuffix(current, old, searchLength) {
|
|
1421
|
+
let index1 = current.length;
|
|
1422
|
+
let index2 = old.length;
|
|
1423
|
+
let count = 0;
|
|
1424
|
+
while (count < searchLength && current[--index1] === old[--index2]) {
|
|
1425
|
+
count++;
|
|
1426
|
+
}
|
|
1427
|
+
return count;
|
|
1428
|
+
}
|
|
1429
|
+
function intersect(start1, end1, start2, end2) {
|
|
1430
|
+
// Disjoint
|
|
1431
|
+
if (end1 < start2 || end2 < start1) {
|
|
1432
|
+
return -1;
|
|
1433
|
+
}
|
|
1434
|
+
// Adjacent
|
|
1435
|
+
if (end1 === start2 || end2 === start1) {
|
|
1436
|
+
return 0;
|
|
1437
|
+
}
|
|
1438
|
+
// Non-zero intersect, span1 first
|
|
1439
|
+
if (start1 < start2) {
|
|
1440
|
+
if (end1 < end2) {
|
|
1441
|
+
return end1 - start2; // Overlap
|
|
1442
|
+
}
|
|
1443
|
+
return end2 - start2; // Contained
|
|
1444
|
+
}
|
|
1445
|
+
// Non-zero intersect, span2 first
|
|
1446
|
+
if (end2 < end1) {
|
|
1447
|
+
return end2 - start1; // Overlap
|
|
1448
|
+
}
|
|
1449
|
+
return end1 - start1; // Contained
|
|
1450
|
+
}
|
|
1451
|
+
/**
|
|
1452
|
+
* @remarks
|
|
1453
|
+
* Lacking individual splice mutation information, the minimal set of
|
|
1454
|
+
* splices can be synthesized given the previous state and final state of an
|
|
1455
|
+
* array. The basic approach is to calculate the edit distance matrix and
|
|
1456
|
+
* choose the shortest path through it.
|
|
1457
|
+
*
|
|
1458
|
+
* Complexity: O(l * p)
|
|
1459
|
+
* l: The length of the current array
|
|
1460
|
+
* p: The length of the old array
|
|
1461
|
+
*/
|
|
1462
|
+
function calc(current, currentStart, currentEnd, old, oldStart, oldEnd) {
|
|
1463
|
+
let prefixCount = 0;
|
|
1464
|
+
let suffixCount = 0;
|
|
1465
|
+
const minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
|
|
1466
|
+
if (currentStart === 0 && oldStart === 0) {
|
|
1467
|
+
prefixCount = sharedPrefix(current, old, minLength);
|
|
1468
|
+
}
|
|
1469
|
+
if (currentEnd === current.length && oldEnd === old.length) {
|
|
1470
|
+
suffixCount = sharedSuffix(current, old, minLength - prefixCount);
|
|
1471
|
+
}
|
|
1472
|
+
currentStart += prefixCount;
|
|
1473
|
+
oldStart += prefixCount;
|
|
1474
|
+
currentEnd -= suffixCount;
|
|
1475
|
+
oldEnd -= suffixCount;
|
|
1476
|
+
if (currentEnd - currentStart === 0 && oldEnd - oldStart === 0) {
|
|
1477
|
+
return emptyArray;
|
|
1478
|
+
}
|
|
1479
|
+
if (currentStart === currentEnd) {
|
|
1480
|
+
const splice = new Splice(currentStart, [], 0);
|
|
1481
|
+
while (oldStart < oldEnd) {
|
|
1482
|
+
splice.removed.push(old[oldStart++]);
|
|
1483
|
+
}
|
|
1484
|
+
return [splice];
|
|
1485
|
+
}
|
|
1486
|
+
else if (oldStart === oldEnd) {
|
|
1487
|
+
return [new Splice(currentStart, [], currentEnd - currentStart)];
|
|
1488
|
+
}
|
|
1489
|
+
const ops = spliceOperationsFromEditDistances(calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
|
|
1490
|
+
const splices = [];
|
|
1491
|
+
let splice = void 0;
|
|
1492
|
+
let index = currentStart;
|
|
1493
|
+
let oldIndex = oldStart;
|
|
1494
|
+
for (let i = 0; i < ops.length; ++i) {
|
|
1495
|
+
switch (ops[i]) {
|
|
1496
|
+
case 0 /* Edit.leave */:
|
|
1497
|
+
if (splice !== void 0) {
|
|
1498
|
+
splices.push(splice);
|
|
1499
|
+
splice = void 0;
|
|
1500
|
+
}
|
|
1501
|
+
index++;
|
|
1502
|
+
oldIndex++;
|
|
1503
|
+
break;
|
|
1504
|
+
case 1 /* Edit.update */:
|
|
1505
|
+
if (splice === void 0) {
|
|
1506
|
+
splice = new Splice(index, [], 0);
|
|
1507
|
+
}
|
|
1508
|
+
splice.addedCount++;
|
|
1509
|
+
index++;
|
|
1510
|
+
splice.removed.push(old[oldIndex]);
|
|
1511
|
+
oldIndex++;
|
|
1512
|
+
break;
|
|
1513
|
+
case 2 /* Edit.add */:
|
|
1514
|
+
if (splice === void 0) {
|
|
1515
|
+
splice = new Splice(index, [], 0);
|
|
1516
|
+
}
|
|
1517
|
+
splice.addedCount++;
|
|
1518
|
+
index++;
|
|
1519
|
+
break;
|
|
1520
|
+
case 3 /* Edit.delete */:
|
|
1521
|
+
if (splice === void 0) {
|
|
1522
|
+
splice = new Splice(index, [], 0);
|
|
1523
|
+
}
|
|
1524
|
+
splice.removed.push(old[oldIndex]);
|
|
1525
|
+
oldIndex++;
|
|
1526
|
+
break;
|
|
1527
|
+
// no default
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
if (splice !== void 0) {
|
|
1531
|
+
splices.push(splice);
|
|
1532
|
+
}
|
|
1533
|
+
return splices;
|
|
1534
|
+
}
|
|
1535
|
+
function merge(splice, splices) {
|
|
1536
|
+
let inserted = false;
|
|
1537
|
+
let insertionOffset = 0;
|
|
1538
|
+
for (let i = 0; i < splices.length; i++) {
|
|
1539
|
+
const current = splices[i];
|
|
1540
|
+
current.index += insertionOffset;
|
|
1541
|
+
if (inserted) {
|
|
1542
|
+
continue;
|
|
1543
|
+
}
|
|
1544
|
+
const intersectCount = intersect(splice.index, splice.index + splice.removed.length, current.index, current.index + current.addedCount);
|
|
1545
|
+
if (intersectCount >= 0) {
|
|
1546
|
+
// Merge the two splices
|
|
1547
|
+
splices.splice(i, 1);
|
|
1548
|
+
i--;
|
|
1549
|
+
insertionOffset -= current.addedCount - current.removed.length;
|
|
1550
|
+
splice.addedCount += current.addedCount - intersectCount;
|
|
1551
|
+
const deleteCount = splice.removed.length + current.removed.length - intersectCount;
|
|
1552
|
+
if (!splice.addedCount && !deleteCount) {
|
|
1553
|
+
// merged splice is a noop. discard.
|
|
1554
|
+
inserted = true;
|
|
1555
|
+
}
|
|
1556
|
+
else {
|
|
1557
|
+
let currentRemoved = current.removed;
|
|
1558
|
+
if (splice.index < current.index) {
|
|
1559
|
+
// some prefix of splice.removed is prepended to current.removed.
|
|
1560
|
+
const prepend = splice.removed.slice(0, current.index - splice.index);
|
|
1561
|
+
prepend.push(...currentRemoved);
|
|
1562
|
+
currentRemoved = prepend;
|
|
1563
|
+
}
|
|
1564
|
+
if (splice.index + splice.removed.length >
|
|
1565
|
+
current.index + current.addedCount) {
|
|
1566
|
+
// some suffix of splice.removed is appended to current.removed.
|
|
1567
|
+
const append = splice.removed.slice(current.index + current.addedCount - splice.index);
|
|
1568
|
+
currentRemoved.push(...append);
|
|
1569
|
+
}
|
|
1570
|
+
splice.removed = currentRemoved;
|
|
1571
|
+
if (current.index < splice.index) {
|
|
1572
|
+
splice.index = current.index;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
else if (splice.index < current.index) {
|
|
1577
|
+
// Insert splice here.
|
|
1578
|
+
inserted = true;
|
|
1579
|
+
splices.splice(i, 0, splice);
|
|
1580
|
+
i++;
|
|
1581
|
+
const offset = splice.addedCount - splice.removed.length;
|
|
1582
|
+
current.index += offset;
|
|
1583
|
+
insertionOffset += offset;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
if (!inserted) {
|
|
1587
|
+
splices.push(splice);
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
function project(array, changes) {
|
|
1591
|
+
let splices = [];
|
|
1592
|
+
const initialSplices = [];
|
|
1593
|
+
for (let i = 0, ii = changes.length; i < ii; i++) {
|
|
1594
|
+
merge(changes[i], initialSplices);
|
|
1595
|
+
}
|
|
1596
|
+
for (let i = 0, ii = initialSplices.length; i < ii; ++i) {
|
|
1597
|
+
const splice = initialSplices[i];
|
|
1598
|
+
if (splice.addedCount === 1 && splice.removed.length === 1) {
|
|
1599
|
+
if (splice.removed[0] !== array[splice.index]) {
|
|
1600
|
+
splices.push(splice);
|
|
1601
|
+
}
|
|
1602
|
+
continue;
|
|
1603
|
+
}
|
|
1604
|
+
splices = splices.concat(calc(array, splice.index, splice.index + splice.addedCount, splice.removed, 0, splice.removed.length));
|
|
1605
|
+
}
|
|
1606
|
+
return splices;
|
|
1607
|
+
}
|
|
1608
|
+
/**
|
|
1609
|
+
* A SpliceStrategy that attempts to merge all splices into the minimal set of
|
|
1610
|
+
* splices needed to represent the change from the old array to the new array.
|
|
1611
|
+
* @public
|
|
1612
|
+
*/
|
|
877
1613
|
let defaultSpliceStrategy = Object.freeze({
|
|
878
|
-
support: SpliceStrategySupport.
|
|
1614
|
+
support: SpliceStrategySupport.optimized,
|
|
879
1615
|
normalize(previous, current, changes) {
|
|
880
|
-
|
|
1616
|
+
if (previous === void 0) {
|
|
1617
|
+
if (changes === void 0) {
|
|
1618
|
+
return emptyArray;
|
|
1619
|
+
}
|
|
1620
|
+
return changes.length > 1 ? project(current, changes) : changes;
|
|
1621
|
+
}
|
|
1622
|
+
return resetSplices;
|
|
881
1623
|
},
|
|
882
1624
|
pop(array, observer, pop, args) {
|
|
883
1625
|
const notEmpty = array.length > 0;
|
|
@@ -1075,7 +1817,6 @@ function lengthOf(array) {
|
|
|
1075
1817
|
return array.length;
|
|
1076
1818
|
}
|
|
1077
1819
|
|
|
1078
|
-
const styleSheetCache = new Map();
|
|
1079
1820
|
let DefaultStyleStrategy;
|
|
1080
1821
|
function reduceStyles(styles) {
|
|
1081
1822
|
return styles
|
|
@@ -1146,42 +1887,26 @@ class ElementStyles {
|
|
|
1146
1887
|
static setDefaultStrategy(Strategy) {
|
|
1147
1888
|
DefaultStyleStrategy = Strategy;
|
|
1148
1889
|
}
|
|
1890
|
+
/**
|
|
1891
|
+
* Normalizes a set of composable style options.
|
|
1892
|
+
* @param styles - The style options to normalize.
|
|
1893
|
+
* @returns A singular ElementStyles instance or undefined.
|
|
1894
|
+
*/
|
|
1895
|
+
static normalize(styles) {
|
|
1896
|
+
return styles === void 0
|
|
1897
|
+
? void 0
|
|
1898
|
+
: Array.isArray(styles)
|
|
1899
|
+
? new ElementStyles(styles)
|
|
1900
|
+
: styles instanceof ElementStyles
|
|
1901
|
+
? styles
|
|
1902
|
+
: new ElementStyles([styles]);
|
|
1903
|
+
}
|
|
1149
1904
|
}
|
|
1150
1905
|
/**
|
|
1151
1906
|
* Indicates whether the DOM supports the adoptedStyleSheets feature.
|
|
1152
1907
|
*/
|
|
1153
1908
|
ElementStyles.supportsAdoptedStyleSheets = Array.isArray(document.adoptedStyleSheets) &&
|
|
1154
1909
|
"replace" in CSSStyleSheet.prototype;
|
|
1155
|
-
/**
|
|
1156
|
-
* https://wicg.github.io/construct-stylesheets/
|
|
1157
|
-
* https://developers.google.com/web/updates/2019/02/constructable-stylesheets
|
|
1158
|
-
*
|
|
1159
|
-
* @internal
|
|
1160
|
-
*/
|
|
1161
|
-
class AdoptedStyleSheetsStrategy {
|
|
1162
|
-
constructor(styles) {
|
|
1163
|
-
this.sheets = styles.map((x) => {
|
|
1164
|
-
if (x instanceof CSSStyleSheet) {
|
|
1165
|
-
return x;
|
|
1166
|
-
}
|
|
1167
|
-
let sheet = styleSheetCache.get(x);
|
|
1168
|
-
if (sheet === void 0) {
|
|
1169
|
-
sheet = new CSSStyleSheet();
|
|
1170
|
-
sheet.replaceSync(x);
|
|
1171
|
-
styleSheetCache.set(x, sheet);
|
|
1172
|
-
}
|
|
1173
|
-
return sheet;
|
|
1174
|
-
});
|
|
1175
|
-
}
|
|
1176
|
-
addStylesTo(target) {
|
|
1177
|
-
target.adoptedStyleSheets = [...target.adoptedStyleSheets, ...this.sheets];
|
|
1178
|
-
}
|
|
1179
|
-
removeStylesFrom(target) {
|
|
1180
|
-
const sheets = this.sheets;
|
|
1181
|
-
target.adoptedStyleSheets = target.adoptedStyleSheets.filter((x) => sheets.indexOf(x) === -1);
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
ElementStyles.setDefaultStrategy(FAST.getById(5 /* KernelServiceId.styleSheetStrategy */, () => AdoptedStyleSheetsStrategy));
|
|
1185
1910
|
|
|
1186
1911
|
const registry$1 = createTypeRegistry();
|
|
1187
1912
|
/**
|
|
@@ -1269,101 +1994,47 @@ const css = ((strings, ...values) => {
|
|
|
1269
1994
|
class CSSPartial {
|
|
1270
1995
|
constructor(styles, behaviors) {
|
|
1271
1996
|
this.behaviors = behaviors;
|
|
1272
|
-
this.css = "";
|
|
1273
|
-
const stylesheets = styles.reduce((accumulated, current) => {
|
|
1274
|
-
if (isString(current)) {
|
|
1275
|
-
this.css += current;
|
|
1276
|
-
}
|
|
1277
|
-
else {
|
|
1278
|
-
accumulated.push(current);
|
|
1279
|
-
}
|
|
1280
|
-
return accumulated;
|
|
1281
|
-
}, []);
|
|
1282
|
-
if (stylesheets.length) {
|
|
1283
|
-
this.styles = new ElementStyles(stylesheets);
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
createCSS(add) {
|
|
1287
|
-
this.behaviors.forEach(add);
|
|
1288
|
-
if (this.styles) {
|
|
1289
|
-
add(this);
|
|
1290
|
-
}
|
|
1291
|
-
return this.css;
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
CSSDirective.define(CSSPartial);
|
|
1301
|
-
css.partial = (strings, ...values) => {
|
|
1302
|
-
const { styles, behaviors } = collectStyles(strings, values);
|
|
1303
|
-
return new CSSPartial(styles, behaviors);
|
|
1304
|
-
};
|
|
1305
|
-
/**
|
|
1306
|
-
* @deprecated Use css.partial instead.
|
|
1307
|
-
* @public
|
|
1308
|
-
*/
|
|
1309
|
-
const cssPartial = css.partial;
|
|
1310
|
-
|
|
1311
|
-
/**
|
|
1312
|
-
* Common DOM APIs.
|
|
1313
|
-
* @public
|
|
1314
|
-
*/
|
|
1315
|
-
const DOM = Object.freeze({
|
|
1316
|
-
/**
|
|
1317
|
-
* @deprecated
|
|
1318
|
-
* Use Updates.enqueue().
|
|
1319
|
-
*/
|
|
1320
|
-
queueUpdate: Updates.enqueue,
|
|
1321
|
-
/**
|
|
1322
|
-
* @deprecated
|
|
1323
|
-
* Use Updates.next()
|
|
1324
|
-
*/
|
|
1325
|
-
nextUpdate: Updates.next,
|
|
1326
|
-
/**
|
|
1327
|
-
* @deprecated
|
|
1328
|
-
* Use Updates.process()
|
|
1329
|
-
*/
|
|
1330
|
-
processUpdates: Updates.process,
|
|
1331
|
-
/**
|
|
1332
|
-
* Sets an attribute value on an element.
|
|
1333
|
-
* @param element - The element to set the attribute value on.
|
|
1334
|
-
* @param attributeName - The attribute name to set.
|
|
1335
|
-
* @param value - The value of the attribute to set.
|
|
1336
|
-
* @remarks
|
|
1337
|
-
* If the value is `null` or `undefined`, the attribute is removed, otherwise
|
|
1338
|
-
* it is set to the provided value using the standard `setAttribute` API.
|
|
1339
|
-
*/
|
|
1340
|
-
setAttribute(element, attributeName, value) {
|
|
1341
|
-
value === null || value === undefined
|
|
1342
|
-
? element.removeAttribute(attributeName)
|
|
1343
|
-
: element.setAttribute(attributeName, value);
|
|
1344
|
-
},
|
|
1345
|
-
/**
|
|
1346
|
-
* Sets a boolean attribute value.
|
|
1347
|
-
* @param element - The element to set the boolean attribute value on.
|
|
1348
|
-
* @param attributeName - The attribute name to set.
|
|
1349
|
-
* @param value - The value of the attribute to set.
|
|
1350
|
-
* @remarks
|
|
1351
|
-
* If the value is true, the attribute is added; otherwise it is removed.
|
|
1352
|
-
*/
|
|
1353
|
-
setBooleanAttribute(element, attributeName, value) {
|
|
1354
|
-
value
|
|
1355
|
-
? element.setAttribute(attributeName, "")
|
|
1356
|
-
: element.removeAttribute(attributeName);
|
|
1357
|
-
},
|
|
1358
|
-
});
|
|
1997
|
+
this.css = "";
|
|
1998
|
+
const stylesheets = styles.reduce((accumulated, current) => {
|
|
1999
|
+
if (isString(current)) {
|
|
2000
|
+
this.css += current;
|
|
2001
|
+
}
|
|
2002
|
+
else {
|
|
2003
|
+
accumulated.push(current);
|
|
2004
|
+
}
|
|
2005
|
+
return accumulated;
|
|
2006
|
+
}, []);
|
|
2007
|
+
if (stylesheets.length) {
|
|
2008
|
+
this.styles = new ElementStyles(stylesheets);
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
createCSS(add) {
|
|
2012
|
+
this.behaviors.forEach(add);
|
|
2013
|
+
if (this.styles) {
|
|
2014
|
+
add(this);
|
|
2015
|
+
}
|
|
2016
|
+
return this.css;
|
|
2017
|
+
}
|
|
2018
|
+
addedCallback(controller) {
|
|
2019
|
+
controller.addStyles(this.styles);
|
|
2020
|
+
}
|
|
2021
|
+
removedCallback(controller) {
|
|
2022
|
+
controller.removeStyles(this.styles);
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
CSSDirective.define(CSSPartial);
|
|
2026
|
+
css.partial = (strings, ...values) => {
|
|
2027
|
+
const { styles, behaviors } = collectStyles(strings, values);
|
|
2028
|
+
return new CSSPartial(styles, behaviors);
|
|
2029
|
+
};
|
|
1359
2030
|
|
|
1360
2031
|
const marker = `fast-${Math.random().toString(36).substring(2, 8)}`;
|
|
1361
2032
|
const interpolationStart = `${marker}{`;
|
|
1362
2033
|
const interpolationEnd = `}${marker}`;
|
|
1363
2034
|
const interpolationEndLength = interpolationEnd.length;
|
|
1364
|
-
let id = 0;
|
|
2035
|
+
let id$1 = 0;
|
|
1365
2036
|
/** @internal */
|
|
1366
|
-
const nextId = () => `${marker}-${++id}`;
|
|
2037
|
+
const nextId = () => `${marker}-${++id$1}`;
|
|
1367
2038
|
/**
|
|
1368
2039
|
* Common APIs related to markup generation.
|
|
1369
2040
|
* @public
|
|
@@ -1460,97 +2131,71 @@ const HTMLDirective = Object.freeze({
|
|
|
1460
2131
|
registry.register(options);
|
|
1461
2132
|
return type;
|
|
1462
2133
|
},
|
|
1463
|
-
});
|
|
1464
|
-
/**
|
|
1465
|
-
* Decorator: Defines an HTMLDirective.
|
|
1466
|
-
* @param options - Provides options that specify the directive's application.
|
|
1467
|
-
* @public
|
|
1468
|
-
*/
|
|
1469
|
-
function htmlDirective(options) {
|
|
1470
|
-
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
1471
|
-
return function (type) {
|
|
1472
|
-
HTMLDirective.define(type, options);
|
|
1473
|
-
};
|
|
1474
|
-
}
|
|
1475
|
-
/**
|
|
1476
|
-
* The type of HTML aspect to target.
|
|
1477
|
-
* @public
|
|
1478
|
-
*/
|
|
1479
|
-
const Aspect = Object.freeze({
|
|
1480
|
-
/**
|
|
1481
|
-
* Not aspected.
|
|
1482
|
-
*/
|
|
1483
|
-
none: 0,
|
|
1484
|
-
/**
|
|
1485
|
-
* An attribute.
|
|
1486
|
-
*/
|
|
1487
|
-
attribute: 1,
|
|
1488
|
-
/**
|
|
1489
|
-
* A boolean attribute.
|
|
1490
|
-
*/
|
|
1491
|
-
booleanAttribute: 2,
|
|
1492
|
-
/**
|
|
1493
|
-
* A property.
|
|
1494
|
-
*/
|
|
1495
|
-
property: 3,
|
|
1496
|
-
/**
|
|
1497
|
-
* Content
|
|
1498
|
-
*/
|
|
1499
|
-
content: 4,
|
|
1500
|
-
/**
|
|
1501
|
-
* A token list.
|
|
1502
|
-
*/
|
|
1503
|
-
tokenList: 5,
|
|
1504
|
-
/**
|
|
1505
|
-
* An event.
|
|
1506
|
-
*/
|
|
1507
|
-
event: 6,
|
|
1508
2134
|
/**
|
|
1509
2135
|
*
|
|
1510
2136
|
* @param directive - The directive to assign the aspect to.
|
|
1511
2137
|
* @param value - The value to base the aspect determination on.
|
|
2138
|
+
* @remarks
|
|
2139
|
+
* If a falsy value is provided, then the content aspect will be assigned.
|
|
1512
2140
|
*/
|
|
1513
|
-
|
|
1514
|
-
directive.sourceAspect = value;
|
|
2141
|
+
assignAspect(directive, value) {
|
|
1515
2142
|
if (!value) {
|
|
2143
|
+
directive.aspectType = DOMAspect.content;
|
|
1516
2144
|
return;
|
|
1517
2145
|
}
|
|
2146
|
+
directive.sourceAspect = value;
|
|
1518
2147
|
switch (value[0]) {
|
|
1519
2148
|
case ":":
|
|
1520
2149
|
directive.targetAspect = value.substring(1);
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
case "classList":
|
|
1526
|
-
directive.aspectType = Aspect.tokenList;
|
|
1527
|
-
break;
|
|
1528
|
-
default:
|
|
1529
|
-
directive.aspectType = Aspect.property;
|
|
1530
|
-
break;
|
|
1531
|
-
}
|
|
2150
|
+
directive.aspectType =
|
|
2151
|
+
directive.targetAspect === "classList"
|
|
2152
|
+
? DOMAspect.tokenList
|
|
2153
|
+
: DOMAspect.property;
|
|
1532
2154
|
break;
|
|
1533
2155
|
case "?":
|
|
1534
2156
|
directive.targetAspect = value.substring(1);
|
|
1535
|
-
directive.aspectType =
|
|
2157
|
+
directive.aspectType = DOMAspect.booleanAttribute;
|
|
1536
2158
|
break;
|
|
1537
2159
|
case "@":
|
|
1538
2160
|
directive.targetAspect = value.substring(1);
|
|
1539
|
-
directive.aspectType =
|
|
2161
|
+
directive.aspectType = DOMAspect.event;
|
|
1540
2162
|
break;
|
|
1541
2163
|
default:
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
directive.aspectType = Aspect.property;
|
|
1545
|
-
}
|
|
1546
|
-
else {
|
|
1547
|
-
directive.targetAspect = value;
|
|
1548
|
-
directive.aspectType = Aspect.attribute;
|
|
1549
|
-
}
|
|
2164
|
+
directive.targetAspect = value;
|
|
2165
|
+
directive.aspectType = DOMAspect.attribute;
|
|
1550
2166
|
break;
|
|
1551
2167
|
}
|
|
1552
2168
|
},
|
|
1553
2169
|
});
|
|
2170
|
+
/**
|
|
2171
|
+
* Decorator: Defines an HTMLDirective.
|
|
2172
|
+
* @param options - Provides options that specify the directive's application.
|
|
2173
|
+
* @public
|
|
2174
|
+
*/
|
|
2175
|
+
function htmlDirective(options) {
|
|
2176
|
+
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
2177
|
+
return function (type) {
|
|
2178
|
+
HTMLDirective.define(type, options);
|
|
2179
|
+
};
|
|
2180
|
+
}
|
|
2181
|
+
/**
|
|
2182
|
+
* Captures a binding expression along with related information and capabilities.
|
|
2183
|
+
*
|
|
2184
|
+
* @public
|
|
2185
|
+
*/
|
|
2186
|
+
class Binding {
|
|
2187
|
+
/**
|
|
2188
|
+
* Creates a binding.
|
|
2189
|
+
* @param evaluate - Evaluates the binding.
|
|
2190
|
+
* @param policy - The security policy to associate with this binding.
|
|
2191
|
+
* @param isVolatile - Indicates whether the binding is volatile.
|
|
2192
|
+
*/
|
|
2193
|
+
constructor(evaluate, policy, isVolatile = false) {
|
|
2194
|
+
this.evaluate = evaluate;
|
|
2195
|
+
this.policy = policy;
|
|
2196
|
+
this.isVolatile = isVolatile;
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
1554
2199
|
/**
|
|
1555
2200
|
* A base class used for attribute directives that don't need internal state.
|
|
1556
2201
|
* @public
|
|
@@ -1562,13 +2207,11 @@ class StatelessAttachedAttributeDirective {
|
|
|
1562
2207
|
*/
|
|
1563
2208
|
constructor(options) {
|
|
1564
2209
|
this.options = options;
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
createBehavior(targets) {
|
|
1571
|
-
return this;
|
|
2210
|
+
/**
|
|
2211
|
+
* Opts out of JSON stringification.
|
|
2212
|
+
* @internal
|
|
2213
|
+
*/
|
|
2214
|
+
this.toJSON = noop;
|
|
1572
2215
|
}
|
|
1573
2216
|
/**
|
|
1574
2217
|
* Creates a placeholder string based on the directive's index within the template.
|
|
@@ -1579,118 +2222,43 @@ class StatelessAttachedAttributeDirective {
|
|
|
1579
2222
|
createHTML(add) {
|
|
1580
2223
|
return Markup.attribute(add(this));
|
|
1581
2224
|
}
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
const createInnerHTMLBinding = globalThis.TrustedHTML
|
|
1585
|
-
? (binding) => (s, c) => {
|
|
1586
|
-
const value = binding(s, c);
|
|
1587
|
-
if (value instanceof TrustedHTML) {
|
|
1588
|
-
return value;
|
|
1589
|
-
}
|
|
1590
|
-
throw FAST.error(1202 /* Message.bindingInnerHTMLRequiresTrustedTypes */);
|
|
1591
|
-
}
|
|
1592
|
-
: (binding) => binding;
|
|
1593
|
-
/**
|
|
1594
|
-
* Describes how aspects of an HTML element will be affected by bindings.
|
|
1595
|
-
* @public
|
|
1596
|
-
*/
|
|
1597
|
-
const BindingMode = Object.freeze({
|
|
1598
|
-
/**
|
|
1599
|
-
* Creates a binding mode based on the supplied behavior types.
|
|
1600
|
-
* @param UpdateType - The base behavior type used to update aspects.
|
|
1601
|
-
* @param EventType - The base behavior type used to respond to events.
|
|
1602
|
-
* @returns A new binding mode.
|
|
1603
|
-
*/
|
|
1604
|
-
define(UpdateType, EventType = EventBinding) {
|
|
1605
|
-
return Object.freeze({
|
|
1606
|
-
[1]: d => new UpdateType(d, DOM.setAttribute),
|
|
1607
|
-
[2]: d => new UpdateType(d, DOM.setBooleanAttribute),
|
|
1608
|
-
[3]: d => new UpdateType(d, (t, a, v) => (t[a] = v)),
|
|
1609
|
-
[4]: d => new (createContentBinding(UpdateType))(d, updateContentTarget),
|
|
1610
|
-
[5]: d => new UpdateType(d, updateTokenListTarget),
|
|
1611
|
-
[6]: d => new EventType(d),
|
|
1612
|
-
});
|
|
1613
|
-
},
|
|
1614
|
-
});
|
|
1615
|
-
/**
|
|
1616
|
-
* Describes the configuration for a binding expression.
|
|
1617
|
-
* @public
|
|
1618
|
-
*/
|
|
1619
|
-
const BindingConfig = Object.freeze({
|
|
1620
|
-
/**
|
|
1621
|
-
* Creates a binding configuration based on the provided mode and options.
|
|
1622
|
-
* @param mode - The mode to use for the configuration.
|
|
1623
|
-
* @param defaultOptions - The default options to use for the configuration.
|
|
1624
|
-
* @returns A new binding configuration.
|
|
1625
|
-
*/
|
|
1626
|
-
define(mode, defaultOptions) {
|
|
1627
|
-
const config = (options) => {
|
|
1628
|
-
return {
|
|
1629
|
-
mode: config.mode,
|
|
1630
|
-
options: Object.assign({}, defaultOptions, options),
|
|
1631
|
-
};
|
|
1632
|
-
};
|
|
1633
|
-
config.options = defaultOptions;
|
|
1634
|
-
config.mode = mode;
|
|
1635
|
-
return config;
|
|
1636
|
-
},
|
|
1637
|
-
});
|
|
1638
|
-
/**
|
|
1639
|
-
* A base binding behavior for DOM updates.
|
|
1640
|
-
* @public
|
|
1641
|
-
*/
|
|
1642
|
-
class UpdateBinding {
|
|
1643
|
-
/**
|
|
1644
|
-
* Creates an instance of UpdateBinding.
|
|
1645
|
-
* @param directive - The directive that has the configuration for this behavior.
|
|
1646
|
-
* @param updateTarget - The function used to update the target with the latest value.
|
|
1647
|
-
*/
|
|
1648
|
-
constructor(directive, updateTarget) {
|
|
1649
|
-
this.directive = directive;
|
|
1650
|
-
this.updateTarget = updateTarget;
|
|
1651
|
-
}
|
|
1652
|
-
/**
|
|
1653
|
-
* Bind this behavior to the source.
|
|
1654
|
-
* @param source - The source to bind to.
|
|
1655
|
-
* @param context - The execution context that the binding is operating within.
|
|
1656
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1657
|
-
*/
|
|
1658
|
-
bind(source, context, targets) { }
|
|
1659
|
-
/**
|
|
1660
|
-
* Unbinds this behavior from the source.
|
|
1661
|
-
* @param source - The source to unbind from.
|
|
1662
|
-
* @param context - The execution context that the binding is operating within.
|
|
1663
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1664
|
-
*/
|
|
1665
|
-
unbind(source, context, targets) { }
|
|
1666
2225
|
/**
|
|
1667
2226
|
* Creates a behavior.
|
|
1668
2227
|
* @param targets - The targets available for behaviors to be attached to.
|
|
1669
2228
|
*/
|
|
1670
|
-
createBehavior(
|
|
2229
|
+
createBehavior() {
|
|
1671
2230
|
return this;
|
|
1672
2231
|
}
|
|
1673
2232
|
}
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
2233
|
+
|
|
2234
|
+
class OnChangeBinding extends Binding {
|
|
2235
|
+
createObserver(_, subscriber) {
|
|
2236
|
+
return Observable.binding(this.evaluate, subscriber, this.isVolatile);
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
class OneTimeBinding extends Binding {
|
|
2240
|
+
constructor() {
|
|
2241
|
+
super(...arguments);
|
|
2242
|
+
/**
|
|
2243
|
+
* Opts out of JSON stringification.
|
|
2244
|
+
* @internal
|
|
2245
|
+
*/
|
|
2246
|
+
this.toJSON = noop;
|
|
2247
|
+
}
|
|
2248
|
+
createObserver() {
|
|
2249
|
+
return this;
|
|
2250
|
+
}
|
|
2251
|
+
bind(controller) {
|
|
2252
|
+
return this.evaluate(controller.source, controller.context);
|
|
2253
|
+
}
|
|
1686
2254
|
}
|
|
1687
|
-
function
|
|
2255
|
+
function updateContent(target, aspect, value, controller) {
|
|
1688
2256
|
// If there's no actual value, then this equates to the
|
|
1689
2257
|
// empty string for the purposes of content bindings.
|
|
1690
2258
|
if (value === null || value === undefined) {
|
|
1691
2259
|
value = "";
|
|
1692
2260
|
}
|
|
1693
|
-
// If the value has a "create" method, then it's a
|
|
2261
|
+
// If the value has a "create" method, then it's a ContentTemplate.
|
|
1694
2262
|
if (value.create) {
|
|
1695
2263
|
target.textContent = "";
|
|
1696
2264
|
let view = target.$fastView;
|
|
@@ -1716,14 +2284,14 @@ function updateContentTarget(target, aspect, value, source, context) {
|
|
|
1716
2284
|
// and that there's actually no need to compose it.
|
|
1717
2285
|
if (!view.isComposed) {
|
|
1718
2286
|
view.isComposed = true;
|
|
1719
|
-
view.bind(source, context);
|
|
2287
|
+
view.bind(controller.source, controller.context);
|
|
1720
2288
|
view.insertBefore(target);
|
|
1721
2289
|
target.$fastView = view;
|
|
1722
2290
|
target.$fastTemplate = value;
|
|
1723
2291
|
}
|
|
1724
2292
|
else if (view.needsBindOnly) {
|
|
1725
2293
|
view.needsBindOnly = false;
|
|
1726
|
-
view.bind(source, context);
|
|
2294
|
+
view.bind(controller.source, controller.context);
|
|
1727
2295
|
}
|
|
1728
2296
|
}
|
|
1729
2297
|
else {
|
|
@@ -1731,199 +2299,58 @@ function updateContentTarget(target, aspect, value, source, context) {
|
|
|
1731
2299
|
// If there is a view and it's currently composed into
|
|
1732
2300
|
// the DOM, then we need to remove it.
|
|
1733
2301
|
if (view !== void 0 && view.isComposed) {
|
|
1734
|
-
view.isComposed = false;
|
|
1735
|
-
view.remove();
|
|
1736
|
-
if (view.needsBindOnly) {
|
|
1737
|
-
view.needsBindOnly = false;
|
|
1738
|
-
}
|
|
1739
|
-
else {
|
|
1740
|
-
view.unbind();
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
target.textContent = value;
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1746
|
-
function updateTokenListTarget(target, aspect, value) {
|
|
1747
|
-
var _a;
|
|
1748
|
-
const directive = this.directive;
|
|
1749
|
-
const lookup = `${directive.id}-t`;
|
|
1750
|
-
const state = (_a = target[lookup]) !== null && _a !== void 0 ? _a : (target[lookup] = { c: 0, v: Object.create(null) });
|
|
1751
|
-
const versions = state.v;
|
|
1752
|
-
let currentVersion = state.c;
|
|
1753
|
-
const tokenList = target[aspect];
|
|
1754
|
-
// Add the classes, tracking the version at which they were added.
|
|
1755
|
-
if (value !== null && value !== undefined && value.length) {
|
|
1756
|
-
const names = value.split(/\s+/);
|
|
1757
|
-
for (let i = 0, ii = names.length; i < ii; ++i) {
|
|
1758
|
-
const currentName = names[i];
|
|
1759
|
-
if (currentName === "") {
|
|
1760
|
-
continue;
|
|
1761
|
-
}
|
|
1762
|
-
versions[currentName] = currentVersion;
|
|
1763
|
-
tokenList.add(currentName);
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
state.v = currentVersion + 1;
|
|
1767
|
-
// If this is the first call to add classes, there's no need to remove old ones.
|
|
1768
|
-
if (currentVersion === 0) {
|
|
1769
|
-
return;
|
|
1770
|
-
}
|
|
1771
|
-
// Remove classes from the previous version.
|
|
1772
|
-
currentVersion -= 1;
|
|
1773
|
-
for (const name in versions) {
|
|
1774
|
-
if (versions[name] === currentVersion) {
|
|
1775
|
-
tokenList.remove(name);
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
/**
|
|
1780
|
-
* A binding behavior for one-time bindings.
|
|
1781
|
-
* @public
|
|
1782
|
-
*/
|
|
1783
|
-
class OneTimeBinding extends UpdateBinding {
|
|
1784
|
-
/**
|
|
1785
|
-
* Bind this behavior to the source.
|
|
1786
|
-
* @param source - The source to bind to.
|
|
1787
|
-
* @param context - The execution context that the binding is operating within.
|
|
1788
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1789
|
-
*/
|
|
1790
|
-
bind(source, context, targets) {
|
|
1791
|
-
const directive = this.directive;
|
|
1792
|
-
this.updateTarget(targets[directive.nodeId], directive.targetAspect, directive.binding(source, context), source, context);
|
|
1793
|
-
}
|
|
1794
|
-
}
|
|
1795
|
-
/**
|
|
1796
|
-
* A binding behavior for bindings that change.
|
|
1797
|
-
* @public
|
|
1798
|
-
*/
|
|
1799
|
-
class ChangeBinding extends UpdateBinding {
|
|
1800
|
-
/**
|
|
1801
|
-
* Creates an instance of ChangeBinding.
|
|
1802
|
-
* @param directive - The directive that has the configuration for this behavior.
|
|
1803
|
-
* @param updateTarget - The function used to update the target with the latest value.
|
|
1804
|
-
*/
|
|
1805
|
-
constructor(directive, updateTarget) {
|
|
1806
|
-
super(directive, updateTarget);
|
|
1807
|
-
this.isBindingVolatile = Observable.isVolatileBinding(directive.binding);
|
|
1808
|
-
this.observerProperty = `${directive.id}-o`;
|
|
1809
|
-
}
|
|
1810
|
-
/**
|
|
1811
|
-
* Returns the binding observer used to update the node.
|
|
1812
|
-
* @param target - The target node.
|
|
1813
|
-
* @returns A BindingObserver.
|
|
1814
|
-
*/
|
|
1815
|
-
getObserver(target) {
|
|
1816
|
-
var _a;
|
|
1817
|
-
return ((_a = target[this.observerProperty]) !== null && _a !== void 0 ? _a : (target[this.observerProperty] = Observable.binding(this.directive.binding, this, this.isBindingVolatile)));
|
|
1818
|
-
}
|
|
1819
|
-
/**
|
|
1820
|
-
* Bind this behavior to the source.
|
|
1821
|
-
* @param source - The source to bind to.
|
|
1822
|
-
* @param context - The execution context that the binding is operating within.
|
|
1823
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1824
|
-
*/
|
|
1825
|
-
bind(source, context, targets) {
|
|
1826
|
-
const directive = this.directive;
|
|
1827
|
-
const target = targets[directive.nodeId];
|
|
1828
|
-
const observer = this.getObserver(target);
|
|
1829
|
-
observer.target = target;
|
|
1830
|
-
observer.source = source;
|
|
1831
|
-
observer.context = context;
|
|
1832
|
-
this.updateTarget(target, directive.targetAspect, observer.observe(source, context), source, context);
|
|
1833
|
-
}
|
|
1834
|
-
/**
|
|
1835
|
-
* Unbinds this behavior from the source.
|
|
1836
|
-
* @param source - The source to unbind from.
|
|
1837
|
-
* @param context - The execution context that the binding is operating within.
|
|
1838
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1839
|
-
*/
|
|
1840
|
-
unbind(source, context, targets) {
|
|
1841
|
-
const target = targets[this.directive.nodeId];
|
|
1842
|
-
const observer = this.getObserver(target);
|
|
1843
|
-
observer.dispose();
|
|
1844
|
-
observer.target = null;
|
|
1845
|
-
observer.source = null;
|
|
1846
|
-
observer.context = null;
|
|
1847
|
-
}
|
|
1848
|
-
/** @internal */
|
|
1849
|
-
handleChange(binding, observer) {
|
|
1850
|
-
const target = observer.target;
|
|
1851
|
-
const source = observer.source;
|
|
1852
|
-
const context = observer.context;
|
|
1853
|
-
this.updateTarget(target, this.directive.targetAspect, observer.observe(source, context), source, context);
|
|
1854
|
-
}
|
|
1855
|
-
}
|
|
1856
|
-
/**
|
|
1857
|
-
* A binding behavior for handling events.
|
|
1858
|
-
* @public
|
|
1859
|
-
*/
|
|
1860
|
-
class EventBinding {
|
|
1861
|
-
/**
|
|
1862
|
-
* Creates an instance of EventBinding.
|
|
1863
|
-
* @param directive - The directive that has the configuration for this behavior.
|
|
1864
|
-
*/
|
|
1865
|
-
constructor(directive) {
|
|
1866
|
-
this.directive = directive;
|
|
1867
|
-
this.sourceProperty = `${directive.id}-s`;
|
|
1868
|
-
this.contextProperty = `${directive.id}-c`;
|
|
1869
|
-
}
|
|
1870
|
-
/**
|
|
1871
|
-
* Bind this behavior to the source.
|
|
1872
|
-
* @param source - The source to bind to.
|
|
1873
|
-
* @param context - The execution context that the binding is operating within.
|
|
1874
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1875
|
-
*/
|
|
1876
|
-
bind(source, context, targets) {
|
|
1877
|
-
const directive = this.directive;
|
|
1878
|
-
const target = targets[directive.nodeId];
|
|
1879
|
-
target[this.sourceProperty] = source;
|
|
1880
|
-
target[this.contextProperty] = context;
|
|
1881
|
-
target.addEventListener(directive.targetAspect, this, directive.options);
|
|
2302
|
+
view.isComposed = false;
|
|
2303
|
+
view.remove();
|
|
2304
|
+
if (view.needsBindOnly) {
|
|
2305
|
+
view.needsBindOnly = false;
|
|
2306
|
+
}
|
|
2307
|
+
else {
|
|
2308
|
+
view.unbind();
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
target.textContent = value;
|
|
1882
2312
|
}
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
2313
|
+
}
|
|
2314
|
+
function updateTokenList(target, aspect, value) {
|
|
2315
|
+
var _a;
|
|
2316
|
+
const lookup = `${this.id}-t`;
|
|
2317
|
+
const state = (_a = target[lookup]) !== null && _a !== void 0 ? _a : (target[lookup] = { v: 0, cv: Object.create(null) });
|
|
2318
|
+
const classVersions = state.cv;
|
|
2319
|
+
let version = state.v;
|
|
2320
|
+
const tokenList = target[aspect];
|
|
2321
|
+
// Add the classes, tracking the version at which they were added.
|
|
2322
|
+
if (value !== null && value !== undefined && value.length) {
|
|
2323
|
+
const names = value.split(/\s+/);
|
|
2324
|
+
for (let i = 0, ii = names.length; i < ii; ++i) {
|
|
2325
|
+
const currentName = names[i];
|
|
2326
|
+
if (currentName === "") {
|
|
2327
|
+
continue;
|
|
2328
|
+
}
|
|
2329
|
+
classVersions[currentName] = version;
|
|
2330
|
+
tokenList.add(currentName);
|
|
2331
|
+
}
|
|
1894
2332
|
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
createBehavior(targets) {
|
|
1900
|
-
return this;
|
|
2333
|
+
state.v = version + 1;
|
|
2334
|
+
// If this is the first call to add classes, there's no need to remove old ones.
|
|
2335
|
+
if (version === 0) {
|
|
2336
|
+
return;
|
|
1901
2337
|
}
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
ExecutionContext.setEvent(event);
|
|
1908
|
-
const result = this.directive.binding(target[this.sourceProperty], target[this.contextProperty]);
|
|
1909
|
-
ExecutionContext.setEvent(null);
|
|
1910
|
-
if (result !== true) {
|
|
1911
|
-
event.preventDefault();
|
|
2338
|
+
// Remove classes from the previous version.
|
|
2339
|
+
version -= 1;
|
|
2340
|
+
for (const name in classVersions) {
|
|
2341
|
+
if (classVersions[name] === version) {
|
|
2342
|
+
tokenList.remove(name);
|
|
1912
2343
|
}
|
|
1913
2344
|
}
|
|
1914
2345
|
}
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
*/
|
|
1924
|
-
const oneTime = BindingConfig.define(BindingMode.define(OneTimeBinding), {
|
|
1925
|
-
once: true,
|
|
1926
|
-
});
|
|
2346
|
+
const sinkLookup = {
|
|
2347
|
+
[DOMAspect.attribute]: DOM.setAttribute,
|
|
2348
|
+
[DOMAspect.booleanAttribute]: DOM.setBooleanAttribute,
|
|
2349
|
+
[DOMAspect.property]: (t, a, v) => (t[a] = v),
|
|
2350
|
+
[DOMAspect.content]: updateContent,
|
|
2351
|
+
[DOMAspect.tokenList]: updateTokenList,
|
|
2352
|
+
[DOMAspect.event]: () => void 0,
|
|
2353
|
+
};
|
|
1927
2354
|
/**
|
|
1928
2355
|
* A directive that applies bindings.
|
|
1929
2356
|
* @public
|
|
@@ -1931,19 +2358,15 @@ const oneTime = BindingConfig.define(BindingMode.define(OneTimeBinding), {
|
|
|
1931
2358
|
class HTMLBindingDirective {
|
|
1932
2359
|
/**
|
|
1933
2360
|
* Creates an instance of HTMLBindingDirective.
|
|
1934
|
-
* @param
|
|
1935
|
-
* @param mode - The binding mode to use when applying the binding.
|
|
1936
|
-
* @param options - The options to configure the binding with.
|
|
2361
|
+
* @param dataBinding - The binding configuration to apply.
|
|
1937
2362
|
*/
|
|
1938
|
-
constructor(
|
|
1939
|
-
this.
|
|
1940
|
-
this.
|
|
1941
|
-
this.options = options;
|
|
1942
|
-
this.factory = null;
|
|
2363
|
+
constructor(dataBinding) {
|
|
2364
|
+
this.dataBinding = dataBinding;
|
|
2365
|
+
this.updateTarget = null;
|
|
1943
2366
|
/**
|
|
1944
2367
|
* The type of aspect to target.
|
|
1945
2368
|
*/
|
|
1946
|
-
this.aspectType =
|
|
2369
|
+
this.aspectType = DOMAspect.content;
|
|
1947
2370
|
}
|
|
1948
2371
|
/**
|
|
1949
2372
|
* Creates HTML to be used within a template.
|
|
@@ -1954,31 +2377,114 @@ class HTMLBindingDirective {
|
|
|
1954
2377
|
}
|
|
1955
2378
|
/**
|
|
1956
2379
|
* Creates a behavior.
|
|
1957
|
-
* @param targets - The targets available for behaviors to be attached to.
|
|
1958
2380
|
*/
|
|
1959
|
-
createBehavior(
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
2381
|
+
createBehavior() {
|
|
2382
|
+
var _a;
|
|
2383
|
+
if (this.updateTarget === null) {
|
|
2384
|
+
const sink = sinkLookup[this.aspectType];
|
|
2385
|
+
const policy = (_a = this.dataBinding.policy) !== null && _a !== void 0 ? _a : this.policy;
|
|
2386
|
+
if (!sink) {
|
|
2387
|
+
throw FAST.error(1205 /* Message.unsupportedBindingBehavior */);
|
|
2388
|
+
}
|
|
2389
|
+
this.data = `${this.id}-d`;
|
|
2390
|
+
this.updateTarget = policy.protect(this.targetTagName, this.aspectType, this.targetAspect, sink);
|
|
2391
|
+
}
|
|
2392
|
+
return this;
|
|
2393
|
+
}
|
|
2394
|
+
/** @internal */
|
|
2395
|
+
bind(controller) {
|
|
2396
|
+
var _a;
|
|
2397
|
+
const target = controller.targets[this.targetNodeId];
|
|
2398
|
+
switch (this.aspectType) {
|
|
2399
|
+
case DOMAspect.event:
|
|
2400
|
+
target[this.data] = controller;
|
|
2401
|
+
target.addEventListener(this.targetAspect, this, this.dataBinding.options);
|
|
2402
|
+
break;
|
|
2403
|
+
case DOMAspect.content:
|
|
2404
|
+
controller.onUnbind(this);
|
|
2405
|
+
// intentional fall through
|
|
2406
|
+
default:
|
|
2407
|
+
const observer = (_a = target[this.data]) !== null && _a !== void 0 ? _a : (target[this.data] = this.dataBinding.createObserver(this, this));
|
|
2408
|
+
observer.target = target;
|
|
2409
|
+
observer.controller = controller;
|
|
2410
|
+
this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
|
|
2411
|
+
break;
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
/** @internal */
|
|
2415
|
+
unbind(controller) {
|
|
2416
|
+
const target = controller.targets[this.targetNodeId];
|
|
2417
|
+
const view = target.$fastView;
|
|
2418
|
+
if (view !== void 0 && view.isComposed) {
|
|
2419
|
+
view.unbind();
|
|
2420
|
+
view.needsBindOnly = true;
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
/** @internal */
|
|
2424
|
+
handleEvent(event) {
|
|
2425
|
+
const controller = event.currentTarget[this.data];
|
|
2426
|
+
if (controller.isBound) {
|
|
2427
|
+
ExecutionContext.setEvent(event);
|
|
2428
|
+
const result = this.dataBinding.evaluate(controller.source, controller.context);
|
|
2429
|
+
ExecutionContext.setEvent(null);
|
|
2430
|
+
if (result !== true) {
|
|
2431
|
+
event.preventDefault();
|
|
1963
2432
|
}
|
|
1964
|
-
this.factory = this.mode[this.aspectType](this);
|
|
1965
2433
|
}
|
|
1966
|
-
|
|
2434
|
+
}
|
|
2435
|
+
/** @internal */
|
|
2436
|
+
handleChange(binding, observer) {
|
|
2437
|
+
const target = observer.target;
|
|
2438
|
+
const controller = observer.controller;
|
|
2439
|
+
this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
|
|
1967
2440
|
}
|
|
1968
2441
|
}
|
|
1969
2442
|
HTMLDirective.define(HTMLBindingDirective, { aspected: true });
|
|
1970
2443
|
/**
|
|
1971
|
-
* Creates
|
|
1972
|
-
* @param
|
|
1973
|
-
* @param
|
|
1974
|
-
* @
|
|
2444
|
+
* Creates an standard binding.
|
|
2445
|
+
* @param expression - The binding to refresh when changed.
|
|
2446
|
+
* @param policy - The security policy to associate with th binding.
|
|
2447
|
+
* @param isVolatile - Indicates whether the binding is volatile or not.
|
|
2448
|
+
* @returns A binding configuration.
|
|
1975
2449
|
* @public
|
|
1976
2450
|
*/
|
|
1977
|
-
function bind(
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
2451
|
+
function bind(expression, policy, isVolatile = Observable.isVolatileBinding(expression)) {
|
|
2452
|
+
return new OnChangeBinding(expression, policy, isVolatile);
|
|
2453
|
+
}
|
|
2454
|
+
/**
|
|
2455
|
+
* Creates a one time binding
|
|
2456
|
+
* @param expression - The binding to refresh when signaled.
|
|
2457
|
+
* @param policy - The security policy to associate with th binding.
|
|
2458
|
+
* @returns A binding configuration.
|
|
2459
|
+
* @public
|
|
2460
|
+
*/
|
|
2461
|
+
function oneTime(expression, policy) {
|
|
2462
|
+
return new OneTimeBinding(expression, policy);
|
|
2463
|
+
}
|
|
2464
|
+
/**
|
|
2465
|
+
* Creates an event listener binding.
|
|
2466
|
+
* @param expression - The binding to invoke when the event is raised.
|
|
2467
|
+
* @param options - Event listener options.
|
|
2468
|
+
* @returns A binding configuration.
|
|
2469
|
+
* @public
|
|
2470
|
+
*/
|
|
2471
|
+
function listener(expression, options) {
|
|
2472
|
+
const config = new OnChangeBinding(expression);
|
|
2473
|
+
config.options = options;
|
|
2474
|
+
return config;
|
|
2475
|
+
}
|
|
2476
|
+
/**
|
|
2477
|
+
* Normalizes the input value into a binding.
|
|
2478
|
+
* @param value - The value to create the default binding for.
|
|
2479
|
+
* @returns A binding configuration for the provided value.
|
|
2480
|
+
* @public
|
|
2481
|
+
*/
|
|
2482
|
+
function normalizeBinding(value) {
|
|
2483
|
+
return isFunction(value)
|
|
2484
|
+
? bind(value)
|
|
2485
|
+
: value instanceof Binding
|
|
2486
|
+
? value
|
|
2487
|
+
: oneTime(() => value);
|
|
1982
2488
|
}
|
|
1983
2489
|
|
|
1984
2490
|
function removeNodeSequence(firstNode, lastNode) {
|
|
@@ -2007,17 +2513,92 @@ class HTMLView {
|
|
|
2007
2513
|
this.factories = factories;
|
|
2008
2514
|
this.targets = targets;
|
|
2009
2515
|
this.behaviors = null;
|
|
2516
|
+
this.unbindables = [];
|
|
2010
2517
|
/**
|
|
2011
2518
|
* The data that the view is bound to.
|
|
2012
2519
|
*/
|
|
2013
2520
|
this.source = null;
|
|
2521
|
+
/**
|
|
2522
|
+
* Indicates whether the controller is bound.
|
|
2523
|
+
*/
|
|
2524
|
+
this.isBound = false;
|
|
2525
|
+
/**
|
|
2526
|
+
* Indicates how the source's lifetime relates to the controller's lifetime.
|
|
2527
|
+
*/
|
|
2528
|
+
this.sourceLifetime = SourceLifetime.unknown;
|
|
2014
2529
|
/**
|
|
2015
2530
|
* The execution context the view is running within.
|
|
2016
2531
|
*/
|
|
2017
|
-
this.context =
|
|
2532
|
+
this.context = this;
|
|
2533
|
+
/**
|
|
2534
|
+
* The index of the current item within a repeat context.
|
|
2535
|
+
*/
|
|
2536
|
+
this.index = 0;
|
|
2537
|
+
/**
|
|
2538
|
+
* The length of the current collection within a repeat context.
|
|
2539
|
+
*/
|
|
2540
|
+
this.length = 0;
|
|
2541
|
+
/**
|
|
2542
|
+
* Opts out of JSON stringification.
|
|
2543
|
+
* @internal
|
|
2544
|
+
*/
|
|
2545
|
+
this.toJSON = noop;
|
|
2018
2546
|
this.firstChild = fragment.firstChild;
|
|
2019
2547
|
this.lastChild = fragment.lastChild;
|
|
2020
2548
|
}
|
|
2549
|
+
/**
|
|
2550
|
+
* The current event within an event handler.
|
|
2551
|
+
*/
|
|
2552
|
+
get event() {
|
|
2553
|
+
return ExecutionContext.getEvent();
|
|
2554
|
+
}
|
|
2555
|
+
/**
|
|
2556
|
+
* Indicates whether the current item within a repeat context
|
|
2557
|
+
* has an even index.
|
|
2558
|
+
*/
|
|
2559
|
+
get isEven() {
|
|
2560
|
+
return this.index % 2 === 0;
|
|
2561
|
+
}
|
|
2562
|
+
/**
|
|
2563
|
+
* Indicates whether the current item within a repeat context
|
|
2564
|
+
* has an odd index.
|
|
2565
|
+
*/
|
|
2566
|
+
get isOdd() {
|
|
2567
|
+
return this.index % 2 !== 0;
|
|
2568
|
+
}
|
|
2569
|
+
/**
|
|
2570
|
+
* Indicates whether the current item within a repeat context
|
|
2571
|
+
* is the first item in the collection.
|
|
2572
|
+
*/
|
|
2573
|
+
get isFirst() {
|
|
2574
|
+
return this.index === 0;
|
|
2575
|
+
}
|
|
2576
|
+
/**
|
|
2577
|
+
* Indicates whether the current item within a repeat context
|
|
2578
|
+
* is somewhere in the middle of the collection.
|
|
2579
|
+
*/
|
|
2580
|
+
get isInMiddle() {
|
|
2581
|
+
return !this.isFirst && !this.isLast;
|
|
2582
|
+
}
|
|
2583
|
+
/**
|
|
2584
|
+
* Indicates whether the current item within a repeat context
|
|
2585
|
+
* is the last item in the collection.
|
|
2586
|
+
*/
|
|
2587
|
+
get isLast() {
|
|
2588
|
+
return this.index === this.length - 1;
|
|
2589
|
+
}
|
|
2590
|
+
/**
|
|
2591
|
+
* Returns the typed event detail of a custom event.
|
|
2592
|
+
*/
|
|
2593
|
+
eventDetail() {
|
|
2594
|
+
return this.event.detail;
|
|
2595
|
+
}
|
|
2596
|
+
/**
|
|
2597
|
+
* Returns the typed event target of the event.
|
|
2598
|
+
*/
|
|
2599
|
+
eventTarget() {
|
|
2600
|
+
return this.event.target;
|
|
2601
|
+
}
|
|
2021
2602
|
/**
|
|
2022
2603
|
* Appends the view's DOM nodes to the referenced node.
|
|
2023
2604
|
* @param node - The parent node to append the view's DOM nodes to.
|
|
@@ -2034,8 +2615,10 @@ class HTMLView {
|
|
|
2034
2615
|
node.parentNode.insertBefore(this.fragment, node);
|
|
2035
2616
|
}
|
|
2036
2617
|
else {
|
|
2037
|
-
const parentNode = node.parentNode;
|
|
2038
2618
|
const end = this.lastChild;
|
|
2619
|
+
if (node.previousSibling === end)
|
|
2620
|
+
return;
|
|
2621
|
+
const parentNode = node.parentNode;
|
|
2039
2622
|
let current = this.firstChild;
|
|
2040
2623
|
let next;
|
|
2041
2624
|
while (current !== end) {
|
|
@@ -2070,58 +2653,61 @@ class HTMLView {
|
|
|
2070
2653
|
removeNodeSequence(this.firstChild, this.lastChild);
|
|
2071
2654
|
this.unbind();
|
|
2072
2655
|
}
|
|
2656
|
+
onUnbind(behavior) {
|
|
2657
|
+
this.unbindables.push(behavior);
|
|
2658
|
+
}
|
|
2073
2659
|
/**
|
|
2074
2660
|
* Binds a view's behaviors to its binding source.
|
|
2075
2661
|
* @param source - The binding source for the view's binding behaviors.
|
|
2076
2662
|
* @param context - The execution context to run the behaviors within.
|
|
2077
2663
|
*/
|
|
2078
|
-
bind(source, context) {
|
|
2079
|
-
|
|
2080
|
-
const oldSource = this.source;
|
|
2081
|
-
if (oldSource === source) {
|
|
2664
|
+
bind(source, context = this) {
|
|
2665
|
+
if (this.source === source) {
|
|
2082
2666
|
return;
|
|
2083
2667
|
}
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
2089
|
-
const current = behaviors[i];
|
|
2090
|
-
current.unbind(oldSource, context, targets);
|
|
2091
|
-
current.bind(source, context, targets);
|
|
2092
|
-
}
|
|
2093
|
-
}
|
|
2094
|
-
else if (behaviors === null) {
|
|
2668
|
+
let behaviors = this.behaviors;
|
|
2669
|
+
if (behaviors === null) {
|
|
2670
|
+
this.source = source;
|
|
2671
|
+
this.context = context;
|
|
2095
2672
|
this.behaviors = behaviors = new Array(this.factories.length);
|
|
2096
2673
|
const factories = this.factories;
|
|
2097
2674
|
for (let i = 0, ii = factories.length; i < ii; ++i) {
|
|
2098
|
-
const behavior = factories[i].createBehavior(
|
|
2099
|
-
behavior.bind(
|
|
2675
|
+
const behavior = factories[i].createBehavior();
|
|
2676
|
+
behavior.bind(this);
|
|
2100
2677
|
behaviors[i] = behavior;
|
|
2101
2678
|
}
|
|
2102
2679
|
}
|
|
2103
2680
|
else {
|
|
2681
|
+
if (this.source !== null) {
|
|
2682
|
+
this.evaluateUnbindables();
|
|
2683
|
+
}
|
|
2684
|
+
this.isBound = false;
|
|
2685
|
+
this.source = source;
|
|
2686
|
+
this.context = context;
|
|
2104
2687
|
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
2105
|
-
behaviors[i].bind(
|
|
2688
|
+
behaviors[i].bind(this);
|
|
2106
2689
|
}
|
|
2107
2690
|
}
|
|
2691
|
+
this.isBound = true;
|
|
2108
2692
|
}
|
|
2109
2693
|
/**
|
|
2110
2694
|
* Unbinds a view's behaviors from its binding source.
|
|
2111
2695
|
*/
|
|
2112
2696
|
unbind() {
|
|
2113
|
-
|
|
2114
|
-
if (oldSource === null) {
|
|
2697
|
+
if (!this.isBound || this.source === null) {
|
|
2115
2698
|
return;
|
|
2116
2699
|
}
|
|
2117
|
-
|
|
2118
|
-
const context = this.context;
|
|
2119
|
-
const behaviors = this.behaviors;
|
|
2120
|
-
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
2121
|
-
behaviors[i].unbind(oldSource, context, targets);
|
|
2122
|
-
}
|
|
2700
|
+
this.evaluateUnbindables();
|
|
2123
2701
|
this.source = null;
|
|
2124
|
-
this.context =
|
|
2702
|
+
this.context = this;
|
|
2703
|
+
this.isBound = false;
|
|
2704
|
+
}
|
|
2705
|
+
evaluateUnbindables() {
|
|
2706
|
+
const unbindables = this.unbindables;
|
|
2707
|
+
for (let i = 0, ii = unbindables.length; i < ii; ++i) {
|
|
2708
|
+
unbindables[i].unbind(this);
|
|
2709
|
+
}
|
|
2710
|
+
unbindables.length = 0;
|
|
2125
2711
|
}
|
|
2126
2712
|
/**
|
|
2127
2713
|
* Efficiently disposes of a contiguous range of synthetic view instances.
|
|
@@ -2137,6 +2723,8 @@ class HTMLView {
|
|
|
2137
2723
|
}
|
|
2138
2724
|
}
|
|
2139
2725
|
}
|
|
2726
|
+
Observable.defineProperty(HTMLView.prototype, "index");
|
|
2727
|
+
Observable.defineProperty(HTMLView.prototype, "length");
|
|
2140
2728
|
|
|
2141
2729
|
const targetIdFrom = (parentId, nodeIndex) => `${parentId}.${nodeIndex}`;
|
|
2142
2730
|
const descriptorCache = {};
|
|
@@ -2145,21 +2733,42 @@ const next = {
|
|
|
2145
2733
|
index: 0,
|
|
2146
2734
|
node: null,
|
|
2147
2735
|
};
|
|
2736
|
+
function tryWarn(name) {
|
|
2737
|
+
if (!name.startsWith("fast-")) {
|
|
2738
|
+
FAST.warn(1204 /* Message.hostBindingWithoutHost */, { name });
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
const warningHost = new Proxy(document.createElement("div"), {
|
|
2742
|
+
get(target, property) {
|
|
2743
|
+
tryWarn(property);
|
|
2744
|
+
const value = Reflect.get(target, property);
|
|
2745
|
+
return isFunction(value) ? value.bind(target) : value;
|
|
2746
|
+
},
|
|
2747
|
+
set(target, property, value) {
|
|
2748
|
+
tryWarn(property);
|
|
2749
|
+
return Reflect.set(target, property, value);
|
|
2750
|
+
},
|
|
2751
|
+
});
|
|
2148
2752
|
class CompilationContext {
|
|
2149
|
-
constructor(fragment, directives) {
|
|
2753
|
+
constructor(fragment, directives, policy) {
|
|
2150
2754
|
this.fragment = fragment;
|
|
2151
2755
|
this.directives = directives;
|
|
2756
|
+
this.policy = policy;
|
|
2152
2757
|
this.proto = null;
|
|
2153
2758
|
this.nodeIds = new Set();
|
|
2154
2759
|
this.descriptors = {};
|
|
2155
2760
|
this.factories = [];
|
|
2156
2761
|
}
|
|
2157
|
-
addFactory(factory, parentId, nodeId, targetIndex) {
|
|
2762
|
+
addFactory(factory, parentId, nodeId, targetIndex, tagName) {
|
|
2763
|
+
var _a, _b;
|
|
2158
2764
|
if (!this.nodeIds.has(nodeId)) {
|
|
2159
2765
|
this.nodeIds.add(nodeId);
|
|
2160
2766
|
this.addTargetDescriptor(parentId, nodeId, targetIndex);
|
|
2161
2767
|
}
|
|
2162
|
-
factory.
|
|
2768
|
+
factory.id = (_a = factory.id) !== null && _a !== void 0 ? _a : nextId();
|
|
2769
|
+
factory.targetNodeId = nodeId;
|
|
2770
|
+
factory.targetTagName = tagName;
|
|
2771
|
+
factory.policy = (_b = factory.policy) !== null && _b !== void 0 ? _b : this.policy;
|
|
2163
2772
|
this.factories.push(factory);
|
|
2164
2773
|
}
|
|
2165
2774
|
freeze() {
|
|
@@ -2195,7 +2804,7 @@ class CompilationContext {
|
|
|
2195
2804
|
const fragment = this.fragment.cloneNode(true);
|
|
2196
2805
|
const targets = Object.create(this.proto);
|
|
2197
2806
|
targets.r = fragment;
|
|
2198
|
-
targets.h = hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget :
|
|
2807
|
+
targets.h = hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget : warningHost;
|
|
2199
2808
|
for (const id of this.nodeIds) {
|
|
2200
2809
|
targets[id]; // trigger locator
|
|
2201
2810
|
}
|
|
@@ -2212,19 +2821,19 @@ function compileAttributes(context, parentId, node, nodeId, nodeIndex, includeBa
|
|
|
2212
2821
|
let result = null;
|
|
2213
2822
|
if (parseResult === null) {
|
|
2214
2823
|
if (includeBasicValues) {
|
|
2215
|
-
result =
|
|
2216
|
-
|
|
2824
|
+
result = new HTMLBindingDirective(oneTime(() => attrValue, context.policy));
|
|
2825
|
+
HTMLDirective.assignAspect(result, attr.name);
|
|
2217
2826
|
}
|
|
2218
2827
|
}
|
|
2219
2828
|
else {
|
|
2220
2829
|
/* eslint-disable-next-line @typescript-eslint/no-use-before-define */
|
|
2221
|
-
result = Compiler.aggregate(parseResult);
|
|
2830
|
+
result = Compiler.aggregate(parseResult, context.policy);
|
|
2222
2831
|
}
|
|
2223
2832
|
if (result !== null) {
|
|
2224
2833
|
node.removeAttributeNode(attr);
|
|
2225
2834
|
i--;
|
|
2226
2835
|
ii--;
|
|
2227
|
-
context.addFactory(result, parentId, nodeId, nodeIndex);
|
|
2836
|
+
context.addFactory(result, parentId, nodeId, nodeIndex, node.tagName);
|
|
2228
2837
|
}
|
|
2229
2838
|
}
|
|
2230
2839
|
}
|
|
@@ -2249,7 +2858,8 @@ function compileContent(context, node, parentId, nodeId, nodeIndex) {
|
|
|
2249
2858
|
}
|
|
2250
2859
|
else {
|
|
2251
2860
|
currentNode.textContent = " ";
|
|
2252
|
-
|
|
2861
|
+
HTMLDirective.assignAspect(currentPart);
|
|
2862
|
+
context.addFactory(currentPart, parentId, nodeId, nodeIndex, null);
|
|
2253
2863
|
}
|
|
2254
2864
|
lastNode = currentNode;
|
|
2255
2865
|
}
|
|
@@ -2281,7 +2891,7 @@ function compileNode(context, parentId, node, nodeIndex) {
|
|
|
2281
2891
|
if (parts !== null) {
|
|
2282
2892
|
context.addFactory(
|
|
2283
2893
|
/* eslint-disable-next-line @typescript-eslint/no-use-before-define */
|
|
2284
|
-
Compiler.aggregate(parts), parentId, nodeId, nodeIndex);
|
|
2894
|
+
Compiler.aggregate(parts), parentId, nodeId, nodeIndex, null);
|
|
2285
2895
|
}
|
|
2286
2896
|
break;
|
|
2287
2897
|
}
|
|
@@ -2295,45 +2905,28 @@ function isMarker(node, directives) {
|
|
|
2295
2905
|
Parser.parse(node.data, directives) !== null);
|
|
2296
2906
|
}
|
|
2297
2907
|
const templateTag = "TEMPLATE";
|
|
2298
|
-
const policyOptions = { createHTML: html => html };
|
|
2299
|
-
let htmlPolicy = globalThis.trustedTypes
|
|
2300
|
-
? globalThis.trustedTypes.createPolicy("fast-html", policyOptions)
|
|
2301
|
-
: policyOptions;
|
|
2302
|
-
const fastHTMLPolicy = htmlPolicy;
|
|
2303
2908
|
/**
|
|
2304
2909
|
* Common APIs related to compilation.
|
|
2305
2910
|
* @public
|
|
2306
2911
|
*/
|
|
2307
2912
|
const Compiler = {
|
|
2308
|
-
/**
|
|
2309
|
-
* Sets the HTML trusted types policy used by the compiler.
|
|
2310
|
-
* @param policy - The policy to set for HTML.
|
|
2311
|
-
* @remarks
|
|
2312
|
-
* This API can only be called once, for security reasons. It should be
|
|
2313
|
-
* called by the application developer at the start of their program.
|
|
2314
|
-
*/
|
|
2315
|
-
setHTMLPolicy(policy) {
|
|
2316
|
-
if (htmlPolicy !== fastHTMLPolicy) {
|
|
2317
|
-
throw FAST.error(1201 /* Message.onlySetHTMLPolicyOnce */);
|
|
2318
|
-
}
|
|
2319
|
-
htmlPolicy = policy;
|
|
2320
|
-
},
|
|
2321
2913
|
/**
|
|
2322
2914
|
* Compiles a template and associated directives into a compilation
|
|
2323
2915
|
* result which can be used to create views.
|
|
2324
2916
|
* @param html - The html string or template element to compile.
|
|
2325
|
-
* @param
|
|
2917
|
+
* @param factories - The behavior factories referenced by the template.
|
|
2918
|
+
* @param policy - The security policy to compile the html with.
|
|
2326
2919
|
* @remarks
|
|
2327
2920
|
* The template that is provided for compilation is altered in-place
|
|
2328
2921
|
* and cannot be compiled again. If the original template must be preserved,
|
|
2329
2922
|
* it is recommended that you clone the original and pass the clone to this API.
|
|
2330
2923
|
* @public
|
|
2331
2924
|
*/
|
|
2332
|
-
compile(html,
|
|
2925
|
+
compile(html, factories, policy = DOM.policy) {
|
|
2333
2926
|
let template;
|
|
2334
2927
|
if (isString(html)) {
|
|
2335
2928
|
template = document.createElement(templateTag);
|
|
2336
|
-
template.innerHTML =
|
|
2929
|
+
template.innerHTML = policy.createHTML(html);
|
|
2337
2930
|
const fec = template.content.firstElementChild;
|
|
2338
2931
|
if (fec !== null && fec.tagName === templateTag) {
|
|
2339
2932
|
template = fec;
|
|
@@ -2344,18 +2937,18 @@ const Compiler = {
|
|
|
2344
2937
|
}
|
|
2345
2938
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1111864
|
|
2346
2939
|
const fragment = document.adoptNode(template.content);
|
|
2347
|
-
const context = new CompilationContext(fragment,
|
|
2940
|
+
const context = new CompilationContext(fragment, factories, policy);
|
|
2348
2941
|
compileAttributes(context, "", template, /* host */ "h", 0, true);
|
|
2349
2942
|
if (
|
|
2350
2943
|
// If the first node in a fragment is a marker, that means it's an unstable first node,
|
|
2351
2944
|
// because something like a when, repeat, etc. could add nodes before the marker.
|
|
2352
2945
|
// To mitigate this, we insert a stable first node. However, if we insert a node,
|
|
2353
2946
|
// that will alter the result of the TreeWalker. So, we also need to offset the target index.
|
|
2354
|
-
isMarker(fragment.firstChild,
|
|
2947
|
+
isMarker(fragment.firstChild, factories) ||
|
|
2355
2948
|
// Or if there is only one node and a directive, it means the template's content
|
|
2356
2949
|
// is *only* the directive. In that case, HTMLView.dispose() misses any nodes inserted by
|
|
2357
2950
|
// the directive. Inserting a new node ensures proper disposal of nodes added by the directive.
|
|
2358
|
-
(fragment.childNodes.length === 1 && Object.keys(
|
|
2951
|
+
(fragment.childNodes.length === 1 && Object.keys(factories).length > 0)) {
|
|
2359
2952
|
fragment.insertBefore(document.createComment(""), fragment.firstChild);
|
|
2360
2953
|
}
|
|
2361
2954
|
compileChildren(context, fragment, /* root */ "r");
|
|
@@ -2374,34 +2967,88 @@ const Compiler = {
|
|
|
2374
2967
|
* Aggregates an array of strings and directives into a single directive.
|
|
2375
2968
|
* @param parts - A heterogeneous array of static strings interspersed with
|
|
2376
2969
|
* directives.
|
|
2970
|
+
* @param policy - The security policy to use with the aggregated bindings.
|
|
2377
2971
|
* @returns A single inline directive that aggregates the behavior of all the parts.
|
|
2378
2972
|
*/
|
|
2379
|
-
aggregate(parts) {
|
|
2973
|
+
aggregate(parts, policy = DOM.policy) {
|
|
2380
2974
|
if (parts.length === 1) {
|
|
2381
2975
|
return parts[0];
|
|
2382
2976
|
}
|
|
2383
2977
|
let sourceAspect;
|
|
2978
|
+
let binding;
|
|
2979
|
+
let isVolatile = false;
|
|
2980
|
+
let bindingPolicy = void 0;
|
|
2384
2981
|
const partCount = parts.length;
|
|
2385
2982
|
const finalParts = parts.map((x) => {
|
|
2386
2983
|
if (isString(x)) {
|
|
2387
2984
|
return () => x;
|
|
2388
2985
|
}
|
|
2389
2986
|
sourceAspect = x.sourceAspect || sourceAspect;
|
|
2390
|
-
|
|
2987
|
+
binding = x.dataBinding || binding;
|
|
2988
|
+
isVolatile = isVolatile || x.dataBinding.isVolatile;
|
|
2989
|
+
bindingPolicy = bindingPolicy || x.dataBinding.policy;
|
|
2990
|
+
return x.dataBinding.evaluate;
|
|
2391
2991
|
});
|
|
2392
|
-
const
|
|
2992
|
+
const expression = (scope, context) => {
|
|
2393
2993
|
let output = "";
|
|
2394
2994
|
for (let i = 0; i < partCount; ++i) {
|
|
2395
2995
|
output += finalParts[i](scope, context);
|
|
2396
2996
|
}
|
|
2397
2997
|
return output;
|
|
2398
2998
|
};
|
|
2399
|
-
|
|
2400
|
-
|
|
2999
|
+
binding.evaluate = expression;
|
|
3000
|
+
binding.isVolatile = isVolatile;
|
|
3001
|
+
binding.policy = bindingPolicy !== null && bindingPolicy !== void 0 ? bindingPolicy : policy;
|
|
3002
|
+
const directive = new HTMLBindingDirective(binding);
|
|
3003
|
+
HTMLDirective.assignAspect(directive, sourceAspect);
|
|
2401
3004
|
return directive;
|
|
2402
3005
|
},
|
|
2403
3006
|
};
|
|
2404
3007
|
|
|
3008
|
+
// Much thanks to LitHTML for working this out!
|
|
3009
|
+
const lastAttributeNameRegex =
|
|
3010
|
+
/* eslint-disable-next-line no-control-regex */
|
|
3011
|
+
/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;
|
|
3012
|
+
const noFactories = Object.create(null);
|
|
3013
|
+
/**
|
|
3014
|
+
* Inlines a template into another template.
|
|
3015
|
+
* @public
|
|
3016
|
+
*/
|
|
3017
|
+
class InlineTemplateDirective {
|
|
3018
|
+
/**
|
|
3019
|
+
* Creates an instance of InlineTemplateDirective.
|
|
3020
|
+
* @param template - The template to inline.
|
|
3021
|
+
*/
|
|
3022
|
+
constructor(html, factories = noFactories) {
|
|
3023
|
+
this.html = html;
|
|
3024
|
+
this.factories = factories;
|
|
3025
|
+
}
|
|
3026
|
+
/**
|
|
3027
|
+
* Creates HTML to be used within a template.
|
|
3028
|
+
* @param add - Can be used to add behavior factories to a template.
|
|
3029
|
+
*/
|
|
3030
|
+
createHTML(add) {
|
|
3031
|
+
const factories = this.factories;
|
|
3032
|
+
for (const key in factories) {
|
|
3033
|
+
add(factories[key]);
|
|
3034
|
+
}
|
|
3035
|
+
return this.html;
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
/**
|
|
3039
|
+
* An empty template partial.
|
|
3040
|
+
*/
|
|
3041
|
+
InlineTemplateDirective.empty = new InlineTemplateDirective("");
|
|
3042
|
+
HTMLDirective.define(InlineTemplateDirective);
|
|
3043
|
+
function createHTML(value, prevString, add, definition = HTMLDirective.getForInstance(value)) {
|
|
3044
|
+
if (definition.aspected) {
|
|
3045
|
+
const match = lastAttributeNameRegex.exec(prevString);
|
|
3046
|
+
if (match !== null) {
|
|
3047
|
+
HTMLDirective.assignAspect(value, match[2]);
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
return value.createHTML(add);
|
|
3051
|
+
}
|
|
2405
3052
|
/**
|
|
2406
3053
|
* A template capable of creating HTMLView instances or rendering directly to DOM.
|
|
2407
3054
|
* @public
|
|
@@ -2411,9 +3058,16 @@ class ViewTemplate {
|
|
|
2411
3058
|
* Creates an instance of ViewTemplate.
|
|
2412
3059
|
* @param html - The html representing what this template will instantiate, including placeholders for directives.
|
|
2413
3060
|
* @param factories - The directives that will be connected to placeholders in the html.
|
|
3061
|
+
* @param policy - The security policy to use when compiling this template.
|
|
2414
3062
|
*/
|
|
2415
|
-
constructor(html, factories) {
|
|
3063
|
+
constructor(html, factories = {}, policy) {
|
|
3064
|
+
this.policy = policy;
|
|
2416
3065
|
this.result = null;
|
|
3066
|
+
/**
|
|
3067
|
+
* Opts out of JSON stringification.
|
|
3068
|
+
* @internal
|
|
3069
|
+
*/
|
|
3070
|
+
this.toJSON = noop;
|
|
2417
3071
|
this.html = html;
|
|
2418
3072
|
this.factories = factories;
|
|
2419
3073
|
}
|
|
@@ -2423,10 +3077,34 @@ class ViewTemplate {
|
|
|
2423
3077
|
*/
|
|
2424
3078
|
create(hostBindingTarget) {
|
|
2425
3079
|
if (this.result === null) {
|
|
2426
|
-
this.result = Compiler.compile(this.html, this.factories);
|
|
3080
|
+
this.result = Compiler.compile(this.html, this.factories, this.policy);
|
|
2427
3081
|
}
|
|
2428
3082
|
return this.result.createView(hostBindingTarget);
|
|
2429
3083
|
}
|
|
3084
|
+
/**
|
|
3085
|
+
* Returns a directive that can inline the template.
|
|
3086
|
+
*/
|
|
3087
|
+
inline() {
|
|
3088
|
+
return new InlineTemplateDirective(isString(this.html) ? this.html : this.html.innerHTML, this.factories);
|
|
3089
|
+
}
|
|
3090
|
+
/**
|
|
3091
|
+
* Sets the DOMPolicy for this template.
|
|
3092
|
+
* @param policy - The policy to associated with this template.
|
|
3093
|
+
* @returns The modified template instance.
|
|
3094
|
+
* @remarks
|
|
3095
|
+
* The DOMPolicy can only be set once for a template and cannot be
|
|
3096
|
+
* set after the template is compiled.
|
|
3097
|
+
*/
|
|
3098
|
+
withPolicy(policy) {
|
|
3099
|
+
if (this.result) {
|
|
3100
|
+
throw FAST.error(1208 /* Message.cannotSetTemplatePolicyAfterCompilation */);
|
|
3101
|
+
}
|
|
3102
|
+
if (this.policy) {
|
|
3103
|
+
throw FAST.error(1207 /* Message.onlySetTemplatePolicyOnce */);
|
|
3104
|
+
}
|
|
3105
|
+
this.policy = policy;
|
|
3106
|
+
return this;
|
|
3107
|
+
}
|
|
2430
3108
|
/**
|
|
2431
3109
|
* Creates an HTMLView from this template, binds it to the source, and then appends it to the host.
|
|
2432
3110
|
* @param source - The data source to bind the template to.
|
|
@@ -2434,75 +3112,72 @@ class ViewTemplate {
|
|
|
2434
3112
|
* @param hostBindingTarget - An HTML element to target the host bindings at if different from the
|
|
2435
3113
|
* host that the template is being attached to.
|
|
2436
3114
|
*/
|
|
2437
|
-
render(source, host, hostBindingTarget
|
|
2438
|
-
const view = this.create(hostBindingTarget
|
|
2439
|
-
view.bind(source
|
|
3115
|
+
render(source, host, hostBindingTarget) {
|
|
3116
|
+
const view = this.create(hostBindingTarget);
|
|
3117
|
+
view.bind(source);
|
|
2440
3118
|
view.appendTo(host);
|
|
2441
3119
|
return view;
|
|
2442
3120
|
}
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
};
|
|
2473
|
-
for (let i = 0, ii = strings.length - 1; i < ii; ++i) {
|
|
2474
|
-
const currentString = strings[i];
|
|
2475
|
-
const currentValue = values[i];
|
|
2476
|
-
let definition;
|
|
2477
|
-
html += currentString;
|
|
2478
|
-
if (isFunction(currentValue)) {
|
|
2479
|
-
html += createAspectedHTML(bind(currentValue), currentString, add);
|
|
2480
|
-
}
|
|
2481
|
-
else if (isString(currentValue)) {
|
|
2482
|
-
const match = lastAttributeNameRegex.exec(currentString);
|
|
2483
|
-
if (match !== null) {
|
|
2484
|
-
const directive = bind(() => currentValue, oneTime);
|
|
2485
|
-
Aspect.assign(directive, match[2]);
|
|
2486
|
-
html += directive.createHTML(add);
|
|
2487
|
-
}
|
|
2488
|
-
else {
|
|
2489
|
-
html += currentValue;
|
|
3121
|
+
/**
|
|
3122
|
+
* Creates a template based on a set of static strings and dynamic values.
|
|
3123
|
+
* @param strings - The static strings to create the template with.
|
|
3124
|
+
* @param values - The dynamic values to create the template with.
|
|
3125
|
+
* @param policy - The DOMPolicy to associated with the template.
|
|
3126
|
+
* @returns A ViewTemplate.
|
|
3127
|
+
* @remarks
|
|
3128
|
+
* This API should not be used directly under normal circumstances because constructing
|
|
3129
|
+
* a template in this way, if not done properly, can open up the application to XSS
|
|
3130
|
+
* attacks. When using this API, provide a strong DOMPolicy that can properly sanitize
|
|
3131
|
+
* and also be sure to manually sanitize all static strings particularly if they can
|
|
3132
|
+
* come from user input.
|
|
3133
|
+
*/
|
|
3134
|
+
static create(strings, values, policy) {
|
|
3135
|
+
let html = "";
|
|
3136
|
+
const factories = Object.create(null);
|
|
3137
|
+
const add = (factory) => {
|
|
3138
|
+
var _a;
|
|
3139
|
+
const id = (_a = factory.id) !== null && _a !== void 0 ? _a : (factory.id = nextId());
|
|
3140
|
+
factories[id] = factory;
|
|
3141
|
+
return id;
|
|
3142
|
+
};
|
|
3143
|
+
for (let i = 0, ii = strings.length - 1; i < ii; ++i) {
|
|
3144
|
+
const currentString = strings[i];
|
|
3145
|
+
let currentValue = values[i];
|
|
3146
|
+
let definition;
|
|
3147
|
+
html += currentString;
|
|
3148
|
+
if (isFunction(currentValue)) {
|
|
3149
|
+
currentValue = new HTMLBindingDirective(bind(currentValue));
|
|
2490
3150
|
}
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
html += createAspectedHTML(bind(() => currentValue, oneTime), currentString, add);
|
|
2494
|
-
}
|
|
2495
|
-
else {
|
|
2496
|
-
if (definition.aspected) {
|
|
2497
|
-
html += createAspectedHTML(currentValue, currentString, add);
|
|
3151
|
+
else if (currentValue instanceof Binding) {
|
|
3152
|
+
currentValue = new HTMLBindingDirective(currentValue);
|
|
2498
3153
|
}
|
|
2499
|
-
else {
|
|
2500
|
-
|
|
3154
|
+
else if (!(definition = HTMLDirective.getForInstance(currentValue))) {
|
|
3155
|
+
const staticValue = currentValue;
|
|
3156
|
+
currentValue = new HTMLBindingDirective(oneTime(() => staticValue));
|
|
2501
3157
|
}
|
|
3158
|
+
html += createHTML(currentValue, currentString, add, definition);
|
|
2502
3159
|
}
|
|
3160
|
+
return new ViewTemplate(html + strings[strings.length - 1], factories, policy);
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
/**
|
|
3164
|
+
* Transforms a template literal string into a ViewTemplate.
|
|
3165
|
+
* @param strings - The string fragments that are interpolated with the values.
|
|
3166
|
+
* @param values - The values that are interpolated with the string fragments.
|
|
3167
|
+
* @remarks
|
|
3168
|
+
* The html helper supports interpolation of strings, numbers, binding expressions,
|
|
3169
|
+
* other template instances, and Directive instances.
|
|
3170
|
+
* @public
|
|
3171
|
+
*/
|
|
3172
|
+
const html = ((strings, ...values) => {
|
|
3173
|
+
if (Array.isArray(strings) && Array.isArray(strings.raw)) {
|
|
3174
|
+
return ViewTemplate.create(strings, values);
|
|
2503
3175
|
}
|
|
2504
|
-
|
|
2505
|
-
}
|
|
3176
|
+
throw FAST.error(1206 /* Message.directCallToHTMLTagNotAllowed */);
|
|
3177
|
+
});
|
|
3178
|
+
html.partial = (html) => {
|
|
3179
|
+
return new InlineTemplateDirective(html);
|
|
3180
|
+
};
|
|
2506
3181
|
|
|
2507
3182
|
/**
|
|
2508
3183
|
* The runtime behavior for template references.
|
|
@@ -2510,20 +3185,12 @@ function html(strings, ...values) {
|
|
|
2510
3185
|
*/
|
|
2511
3186
|
class RefDirective extends StatelessAttachedAttributeDirective {
|
|
2512
3187
|
/**
|
|
2513
|
-
* Bind this behavior
|
|
2514
|
-
* @param
|
|
2515
|
-
* @param context - The execution context that the binding is operating within.
|
|
2516
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
3188
|
+
* Bind this behavior.
|
|
3189
|
+
* @param controller - The view controller that manages the lifecycle of this behavior.
|
|
2517
3190
|
*/
|
|
2518
|
-
bind(
|
|
2519
|
-
source[this.options] = targets[this.
|
|
3191
|
+
bind(controller) {
|
|
3192
|
+
controller.source[this.options] = controller.targets[this.targetNodeId];
|
|
2520
3193
|
}
|
|
2521
|
-
/**
|
|
2522
|
-
* Unbinds this behavior from the source.
|
|
2523
|
-
* @param source - The source to unbind from.
|
|
2524
|
-
*/
|
|
2525
|
-
/* eslint-disable-next-line @typescript-eslint/no-empty-function */
|
|
2526
|
-
unbind() { }
|
|
2527
3194
|
}
|
|
2528
3195
|
HTMLDirective.define(RefDirective);
|
|
2529
3196
|
/**
|
|
@@ -2535,27 +3202,34 @@ const ref = (propertyName) => new RefDirective(propertyName);
|
|
|
2535
3202
|
|
|
2536
3203
|
/**
|
|
2537
3204
|
* A directive that enables basic conditional rendering in a template.
|
|
2538
|
-
* @param
|
|
3205
|
+
* @param condition - The condition to test for rendering.
|
|
2539
3206
|
* @param templateOrTemplateBinding - The template or a binding that gets
|
|
2540
3207
|
* the template to render when the condition is true.
|
|
2541
3208
|
* @public
|
|
2542
3209
|
*/
|
|
2543
|
-
function when(
|
|
2544
|
-
const
|
|
3210
|
+
function when(condition, templateOrTemplateBinding) {
|
|
3211
|
+
const dataBinding = isFunction(condition) ? condition : () => condition;
|
|
3212
|
+
const templateBinding = isFunction(templateOrTemplateBinding)
|
|
2545
3213
|
? templateOrTemplateBinding
|
|
2546
3214
|
: () => templateOrTemplateBinding;
|
|
2547
|
-
return (source, context) =>
|
|
3215
|
+
return (source, context) => dataBinding(source, context) ? templateBinding(source, context) : null;
|
|
2548
3216
|
}
|
|
2549
3217
|
|
|
2550
3218
|
const defaultRepeatOptions = Object.freeze({
|
|
2551
3219
|
positioning: false,
|
|
2552
3220
|
recycle: true,
|
|
2553
3221
|
});
|
|
2554
|
-
function bindWithoutPositioning(view, items, index,
|
|
2555
|
-
view.
|
|
3222
|
+
function bindWithoutPositioning(view, items, index, controller) {
|
|
3223
|
+
view.context.parent = controller.source;
|
|
3224
|
+
view.context.parentContext = controller.context;
|
|
3225
|
+
view.bind(items[index]);
|
|
2556
3226
|
}
|
|
2557
|
-
function bindWithPositioning(view, items, index,
|
|
2558
|
-
view.
|
|
3227
|
+
function bindWithPositioning(view, items, index, controller) {
|
|
3228
|
+
view.context.parent = controller.source;
|
|
3229
|
+
view.context.parentContext = controller.context;
|
|
3230
|
+
view.context.length = items.length;
|
|
3231
|
+
view.context.index = index;
|
|
3232
|
+
view.bind(items[index]);
|
|
2559
3233
|
}
|
|
2560
3234
|
/**
|
|
2561
3235
|
* A behavior that renders a template for each item in an array.
|
|
@@ -2565,57 +3239,46 @@ class RepeatBehavior {
|
|
|
2565
3239
|
/**
|
|
2566
3240
|
* Creates an instance of RepeatBehavior.
|
|
2567
3241
|
* @param location - The location in the DOM to render the repeat.
|
|
2568
|
-
* @param
|
|
3242
|
+
* @param dataBinding - The array to render.
|
|
2569
3243
|
* @param isItemsBindingVolatile - Indicates whether the items binding has volatile dependencies.
|
|
2570
3244
|
* @param templateBinding - The template to render for each item.
|
|
2571
3245
|
* @param isTemplateBindingVolatile - Indicates whether the template binding has volatile dependencies.
|
|
2572
3246
|
* @param options - Options used to turn on special repeat features.
|
|
2573
3247
|
*/
|
|
2574
|
-
constructor(
|
|
2575
|
-
this.
|
|
2576
|
-
this.itemsBinding = itemsBinding;
|
|
2577
|
-
this.templateBinding = templateBinding;
|
|
2578
|
-
this.options = options;
|
|
2579
|
-
this.source = null;
|
|
2580
|
-
this.views = [];
|
|
3248
|
+
constructor(directive) {
|
|
3249
|
+
this.directive = directive;
|
|
2581
3250
|
this.items = null;
|
|
2582
3251
|
this.itemsObserver = null;
|
|
2583
|
-
this.context = void 0;
|
|
2584
|
-
this.childContext = void 0;
|
|
2585
3252
|
this.bindView = bindWithoutPositioning;
|
|
2586
|
-
|
|
2587
|
-
this.
|
|
2588
|
-
|
|
3253
|
+
/** @internal */
|
|
3254
|
+
this.views = [];
|
|
3255
|
+
this.itemsBindingObserver = directive.dataBinding.createObserver(directive, this);
|
|
3256
|
+
this.templateBindingObserver = directive.templateBinding.createObserver(directive, this);
|
|
3257
|
+
if (directive.options.positioning) {
|
|
2589
3258
|
this.bindView = bindWithPositioning;
|
|
2590
3259
|
}
|
|
2591
3260
|
}
|
|
2592
3261
|
/**
|
|
2593
|
-
* Bind this behavior
|
|
2594
|
-
* @param
|
|
2595
|
-
* @param context - The execution context that the binding is operating within.
|
|
3262
|
+
* Bind this behavior.
|
|
3263
|
+
* @param controller - The view controller that manages the lifecycle of this behavior.
|
|
2596
3264
|
*/
|
|
2597
|
-
bind(
|
|
2598
|
-
this.
|
|
2599
|
-
this.
|
|
2600
|
-
this.
|
|
2601
|
-
this.
|
|
2602
|
-
this.template = this.templateBindingObserver.observe(source, this.context);
|
|
3265
|
+
bind(controller) {
|
|
3266
|
+
this.location = controller.targets[this.directive.targetNodeId];
|
|
3267
|
+
this.controller = controller;
|
|
3268
|
+
this.items = this.itemsBindingObserver.bind(controller);
|
|
3269
|
+
this.template = this.templateBindingObserver.bind(controller);
|
|
2603
3270
|
this.observeItems(true);
|
|
2604
3271
|
this.refreshAllViews();
|
|
3272
|
+
controller.onUnbind(this);
|
|
2605
3273
|
}
|
|
2606
3274
|
/**
|
|
2607
|
-
* Unbinds this behavior
|
|
2608
|
-
* @param source - The source to unbind from.
|
|
3275
|
+
* Unbinds this behavior.
|
|
2609
3276
|
*/
|
|
2610
3277
|
unbind() {
|
|
2611
|
-
this.source = null;
|
|
2612
|
-
this.items = null;
|
|
2613
3278
|
if (this.itemsObserver !== null) {
|
|
2614
3279
|
this.itemsObserver.unsubscribe(this);
|
|
2615
3280
|
}
|
|
2616
3281
|
this.unbindAllViews();
|
|
2617
|
-
this.itemsBindingObserver.dispose();
|
|
2618
|
-
this.templateBindingObserver.dispose();
|
|
2619
3282
|
}
|
|
2620
3283
|
/**
|
|
2621
3284
|
* Handles changes in the array, its items, and the repeat template.
|
|
@@ -2623,15 +3286,18 @@ class RepeatBehavior {
|
|
|
2623
3286
|
* @param args - The details about what was changed.
|
|
2624
3287
|
*/
|
|
2625
3288
|
handleChange(source, args) {
|
|
2626
|
-
if (
|
|
2627
|
-
this.items = this.itemsBindingObserver.
|
|
3289
|
+
if (args === this.itemsBindingObserver) {
|
|
3290
|
+
this.items = this.itemsBindingObserver.bind(this.controller);
|
|
2628
3291
|
this.observeItems();
|
|
2629
3292
|
this.refreshAllViews();
|
|
2630
3293
|
}
|
|
2631
|
-
else if (
|
|
2632
|
-
this.template = this.templateBindingObserver.
|
|
3294
|
+
else if (args === this.templateBindingObserver) {
|
|
3295
|
+
this.template = this.templateBindingObserver.bind(this.controller);
|
|
2633
3296
|
this.refreshAllViews(true);
|
|
2634
3297
|
}
|
|
3298
|
+
else if (!args[0]) {
|
|
3299
|
+
return;
|
|
3300
|
+
}
|
|
2635
3301
|
else if (args[0].reset) {
|
|
2636
3302
|
this.refreshAllViews();
|
|
2637
3303
|
}
|
|
@@ -2656,39 +3322,57 @@ class RepeatBehavior {
|
|
|
2656
3322
|
}
|
|
2657
3323
|
updateViews(splices) {
|
|
2658
3324
|
const views = this.views;
|
|
2659
|
-
const childContext = this.childContext;
|
|
2660
|
-
const totalRemoved = [];
|
|
2661
3325
|
const bindView = this.bindView;
|
|
2662
|
-
let removeDelta = 0;
|
|
2663
|
-
for (let i = 0, ii = splices.length; i < ii; ++i) {
|
|
2664
|
-
const splice = splices[i];
|
|
2665
|
-
const removed = splice.removed;
|
|
2666
|
-
totalRemoved.push(...views.splice(splice.index + removeDelta, removed.length));
|
|
2667
|
-
removeDelta -= splice.addedCount;
|
|
2668
|
-
}
|
|
2669
3326
|
const items = this.items;
|
|
2670
3327
|
const template = this.template;
|
|
3328
|
+
const controller = this.controller;
|
|
3329
|
+
const recycle = this.directive.options.recycle;
|
|
3330
|
+
const leftoverViews = [];
|
|
3331
|
+
let leftoverIndex = 0;
|
|
3332
|
+
let availableViews = 0;
|
|
2671
3333
|
for (let i = 0, ii = splices.length; i < ii; ++i) {
|
|
2672
3334
|
const splice = splices[i];
|
|
3335
|
+
const removed = splice.removed;
|
|
3336
|
+
let removeIndex = 0;
|
|
2673
3337
|
let addIndex = splice.index;
|
|
2674
3338
|
const end = addIndex + splice.addedCount;
|
|
3339
|
+
const removedViews = views.splice(splice.index, removed.length);
|
|
3340
|
+
const totalAvailableViews = (availableViews =
|
|
3341
|
+
leftoverViews.length + removedViews.length);
|
|
2675
3342
|
for (; addIndex < end; ++addIndex) {
|
|
2676
3343
|
const neighbor = views[addIndex];
|
|
2677
3344
|
const location = neighbor ? neighbor.firstChild : this.location;
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
3345
|
+
let view;
|
|
3346
|
+
if (recycle && availableViews > 0) {
|
|
3347
|
+
if (removeIndex <= totalAvailableViews && removedViews.length > 0) {
|
|
3348
|
+
view = removedViews[removeIndex];
|
|
3349
|
+
removeIndex++;
|
|
3350
|
+
}
|
|
3351
|
+
else {
|
|
3352
|
+
view = leftoverViews[leftoverIndex];
|
|
3353
|
+
leftoverIndex++;
|
|
3354
|
+
}
|
|
3355
|
+
availableViews--;
|
|
3356
|
+
}
|
|
3357
|
+
else {
|
|
3358
|
+
view = template.create();
|
|
3359
|
+
}
|
|
2681
3360
|
views.splice(addIndex, 0, view);
|
|
2682
|
-
bindView(view, items, addIndex,
|
|
3361
|
+
bindView(view, items, addIndex, controller);
|
|
2683
3362
|
view.insertBefore(location);
|
|
2684
3363
|
}
|
|
3364
|
+
if (removedViews[removeIndex]) {
|
|
3365
|
+
leftoverViews.push(...removedViews.slice(removeIndex));
|
|
3366
|
+
}
|
|
2685
3367
|
}
|
|
2686
|
-
for (let i =
|
|
2687
|
-
|
|
3368
|
+
for (let i = leftoverIndex, ii = leftoverViews.length; i < ii; ++i) {
|
|
3369
|
+
leftoverViews[i].dispose();
|
|
2688
3370
|
}
|
|
2689
|
-
if (this.options.positioning) {
|
|
2690
|
-
for (let i = 0,
|
|
2691
|
-
views[i].context
|
|
3371
|
+
if (this.directive.options.positioning) {
|
|
3372
|
+
for (let i = 0, viewsLength = views.length; i < viewsLength; ++i) {
|
|
3373
|
+
const context = views[i].context;
|
|
3374
|
+
context.length = viewsLength;
|
|
3375
|
+
context.index = i;
|
|
2692
3376
|
}
|
|
2693
3377
|
}
|
|
2694
3378
|
}
|
|
@@ -2697,11 +3381,11 @@ class RepeatBehavior {
|
|
|
2697
3381
|
const template = this.template;
|
|
2698
3382
|
const location = this.location;
|
|
2699
3383
|
const bindView = this.bindView;
|
|
2700
|
-
const
|
|
3384
|
+
const controller = this.controller;
|
|
2701
3385
|
let itemsLength = items.length;
|
|
2702
3386
|
let views = this.views;
|
|
2703
3387
|
let viewsLength = views.length;
|
|
2704
|
-
if (itemsLength === 0 || templateChanged || !this.options.recycle) {
|
|
3388
|
+
if (itemsLength === 0 || templateChanged || !this.directive.options.recycle) {
|
|
2705
3389
|
// all views need to be removed
|
|
2706
3390
|
HTMLView.disposeContiguousBatch(views);
|
|
2707
3391
|
viewsLength = 0;
|
|
@@ -2711,7 +3395,7 @@ class RepeatBehavior {
|
|
|
2711
3395
|
this.views = views = new Array(itemsLength);
|
|
2712
3396
|
for (let i = 0; i < itemsLength; ++i) {
|
|
2713
3397
|
const view = template.create();
|
|
2714
|
-
bindView(view, items, i,
|
|
3398
|
+
bindView(view, items, i, controller);
|
|
2715
3399
|
views[i] = view;
|
|
2716
3400
|
view.insertBefore(location);
|
|
2717
3401
|
}
|
|
@@ -2722,11 +3406,11 @@ class RepeatBehavior {
|
|
|
2722
3406
|
for (; i < itemsLength; ++i) {
|
|
2723
3407
|
if (i < viewsLength) {
|
|
2724
3408
|
const view = views[i];
|
|
2725
|
-
bindView(view, items, i,
|
|
3409
|
+
bindView(view, items, i, controller);
|
|
2726
3410
|
}
|
|
2727
3411
|
else {
|
|
2728
3412
|
const view = template.create();
|
|
2729
|
-
bindView(view, items, i,
|
|
3413
|
+
bindView(view, items, i, controller);
|
|
2730
3414
|
views.push(view);
|
|
2731
3415
|
view.insertBefore(location);
|
|
2732
3416
|
}
|
|
@@ -2751,17 +3435,15 @@ class RepeatBehavior {
|
|
|
2751
3435
|
class RepeatDirective {
|
|
2752
3436
|
/**
|
|
2753
3437
|
* Creates an instance of RepeatDirective.
|
|
2754
|
-
* @param
|
|
3438
|
+
* @param dataBinding - The binding that provides the array to render.
|
|
2755
3439
|
* @param templateBinding - The template binding used to obtain a template to render for each item in the array.
|
|
2756
3440
|
* @param options - Options used to turn on special repeat features.
|
|
2757
3441
|
*/
|
|
2758
|
-
constructor(
|
|
2759
|
-
this.
|
|
3442
|
+
constructor(dataBinding, templateBinding, options) {
|
|
3443
|
+
this.dataBinding = dataBinding;
|
|
2760
3444
|
this.templateBinding = templateBinding;
|
|
2761
3445
|
this.options = options;
|
|
2762
3446
|
ArrayObserver.enable();
|
|
2763
|
-
this.isItemsBindingVolatile = Observable.isVolatileBinding(itemsBinding);
|
|
2764
|
-
this.isTemplateBindingVolatile = Observable.isVolatileBinding(templateBinding);
|
|
2765
3447
|
}
|
|
2766
3448
|
/**
|
|
2767
3449
|
* Creates a placeholder string based on the directive's index within the template.
|
|
@@ -2774,24 +3456,23 @@ class RepeatDirective {
|
|
|
2774
3456
|
* Creates a behavior for the provided target node.
|
|
2775
3457
|
* @param target - The node instance to create the behavior for.
|
|
2776
3458
|
*/
|
|
2777
|
-
createBehavior(
|
|
2778
|
-
return new RepeatBehavior(
|
|
3459
|
+
createBehavior() {
|
|
3460
|
+
return new RepeatBehavior(this);
|
|
2779
3461
|
}
|
|
2780
3462
|
}
|
|
2781
3463
|
HTMLDirective.define(RepeatDirective);
|
|
2782
3464
|
/**
|
|
2783
3465
|
* A directive that enables list rendering.
|
|
2784
|
-
* @param
|
|
2785
|
-
* @param
|
|
3466
|
+
* @param items - The array to render.
|
|
3467
|
+
* @param template - The template or a template binding used obtain a template
|
|
2786
3468
|
* to render for each item in the array.
|
|
2787
3469
|
* @param options - Options used to turn on special repeat features.
|
|
2788
3470
|
* @public
|
|
2789
3471
|
*/
|
|
2790
|
-
function repeat(
|
|
2791
|
-
const
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
return new RepeatDirective(itemsBinding, templateBinding, options);
|
|
3472
|
+
function repeat(items, template, options = defaultRepeatOptions) {
|
|
3473
|
+
const dataBinding = normalizeBinding(items);
|
|
3474
|
+
const templateBinding = normalizeBinding(template);
|
|
3475
|
+
return new RepeatDirective(dataBinding, templateBinding, Object.assign(Object.assign({}, defaultRepeatOptions), options));
|
|
2795
3476
|
}
|
|
2796
3477
|
|
|
2797
3478
|
const selectElements = (value) => value.nodeType === 1;
|
|
@@ -2810,9 +3491,15 @@ const elements = (selector) => selector
|
|
|
2810
3491
|
* Internally used by the SlottedDirective and the ChildrenDirective.
|
|
2811
3492
|
*/
|
|
2812
3493
|
class NodeObservationDirective extends StatelessAttachedAttributeDirective {
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
3494
|
+
/**
|
|
3495
|
+
* The unique id of the factory.
|
|
3496
|
+
*/
|
|
3497
|
+
get id() {
|
|
3498
|
+
return this._id;
|
|
3499
|
+
}
|
|
3500
|
+
set id(value) {
|
|
3501
|
+
this._id = value;
|
|
3502
|
+
this._controllerProperty = `${value}-c`;
|
|
2816
3503
|
}
|
|
2817
3504
|
/**
|
|
2818
3505
|
* Bind this behavior to the source.
|
|
@@ -2820,11 +3507,12 @@ class NodeObservationDirective extends StatelessAttachedAttributeDirective {
|
|
|
2820
3507
|
* @param context - The execution context that the binding is operating within.
|
|
2821
3508
|
* @param targets - The targets that behaviors in a view can attach to.
|
|
2822
3509
|
*/
|
|
2823
|
-
bind(
|
|
2824
|
-
const target = targets[this.
|
|
2825
|
-
target[this.
|
|
2826
|
-
this.updateTarget(source, this.computeNodes(target));
|
|
3510
|
+
bind(controller) {
|
|
3511
|
+
const target = controller.targets[this.targetNodeId];
|
|
3512
|
+
target[this._controllerProperty] = controller;
|
|
3513
|
+
this.updateTarget(controller.source, this.computeNodes(target));
|
|
2827
3514
|
this.observe(target);
|
|
3515
|
+
controller.onUnbind(this);
|
|
2828
3516
|
}
|
|
2829
3517
|
/**
|
|
2830
3518
|
* Unbinds this behavior from the source.
|
|
@@ -2832,11 +3520,11 @@ class NodeObservationDirective extends StatelessAttachedAttributeDirective {
|
|
|
2832
3520
|
* @param context - The execution context that the binding is operating within.
|
|
2833
3521
|
* @param targets - The targets that behaviors in a view can attach to.
|
|
2834
3522
|
*/
|
|
2835
|
-
unbind(
|
|
2836
|
-
const target = targets[this.
|
|
2837
|
-
this.updateTarget(source, emptyArray);
|
|
3523
|
+
unbind(controller) {
|
|
3524
|
+
const target = controller.targets[this.targetNodeId];
|
|
3525
|
+
this.updateTarget(controller.source, emptyArray);
|
|
2838
3526
|
this.disconnect(target);
|
|
2839
|
-
target[this.
|
|
3527
|
+
target[this._controllerProperty] = null;
|
|
2840
3528
|
}
|
|
2841
3529
|
/**
|
|
2842
3530
|
* Gets the data source for the target.
|
|
@@ -2844,7 +3532,7 @@ class NodeObservationDirective extends StatelessAttachedAttributeDirective {
|
|
|
2844
3532
|
* @returns The source.
|
|
2845
3533
|
*/
|
|
2846
3534
|
getSource(target) {
|
|
2847
|
-
return target[this.
|
|
3535
|
+
return target[this._controllerProperty].source;
|
|
2848
3536
|
}
|
|
2849
3537
|
/**
|
|
2850
3538
|
* Updates the source property with the computed nodes.
|
|
@@ -2940,9 +3628,13 @@ class ChildrenDirective extends NodeObservationDirective {
|
|
|
2940
3628
|
* @param target - The target to observe.
|
|
2941
3629
|
*/
|
|
2942
3630
|
observe(target) {
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
3631
|
+
let observer = target[this.observerProperty];
|
|
3632
|
+
if (!observer) {
|
|
3633
|
+
observer = new MutationObserver(this.handleEvent);
|
|
3634
|
+
observer.toJSON = noop;
|
|
3635
|
+
observer.target = target;
|
|
3636
|
+
target[this.observerProperty] = observer;
|
|
3637
|
+
}
|
|
2946
3638
|
observer.observe(target, this.options);
|
|
2947
3639
|
}
|
|
2948
3640
|
/**
|
|
@@ -2983,6 +3675,16 @@ function children(propertyOrOptions) {
|
|
|
2983
3675
|
|
|
2984
3676
|
const booleanMode = "boolean";
|
|
2985
3677
|
const reflectMode = "reflect";
|
|
3678
|
+
/**
|
|
3679
|
+
* Metadata used to configure a custom attribute's behavior.
|
|
3680
|
+
* @public
|
|
3681
|
+
*/
|
|
3682
|
+
const AttributeConfiguration = Object.freeze({
|
|
3683
|
+
/**
|
|
3684
|
+
* Locates all attribute configurations associated with a type.
|
|
3685
|
+
*/
|
|
3686
|
+
locate: createMetadataLocator(),
|
|
3687
|
+
});
|
|
2986
3688
|
/**
|
|
2987
3689
|
* A {@link ValueConverter} that converts to and from `boolean` values.
|
|
2988
3690
|
* @remarks
|
|
@@ -3003,6 +3705,20 @@ const booleanConverter = {
|
|
|
3003
3705
|
: true;
|
|
3004
3706
|
},
|
|
3005
3707
|
};
|
|
3708
|
+
/**
|
|
3709
|
+
* A {@link ValueConverter} that converts to and from `boolean` values. `null`, `undefined`, `""`, and `void` values are converted to `null`.
|
|
3710
|
+
* @public
|
|
3711
|
+
*/
|
|
3712
|
+
const nullableBooleanConverter = {
|
|
3713
|
+
toView(value) {
|
|
3714
|
+
return typeof value === "boolean" ? value.toString() : "";
|
|
3715
|
+
},
|
|
3716
|
+
fromView(value) {
|
|
3717
|
+
return [null, undefined, void 0].includes(value)
|
|
3718
|
+
? null
|
|
3719
|
+
: booleanConverter.fromView(value);
|
|
3720
|
+
},
|
|
3721
|
+
};
|
|
3006
3722
|
function toNumber(value) {
|
|
3007
3723
|
if (value === null || value === undefined) {
|
|
3008
3724
|
return null;
|
|
@@ -3120,7 +3836,7 @@ class AttributeDefinition {
|
|
|
3120
3836
|
*/
|
|
3121
3837
|
static collect(Owner, ...attributeLists) {
|
|
3122
3838
|
const attributes = [];
|
|
3123
|
-
attributeLists.push(Owner
|
|
3839
|
+
attributeLists.push(AttributeConfiguration.locate(Owner));
|
|
3124
3840
|
for (let i = 0, ii = attributeLists.length; i < ii; ++i) {
|
|
3125
3841
|
const list = attributeLists[i];
|
|
3126
3842
|
if (list === void 0) {
|
|
@@ -3150,9 +3866,7 @@ function attr(configOrTarget, prop) {
|
|
|
3150
3866
|
// - @attr({...opts})
|
|
3151
3867
|
config.property = $prop;
|
|
3152
3868
|
}
|
|
3153
|
-
|
|
3154
|
-
($target.constructor.attributes = []);
|
|
3155
|
-
attributes.push(config);
|
|
3869
|
+
AttributeConfiguration.locate($target.constructor).push(config);
|
|
3156
3870
|
}
|
|
3157
3871
|
if (arguments.length > 1) {
|
|
3158
3872
|
// Non invocation:
|
|
@@ -3170,25 +3884,24 @@ function attr(configOrTarget, prop) {
|
|
|
3170
3884
|
|
|
3171
3885
|
const defaultShadowOptions = { mode: "open" };
|
|
3172
3886
|
const defaultElementOptions = {};
|
|
3173
|
-
const
|
|
3887
|
+
const fastElementBaseTypes = new Set();
|
|
3888
|
+
const fastElementRegistry = FAST.getById(KernelServiceId.elementRegistry, () => createTypeRegistry());
|
|
3174
3889
|
/**
|
|
3175
3890
|
* Defines metadata for a FASTElement.
|
|
3176
3891
|
* @public
|
|
3177
3892
|
*/
|
|
3178
3893
|
class FASTElementDefinition {
|
|
3179
|
-
/**
|
|
3180
|
-
* Creates an instance of FASTElementDefinition.
|
|
3181
|
-
* @param type - The type this definition is being created for.
|
|
3182
|
-
* @param nameOrConfig - The name of the element to define or a config object
|
|
3183
|
-
* that describes the element to define.
|
|
3184
|
-
*/
|
|
3185
3894
|
constructor(type, nameOrConfig = type.definition) {
|
|
3895
|
+
var _a;
|
|
3896
|
+
this.platformDefined = false;
|
|
3186
3897
|
if (isString(nameOrConfig)) {
|
|
3187
3898
|
nameOrConfig = { name: nameOrConfig };
|
|
3188
3899
|
}
|
|
3189
3900
|
this.type = type;
|
|
3190
3901
|
this.name = nameOrConfig.name;
|
|
3191
3902
|
this.template = nameOrConfig.template;
|
|
3903
|
+
this.registry = (_a = nameOrConfig.registry) !== null && _a !== void 0 ? _a : customElements;
|
|
3904
|
+
const proto = type.prototype;
|
|
3192
3905
|
const attributes = AttributeDefinition.collect(type, nameOrConfig.attributes);
|
|
3193
3906
|
const observedAttributes = new Array(attributes.length);
|
|
3194
3907
|
const propertyLookup = {};
|
|
@@ -3198,9 +3911,13 @@ class FASTElementDefinition {
|
|
|
3198
3911
|
observedAttributes[i] = current.attribute;
|
|
3199
3912
|
propertyLookup[current.name] = current;
|
|
3200
3913
|
attributeLookup[current.attribute] = current;
|
|
3914
|
+
Observable.defineProperty(proto, current);
|
|
3201
3915
|
}
|
|
3916
|
+
Reflect.defineProperty(type, "observedAttributes", {
|
|
3917
|
+
value: observedAttributes,
|
|
3918
|
+
enumerable: true,
|
|
3919
|
+
});
|
|
3202
3920
|
this.attributes = attributes;
|
|
3203
|
-
this.observedAttributes = observedAttributes;
|
|
3204
3921
|
this.propertyLookup = propertyLookup;
|
|
3205
3922
|
this.attributeLookup = attributeLookup;
|
|
3206
3923
|
this.shadowOptions =
|
|
@@ -3213,20 +3930,14 @@ class FASTElementDefinition {
|
|
|
3213
3930
|
nameOrConfig.elementOptions === void 0
|
|
3214
3931
|
? defaultElementOptions
|
|
3215
3932
|
: Object.assign(Object.assign({}, defaultElementOptions), nameOrConfig.elementOptions);
|
|
3216
|
-
this.styles =
|
|
3217
|
-
|
|
3218
|
-
? void 0
|
|
3219
|
-
: Array.isArray(nameOrConfig.styles)
|
|
3220
|
-
? new ElementStyles(nameOrConfig.styles)
|
|
3221
|
-
: nameOrConfig.styles instanceof ElementStyles
|
|
3222
|
-
? nameOrConfig.styles
|
|
3223
|
-
: new ElementStyles([nameOrConfig.styles]);
|
|
3933
|
+
this.styles = ElementStyles.normalize(nameOrConfig.styles);
|
|
3934
|
+
fastElementRegistry.register(this);
|
|
3224
3935
|
}
|
|
3225
3936
|
/**
|
|
3226
3937
|
* Indicates if this element has been defined in at least one registry.
|
|
3227
3938
|
*/
|
|
3228
3939
|
get isDefined() {
|
|
3229
|
-
return
|
|
3940
|
+
return this.platformDefined;
|
|
3230
3941
|
}
|
|
3231
3942
|
/**
|
|
3232
3943
|
* Defines a custom element based on this definition.
|
|
@@ -3234,24 +3945,35 @@ class FASTElementDefinition {
|
|
|
3234
3945
|
* @remarks
|
|
3235
3946
|
* This operation is idempotent per registry.
|
|
3236
3947
|
*/
|
|
3237
|
-
define(registry =
|
|
3948
|
+
define(registry = this.registry) {
|
|
3238
3949
|
const type = this.type;
|
|
3239
|
-
if (fastElementRegistry.register(this)) {
|
|
3240
|
-
const attributes = this.attributes;
|
|
3241
|
-
const proto = type.prototype;
|
|
3242
|
-
for (let i = 0, ii = attributes.length; i < ii; ++i) {
|
|
3243
|
-
Observable.defineProperty(proto, attributes[i]);
|
|
3244
|
-
}
|
|
3245
|
-
Reflect.defineProperty(type, "observedAttributes", {
|
|
3246
|
-
value: this.observedAttributes,
|
|
3247
|
-
enumerable: true,
|
|
3248
|
-
});
|
|
3249
|
-
}
|
|
3250
3950
|
if (!registry.get(this.name)) {
|
|
3951
|
+
this.platformDefined = true;
|
|
3251
3952
|
registry.define(this.name, type, this.elementOptions);
|
|
3252
3953
|
}
|
|
3253
3954
|
return this;
|
|
3254
3955
|
}
|
|
3956
|
+
/**
|
|
3957
|
+
* Creates an instance of FASTElementDefinition.
|
|
3958
|
+
* @param type - The type this definition is being created for.
|
|
3959
|
+
* @param nameOrDef - The name of the element to define or a config object
|
|
3960
|
+
* that describes the element to define.
|
|
3961
|
+
*/
|
|
3962
|
+
static compose(type, nameOrDef) {
|
|
3963
|
+
if (fastElementBaseTypes.has(type) || fastElementRegistry.getByType(type)) {
|
|
3964
|
+
return new FASTElementDefinition(class extends type {
|
|
3965
|
+
}, nameOrDef);
|
|
3966
|
+
}
|
|
3967
|
+
return new FASTElementDefinition(type, nameOrDef);
|
|
3968
|
+
}
|
|
3969
|
+
/**
|
|
3970
|
+
* Registers a FASTElement base type.
|
|
3971
|
+
* @param type - The type to register as a base type.
|
|
3972
|
+
* @internal
|
|
3973
|
+
*/
|
|
3974
|
+
static registerBaseType(type) {
|
|
3975
|
+
fastElementBaseTypes.add(type);
|
|
3976
|
+
}
|
|
3255
3977
|
}
|
|
3256
3978
|
/**
|
|
3257
3979
|
* Gets the element definition associated with the specified type.
|
|
@@ -3264,22 +3986,23 @@ FASTElementDefinition.getByType = fastElementRegistry.getByType;
|
|
|
3264
3986
|
*/
|
|
3265
3987
|
FASTElementDefinition.getForInstance = fastElementRegistry.getForInstance;
|
|
3266
3988
|
|
|
3267
|
-
const shadowRoots = new WeakMap();
|
|
3268
3989
|
const defaultEventOptions = {
|
|
3269
3990
|
bubbles: true,
|
|
3270
3991
|
composed: true,
|
|
3271
3992
|
cancelable: true,
|
|
3272
3993
|
};
|
|
3994
|
+
const isConnectedPropertyName = "isConnected";
|
|
3995
|
+
const shadowRoots = new WeakMap();
|
|
3273
3996
|
function getShadowRoot(element) {
|
|
3274
3997
|
var _a, _b;
|
|
3275
3998
|
return (_b = (_a = element.shadowRoot) !== null && _a !== void 0 ? _a : shadowRoots.get(element)) !== null && _b !== void 0 ? _b : null;
|
|
3276
3999
|
}
|
|
3277
|
-
|
|
4000
|
+
let elementControllerStrategy;
|
|
3278
4001
|
/**
|
|
3279
4002
|
* Controls the lifecycle and rendering of a `FASTElement`.
|
|
3280
4003
|
* @public
|
|
3281
4004
|
*/
|
|
3282
|
-
class
|
|
4005
|
+
class ElementController extends PropertyChangeNotifier {
|
|
3283
4006
|
/**
|
|
3284
4007
|
* Creates a Controller to control the specified element.
|
|
3285
4008
|
* @param element - The element to be controlled by this controller.
|
|
@@ -3290,12 +4013,18 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3290
4013
|
constructor(element, definition) {
|
|
3291
4014
|
super(element);
|
|
3292
4015
|
this.boundObservables = null;
|
|
3293
|
-
this.behaviors = null;
|
|
3294
4016
|
this.needsInitialization = true;
|
|
3295
4017
|
this.hasExistingShadowRoot = false;
|
|
3296
4018
|
this._template = null;
|
|
3297
|
-
this.
|
|
3298
|
-
|
|
4019
|
+
this.stage = 3 /* Stages.disconnected */;
|
|
4020
|
+
/**
|
|
4021
|
+
* A guard against connecting behaviors multiple times
|
|
4022
|
+
* during connect in scenarios where a behavior adds
|
|
4023
|
+
* another behavior during it's connectedCallback
|
|
4024
|
+
*/
|
|
4025
|
+
this.guardBehaviorConnection = false;
|
|
4026
|
+
this.behaviors = null;
|
|
4027
|
+
this._mainStyles = null;
|
|
3299
4028
|
/**
|
|
3300
4029
|
* This allows Observable.getNotifier(...) to return the Controller
|
|
3301
4030
|
* when the notifier for the Controller itself is being requested. The
|
|
@@ -3311,7 +4040,12 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3311
4040
|
* If `null` then the element is managing its own rendering.
|
|
3312
4041
|
*/
|
|
3313
4042
|
this.view = null;
|
|
3314
|
-
|
|
4043
|
+
/**
|
|
4044
|
+
* Opts out of JSON stringification.
|
|
4045
|
+
* @internal
|
|
4046
|
+
*/
|
|
4047
|
+
this.toJSON = noop;
|
|
4048
|
+
this.source = element;
|
|
3315
4049
|
this.definition = definition;
|
|
3316
4050
|
const shadowOptions = definition.shadowOptions;
|
|
3317
4051
|
if (shadowOptions !== void 0) {
|
|
@@ -3349,11 +4083,7 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3349
4083
|
*/
|
|
3350
4084
|
get isConnected() {
|
|
3351
4085
|
Observable.track(this, isConnectedPropertyName);
|
|
3352
|
-
return this.
|
|
3353
|
-
}
|
|
3354
|
-
setIsConnected(value) {
|
|
3355
|
-
this._isConnected = value;
|
|
3356
|
-
Observable.notify(this, isConnectedPropertyName);
|
|
4086
|
+
return this.stage === 1 /* Stages.connected */;
|
|
3357
4087
|
}
|
|
3358
4088
|
/**
|
|
3359
4089
|
* Gets/sets the template used to render the component.
|
|
@@ -3365,9 +4095,9 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3365
4095
|
// 1. Template overrides take top precedence.
|
|
3366
4096
|
if (this._template === null) {
|
|
3367
4097
|
const definition = this.definition;
|
|
3368
|
-
if (this.
|
|
4098
|
+
if (this.source.resolveTemplate) {
|
|
3369
4099
|
// 2. Allow for element instance overrides next.
|
|
3370
|
-
this._template = this.
|
|
4100
|
+
this._template = this.source.resolveTemplate();
|
|
3371
4101
|
}
|
|
3372
4102
|
else if (definition.template) {
|
|
3373
4103
|
// 3. Default to the static definition.
|
|
@@ -3386,56 +4116,104 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3386
4116
|
}
|
|
3387
4117
|
}
|
|
3388
4118
|
/**
|
|
3389
|
-
*
|
|
3390
|
-
*
|
|
3391
|
-
* This value can only be accurately read after connect but can be set at any time.
|
|
4119
|
+
* The main set of styles used for the component, independent
|
|
4120
|
+
* of any dynamically added styles.
|
|
3392
4121
|
*/
|
|
3393
|
-
get
|
|
4122
|
+
get mainStyles() {
|
|
3394
4123
|
var _a;
|
|
3395
4124
|
// 1. Styles overrides take top precedence.
|
|
3396
|
-
if (this.
|
|
4125
|
+
if (this._mainStyles === null) {
|
|
3397
4126
|
const definition = this.definition;
|
|
3398
|
-
if (this.
|
|
4127
|
+
if (this.source.resolveStyles) {
|
|
3399
4128
|
// 2. Allow for element instance overrides next.
|
|
3400
|
-
this.
|
|
4129
|
+
this._mainStyles = this.source.resolveStyles();
|
|
3401
4130
|
}
|
|
3402
4131
|
else if (definition.styles) {
|
|
3403
4132
|
// 3. Default to the static definition.
|
|
3404
|
-
this.
|
|
4133
|
+
this._mainStyles = (_a = definition.styles) !== null && _a !== void 0 ? _a : null;
|
|
3405
4134
|
}
|
|
3406
4135
|
}
|
|
3407
|
-
return this.
|
|
4136
|
+
return this._mainStyles;
|
|
3408
4137
|
}
|
|
3409
|
-
set
|
|
3410
|
-
if (this.
|
|
4138
|
+
set mainStyles(value) {
|
|
4139
|
+
if (this._mainStyles === value) {
|
|
3411
4140
|
return;
|
|
3412
4141
|
}
|
|
3413
|
-
if (this.
|
|
3414
|
-
this.removeStyles(this.
|
|
4142
|
+
if (this._mainStyles !== null) {
|
|
4143
|
+
this.removeStyles(this._mainStyles);
|
|
3415
4144
|
}
|
|
3416
|
-
this.
|
|
4145
|
+
this._mainStyles = value;
|
|
3417
4146
|
if (!this.needsInitialization) {
|
|
3418
4147
|
this.addStyles(value);
|
|
3419
4148
|
}
|
|
3420
4149
|
}
|
|
4150
|
+
/**
|
|
4151
|
+
* Adds the behavior to the component.
|
|
4152
|
+
* @param behavior - The behavior to add.
|
|
4153
|
+
*/
|
|
4154
|
+
addBehavior(behavior) {
|
|
4155
|
+
var _a, _b;
|
|
4156
|
+
const targetBehaviors = (_a = this.behaviors) !== null && _a !== void 0 ? _a : (this.behaviors = new Map());
|
|
4157
|
+
const count = (_b = targetBehaviors.get(behavior)) !== null && _b !== void 0 ? _b : 0;
|
|
4158
|
+
if (count === 0) {
|
|
4159
|
+
targetBehaviors.set(behavior, 1);
|
|
4160
|
+
behavior.addedCallback && behavior.addedCallback(this);
|
|
4161
|
+
if (behavior.connectedCallback &&
|
|
4162
|
+
!this.guardBehaviorConnection &&
|
|
4163
|
+
(this.stage === 1 /* Stages.connected */ || this.stage === 0 /* Stages.connecting */)) {
|
|
4164
|
+
behavior.connectedCallback(this);
|
|
4165
|
+
}
|
|
4166
|
+
}
|
|
4167
|
+
else {
|
|
4168
|
+
targetBehaviors.set(behavior, count + 1);
|
|
4169
|
+
}
|
|
4170
|
+
}
|
|
4171
|
+
/**
|
|
4172
|
+
* Removes the behavior from the component.
|
|
4173
|
+
* @param behavior - The behavior to remove.
|
|
4174
|
+
* @param force - Forces removal even if this behavior was added more than once.
|
|
4175
|
+
*/
|
|
4176
|
+
removeBehavior(behavior, force = false) {
|
|
4177
|
+
const targetBehaviors = this.behaviors;
|
|
4178
|
+
if (targetBehaviors === null) {
|
|
4179
|
+
return;
|
|
4180
|
+
}
|
|
4181
|
+
const count = targetBehaviors.get(behavior);
|
|
4182
|
+
if (count === void 0) {
|
|
4183
|
+
return;
|
|
4184
|
+
}
|
|
4185
|
+
if (count === 1 || force) {
|
|
4186
|
+
targetBehaviors.delete(behavior);
|
|
4187
|
+
if (behavior.disconnectedCallback && this.stage !== 3 /* Stages.disconnected */) {
|
|
4188
|
+
behavior.disconnectedCallback(this);
|
|
4189
|
+
}
|
|
4190
|
+
behavior.removedCallback && behavior.removedCallback(this);
|
|
4191
|
+
}
|
|
4192
|
+
else {
|
|
4193
|
+
targetBehaviors.set(behavior, count - 1);
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
3421
4196
|
/**
|
|
3422
4197
|
* Adds styles to this element. Providing an HTMLStyleElement will attach the element instance to the shadowRoot.
|
|
3423
4198
|
* @param styles - The styles to add.
|
|
3424
4199
|
*/
|
|
3425
4200
|
addStyles(styles) {
|
|
4201
|
+
var _a;
|
|
3426
4202
|
if (!styles) {
|
|
3427
4203
|
return;
|
|
3428
4204
|
}
|
|
3429
|
-
const
|
|
3430
|
-
this.element.getRootNode();
|
|
4205
|
+
const source = this.source;
|
|
3431
4206
|
if (styles instanceof HTMLElement) {
|
|
4207
|
+
const target = (_a = getShadowRoot(source)) !== null && _a !== void 0 ? _a : this.source;
|
|
3432
4208
|
target.append(styles);
|
|
3433
4209
|
}
|
|
3434
|
-
else if (!styles.isAttachedTo(
|
|
4210
|
+
else if (!styles.isAttachedTo(source)) {
|
|
3435
4211
|
const sourceBehaviors = styles.behaviors;
|
|
3436
|
-
styles.addStylesTo(
|
|
4212
|
+
styles.addStylesTo(source);
|
|
3437
4213
|
if (sourceBehaviors !== null) {
|
|
3438
|
-
|
|
4214
|
+
for (let i = 0, ii = sourceBehaviors.length; i < ii; ++i) {
|
|
4215
|
+
this.addBehavior(sourceBehaviors[i]);
|
|
4216
|
+
}
|
|
3439
4217
|
}
|
|
3440
4218
|
}
|
|
3441
4219
|
}
|
|
@@ -3444,121 +4222,82 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3444
4222
|
* @param styles - the styles to remove.
|
|
3445
4223
|
*/
|
|
3446
4224
|
removeStyles(styles) {
|
|
4225
|
+
var _a;
|
|
3447
4226
|
if (!styles) {
|
|
3448
4227
|
return;
|
|
3449
4228
|
}
|
|
3450
|
-
const
|
|
3451
|
-
this.element.getRootNode();
|
|
4229
|
+
const source = this.source;
|
|
3452
4230
|
if (styles instanceof HTMLElement) {
|
|
4231
|
+
const target = (_a = getShadowRoot(source)) !== null && _a !== void 0 ? _a : source;
|
|
3453
4232
|
target.removeChild(styles);
|
|
3454
4233
|
}
|
|
3455
|
-
else if (styles.isAttachedTo(
|
|
4234
|
+
else if (styles.isAttachedTo(source)) {
|
|
3456
4235
|
const sourceBehaviors = styles.behaviors;
|
|
3457
|
-
styles.removeStylesFrom(
|
|
4236
|
+
styles.removeStylesFrom(source);
|
|
3458
4237
|
if (sourceBehaviors !== null) {
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
}
|
|
3463
|
-
/**
|
|
3464
|
-
* Adds behaviors to this element.
|
|
3465
|
-
* @param behaviors - The behaviors to add.
|
|
3466
|
-
*/
|
|
3467
|
-
addBehaviors(behaviors) {
|
|
3468
|
-
var _a;
|
|
3469
|
-
const targetBehaviors = (_a = this.behaviors) !== null && _a !== void 0 ? _a : (this.behaviors = new Map());
|
|
3470
|
-
const length = behaviors.length;
|
|
3471
|
-
const behaviorsToBind = [];
|
|
3472
|
-
for (let i = 0; i < length; ++i) {
|
|
3473
|
-
const behavior = behaviors[i];
|
|
3474
|
-
if (targetBehaviors.has(behavior)) {
|
|
3475
|
-
targetBehaviors.set(behavior, targetBehaviors.get(behavior) + 1);
|
|
3476
|
-
}
|
|
3477
|
-
else {
|
|
3478
|
-
targetBehaviors.set(behavior, 1);
|
|
3479
|
-
behaviorsToBind.push(behavior);
|
|
3480
|
-
}
|
|
3481
|
-
}
|
|
3482
|
-
if (this._isConnected) {
|
|
3483
|
-
const element = this.element;
|
|
3484
|
-
const context = ExecutionContext.default;
|
|
3485
|
-
for (let i = 0; i < behaviorsToBind.length; ++i) {
|
|
3486
|
-
behaviorsToBind[i].bind(element, context);
|
|
4238
|
+
for (let i = 0, ii = sourceBehaviors.length; i < ii; ++i) {
|
|
4239
|
+
this.addBehavior(sourceBehaviors[i]);
|
|
4240
|
+
}
|
|
3487
4241
|
}
|
|
3488
4242
|
}
|
|
3489
4243
|
}
|
|
3490
4244
|
/**
|
|
3491
|
-
*
|
|
3492
|
-
* @param behaviors - The behaviors to remove.
|
|
3493
|
-
* @param force - Forces unbinding of behaviors.
|
|
4245
|
+
* Runs connected lifecycle behavior on the associated element.
|
|
3494
4246
|
*/
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
if (targetBehaviors === null) {
|
|
4247
|
+
connect() {
|
|
4248
|
+
if (this.stage !== 3 /* Stages.disconnected */) {
|
|
3498
4249
|
return;
|
|
3499
4250
|
}
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
const
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
4251
|
+
this.stage = 0 /* Stages.connecting */;
|
|
4252
|
+
// If we have any observables that were bound, re-apply their values.
|
|
4253
|
+
if (this.boundObservables !== null) {
|
|
4254
|
+
const element = this.source;
|
|
4255
|
+
const boundObservables = this.boundObservables;
|
|
4256
|
+
const propertyNames = Object.keys(boundObservables);
|
|
4257
|
+
for (let i = 0, ii = propertyNames.length; i < ii; ++i) {
|
|
4258
|
+
const propertyName = propertyNames[i];
|
|
4259
|
+
element[propertyName] = boundObservables[propertyName];
|
|
3509
4260
|
}
|
|
4261
|
+
this.boundObservables = null;
|
|
3510
4262
|
}
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
for (
|
|
3515
|
-
|
|
4263
|
+
const behaviors = this.behaviors;
|
|
4264
|
+
if (behaviors !== null) {
|
|
4265
|
+
this.guardBehaviorConnection = true;
|
|
4266
|
+
for (const key of behaviors.keys()) {
|
|
4267
|
+
key.connectedCallback && key.connectedCallback(this);
|
|
3516
4268
|
}
|
|
4269
|
+
this.guardBehaviorConnection = false;
|
|
3517
4270
|
}
|
|
3518
|
-
}
|
|
3519
|
-
/**
|
|
3520
|
-
* Runs connected lifecycle behavior on the associated element.
|
|
3521
|
-
*/
|
|
3522
|
-
onConnectedCallback() {
|
|
3523
|
-
if (this._isConnected) {
|
|
3524
|
-
return;
|
|
3525
|
-
}
|
|
3526
|
-
const element = this.element;
|
|
3527
|
-
const context = ExecutionContext.default;
|
|
3528
4271
|
if (this.needsInitialization) {
|
|
3529
|
-
this.
|
|
4272
|
+
this.renderTemplate(this.template);
|
|
4273
|
+
this.addStyles(this.mainStyles);
|
|
4274
|
+
this.needsInitialization = false;
|
|
3530
4275
|
}
|
|
3531
4276
|
else if (this.view !== null) {
|
|
3532
|
-
this.view.bind(
|
|
3533
|
-
}
|
|
3534
|
-
const behaviors = this.behaviors;
|
|
3535
|
-
if (behaviors !== null) {
|
|
3536
|
-
for (const behavior of behaviors.keys()) {
|
|
3537
|
-
behavior.bind(element, context);
|
|
3538
|
-
}
|
|
4277
|
+
this.view.bind(this.source);
|
|
3539
4278
|
}
|
|
3540
|
-
this.
|
|
4279
|
+
this.stage = 1 /* Stages.connected */;
|
|
4280
|
+
Observable.notify(this, isConnectedPropertyName);
|
|
3541
4281
|
}
|
|
3542
4282
|
/**
|
|
3543
4283
|
* Runs disconnected lifecycle behavior on the associated element.
|
|
3544
4284
|
*/
|
|
3545
|
-
|
|
3546
|
-
if (
|
|
4285
|
+
disconnect() {
|
|
4286
|
+
if (this.stage !== 1 /* Stages.connected */) {
|
|
3547
4287
|
return;
|
|
3548
4288
|
}
|
|
3549
|
-
this.
|
|
3550
|
-
|
|
3551
|
-
if (view !== null) {
|
|
3552
|
-
view.unbind();
|
|
4289
|
+
this.stage = 2 /* Stages.disconnecting */;
|
|
4290
|
+
Observable.notify(this, isConnectedPropertyName);
|
|
4291
|
+
if (this.view !== null) {
|
|
4292
|
+
this.view.unbind();
|
|
3553
4293
|
}
|
|
3554
4294
|
const behaviors = this.behaviors;
|
|
3555
4295
|
if (behaviors !== null) {
|
|
3556
|
-
const
|
|
3557
|
-
|
|
3558
|
-
for (const behavior of behaviors.keys()) {
|
|
3559
|
-
behavior.unbind(element, context);
|
|
4296
|
+
for (const key of behaviors.keys()) {
|
|
4297
|
+
key.disconnectedCallback && key.disconnectedCallback(this);
|
|
3560
4298
|
}
|
|
3561
4299
|
}
|
|
4300
|
+
this.stage = 3 /* Stages.disconnected */;
|
|
3562
4301
|
}
|
|
3563
4302
|
/**
|
|
3564
4303
|
* Runs the attribute changed callback for the associated element.
|
|
@@ -3569,7 +4308,7 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3569
4308
|
onAttributeChangedCallback(name, oldValue, newValue) {
|
|
3570
4309
|
const attrDef = this.definition.attributeLookup[name];
|
|
3571
4310
|
if (attrDef !== void 0) {
|
|
3572
|
-
attrDef.onAttributeChangedCallback(this.
|
|
4311
|
+
attrDef.onAttributeChangedCallback(this.source, newValue);
|
|
3573
4312
|
}
|
|
3574
4313
|
}
|
|
3575
4314
|
/**
|
|
@@ -3581,33 +4320,17 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3581
4320
|
* Only emits events if connected.
|
|
3582
4321
|
*/
|
|
3583
4322
|
emit(type, detail, options) {
|
|
3584
|
-
if (this.
|
|
3585
|
-
return this.
|
|
4323
|
+
if (this.stage === 1 /* Stages.connected */) {
|
|
4324
|
+
return this.source.dispatchEvent(new CustomEvent(type, Object.assign(Object.assign({ detail }, defaultEventOptions), options)));
|
|
3586
4325
|
}
|
|
3587
4326
|
return false;
|
|
3588
4327
|
}
|
|
3589
|
-
finishInitialization() {
|
|
3590
|
-
const element = this.element;
|
|
3591
|
-
const boundObservables = this.boundObservables;
|
|
3592
|
-
// If we have any observables that were bound, re-apply their values.
|
|
3593
|
-
if (boundObservables !== null) {
|
|
3594
|
-
const propertyNames = Object.keys(boundObservables);
|
|
3595
|
-
for (let i = 0, ii = propertyNames.length; i < ii; ++i) {
|
|
3596
|
-
const propertyName = propertyNames[i];
|
|
3597
|
-
element[propertyName] = boundObservables[propertyName];
|
|
3598
|
-
}
|
|
3599
|
-
this.boundObservables = null;
|
|
3600
|
-
}
|
|
3601
|
-
this.renderTemplate(this.template);
|
|
3602
|
-
this.addStyles(this.styles);
|
|
3603
|
-
this.needsInitialization = false;
|
|
3604
|
-
}
|
|
3605
4328
|
renderTemplate(template) {
|
|
3606
4329
|
var _a;
|
|
3607
|
-
const element = this.element;
|
|
3608
4330
|
// When getting the host to render to, we start by looking
|
|
3609
4331
|
// up the shadow root. If there isn't one, then that means
|
|
3610
4332
|
// we're doing a Light DOM render to the element's direct children.
|
|
4333
|
+
const element = this.source;
|
|
3611
4334
|
const host = (_a = getShadowRoot(element)) !== null && _a !== void 0 ? _a : element;
|
|
3612
4335
|
if (this.view !== null) {
|
|
3613
4336
|
// If there's already a view, we need to unbind and remove through dispose.
|
|
@@ -3624,6 +4347,8 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3624
4347
|
if (template) {
|
|
3625
4348
|
// If a new template was provided, render it.
|
|
3626
4349
|
this.view = template.render(element, host, element);
|
|
4350
|
+
this.view.sourceLifetime =
|
|
4351
|
+
SourceLifetime.coupled;
|
|
3627
4352
|
}
|
|
3628
4353
|
}
|
|
3629
4354
|
/**
|
|
@@ -3643,31 +4368,145 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3643
4368
|
if (definition === void 0) {
|
|
3644
4369
|
throw FAST.error(1401 /* Message.missingElementDefinition */);
|
|
3645
4370
|
}
|
|
3646
|
-
return (element.$fastController = new
|
|
4371
|
+
return (element.$fastController = new elementControllerStrategy(element, definition));
|
|
4372
|
+
}
|
|
4373
|
+
/**
|
|
4374
|
+
* Sets the strategy that ElementController.forCustomElement uses to construct
|
|
4375
|
+
* ElementController instances for an element.
|
|
4376
|
+
* @param strategy - The strategy to use.
|
|
4377
|
+
*/
|
|
4378
|
+
static setStrategy(strategy) {
|
|
4379
|
+
elementControllerStrategy = strategy;
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
// Set default strategy for ElementController
|
|
4383
|
+
ElementController.setStrategy(ElementController);
|
|
4384
|
+
/**
|
|
4385
|
+
* Converts a styleTarget into the operative target. When the provided target is an Element
|
|
4386
|
+
* that is a FASTElement, the function will return the ShadowRoot for that element. Otherwise,
|
|
4387
|
+
* it will return the root node for the element.
|
|
4388
|
+
* @param target
|
|
4389
|
+
* @returns
|
|
4390
|
+
*/
|
|
4391
|
+
function normalizeStyleTarget(target) {
|
|
4392
|
+
var _a;
|
|
4393
|
+
if ("adoptedStyleSheets" in target) {
|
|
4394
|
+
return target;
|
|
4395
|
+
}
|
|
4396
|
+
else {
|
|
4397
|
+
return ((_a = getShadowRoot(target)) !== null && _a !== void 0 ? _a : target.getRootNode());
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
// Default StyleStrategy implementations are defined in this module because they
|
|
4401
|
+
// require access to element shadowRoots, and we don't want to leak shadowRoot
|
|
4402
|
+
// objects out of this module.
|
|
4403
|
+
/**
|
|
4404
|
+
* https://wicg.github.io/construct-stylesheets/
|
|
4405
|
+
* https://developers.google.com/web/updates/2019/02/constructable-stylesheets
|
|
4406
|
+
*
|
|
4407
|
+
* @internal
|
|
4408
|
+
*/
|
|
4409
|
+
class AdoptedStyleSheetsStrategy {
|
|
4410
|
+
constructor(styles) {
|
|
4411
|
+
const styleSheetCache = AdoptedStyleSheetsStrategy.styleSheetCache;
|
|
4412
|
+
this.sheets = styles.map((x) => {
|
|
4413
|
+
if (x instanceof CSSStyleSheet) {
|
|
4414
|
+
return x;
|
|
4415
|
+
}
|
|
4416
|
+
let sheet = styleSheetCache.get(x);
|
|
4417
|
+
if (sheet === void 0) {
|
|
4418
|
+
sheet = new CSSStyleSheet();
|
|
4419
|
+
sheet.replaceSync(x);
|
|
4420
|
+
styleSheetCache.set(x, sheet);
|
|
4421
|
+
}
|
|
4422
|
+
return sheet;
|
|
4423
|
+
});
|
|
4424
|
+
}
|
|
4425
|
+
addStylesTo(target) {
|
|
4426
|
+
const t = normalizeStyleTarget(target);
|
|
4427
|
+
t.adoptedStyleSheets = [...t.adoptedStyleSheets, ...this.sheets];
|
|
4428
|
+
}
|
|
4429
|
+
removeStylesFrom(target) {
|
|
4430
|
+
const t = normalizeStyleTarget(target);
|
|
4431
|
+
const sheets = this.sheets;
|
|
4432
|
+
t.adoptedStyleSheets = t.adoptedStyleSheets.filter((x) => sheets.indexOf(x) === -1);
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4435
|
+
AdoptedStyleSheetsStrategy.styleSheetCache = new Map();
|
|
4436
|
+
let id = 0;
|
|
4437
|
+
const nextStyleId = () => `fast-${++id}`;
|
|
4438
|
+
function usableStyleTarget(target) {
|
|
4439
|
+
return target === document ? document.body : target;
|
|
4440
|
+
}
|
|
4441
|
+
/**
|
|
4442
|
+
* @internal
|
|
4443
|
+
*/
|
|
4444
|
+
class StyleElementStrategy {
|
|
4445
|
+
constructor(styles) {
|
|
4446
|
+
this.styles = styles;
|
|
4447
|
+
this.styleClass = nextStyleId();
|
|
4448
|
+
}
|
|
4449
|
+
addStylesTo(target) {
|
|
4450
|
+
target = usableStyleTarget(normalizeStyleTarget(target));
|
|
4451
|
+
const styles = this.styles;
|
|
4452
|
+
const styleClass = this.styleClass;
|
|
4453
|
+
for (let i = 0; i < styles.length; i++) {
|
|
4454
|
+
const element = document.createElement("style");
|
|
4455
|
+
element.innerHTML = styles[i];
|
|
4456
|
+
element.className = styleClass;
|
|
4457
|
+
target.append(element);
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
removeStylesFrom(target) {
|
|
4461
|
+
target = usableStyleTarget(normalizeStyleTarget(target));
|
|
4462
|
+
const styles = target.querySelectorAll(`.${this.styleClass}`);
|
|
4463
|
+
for (let i = 0, ii = styles.length; i < ii; ++i) {
|
|
4464
|
+
target.removeChild(styles[i]);
|
|
4465
|
+
}
|
|
3647
4466
|
}
|
|
3648
4467
|
}
|
|
4468
|
+
ElementStyles.setDefaultStrategy(ElementStyles.supportsAdoptedStyleSheets
|
|
4469
|
+
? AdoptedStyleSheetsStrategy
|
|
4470
|
+
: StyleElementStrategy);
|
|
3649
4471
|
|
|
3650
4472
|
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
3651
4473
|
function createFASTElement(BaseType) {
|
|
3652
|
-
|
|
4474
|
+
const type = class extends BaseType {
|
|
3653
4475
|
constructor() {
|
|
3654
4476
|
/* eslint-disable-next-line */
|
|
3655
4477
|
super();
|
|
3656
|
-
|
|
4478
|
+
ElementController.forCustomElement(this);
|
|
3657
4479
|
}
|
|
3658
4480
|
$emit(type, detail, options) {
|
|
3659
4481
|
return this.$fastController.emit(type, detail, options);
|
|
3660
4482
|
}
|
|
3661
4483
|
connectedCallback() {
|
|
3662
|
-
this.$fastController.
|
|
4484
|
+
this.$fastController.connect();
|
|
3663
4485
|
}
|
|
3664
4486
|
disconnectedCallback() {
|
|
3665
|
-
this.$fastController.
|
|
4487
|
+
this.$fastController.disconnect();
|
|
3666
4488
|
}
|
|
3667
4489
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
3668
4490
|
this.$fastController.onAttributeChangedCallback(name, oldValue, newValue);
|
|
3669
4491
|
}
|
|
3670
4492
|
};
|
|
4493
|
+
FASTElementDefinition.registerBaseType(type);
|
|
4494
|
+
return type;
|
|
4495
|
+
}
|
|
4496
|
+
function compose(type, nameOrDef) {
|
|
4497
|
+
if (isFunction(type)) {
|
|
4498
|
+
return FASTElementDefinition.compose(type, nameOrDef);
|
|
4499
|
+
}
|
|
4500
|
+
return FASTElementDefinition.compose(this, type);
|
|
4501
|
+
}
|
|
4502
|
+
function define(type, nameOrDef) {
|
|
4503
|
+
if (isFunction(type)) {
|
|
4504
|
+
return FASTElementDefinition.compose(type, nameOrDef).define().type;
|
|
4505
|
+
}
|
|
4506
|
+
return FASTElementDefinition.compose(this, type).define().type;
|
|
4507
|
+
}
|
|
4508
|
+
function from(BaseType) {
|
|
4509
|
+
return createFASTElement(BaseType);
|
|
3671
4510
|
}
|
|
3672
4511
|
/**
|
|
3673
4512
|
* A minimal base class for FASTElements that also provides
|
|
@@ -3680,26 +4519,19 @@ const FASTElement = Object.assign(createFASTElement(HTMLElement), {
|
|
|
3680
4519
|
* provided base type.
|
|
3681
4520
|
* @param BaseType - The base element type to inherit from.
|
|
3682
4521
|
*/
|
|
3683
|
-
from
|
|
3684
|
-
return createFASTElement(BaseType);
|
|
3685
|
-
},
|
|
4522
|
+
from,
|
|
3686
4523
|
/**
|
|
3687
4524
|
* Defines a platform custom element based on the provided type and definition.
|
|
3688
4525
|
* @param type - The custom element type to define.
|
|
3689
4526
|
* @param nameOrDef - The name of the element to define or a definition object
|
|
3690
4527
|
* that describes the element to define.
|
|
3691
4528
|
*/
|
|
3692
|
-
define
|
|
3693
|
-
return this.metadata(type, nameOrDef).define().type;
|
|
3694
|
-
},
|
|
4529
|
+
define,
|
|
3695
4530
|
/**
|
|
3696
4531
|
* Defines metadata for a FASTElement which can be used to later define the element.
|
|
3697
|
-
* IMPORTANT: This API will be renamed to "compose" in a future beta.
|
|
3698
4532
|
* @public
|
|
3699
4533
|
*/
|
|
3700
|
-
|
|
3701
|
-
return new FASTElementDefinition(type, nameOrDef);
|
|
3702
|
-
},
|
|
4534
|
+
compose,
|
|
3703
4535
|
});
|
|
3704
4536
|
/**
|
|
3705
4537
|
* Decorator: Defines a platform custom element based on `FASTElement`.
|
|
@@ -3710,8 +4542,10 @@ const FASTElement = Object.assign(createFASTElement(HTMLElement), {
|
|
|
3710
4542
|
function customElement(nameOrDef) {
|
|
3711
4543
|
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
3712
4544
|
return function (type) {
|
|
3713
|
-
|
|
4545
|
+
define(type, nameOrDef);
|
|
3714
4546
|
};
|
|
3715
4547
|
}
|
|
3716
4548
|
|
|
3717
|
-
|
|
4549
|
+
DOM.setPolicy(DOMPolicy.create());
|
|
4550
|
+
|
|
4551
|
+
export { ArrayObserver, AttributeConfiguration, AttributeDefinition, Binding, CSSDirective, ChildrenDirective, Compiler, DOM, DOMAspect, ElementController, ElementStyles, ExecutionContext, FAST, FASTElement, FASTElementDefinition, HTMLBindingDirective, HTMLDirective, HTMLView, InlineTemplateDirective, Markup, NodeObservationDirective, Observable, Parser, PropertyChangeNotifier, RefDirective, RepeatBehavior, RepeatDirective, SlottedDirective, SourceLifetime, Splice, SpliceStrategy, SpliceStrategySupport, StatelessAttachedAttributeDirective, SubscriberSet, Updates, ViewTemplate, attr, bind, booleanConverter, children, createMetadataLocator, createTypeRegistry, css, cssDirective, customElement, elements, emptyArray, html, htmlDirective, lengthOf, listener, normalizeBinding, nullableBooleanConverter, nullableNumberConverter, observable, oneTime, ref, repeat, slotted, volatile, when };
|