@microsoft/fast-element 2.0.0-beta.8 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +1 -1
- package/CHANGELOG.json +512 -0
- package/CHANGELOG.md +180 -1
- package/README.md +1 -9
- package/api-extractor.context.json +14 -0
- package/api-extractor.di.json +14 -0
- package/dist/context/context.api.json +1068 -0
- package/dist/di/di.api.json +4929 -0
- package/dist/dts/binding/binding.d.ts +49 -0
- package/dist/dts/binding/normalize.d.ts +9 -0
- package/dist/dts/binding/one-time.d.ts +11 -0
- package/dist/dts/binding/one-way.d.ts +20 -0
- package/dist/dts/{templating/binding-signal.d.ts → binding/signal.d.ts} +19 -4
- package/dist/dts/{templating/binding-two-way.d.ts → binding/two-way.d.ts} +9 -5
- package/dist/dts/components/attributes.d.ts +6 -0
- package/dist/dts/components/element-controller.d.ts +104 -8
- package/dist/dts/components/element-hydration.d.ts +2 -0
- package/dist/dts/components/fast-definitions.d.ts +6 -0
- package/dist/dts/components/hydration.d.ts +56 -0
- package/dist/dts/components/install-hydration.d.ts +1 -0
- package/dist/dts/context.d.ts +29 -15
- package/dist/dts/di/di.d.ts +0 -5
- package/dist/dts/dom-policy.d.ts +83 -0
- package/dist/dts/dom.d.ts +100 -0
- package/dist/dts/hydration/target-builder.d.ts +63 -0
- package/dist/dts/index.d.ts +33 -26
- 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 +32 -82
- package/dist/dts/metadata.d.ts +6 -5
- package/dist/dts/observation/arrays.d.ts +1 -1
- package/dist/dts/observation/observable.bench.d.ts +18 -0
- package/dist/dts/observation/observable.d.ts +5 -5
- package/dist/dts/pending-task.d.ts +19 -7
- package/dist/dts/platform.d.ts +11 -2
- package/dist/dts/polyfills.d.ts +0 -8
- package/dist/dts/styles/css-binding-directive.d.ts +60 -0
- package/dist/dts/styles/css.d.ts +9 -7
- package/dist/dts/styles/element-styles.d.ts +1 -14
- package/dist/dts/styles/host.d.ts +2 -5
- package/dist/dts/styles/style-strategy.d.ts +42 -0
- package/dist/dts/templating/compiler.d.ts +11 -13
- package/dist/dts/templating/{binding.d.ts → html-binding-directive.d.ts} +22 -42
- package/dist/dts/templating/html-directive.d.ts +44 -140
- package/dist/dts/templating/install-hydratable-view-templates.d.ts +1 -0
- package/dist/dts/templating/node-observation.d.ts +11 -1
- package/dist/dts/templating/ref.d.ts +4 -0
- package/dist/dts/templating/render.bench.d.ts +3 -0
- package/dist/dts/templating/render.d.ts +49 -9
- package/dist/dts/templating/repeat-basic-reverse.bench.d.ts +3 -0
- package/dist/dts/templating/repeat-basic-shift.bench.d.ts +3 -0
- package/dist/dts/templating/repeat.d.ts +31 -9
- package/dist/dts/templating/template.d.ts +97 -12
- package/dist/dts/templating/view.d.ts +149 -26
- package/dist/dts/templating/when-basic.bench.d.ts +3 -0
- package/dist/dts/templating/when-conditional.bench.d.ts +3 -0
- package/dist/dts/templating/when-switch.bench.d.ts +3 -0
- package/dist/dts/templating/when.d.ts +3 -1
- package/dist/dts/testing/fakes.d.ts +12 -1
- package/dist/dts/tsdoc-metadata.json +1 -1
- package/dist/dts/utilities.d.ts +55 -1
- package/dist/esm/binding/binding.js +18 -0
- package/dist/esm/binding/normalize.js +17 -0
- package/dist/esm/binding/one-time.js +21 -0
- package/dist/esm/binding/one-way.js +30 -0
- package/dist/esm/{templating/binding-signal.js → binding/signal.js} +22 -6
- package/dist/esm/{templating/binding-two-way.js → binding/two-way.js} +18 -12
- package/dist/esm/components/attributes.js +16 -1
- package/dist/esm/components/element-controller.js +319 -49
- package/dist/esm/components/element-hydration.js +2 -0
- package/dist/esm/components/fast-definitions.js +12 -4
- package/dist/esm/components/fast-element.js +3 -1
- package/dist/esm/components/hydration.js +104 -0
- package/dist/esm/components/install-hydration.js +3 -0
- package/dist/esm/context.js +26 -4
- package/dist/esm/debug.js +8 -2
- package/dist/esm/di/di.js +9 -12
- package/dist/esm/dom-policy.js +345 -0
- package/dist/esm/dom.js +101 -0
- package/dist/esm/hydration/target-builder.js +175 -0
- package/dist/esm/index.js +34 -25
- package/dist/esm/index.rollup.debug.js +3 -1
- package/dist/esm/index.rollup.js +3 -1
- package/dist/esm/interfaces.js +51 -3
- package/dist/esm/metadata.js +11 -8
- package/dist/esm/observation/arrays.js +1 -1
- package/dist/esm/observation/observable.bench.js +79 -0
- package/dist/esm/observation/observable.js +20 -15
- package/dist/esm/observation/update-queue.js +2 -2
- package/dist/esm/pending-task.js +13 -1
- package/dist/esm/platform.js +12 -2
- package/dist/esm/polyfills.js +3 -61
- package/dist/esm/styles/css-binding-directive.js +76 -0
- package/dist/esm/styles/css.js +14 -7
- package/dist/esm/styles/element-styles.js +0 -33
- package/dist/esm/styles/style-strategy.js +1 -0
- package/dist/esm/templating/children.js +8 -4
- package/dist/esm/templating/compiler.js +37 -44
- package/dist/esm/templating/html-binding-directive.js +218 -0
- package/dist/esm/templating/html-directive.js +25 -152
- package/dist/esm/templating/install-hydratable-view-templates.js +17 -0
- package/dist/esm/templating/node-observation.js +14 -8
- package/dist/esm/templating/ref.js +1 -1
- package/dist/esm/templating/render.bench.js +56 -0
- package/dist/esm/templating/render.js +74 -30
- package/dist/esm/templating/repeat-basic-reverse.bench.js +43 -0
- package/dist/esm/templating/repeat-basic-shift.bench.js +43 -0
- package/dist/esm/templating/repeat.js +116 -17
- package/dist/esm/templating/template.js +135 -60
- package/dist/esm/templating/view.js +259 -32
- package/dist/esm/templating/when-basic.bench.js +36 -0
- package/dist/esm/templating/when-conditional.bench.js +39 -0
- package/dist/esm/templating/when-switch.bench.js +68 -0
- package/dist/esm/templating/when.js +12 -5
- package/dist/esm/testing/fakes.js +32 -1
- package/dist/esm/testing/fixture.js +1 -1
- package/dist/esm/utilities.js +97 -1
- package/dist/fast-element.api.json +9804 -5622
- package/dist/fast-element.d.ts +813 -2386
- package/dist/fast-element.debug.js +2797 -974
- package/dist/fast-element.debug.min.js +3 -1
- package/dist/fast-element.js +2642 -825
- package/dist/fast-element.min.js +3 -1
- package/dist/fast-element.untrimmed.d.ts +669 -315
- package/docs/{api-report.md → api-report.api.md} +243 -158
- package/docs/context/api-report.api.md +69 -0
- package/docs/di/api-report.api.md +315 -0
- package/karma.conf.cjs +2 -1
- package/package.json +59 -47
- package/scripts/run-api-extractor.js +51 -0
- package/scripts/run-benchmarks.js +46 -0
- package/tensile.config.js +12 -0
- package/dist/dts/templating/dom.d.ts +0 -41
- package/dist/esm/templating/binding.js +0 -282
- package/dist/esm/templating/dom.js +0 -49
- package/docs/guide/declaring-templates.md +0 -230
- package/docs/guide/defining-elements.md +0 -214
- package/docs/guide/leveraging-css.md +0 -253
- package/docs/guide/next-steps.md +0 -13
- package/docs/guide/observables-and-state.md +0 -213
- package/docs/guide/using-directives.md +0 -576
- package/docs/guide/working-with-shadow-dom.md +0 -296
package/dist/esm/polyfills.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
1
2
|
(function ensureGlobalThis() {
|
|
2
3
|
if (typeof globalThis !== "undefined") {
|
|
3
4
|
// We're running in a modern environment.
|
|
4
5
|
return;
|
|
5
6
|
}
|
|
7
|
+
// @ts-ignore
|
|
6
8
|
if (typeof global !== "undefined") {
|
|
7
9
|
// We're running in NodeJS
|
|
10
|
+
// @ts-ignore
|
|
8
11
|
global.globalThis = global;
|
|
9
12
|
}
|
|
10
13
|
else if (typeof self !== "undefined") {
|
|
@@ -22,64 +25,3 @@
|
|
|
22
25
|
result.globalThis = result;
|
|
23
26
|
}
|
|
24
27
|
})();
|
|
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 = {
|
|
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));
|
|
39
|
-
}
|
|
40
|
-
const FAST = globalThis.FAST;
|
|
41
|
-
if (FAST.getById === void 0) {
|
|
42
|
-
const storage = Object.create(null);
|
|
43
|
-
Reflect.defineProperty(FAST, "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));
|
|
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 = 0;
|
|
58
|
-
const nextStyleId = () => `fast-${++id}`;
|
|
59
|
-
export 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.getById(/* KernelServiceId.styleSheetStrategy */ 5, () => StyleElementStrategy);
|
|
85
|
-
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { CSSDirective } from "./css-directive.js";
|
|
2
|
+
function handleChange(directive, controller, observer) {
|
|
3
|
+
controller.source.style.setProperty(directive.targetAspect, observer.bind(controller));
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Enables bindings in CSS.
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export class CSSBindingDirective {
|
|
11
|
+
/**
|
|
12
|
+
* Creates an instance of CSSBindingDirective.
|
|
13
|
+
* @param dataBinding - The binding to use in CSS.
|
|
14
|
+
* @param targetAspect - The CSS property to target.
|
|
15
|
+
*/
|
|
16
|
+
constructor(dataBinding, targetAspect) {
|
|
17
|
+
this.dataBinding = dataBinding;
|
|
18
|
+
this.targetAspect = targetAspect;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates a CSS fragment to interpolate into the CSS document.
|
|
22
|
+
* @returns - the string to interpolate into CSS
|
|
23
|
+
*/
|
|
24
|
+
createCSS(add) {
|
|
25
|
+
add(this);
|
|
26
|
+
return `var(${this.targetAspect})`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Executed when this behavior is attached to a controller.
|
|
30
|
+
* @param controller - Controls the behavior lifecycle.
|
|
31
|
+
*/
|
|
32
|
+
addedCallback(controller) {
|
|
33
|
+
var _a;
|
|
34
|
+
const element = controller.source;
|
|
35
|
+
if (!element.$cssBindings) {
|
|
36
|
+
element.$cssBindings = new Map();
|
|
37
|
+
const setAttribute = element.setAttribute;
|
|
38
|
+
element.setAttribute = (attr, value) => {
|
|
39
|
+
setAttribute.call(element, attr, value);
|
|
40
|
+
if (attr === "style") {
|
|
41
|
+
element.$cssBindings.forEach((v, k) => handleChange(k, v.controller, v.observer));
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const observer = (_a = controller[this.targetAspect]) !== null && _a !== void 0 ? _a : (controller[this.targetAspect] = this.dataBinding.createObserver(this, this));
|
|
46
|
+
observer.controller = controller;
|
|
47
|
+
controller.source.$cssBindings.set(this, { controller, observer });
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Executed when this behavior's host is connected.
|
|
51
|
+
* @param controller - Controls the behavior lifecycle.
|
|
52
|
+
*/
|
|
53
|
+
connectedCallback(controller) {
|
|
54
|
+
handleChange(this, controller, controller[this.targetAspect]);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Executed when this behavior is detached from a controller.
|
|
58
|
+
* @param controller - Controls the behavior lifecycle.
|
|
59
|
+
*/
|
|
60
|
+
removedCallback(controller) {
|
|
61
|
+
if (controller.source.$cssBindings) {
|
|
62
|
+
controller.source.$cssBindings.delete(this);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Called when a subject this instance has subscribed to changes.
|
|
67
|
+
* @param subject - The subject of the change.
|
|
68
|
+
* @param args - The event args detailing the change that occurred.
|
|
69
|
+
*
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
handleChange(_, observer) {
|
|
73
|
+
handleChange(this, observer.controller, observer);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
CSSDirective.define(CSSBindingDirective);
|
package/dist/esm/styles/css.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import { isString } from "../interfaces.js";
|
|
1
|
+
import { isFunction, isString } from "../interfaces.js";
|
|
2
|
+
import { Binding } from "../binding/binding.js";
|
|
3
|
+
import { oneWay } from "../binding/one-way.js";
|
|
2
4
|
import { CSSDirective } from "./css-directive.js";
|
|
3
5
|
import { ElementStyles } from "./element-styles.js";
|
|
6
|
+
import { CSSBindingDirective } from "./css-binding-directive.js";
|
|
7
|
+
const marker = `${Math.random().toString(36).substring(2, 8)}`;
|
|
8
|
+
let varId = 0;
|
|
9
|
+
const nextCSSVariable = () => `--v${marker}${++varId}`;
|
|
4
10
|
function collectStyles(strings, values) {
|
|
5
11
|
const styles = [];
|
|
6
12
|
let cssString = "";
|
|
@@ -11,7 +17,13 @@ function collectStyles(strings, values) {
|
|
|
11
17
|
for (let i = 0, ii = strings.length - 1; i < ii; ++i) {
|
|
12
18
|
cssString += strings[i];
|
|
13
19
|
let value = values[i];
|
|
14
|
-
if (
|
|
20
|
+
if (isFunction(value)) {
|
|
21
|
+
value = new CSSBindingDirective(oneWay(value), nextCSSVariable()).createCSS(add);
|
|
22
|
+
}
|
|
23
|
+
else if (value instanceof Binding) {
|
|
24
|
+
value = new CSSBindingDirective(value, nextCSSVariable()).createCSS(add);
|
|
25
|
+
}
|
|
26
|
+
else if (CSSDirective.getForInstance(value) !== void 0) {
|
|
15
27
|
value = value.createCSS(add);
|
|
16
28
|
}
|
|
17
29
|
if (value instanceof ElementStyles || value instanceof CSSStyleSheet) {
|
|
@@ -83,8 +95,3 @@ css.partial = (strings, ...values) => {
|
|
|
83
95
|
const { styles, behaviors } = collectStyles(strings, values);
|
|
84
96
|
return new CSSPartial(styles, behaviors);
|
|
85
97
|
};
|
|
86
|
-
/**
|
|
87
|
-
* @deprecated Use css.partial instead.
|
|
88
|
-
* @public
|
|
89
|
-
*/
|
|
90
|
-
export const cssPartial = css.partial;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { FAST } from "../platform.js";
|
|
2
|
-
import "../interfaces.js";
|
|
3
|
-
const styleSheetCache = new Map();
|
|
4
1
|
let DefaultStyleStrategy;
|
|
5
2
|
function reduceStyles(styles) {
|
|
6
3
|
return styles
|
|
@@ -91,33 +88,3 @@ export class ElementStyles {
|
|
|
91
88
|
*/
|
|
92
89
|
ElementStyles.supportsAdoptedStyleSheets = Array.isArray(document.adoptedStyleSheets) &&
|
|
93
90
|
"replace" in CSSStyleSheet.prototype;
|
|
94
|
-
/**
|
|
95
|
-
* https://wicg.github.io/construct-stylesheets/
|
|
96
|
-
* https://developers.google.com/web/updates/2019/02/constructable-stylesheets
|
|
97
|
-
*
|
|
98
|
-
* @internal
|
|
99
|
-
*/
|
|
100
|
-
export class AdoptedStyleSheetsStrategy {
|
|
101
|
-
constructor(styles) {
|
|
102
|
-
this.sheets = styles.map((x) => {
|
|
103
|
-
if (x instanceof CSSStyleSheet) {
|
|
104
|
-
return x;
|
|
105
|
-
}
|
|
106
|
-
let sheet = styleSheetCache.get(x);
|
|
107
|
-
if (sheet === void 0) {
|
|
108
|
-
sheet = new CSSStyleSheet();
|
|
109
|
-
sheet.replaceSync(x);
|
|
110
|
-
styleSheetCache.set(x, sheet);
|
|
111
|
-
}
|
|
112
|
-
return sheet;
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
addStylesTo(target) {
|
|
116
|
-
target.adoptedStyleSheets = [...target.adoptedStyleSheets, ...this.sheets];
|
|
117
|
-
}
|
|
118
|
-
removeStylesFrom(target) {
|
|
119
|
-
const sheets = this.sheets;
|
|
120
|
-
target.adoptedStyleSheets = target.adoptedStyleSheets.filter((x) => sheets.indexOf(x) === -1);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
ElementStyles.setDefaultStrategy(FAST.getById(5 /* KernelServiceId.styleSheetStrategy */, () => AdoptedStyleSheetsStrategy));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isString } from "../interfaces.js";
|
|
1
|
+
import { isString, noop } from "../interfaces.js";
|
|
2
2
|
import { HTMLDirective } from "./html-directive.js";
|
|
3
3
|
import { NodeObservationDirective } from "./node-observation.js";
|
|
4
4
|
/**
|
|
@@ -12,7 +12,7 @@ export class ChildrenDirective extends NodeObservationDirective {
|
|
|
12
12
|
*/
|
|
13
13
|
constructor(options) {
|
|
14
14
|
super(options);
|
|
15
|
-
this.observerProperty =
|
|
15
|
+
this.observerProperty = Symbol();
|
|
16
16
|
this.handleEvent = (mutations, observer) => {
|
|
17
17
|
const target = observer.target;
|
|
18
18
|
this.updateTarget(this.getSource(target), this.computeNodes(target));
|
|
@@ -24,8 +24,12 @@ export class ChildrenDirective extends NodeObservationDirective {
|
|
|
24
24
|
* @param target - The target to observe.
|
|
25
25
|
*/
|
|
26
26
|
observe(target) {
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
let observer = target[this.observerProperty];
|
|
28
|
+
if (!observer) {
|
|
29
|
+
observer = new MutationObserver(this.handleEvent);
|
|
30
|
+
observer.toJSON = noop;
|
|
31
|
+
target[this.observerProperty] = observer;
|
|
32
|
+
}
|
|
29
33
|
observer.target = target;
|
|
30
34
|
observer.observe(target, this.options);
|
|
31
35
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { isFunction, isString } from "../interfaces.js";
|
|
2
2
|
import { FAST } from "../platform.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { DOM } from "../dom.js";
|
|
4
|
+
import { oneTime } from "../binding/one-time.js";
|
|
5
|
+
import { oneWay } from "../binding/one-way.js";
|
|
6
|
+
import { nextId, Parser } from "./markup.js";
|
|
7
|
+
import { HTMLBindingDirective } from "./html-binding-directive.js";
|
|
8
|
+
import { HTMLDirective, } from "./html-directive.js";
|
|
6
9
|
import { HTMLView } from "./view.js";
|
|
7
10
|
const targetIdFrom = (parentId, nodeIndex) => `${parentId}.${nodeIndex}`;
|
|
8
11
|
const descriptorCache = {};
|
|
@@ -28,20 +31,25 @@ const warningHost = new Proxy(document.createElement("div"), {
|
|
|
28
31
|
},
|
|
29
32
|
});
|
|
30
33
|
class CompilationContext {
|
|
31
|
-
constructor(fragment, directives) {
|
|
34
|
+
constructor(fragment, directives, policy) {
|
|
32
35
|
this.fragment = fragment;
|
|
33
36
|
this.directives = directives;
|
|
37
|
+
this.policy = policy;
|
|
34
38
|
this.proto = null;
|
|
35
39
|
this.nodeIds = new Set();
|
|
36
40
|
this.descriptors = {};
|
|
37
41
|
this.factories = [];
|
|
38
42
|
}
|
|
39
|
-
addFactory(factory, parentId, nodeId, targetIndex) {
|
|
43
|
+
addFactory(factory, parentId, nodeId, targetIndex, tagName) {
|
|
44
|
+
var _a, _b;
|
|
40
45
|
if (!this.nodeIds.has(nodeId)) {
|
|
41
46
|
this.nodeIds.add(nodeId);
|
|
42
47
|
this.addTargetDescriptor(parentId, nodeId, targetIndex);
|
|
43
48
|
}
|
|
44
|
-
factory.
|
|
49
|
+
factory.id = (_a = factory.id) !== null && _a !== void 0 ? _a : nextId();
|
|
50
|
+
factory.targetNodeId = nodeId;
|
|
51
|
+
factory.targetTagName = tagName;
|
|
52
|
+
factory.policy = (_b = factory.policy) !== null && _b !== void 0 ? _b : this.policy;
|
|
45
53
|
this.factories.push(factory);
|
|
46
54
|
}
|
|
47
55
|
freeze() {
|
|
@@ -94,19 +102,19 @@ function compileAttributes(context, parentId, node, nodeId, nodeIndex, includeBa
|
|
|
94
102
|
let result = null;
|
|
95
103
|
if (parseResult === null) {
|
|
96
104
|
if (includeBasicValues) {
|
|
97
|
-
result = new HTMLBindingDirective(oneTime(() => attrValue));
|
|
98
|
-
|
|
105
|
+
result = new HTMLBindingDirective(oneTime(() => attrValue, context.policy));
|
|
106
|
+
HTMLDirective.assignAspect(result, attr.name);
|
|
99
107
|
}
|
|
100
108
|
}
|
|
101
109
|
else {
|
|
102
110
|
/* eslint-disable-next-line @typescript-eslint/no-use-before-define */
|
|
103
|
-
result = Compiler.aggregate(parseResult);
|
|
111
|
+
result = Compiler.aggregate(parseResult, context.policy);
|
|
104
112
|
}
|
|
105
113
|
if (result !== null) {
|
|
106
114
|
node.removeAttributeNode(attr);
|
|
107
115
|
i--;
|
|
108
116
|
ii--;
|
|
109
|
-
context.addFactory(result, parentId, nodeId, nodeIndex);
|
|
117
|
+
context.addFactory(result, parentId, nodeId, nodeIndex, node.tagName);
|
|
110
118
|
}
|
|
111
119
|
}
|
|
112
120
|
}
|
|
@@ -131,8 +139,8 @@ function compileContent(context, node, parentId, nodeId, nodeIndex) {
|
|
|
131
139
|
}
|
|
132
140
|
else {
|
|
133
141
|
currentNode.textContent = " ";
|
|
134
|
-
|
|
135
|
-
context.addFactory(currentPart, parentId, nodeId, nodeIndex);
|
|
142
|
+
HTMLDirective.assignAspect(currentPart);
|
|
143
|
+
context.addFactory(currentPart, parentId, nodeId, nodeIndex, null);
|
|
136
144
|
}
|
|
137
145
|
lastNode = currentNode;
|
|
138
146
|
}
|
|
@@ -164,7 +172,7 @@ function compileNode(context, parentId, node, nodeIndex) {
|
|
|
164
172
|
if (parts !== null) {
|
|
165
173
|
context.addFactory(
|
|
166
174
|
/* eslint-disable-next-line @typescript-eslint/no-use-before-define */
|
|
167
|
-
Compiler.aggregate(parts), parentId, nodeId, nodeIndex);
|
|
175
|
+
Compiler.aggregate(parts), parentId, nodeId, nodeIndex, null);
|
|
168
176
|
}
|
|
169
177
|
break;
|
|
170
178
|
}
|
|
@@ -178,45 +186,28 @@ function isMarker(node, directives) {
|
|
|
178
186
|
Parser.parse(node.data, directives) !== null);
|
|
179
187
|
}
|
|
180
188
|
const templateTag = "TEMPLATE";
|
|
181
|
-
const policyOptions = { createHTML: html => html };
|
|
182
|
-
let htmlPolicy = globalThis.trustedTypes
|
|
183
|
-
? globalThis.trustedTypes.createPolicy("fast-html", policyOptions)
|
|
184
|
-
: policyOptions;
|
|
185
|
-
const fastHTMLPolicy = htmlPolicy;
|
|
186
189
|
/**
|
|
187
190
|
* Common APIs related to compilation.
|
|
188
191
|
* @public
|
|
189
192
|
*/
|
|
190
193
|
export const Compiler = {
|
|
191
|
-
/**
|
|
192
|
-
* Sets the HTML trusted types policy used by the compiler.
|
|
193
|
-
* @param policy - The policy to set for HTML.
|
|
194
|
-
* @remarks
|
|
195
|
-
* This API can only be called once, for security reasons. It should be
|
|
196
|
-
* called by the application developer at the start of their program.
|
|
197
|
-
*/
|
|
198
|
-
setHTMLPolicy(policy) {
|
|
199
|
-
if (htmlPolicy !== fastHTMLPolicy) {
|
|
200
|
-
throw FAST.error(1201 /* Message.onlySetHTMLPolicyOnce */);
|
|
201
|
-
}
|
|
202
|
-
htmlPolicy = policy;
|
|
203
|
-
},
|
|
204
194
|
/**
|
|
205
195
|
* Compiles a template and associated directives into a compilation
|
|
206
196
|
* result which can be used to create views.
|
|
207
197
|
* @param html - The html string or template element to compile.
|
|
208
|
-
* @param
|
|
198
|
+
* @param factories - The behavior factories referenced by the template.
|
|
199
|
+
* @param policy - The security policy to compile the html with.
|
|
209
200
|
* @remarks
|
|
210
201
|
* The template that is provided for compilation is altered in-place
|
|
211
202
|
* and cannot be compiled again. If the original template must be preserved,
|
|
212
203
|
* it is recommended that you clone the original and pass the clone to this API.
|
|
213
204
|
* @public
|
|
214
205
|
*/
|
|
215
|
-
compile(html,
|
|
206
|
+
compile(html, factories, policy = DOM.policy) {
|
|
216
207
|
let template;
|
|
217
208
|
if (isString(html)) {
|
|
218
209
|
template = document.createElement(templateTag);
|
|
219
|
-
template.innerHTML =
|
|
210
|
+
template.innerHTML = policy.createHTML(html);
|
|
220
211
|
const fec = template.content.firstElementChild;
|
|
221
212
|
if (fec !== null && fec.tagName === templateTag) {
|
|
222
213
|
template = fec;
|
|
@@ -225,20 +216,23 @@ export const Compiler = {
|
|
|
225
216
|
else {
|
|
226
217
|
template = html;
|
|
227
218
|
}
|
|
219
|
+
if (!template.content.firstChild && !template.content.lastChild) {
|
|
220
|
+
template.content.appendChild(document.createComment(""));
|
|
221
|
+
}
|
|
228
222
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1111864
|
|
229
223
|
const fragment = document.adoptNode(template.content);
|
|
230
|
-
const context = new CompilationContext(fragment,
|
|
224
|
+
const context = new CompilationContext(fragment, factories, policy);
|
|
231
225
|
compileAttributes(context, "", template, /* host */ "h", 0, true);
|
|
232
226
|
if (
|
|
233
227
|
// If the first node in a fragment is a marker, that means it's an unstable first node,
|
|
234
228
|
// because something like a when, repeat, etc. could add nodes before the marker.
|
|
235
229
|
// To mitigate this, we insert a stable first node. However, if we insert a node,
|
|
236
230
|
// that will alter the result of the TreeWalker. So, we also need to offset the target index.
|
|
237
|
-
isMarker(fragment.firstChild,
|
|
231
|
+
isMarker(fragment.firstChild, factories) ||
|
|
238
232
|
// Or if there is only one node and a directive, it means the template's content
|
|
239
233
|
// is *only* the directive. In that case, HTMLView.dispose() misses any nodes inserted by
|
|
240
234
|
// the directive. Inserting a new node ensures proper disposal of nodes added by the directive.
|
|
241
|
-
(fragment.childNodes.length === 1 && Object.keys(
|
|
235
|
+
(fragment.childNodes.length === 1 && Object.keys(factories).length > 0)) {
|
|
242
236
|
fragment.insertBefore(document.createComment(""), fragment.firstChild);
|
|
243
237
|
}
|
|
244
238
|
compileChildren(context, fragment, /* root */ "r");
|
|
@@ -257,23 +251,24 @@ export const Compiler = {
|
|
|
257
251
|
* Aggregates an array of strings and directives into a single directive.
|
|
258
252
|
* @param parts - A heterogeneous array of static strings interspersed with
|
|
259
253
|
* directives.
|
|
254
|
+
* @param policy - The security policy to use with the aggregated bindings.
|
|
260
255
|
* @returns A single inline directive that aggregates the behavior of all the parts.
|
|
261
256
|
*/
|
|
262
|
-
aggregate(parts) {
|
|
257
|
+
aggregate(parts, policy = DOM.policy) {
|
|
263
258
|
if (parts.length === 1) {
|
|
264
259
|
return parts[0];
|
|
265
260
|
}
|
|
266
261
|
let sourceAspect;
|
|
267
|
-
let binding;
|
|
268
262
|
let isVolatile = false;
|
|
263
|
+
let bindingPolicy = void 0;
|
|
269
264
|
const partCount = parts.length;
|
|
270
265
|
const finalParts = parts.map((x) => {
|
|
271
266
|
if (isString(x)) {
|
|
272
267
|
return () => x;
|
|
273
268
|
}
|
|
274
269
|
sourceAspect = x.sourceAspect || sourceAspect;
|
|
275
|
-
binding = x.dataBinding || binding;
|
|
276
270
|
isVolatile = isVolatile || x.dataBinding.isVolatile;
|
|
271
|
+
bindingPolicy = bindingPolicy || x.dataBinding.policy;
|
|
277
272
|
return x.dataBinding.evaluate;
|
|
278
273
|
});
|
|
279
274
|
const expression = (scope, context) => {
|
|
@@ -283,10 +278,8 @@ export const Compiler = {
|
|
|
283
278
|
}
|
|
284
279
|
return output;
|
|
285
280
|
};
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const directive = new HTMLBindingDirective(binding);
|
|
289
|
-
Aspect.assign(directive, sourceAspect);
|
|
281
|
+
const directive = new HTMLBindingDirective(oneWay(expression, bindingPolicy !== null && bindingPolicy !== void 0 ? bindingPolicy : policy, isVolatile));
|
|
282
|
+
HTMLDirective.assignAspect(directive, sourceAspect);
|
|
290
283
|
return directive;
|
|
291
284
|
},
|
|
292
285
|
};
|