@microsoft/fast-element 2.0.0-beta.9 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +1 -1
- package/CHANGELOG.json +518 -0
- package/CHANGELOG.md +181 -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 +7 -1
- 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} +21 -41
- 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 +146 -29
- 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 +19 -6
- 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 +254 -34
- 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 +9789 -5667
- package/dist/fast-element.d.ts +813 -2392
- package/dist/fast-element.debug.js +2788 -974
- package/dist/fast-element.debug.min.js +3 -1
- package/dist/fast-element.js +2641 -833
- package/dist/fast-element.min.js +3 -1
- package/dist/fast-element.untrimmed.d.ts +662 -314
- package/docs/{api-report.md → api-report.api.md} +238 -151
- 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/context.js
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
import "./interfaces.js";
|
|
2
2
|
import { Metadata } from "./metadata.js";
|
|
3
3
|
import { FAST } from "./platform.js";
|
|
4
|
+
const contextsByName = new Map();
|
|
4
5
|
const contextEventType = "context-request";
|
|
5
6
|
let requestStrategy;
|
|
6
7
|
/**
|
|
7
|
-
* Enables using
|
|
8
|
-
* @
|
|
8
|
+
* Enables using:
|
|
9
|
+
* {@link https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md | W3C Community Context protocol.}
|
|
10
|
+
* @public
|
|
9
11
|
*/
|
|
10
12
|
export const Context = Object.freeze({
|
|
11
13
|
/**
|
|
12
14
|
* The event type used for W3C Context Protocol requests.
|
|
13
15
|
*/
|
|
14
16
|
eventType: contextEventType,
|
|
17
|
+
/**
|
|
18
|
+
* Returns a FASTContext object from the global context registry matching the given name if found.
|
|
19
|
+
* Otherwise, returns a new FASTContext with this name.
|
|
20
|
+
* @param name - The name of the FASTContext to get or create.
|
|
21
|
+
* @returns A FASTContext object.
|
|
22
|
+
*/
|
|
23
|
+
for(name) {
|
|
24
|
+
let c = contextsByName.get(name);
|
|
25
|
+
if (c === void 0) {
|
|
26
|
+
c = Context.create(name);
|
|
27
|
+
contextsByName.set(name, c);
|
|
28
|
+
}
|
|
29
|
+
return c;
|
|
30
|
+
},
|
|
15
31
|
/**
|
|
16
32
|
* Creates a W3C Community Protocol-based Context object to use in requesting/providing
|
|
17
33
|
* context through the DOM.
|
|
@@ -94,8 +110,14 @@ export const Context = Object.freeze({
|
|
|
94
110
|
dispatch(target, context, callback, multiple = false) {
|
|
95
111
|
target.dispatchEvent(new ContextEvent(context, callback, multiple));
|
|
96
112
|
},
|
|
113
|
+
/**
|
|
114
|
+
* Enables an event target to provide a context value.
|
|
115
|
+
* @param target The target to provide the context value for.
|
|
116
|
+
* @param context The context to provide the value for.
|
|
117
|
+
* @param value The value to provide for the context.
|
|
118
|
+
*/
|
|
97
119
|
provide(target, context, value) {
|
|
98
|
-
|
|
120
|
+
Context.handle(target, (event) => {
|
|
99
121
|
event.stopImmediatePropagation();
|
|
100
122
|
event.callback(value);
|
|
101
123
|
}, context);
|
|
@@ -132,7 +154,7 @@ export const Context = Object.freeze({
|
|
|
132
154
|
* initialValue if the context isn't handled.
|
|
133
155
|
*/
|
|
134
156
|
defineProperty(target, propertyName, context) {
|
|
135
|
-
const field =
|
|
157
|
+
const field = Symbol.for(`fast:di:${propertyName}`);
|
|
136
158
|
Reflect.defineProperty(target, propertyName, {
|
|
137
159
|
get: function () {
|
|
138
160
|
var _a;
|
package/dist/esm/debug.js
CHANGED
|
@@ -9,18 +9,24 @@ if (globalThis.FAST === void 0) {
|
|
|
9
9
|
const FAST = globalThis.FAST;
|
|
10
10
|
const debugMessages = {
|
|
11
11
|
[1101 /* needsArrayObservation */]: "Must call enableArrayObservation before observing arrays.",
|
|
12
|
-
[1201 /*
|
|
12
|
+
[1201 /* onlySetDOMPolicyOnce */]: "The DOM Policy can only be set once.",
|
|
13
13
|
[1202 /* bindingInnerHTMLRequiresTrustedTypes */]: "To bind innerHTML, you must use a TrustedTypesPolicy.",
|
|
14
14
|
[1203 /* twoWayBindingRequiresObservables */]: "View=>Model update skipped. To use twoWay binding, the target property must be observable.",
|
|
15
15
|
[1204 /* hostBindingWithoutHost */]: "No host element is present. Cannot bind host with ${name}.",
|
|
16
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.",
|
|
17
21
|
[1401 /* missingElementDefinition */]: "Missing FASTElement definition.",
|
|
18
22
|
[1501 /* noRegistrationForContext */]: "No registration for Context/Interface '${name}'.",
|
|
19
23
|
[1502 /* noFactoryForResolver */]: "Dependency injection resolver for '${key}' returned a null factory.",
|
|
20
24
|
[1503 /* invalidResolverStrategy */]: "Invalid dependency injection resolver strategy specified '${strategy}'.",
|
|
21
25
|
[1504 /* cannotAutoregisterDependency */]: "Unable to autoregister dependency.",
|
|
22
26
|
[1505 /* cannotResolveKey */]: "Unable to resolve dependency injection key '${key}'.",
|
|
23
|
-
[1506 /* cannotConstructNativeFunction */]:
|
|
27
|
+
[1506 /* cannotConstructNativeFunction */]:
|
|
28
|
+
/* eslint-disable-next-line max-len */
|
|
29
|
+
"'${name}' is a native function and therefore cannot be safely constructed by DI. If this is intentional, please use a callback or cachedCallback resolver.",
|
|
24
30
|
[1507 /* cannotJITRegisterNonConstructor */]: "Attempted to jitRegister something that is not a constructor '${value}'. Did you forget to register this dependency?",
|
|
25
31
|
[1508 /* cannotJITRegisterIntrinsic */]: "Attempted to jitRegister an intrinsic type '${value}'. Did you forget to add @inject(Key)?",
|
|
26
32
|
[1509 /* cannotJITRegisterInterface */]: "Attempted to jitRegister an interface '${value}'.",
|
package/dist/esm/di/di.js
CHANGED
|
@@ -292,7 +292,8 @@ export const DI = Object.freeze({
|
|
|
292
292
|
* @returns An array of dependency keys.
|
|
293
293
|
*/
|
|
294
294
|
getDependencies(Type) {
|
|
295
|
-
// Note: Every detail of this getDependencies method is pretty deliberate at the moment,
|
|
295
|
+
// Note: Every detail of this getDependencies method is pretty deliberate at the moment,
|
|
296
|
+
// and probably not yet 100% tested from every possible angle,
|
|
296
297
|
// so be careful with making changes here as it can have a huge impact on complex end user apps.
|
|
297
298
|
// Preferably, only make changes to the dependency resolution process via a RFC.
|
|
298
299
|
let dependencies = dependencyLookup.get(Type);
|
|
@@ -371,16 +372,16 @@ export const DI = Object.freeze({
|
|
|
371
372
|
* The respectConnection option is only applicable to elements that descend from FASTElement.
|
|
372
373
|
*/
|
|
373
374
|
defineProperty(target, propertyName, key, respectConnection = false) {
|
|
374
|
-
const
|
|
375
|
+
const field = Symbol.for(`fast:di:${propertyName}`);
|
|
375
376
|
Reflect.defineProperty(target, propertyName, {
|
|
376
377
|
get: function () {
|
|
377
|
-
let value = this[
|
|
378
|
+
let value = this[field];
|
|
378
379
|
if (value === void 0) {
|
|
379
380
|
const container = this instanceof Node
|
|
380
381
|
? DI.findResponsibleContainer(this)
|
|
381
382
|
: DI.getOrCreateDOMContainer();
|
|
382
383
|
value = container.get(key);
|
|
383
|
-
this[
|
|
384
|
+
this[field] = value;
|
|
384
385
|
if (respectConnection) {
|
|
385
386
|
const notifier = this.$fastController;
|
|
386
387
|
if (!notifier) {
|
|
@@ -389,9 +390,9 @@ export const DI = Object.freeze({
|
|
|
389
390
|
const handleChange = () => {
|
|
390
391
|
const newContainer = DI.findResponsibleContainer(this);
|
|
391
392
|
const newValue = newContainer.get(key);
|
|
392
|
-
const oldValue = this[
|
|
393
|
+
const oldValue = this[field];
|
|
393
394
|
if (newValue !== oldValue) {
|
|
394
|
-
this[
|
|
395
|
+
this[field] = value;
|
|
395
396
|
notifier.notify(propertyName);
|
|
396
397
|
}
|
|
397
398
|
};
|
|
@@ -414,11 +415,6 @@ export const DI = Object.freeze({
|
|
|
414
415
|
* in addition to its standard use in an inject array or through direct container APIs.
|
|
415
416
|
*/
|
|
416
417
|
createContext,
|
|
417
|
-
/**
|
|
418
|
-
* @deprecated
|
|
419
|
-
* Use DI.createContext instead.
|
|
420
|
-
*/
|
|
421
|
-
createInterface: createContext,
|
|
422
418
|
/**
|
|
423
419
|
* A decorator that specifies what to inject into its target.
|
|
424
420
|
* @param dependencies - The dependencies to inject.
|
|
@@ -1384,7 +1380,8 @@ const isNativeFunction = (function () {
|
|
|
1384
1380
|
i <= 100 &&
|
|
1385
1381
|
// This whole heuristic *could* be tricked by a comment. Do we need to care about that?
|
|
1386
1382
|
sourceText.charCodeAt(i - 1) === 0x7d && // }
|
|
1387
|
-
// TODO: the spec is a little vague about the precise constraints,
|
|
1383
|
+
// TODO: the spec is a little vague about the precise constraints,
|
|
1384
|
+
// so we do need to test this across various browsers to make sure just one whitespace is a safe assumption.
|
|
1388
1385
|
sourceText.charCodeAt(i - 2) <= 0x20 && // whitespace
|
|
1389
1386
|
sourceText.charCodeAt(i - 3) === 0x5d && // ]
|
|
1390
1387
|
sourceText.charCodeAt(i - 4) === 0x65 && // e
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { DOMAspect } from "./dom.js";
|
|
2
|
+
import { isString } from "./interfaces.js";
|
|
3
|
+
import { FAST } from "./platform.js";
|
|
4
|
+
function safeURL(tagName, aspect, aspectName, sink) {
|
|
5
|
+
return (target, name, value, ...rest) => {
|
|
6
|
+
if (isString(value)) {
|
|
7
|
+
value = value.replace(/(javascript:|vbscript:|data:)/, "");
|
|
8
|
+
}
|
|
9
|
+
sink(target, name, value, ...rest);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function block(tagName, aspect, aspectName, sink) {
|
|
13
|
+
throw FAST.error(1209 /* Message.blockedByDOMPolicy */, {
|
|
14
|
+
aspectName,
|
|
15
|
+
tagName: tagName !== null && tagName !== void 0 ? tagName : "text",
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const defaultDOMElementGuards = {
|
|
19
|
+
a: {
|
|
20
|
+
[DOMAspect.attribute]: {
|
|
21
|
+
href: safeURL,
|
|
22
|
+
},
|
|
23
|
+
[DOMAspect.property]: {
|
|
24
|
+
href: safeURL,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
area: {
|
|
28
|
+
[DOMAspect.attribute]: {
|
|
29
|
+
href: safeURL,
|
|
30
|
+
},
|
|
31
|
+
[DOMAspect.property]: {
|
|
32
|
+
href: safeURL,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
button: {
|
|
36
|
+
[DOMAspect.attribute]: {
|
|
37
|
+
formaction: safeURL,
|
|
38
|
+
},
|
|
39
|
+
[DOMAspect.property]: {
|
|
40
|
+
formAction: safeURL,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
embed: {
|
|
44
|
+
[DOMAspect.attribute]: {
|
|
45
|
+
src: block,
|
|
46
|
+
},
|
|
47
|
+
[DOMAspect.property]: {
|
|
48
|
+
src: block,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
form: {
|
|
52
|
+
[DOMAspect.attribute]: {
|
|
53
|
+
action: safeURL,
|
|
54
|
+
},
|
|
55
|
+
[DOMAspect.property]: {
|
|
56
|
+
action: safeURL,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
frame: {
|
|
60
|
+
[DOMAspect.attribute]: {
|
|
61
|
+
src: safeURL,
|
|
62
|
+
},
|
|
63
|
+
[DOMAspect.property]: {
|
|
64
|
+
src: safeURL,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
iframe: {
|
|
68
|
+
[DOMAspect.attribute]: {
|
|
69
|
+
src: safeURL,
|
|
70
|
+
},
|
|
71
|
+
[DOMAspect.property]: {
|
|
72
|
+
src: safeURL,
|
|
73
|
+
srcdoc: block,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
input: {
|
|
77
|
+
[DOMAspect.attribute]: {
|
|
78
|
+
formaction: safeURL,
|
|
79
|
+
},
|
|
80
|
+
[DOMAspect.property]: {
|
|
81
|
+
formAction: safeURL,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
link: {
|
|
85
|
+
[DOMAspect.attribute]: {
|
|
86
|
+
href: block,
|
|
87
|
+
},
|
|
88
|
+
[DOMAspect.property]: {
|
|
89
|
+
href: block,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
object: {
|
|
93
|
+
[DOMAspect.attribute]: {
|
|
94
|
+
codebase: block,
|
|
95
|
+
data: block,
|
|
96
|
+
},
|
|
97
|
+
[DOMAspect.property]: {
|
|
98
|
+
codeBase: block,
|
|
99
|
+
data: block,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
script: {
|
|
103
|
+
[DOMAspect.attribute]: {
|
|
104
|
+
src: block,
|
|
105
|
+
text: block,
|
|
106
|
+
},
|
|
107
|
+
[DOMAspect.property]: {
|
|
108
|
+
src: block,
|
|
109
|
+
text: block,
|
|
110
|
+
innerText: block,
|
|
111
|
+
textContent: block,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
style: {
|
|
115
|
+
[DOMAspect.property]: {
|
|
116
|
+
innerText: block,
|
|
117
|
+
textContent: block,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
const blockedEvents = {
|
|
122
|
+
onabort: block,
|
|
123
|
+
onauxclick: block,
|
|
124
|
+
onbeforeinput: block,
|
|
125
|
+
onbeforematch: block,
|
|
126
|
+
onblur: block,
|
|
127
|
+
oncancel: block,
|
|
128
|
+
oncanplay: block,
|
|
129
|
+
oncanplaythrough: block,
|
|
130
|
+
onchange: block,
|
|
131
|
+
onclick: block,
|
|
132
|
+
onclose: block,
|
|
133
|
+
oncontextlost: block,
|
|
134
|
+
oncontextmenu: block,
|
|
135
|
+
oncontextrestored: block,
|
|
136
|
+
oncopy: block,
|
|
137
|
+
oncuechange: block,
|
|
138
|
+
oncut: block,
|
|
139
|
+
ondblclick: block,
|
|
140
|
+
ondrag: block,
|
|
141
|
+
ondragend: block,
|
|
142
|
+
ondragenter: block,
|
|
143
|
+
ondragleave: block,
|
|
144
|
+
ondragover: block,
|
|
145
|
+
ondragstart: block,
|
|
146
|
+
ondrop: block,
|
|
147
|
+
ondurationchange: block,
|
|
148
|
+
onemptied: block,
|
|
149
|
+
onended: block,
|
|
150
|
+
onerror: block,
|
|
151
|
+
onfocus: block,
|
|
152
|
+
onformdata: block,
|
|
153
|
+
oninput: block,
|
|
154
|
+
oninvalid: block,
|
|
155
|
+
onkeydown: block,
|
|
156
|
+
onkeypress: block,
|
|
157
|
+
onkeyup: block,
|
|
158
|
+
onload: block,
|
|
159
|
+
onloadeddata: block,
|
|
160
|
+
onloadedmetadata: block,
|
|
161
|
+
onloadstart: block,
|
|
162
|
+
onmousedown: block,
|
|
163
|
+
onmouseenter: block,
|
|
164
|
+
onmouseleave: block,
|
|
165
|
+
onmousemove: block,
|
|
166
|
+
onmouseout: block,
|
|
167
|
+
onmouseover: block,
|
|
168
|
+
onmouseup: block,
|
|
169
|
+
onpaste: block,
|
|
170
|
+
onpause: block,
|
|
171
|
+
onplay: block,
|
|
172
|
+
onplaying: block,
|
|
173
|
+
onprogress: block,
|
|
174
|
+
onratechange: block,
|
|
175
|
+
onreset: block,
|
|
176
|
+
onresize: block,
|
|
177
|
+
onscroll: block,
|
|
178
|
+
onsecuritypolicyviolation: block,
|
|
179
|
+
onseeked: block,
|
|
180
|
+
onseeking: block,
|
|
181
|
+
onselect: block,
|
|
182
|
+
onslotchange: block,
|
|
183
|
+
onstalled: block,
|
|
184
|
+
onsubmit: block,
|
|
185
|
+
onsuspend: block,
|
|
186
|
+
ontimeupdate: block,
|
|
187
|
+
ontoggle: block,
|
|
188
|
+
onvolumechange: block,
|
|
189
|
+
onwaiting: block,
|
|
190
|
+
onwebkitanimationend: block,
|
|
191
|
+
onwebkitanimationiteration: block,
|
|
192
|
+
onwebkitanimationstart: block,
|
|
193
|
+
onwebkittransitionend: block,
|
|
194
|
+
onwheel: block,
|
|
195
|
+
};
|
|
196
|
+
const defaultDOMGuards = {
|
|
197
|
+
elements: defaultDOMElementGuards,
|
|
198
|
+
aspects: {
|
|
199
|
+
[DOMAspect.attribute]: Object.assign({}, blockedEvents),
|
|
200
|
+
[DOMAspect.property]: Object.assign({ innerHTML: block }, blockedEvents),
|
|
201
|
+
[DOMAspect.event]: Object.assign({}, blockedEvents),
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
function createDomSinkGuards(config, defaults) {
|
|
205
|
+
const result = {};
|
|
206
|
+
for (const name in defaults) {
|
|
207
|
+
const overrideValue = config[name];
|
|
208
|
+
const defaultValue = defaults[name];
|
|
209
|
+
switch (overrideValue) {
|
|
210
|
+
case null:
|
|
211
|
+
// remove the default
|
|
212
|
+
break;
|
|
213
|
+
case undefined:
|
|
214
|
+
// keep the default
|
|
215
|
+
result[name] = defaultValue;
|
|
216
|
+
break;
|
|
217
|
+
default:
|
|
218
|
+
// override the default
|
|
219
|
+
result[name] = overrideValue;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// add any new sinks that were not overrides
|
|
224
|
+
for (const name in config) {
|
|
225
|
+
if (!(name in result)) {
|
|
226
|
+
result[name] = config[name];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return Object.freeze(result);
|
|
230
|
+
}
|
|
231
|
+
function createDOMAspectGuards(config, defaults) {
|
|
232
|
+
const result = {};
|
|
233
|
+
for (const aspect in defaults) {
|
|
234
|
+
const overrideValue = config[aspect];
|
|
235
|
+
const defaultValue = defaults[aspect];
|
|
236
|
+
switch (overrideValue) {
|
|
237
|
+
case null:
|
|
238
|
+
// remove the default
|
|
239
|
+
break;
|
|
240
|
+
case undefined:
|
|
241
|
+
// keep the default
|
|
242
|
+
result[aspect] = createDomSinkGuards(defaultValue, {});
|
|
243
|
+
break;
|
|
244
|
+
default:
|
|
245
|
+
// override the default
|
|
246
|
+
result[aspect] = createDomSinkGuards(overrideValue, defaultValue);
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// add any new aspect guards that were not overrides
|
|
251
|
+
for (const aspect in config) {
|
|
252
|
+
if (!(aspect in result)) {
|
|
253
|
+
result[aspect] = createDomSinkGuards(config[aspect], {});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return Object.freeze(result);
|
|
257
|
+
}
|
|
258
|
+
function createElementGuards(config, defaults) {
|
|
259
|
+
const result = {};
|
|
260
|
+
for (const tag in defaults) {
|
|
261
|
+
const overrideValue = config[tag];
|
|
262
|
+
const defaultValue = defaults[tag];
|
|
263
|
+
switch (overrideValue) {
|
|
264
|
+
case null:
|
|
265
|
+
// remove the default
|
|
266
|
+
break;
|
|
267
|
+
case undefined:
|
|
268
|
+
// keep the default
|
|
269
|
+
result[tag] = createDOMAspectGuards(overrideValue, {});
|
|
270
|
+
break;
|
|
271
|
+
default:
|
|
272
|
+
// override the default aspects
|
|
273
|
+
result[tag] = createDOMAspectGuards(overrideValue, defaultValue);
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// Add any new element guards that were not overrides
|
|
278
|
+
for (const tag in config) {
|
|
279
|
+
if (!(tag in result)) {
|
|
280
|
+
result[tag] = createDOMAspectGuards(config[tag], {});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return Object.freeze(result);
|
|
284
|
+
}
|
|
285
|
+
function createDOMGuards(config, defaults) {
|
|
286
|
+
return Object.freeze({
|
|
287
|
+
elements: config.elements
|
|
288
|
+
? createElementGuards(config.elements, defaults.elements)
|
|
289
|
+
: defaults.elements,
|
|
290
|
+
aspects: config.aspects
|
|
291
|
+
? createDOMAspectGuards(config.aspects, defaults.aspects)
|
|
292
|
+
: defaults.aspects,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
function createTrustedType() {
|
|
296
|
+
const createHTML = html => html;
|
|
297
|
+
return globalThis.trustedTypes
|
|
298
|
+
? globalThis.trustedTypes.createPolicy("fast-html", { createHTML })
|
|
299
|
+
: { createHTML };
|
|
300
|
+
}
|
|
301
|
+
function tryGuard(aspectGuards, tagName, aspect, aspectName, sink) {
|
|
302
|
+
const sinkGuards = aspectGuards[aspect];
|
|
303
|
+
if (sinkGuards) {
|
|
304
|
+
const guard = sinkGuards[aspectName];
|
|
305
|
+
if (guard) {
|
|
306
|
+
return guard(tagName, aspect, aspectName, sink);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* A helper for creating DOM policies.
|
|
312
|
+
* @public
|
|
313
|
+
*/
|
|
314
|
+
const DOMPolicy = Object.freeze({
|
|
315
|
+
/**
|
|
316
|
+
* Creates a new DOM Policy object.
|
|
317
|
+
* @param options The options to use in creating the policy.
|
|
318
|
+
* @returns The newly created DOMPolicy.
|
|
319
|
+
*/
|
|
320
|
+
create(options = {}) {
|
|
321
|
+
var _a, _b;
|
|
322
|
+
const trustedType = (_a = options.trustedType) !== null && _a !== void 0 ? _a : createTrustedType();
|
|
323
|
+
const guards = createDOMGuards((_b = options.guards) !== null && _b !== void 0 ? _b : {}, defaultDOMGuards);
|
|
324
|
+
return Object.freeze({
|
|
325
|
+
createHTML(value) {
|
|
326
|
+
return trustedType.createHTML(value);
|
|
327
|
+
},
|
|
328
|
+
protect(tagName, aspect, aspectName, sink) {
|
|
329
|
+
var _a;
|
|
330
|
+
// Check for element-specific guards.
|
|
331
|
+
const key = (tagName !== null && tagName !== void 0 ? tagName : "").toLowerCase();
|
|
332
|
+
const elementGuards = guards.elements[key];
|
|
333
|
+
if (elementGuards) {
|
|
334
|
+
const guard = tryGuard(elementGuards, tagName, aspect, aspectName, sink);
|
|
335
|
+
if (guard) {
|
|
336
|
+
return guard;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// Check for guards applicable to all nodes.
|
|
340
|
+
return ((_a = tryGuard(guards.aspects, tagName, aspect, aspectName, sink)) !== null && _a !== void 0 ? _a : sink);
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
export { DOMPolicy };
|
package/dist/esm/dom.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import "./interfaces.js";
|
|
2
|
+
import { FAST } from "./platform.js";
|
|
3
|
+
/**
|
|
4
|
+
* The type of HTML aspect to target.
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export const DOMAspect = Object.freeze({
|
|
8
|
+
/**
|
|
9
|
+
* Not aspected.
|
|
10
|
+
*/
|
|
11
|
+
none: 0,
|
|
12
|
+
/**
|
|
13
|
+
* An attribute.
|
|
14
|
+
*/
|
|
15
|
+
attribute: 1,
|
|
16
|
+
/**
|
|
17
|
+
* A boolean attribute.
|
|
18
|
+
*/
|
|
19
|
+
booleanAttribute: 2,
|
|
20
|
+
/**
|
|
21
|
+
* A property.
|
|
22
|
+
*/
|
|
23
|
+
property: 3,
|
|
24
|
+
/**
|
|
25
|
+
* Content
|
|
26
|
+
*/
|
|
27
|
+
content: 4,
|
|
28
|
+
/**
|
|
29
|
+
* A token list.
|
|
30
|
+
*/
|
|
31
|
+
tokenList: 5,
|
|
32
|
+
/**
|
|
33
|
+
* An event.
|
|
34
|
+
*/
|
|
35
|
+
event: 6,
|
|
36
|
+
});
|
|
37
|
+
const createHTML = html => html;
|
|
38
|
+
const fastTrustedType = globalThis.trustedTypes
|
|
39
|
+
? globalThis.trustedTypes.createPolicy("fast-html", { createHTML })
|
|
40
|
+
: { createHTML };
|
|
41
|
+
let defaultPolicy = Object.freeze({
|
|
42
|
+
createHTML(value) {
|
|
43
|
+
return fastTrustedType.createHTML(value);
|
|
44
|
+
},
|
|
45
|
+
protect(tagName, aspect, aspectName, sink) {
|
|
46
|
+
return sink;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
const fastPolicy = defaultPolicy;
|
|
50
|
+
/**
|
|
51
|
+
* Common DOM APIs.
|
|
52
|
+
* @public
|
|
53
|
+
*/
|
|
54
|
+
export const DOM = Object.freeze({
|
|
55
|
+
/**
|
|
56
|
+
* Gets the dom policy used by the templating system.
|
|
57
|
+
*/
|
|
58
|
+
get policy() {
|
|
59
|
+
return defaultPolicy;
|
|
60
|
+
},
|
|
61
|
+
/**
|
|
62
|
+
* Sets the dom policy used by the templating system.
|
|
63
|
+
* @param policy - The policy to set.
|
|
64
|
+
* @remarks
|
|
65
|
+
* This API can only be called once, for security reasons. It should be
|
|
66
|
+
* called by the application developer at the start of their program.
|
|
67
|
+
*/
|
|
68
|
+
setPolicy(value) {
|
|
69
|
+
if (defaultPolicy !== fastPolicy) {
|
|
70
|
+
throw FAST.error(1201 /* Message.onlySetDOMPolicyOnce */);
|
|
71
|
+
}
|
|
72
|
+
defaultPolicy = value;
|
|
73
|
+
},
|
|
74
|
+
/**
|
|
75
|
+
* Sets an attribute value on an element.
|
|
76
|
+
* @param element - The element to set the attribute value on.
|
|
77
|
+
* @param attributeName - The attribute name to set.
|
|
78
|
+
* @param value - The value of the attribute to set.
|
|
79
|
+
* @remarks
|
|
80
|
+
* If the value is `null` or `undefined`, the attribute is removed, otherwise
|
|
81
|
+
* it is set to the provided value using the standard `setAttribute` API.
|
|
82
|
+
*/
|
|
83
|
+
setAttribute(element, attributeName, value) {
|
|
84
|
+
value === null || value === undefined
|
|
85
|
+
? element.removeAttribute(attributeName)
|
|
86
|
+
: element.setAttribute(attributeName, value);
|
|
87
|
+
},
|
|
88
|
+
/**
|
|
89
|
+
* Sets a boolean attribute value.
|
|
90
|
+
* @param element - The element to set the boolean attribute value on.
|
|
91
|
+
* @param attributeName - The attribute name to set.
|
|
92
|
+
* @param value - The value of the attribute to set.
|
|
93
|
+
* @remarks
|
|
94
|
+
* If the value is true, the attribute is added; otherwise it is removed.
|
|
95
|
+
*/
|
|
96
|
+
setBooleanAttribute(element, attributeName, value) {
|
|
97
|
+
value
|
|
98
|
+
? element.setAttribute(attributeName, "")
|
|
99
|
+
: element.removeAttribute(attributeName);
|
|
100
|
+
},
|
|
101
|
+
});
|