@microsoft/fast-element 2.0.0-beta.16 → 2.0.0-beta.18
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 +36 -0
- package/CHANGELOG.md +18 -1
- package/dist/dts/components/element-controller.d.ts +5 -0
- package/dist/dts/dom-policy.d.ts +68 -0
- package/dist/dts/dom.d.ts +116 -0
- package/dist/dts/index.d.ts +3 -2
- 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 +15 -24
- package/dist/dts/polyfills.d.ts +0 -1
- package/dist/dts/templating/binding-signal.d.ts +3 -1
- package/dist/dts/templating/binding-two-way.d.ts +3 -1
- package/dist/dts/templating/binding.d.ts +16 -5
- package/dist/dts/templating/compiler.d.ts +11 -13
- package/dist/dts/templating/dangerous-html.d.ts +18 -0
- package/dist/dts/templating/html-directive.d.ts +54 -118
- package/dist/dts/templating/node-observation.d.ts +11 -1
- package/dist/dts/templating/ref.d.ts +4 -0
- package/dist/dts/templating/render.d.ts +30 -6
- package/dist/dts/templating/repeat.d.ts +1 -5
- package/dist/dts/templating/template.d.ts +44 -13
- package/dist/dts/templating/view.d.ts +8 -3
- package/dist/dts/testing/fakes.d.ts +1 -0
- package/dist/dts/utilities.d.ts +39 -0
- package/dist/esm/components/attributes.js +1 -1
- package/dist/esm/components/element-controller.js +6 -1
- package/dist/esm/debug.js +4 -1
- package/dist/esm/dom-policy.js +337 -0
- package/dist/esm/dom.js +117 -0
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.rollup.debug.js +3 -1
- package/dist/esm/index.rollup.js +3 -1
- package/dist/esm/observation/observable.js +5 -1
- package/dist/esm/platform.js +1 -1
- package/dist/esm/polyfills.js +3 -7
- package/dist/esm/templating/binding-signal.js +9 -3
- package/dist/esm/templating/binding-two-way.js +9 -3
- package/dist/esm/templating/binding.js +40 -55
- package/dist/esm/templating/children.js +8 -4
- package/dist/esm/templating/compiler.js +31 -38
- package/dist/esm/templating/dangerous-html.js +23 -0
- package/dist/esm/templating/html-directive.js +42 -133
- package/dist/esm/templating/node-observation.js +14 -8
- package/dist/esm/templating/ref.js +1 -1
- package/dist/esm/templating/render.js +17 -6
- package/dist/esm/templating/repeat.js +2 -6
- package/dist/esm/templating/template.js +86 -56
- package/dist/esm/templating/view.js +6 -0
- package/dist/esm/testing/fakes.js +2 -0
- package/dist/esm/testing/fixture.js +1 -1
- package/dist/esm/utilities.js +68 -0
- package/dist/fast-element.api.json +1088 -608
- package/dist/fast-element.d.ts +194 -147
- package/dist/fast-element.debug.js +745 -381
- package/dist/fast-element.debug.min.js +1 -1
- package/dist/fast-element.js +716 -355
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +208 -145
- package/docs/api-report.md +74 -56
- package/package.json +5 -1
- package/yarn-error.log +177 -0
- package/dist/dts/templating/dom.d.ts +0 -41
- package/dist/esm/templating/dom.js +0 -49
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
import { isFunction } from "../interfaces.js";
|
|
1
|
+
import { isFunction, noop } from "../interfaces.js";
|
|
2
2
|
import { ExecutionContext, Observable, } from "../observation/observable.js";
|
|
3
3
|
import { FAST } from "../platform.js";
|
|
4
|
-
import { DOM } from "
|
|
5
|
-
import {
|
|
6
|
-
import { Markup
|
|
7
|
-
const createInnerHTMLBinding = globalThis.TrustedHTML
|
|
8
|
-
? (binding) => (s, c) => {
|
|
9
|
-
const value = binding(s, c);
|
|
10
|
-
if (value instanceof TrustedHTML) {
|
|
11
|
-
return value;
|
|
12
|
-
}
|
|
13
|
-
throw FAST.error(1202 /* Message.bindingInnerHTMLRequiresTrustedTypes */);
|
|
14
|
-
}
|
|
15
|
-
: (binding) => binding;
|
|
4
|
+
import { DOM, DOMAspect } from "../dom.js";
|
|
5
|
+
import { Binding, HTMLDirective, } from "./html-directive.js";
|
|
6
|
+
import { Markup } from "./markup.js";
|
|
16
7
|
class OnChangeBinding extends Binding {
|
|
17
8
|
createObserver(_, subscriber) {
|
|
18
9
|
return Observable.binding(this.evaluate, subscriber, this.isVolatile);
|
|
19
10
|
}
|
|
20
11
|
}
|
|
21
12
|
class OneTimeBinding extends Binding {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
/**
|
|
16
|
+
* Opts out of JSON stringification.
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
this.toJSON = noop;
|
|
20
|
+
}
|
|
22
21
|
createObserver() {
|
|
23
22
|
return this;
|
|
24
23
|
}
|
|
@@ -117,8 +116,14 @@ function updateTokenList(target, aspect, value) {
|
|
|
117
116
|
}
|
|
118
117
|
}
|
|
119
118
|
}
|
|
120
|
-
const
|
|
121
|
-
|
|
119
|
+
const sinkLookup = {
|
|
120
|
+
[DOMAspect.attribute]: DOM.setAttribute,
|
|
121
|
+
[DOMAspect.booleanAttribute]: DOM.setBooleanAttribute,
|
|
122
|
+
[DOMAspect.property]: (t, a, v) => (t[a] = v),
|
|
123
|
+
[DOMAspect.content]: updateContent,
|
|
124
|
+
[DOMAspect.tokenList]: updateTokenList,
|
|
125
|
+
[DOMAspect.event]: () => void 0,
|
|
126
|
+
};
|
|
122
127
|
/**
|
|
123
128
|
* A directive that applies bindings.
|
|
124
129
|
* @public
|
|
@@ -131,15 +136,10 @@ export class HTMLBindingDirective {
|
|
|
131
136
|
constructor(dataBinding) {
|
|
132
137
|
this.dataBinding = dataBinding;
|
|
133
138
|
this.updateTarget = null;
|
|
134
|
-
/**
|
|
135
|
-
* The unique id of the factory.
|
|
136
|
-
*/
|
|
137
|
-
this.id = nextId();
|
|
138
139
|
/**
|
|
139
140
|
* The type of aspect to target.
|
|
140
141
|
*/
|
|
141
|
-
this.aspectType =
|
|
142
|
-
this.data = `${this.id}-d`;
|
|
142
|
+
this.aspectType = DOMAspect.content;
|
|
143
143
|
}
|
|
144
144
|
/**
|
|
145
145
|
* Creates HTML to be used within a template.
|
|
@@ -152,45 +152,28 @@ export class HTMLBindingDirective {
|
|
|
152
152
|
* Creates a behavior.
|
|
153
153
|
*/
|
|
154
154
|
createBehavior() {
|
|
155
|
+
var _a;
|
|
155
156
|
if (this.updateTarget === null) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
case 1:
|
|
161
|
-
this.updateTarget = DOM.setAttribute;
|
|
162
|
-
break;
|
|
163
|
-
case 2:
|
|
164
|
-
this.updateTarget = DOM.setBooleanAttribute;
|
|
165
|
-
break;
|
|
166
|
-
case 3:
|
|
167
|
-
this.updateTarget = setProperty;
|
|
168
|
-
break;
|
|
169
|
-
case 4:
|
|
170
|
-
this.updateTarget = updateContent;
|
|
171
|
-
break;
|
|
172
|
-
case 5:
|
|
173
|
-
this.updateTarget = updateTokenList;
|
|
174
|
-
break;
|
|
175
|
-
case 6:
|
|
176
|
-
this.updateTarget = eventTarget;
|
|
177
|
-
break;
|
|
178
|
-
default:
|
|
179
|
-
throw FAST.error(1205 /* Message.unsupportedBindingBehavior */);
|
|
157
|
+
const sink = sinkLookup[this.aspectType];
|
|
158
|
+
const policy = (_a = this.dataBinding.policy) !== null && _a !== void 0 ? _a : this.policy;
|
|
159
|
+
if (!sink) {
|
|
160
|
+
throw FAST.error(1205 /* Message.unsupportedBindingBehavior */);
|
|
180
161
|
}
|
|
162
|
+
this.data = `${this.id}-d`;
|
|
163
|
+
this.updateTarget = policy.protect(this.targetTagName, this.aspectType, this.targetAspect, sink);
|
|
181
164
|
}
|
|
182
165
|
return this;
|
|
183
166
|
}
|
|
184
167
|
/** @internal */
|
|
185
168
|
bind(controller) {
|
|
186
169
|
var _a;
|
|
187
|
-
const target = controller.targets[this.
|
|
188
|
-
switch (this.
|
|
189
|
-
case
|
|
170
|
+
const target = controller.targets[this.targetNodeId];
|
|
171
|
+
switch (this.aspectType) {
|
|
172
|
+
case DOMAspect.event:
|
|
190
173
|
target[this.data] = controller;
|
|
191
174
|
target.addEventListener(this.targetAspect, this, this.dataBinding.options);
|
|
192
175
|
break;
|
|
193
|
-
case
|
|
176
|
+
case DOMAspect.content:
|
|
194
177
|
controller.onUnbind(this);
|
|
195
178
|
// intentional fall through
|
|
196
179
|
default:
|
|
@@ -203,7 +186,7 @@ export class HTMLBindingDirective {
|
|
|
203
186
|
}
|
|
204
187
|
/** @internal */
|
|
205
188
|
unbind(controller) {
|
|
206
|
-
const target = controller.targets[this.
|
|
189
|
+
const target = controller.targets[this.targetNodeId];
|
|
207
190
|
const view = target.$fastView;
|
|
208
191
|
if (view !== void 0 && view.isComposed) {
|
|
209
192
|
view.unbind();
|
|
@@ -233,21 +216,23 @@ HTMLDirective.define(HTMLBindingDirective, { aspected: true });
|
|
|
233
216
|
/**
|
|
234
217
|
* Creates an standard binding.
|
|
235
218
|
* @param expression - The binding to refresh when changed.
|
|
219
|
+
* @param policy - The security policy to associate with th binding.
|
|
236
220
|
* @param isVolatile - Indicates whether the binding is volatile or not.
|
|
237
221
|
* @returns A binding configuration.
|
|
238
222
|
* @public
|
|
239
223
|
*/
|
|
240
|
-
export function bind(expression, isVolatile = Observable.isVolatileBinding(expression)) {
|
|
241
|
-
return new OnChangeBinding(expression, isVolatile);
|
|
224
|
+
export function bind(expression, policy, isVolatile = Observable.isVolatileBinding(expression)) {
|
|
225
|
+
return new OnChangeBinding(expression, policy, isVolatile);
|
|
242
226
|
}
|
|
243
227
|
/**
|
|
244
228
|
* Creates a one time binding
|
|
245
229
|
* @param expression - The binding to refresh when signaled.
|
|
230
|
+
* @param policy - The security policy to associate with th binding.
|
|
246
231
|
* @returns A binding configuration.
|
|
247
232
|
* @public
|
|
248
233
|
*/
|
|
249
|
-
export function oneTime(expression) {
|
|
250
|
-
return new OneTimeBinding(expression);
|
|
234
|
+
export function oneTime(expression, policy) {
|
|
235
|
+
return new OneTimeBinding(expression, policy);
|
|
251
236
|
}
|
|
252
237
|
/**
|
|
253
238
|
* Creates an event listener binding.
|
|
@@ -257,7 +242,7 @@ export function oneTime(expression) {
|
|
|
257
242
|
* @public
|
|
258
243
|
*/
|
|
259
244
|
export function listener(expression, options) {
|
|
260
|
-
const config = new OnChangeBinding(expression
|
|
245
|
+
const config = new OnChangeBinding(expression);
|
|
261
246
|
config.options = options;
|
|
262
247
|
return config;
|
|
263
248
|
}
|
|
@@ -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
|
/**
|
|
@@ -24,9 +24,13 @@ export class ChildrenDirective extends NodeObservationDirective {
|
|
|
24
24
|
* @param target - The target to observe.
|
|
25
25
|
*/
|
|
26
26
|
observe(target) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
let observer = target[this.observerProperty];
|
|
28
|
+
if (!observer) {
|
|
29
|
+
observer = new MutationObserver(this.handleEvent);
|
|
30
|
+
observer.toJSON = noop;
|
|
31
|
+
observer.target = target;
|
|
32
|
+
target[this.observerProperty] = observer;
|
|
33
|
+
}
|
|
30
34
|
observer.observe(target, this.options);
|
|
31
35
|
}
|
|
32
36
|
/**
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { isFunction, isString } from "../interfaces.js";
|
|
2
2
|
import { FAST } from "../platform.js";
|
|
3
|
-
import {
|
|
3
|
+
import { DOM } from "../dom.js";
|
|
4
|
+
import { nextId, Parser } from "./markup.js";
|
|
4
5
|
import { HTMLBindingDirective, oneTime } from "./binding.js";
|
|
5
|
-
import {
|
|
6
|
+
import { HTMLDirective, } from "./html-directive.js";
|
|
6
7
|
import { HTMLView } from "./view.js";
|
|
7
8
|
const targetIdFrom = (parentId, nodeIndex) => `${parentId}.${nodeIndex}`;
|
|
8
9
|
const descriptorCache = {};
|
|
@@ -28,20 +29,25 @@ const warningHost = new Proxy(document.createElement("div"), {
|
|
|
28
29
|
},
|
|
29
30
|
});
|
|
30
31
|
class CompilationContext {
|
|
31
|
-
constructor(fragment, directives) {
|
|
32
|
+
constructor(fragment, directives, policy) {
|
|
32
33
|
this.fragment = fragment;
|
|
33
34
|
this.directives = directives;
|
|
35
|
+
this.policy = policy;
|
|
34
36
|
this.proto = null;
|
|
35
37
|
this.nodeIds = new Set();
|
|
36
38
|
this.descriptors = {};
|
|
37
39
|
this.factories = [];
|
|
38
40
|
}
|
|
39
|
-
addFactory(factory, parentId, nodeId, targetIndex) {
|
|
41
|
+
addFactory(factory, parentId, nodeId, targetIndex, tagName) {
|
|
42
|
+
var _a, _b;
|
|
40
43
|
if (!this.nodeIds.has(nodeId)) {
|
|
41
44
|
this.nodeIds.add(nodeId);
|
|
42
45
|
this.addTargetDescriptor(parentId, nodeId, targetIndex);
|
|
43
46
|
}
|
|
44
|
-
factory.
|
|
47
|
+
factory.id = (_a = factory.id) !== null && _a !== void 0 ? _a : nextId();
|
|
48
|
+
factory.targetNodeId = nodeId;
|
|
49
|
+
factory.targetTagName = tagName;
|
|
50
|
+
factory.policy = (_b = factory.policy) !== null && _b !== void 0 ? _b : this.policy;
|
|
45
51
|
this.factories.push(factory);
|
|
46
52
|
}
|
|
47
53
|
freeze() {
|
|
@@ -94,19 +100,19 @@ function compileAttributes(context, parentId, node, nodeId, nodeIndex, includeBa
|
|
|
94
100
|
let result = null;
|
|
95
101
|
if (parseResult === null) {
|
|
96
102
|
if (includeBasicValues) {
|
|
97
|
-
result = new HTMLBindingDirective(oneTime(() => attrValue));
|
|
98
|
-
|
|
103
|
+
result = new HTMLBindingDirective(oneTime(() => attrValue, context.policy));
|
|
104
|
+
HTMLDirective.assignAspect(result, attr.name);
|
|
99
105
|
}
|
|
100
106
|
}
|
|
101
107
|
else {
|
|
102
108
|
/* eslint-disable-next-line @typescript-eslint/no-use-before-define */
|
|
103
|
-
result = Compiler.aggregate(parseResult);
|
|
109
|
+
result = Compiler.aggregate(parseResult, context.policy);
|
|
104
110
|
}
|
|
105
111
|
if (result !== null) {
|
|
106
112
|
node.removeAttributeNode(attr);
|
|
107
113
|
i--;
|
|
108
114
|
ii--;
|
|
109
|
-
context.addFactory(result, parentId, nodeId, nodeIndex);
|
|
115
|
+
context.addFactory(result, parentId, nodeId, nodeIndex, node.tagName);
|
|
110
116
|
}
|
|
111
117
|
}
|
|
112
118
|
}
|
|
@@ -131,8 +137,8 @@ function compileContent(context, node, parentId, nodeId, nodeIndex) {
|
|
|
131
137
|
}
|
|
132
138
|
else {
|
|
133
139
|
currentNode.textContent = " ";
|
|
134
|
-
|
|
135
|
-
context.addFactory(currentPart, parentId, nodeId, nodeIndex);
|
|
140
|
+
HTMLDirective.assignAspect(currentPart);
|
|
141
|
+
context.addFactory(currentPart, parentId, nodeId, nodeIndex, null);
|
|
136
142
|
}
|
|
137
143
|
lastNode = currentNode;
|
|
138
144
|
}
|
|
@@ -164,7 +170,7 @@ function compileNode(context, parentId, node, nodeIndex) {
|
|
|
164
170
|
if (parts !== null) {
|
|
165
171
|
context.addFactory(
|
|
166
172
|
/* eslint-disable-next-line @typescript-eslint/no-use-before-define */
|
|
167
|
-
Compiler.aggregate(parts), parentId, nodeId, nodeIndex);
|
|
173
|
+
Compiler.aggregate(parts), parentId, nodeId, nodeIndex, null);
|
|
168
174
|
}
|
|
169
175
|
break;
|
|
170
176
|
}
|
|
@@ -178,45 +184,28 @@ function isMarker(node, directives) {
|
|
|
178
184
|
Parser.parse(node.data, directives) !== null);
|
|
179
185
|
}
|
|
180
186
|
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
187
|
/**
|
|
187
188
|
* Common APIs related to compilation.
|
|
188
189
|
* @public
|
|
189
190
|
*/
|
|
190
191
|
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
192
|
/**
|
|
205
193
|
* Compiles a template and associated directives into a compilation
|
|
206
194
|
* result which can be used to create views.
|
|
207
195
|
* @param html - The html string or template element to compile.
|
|
208
|
-
* @param
|
|
196
|
+
* @param factories - The behavior factories referenced by the template.
|
|
197
|
+
* @param policy - The security policy to compile the html with.
|
|
209
198
|
* @remarks
|
|
210
199
|
* The template that is provided for compilation is altered in-place
|
|
211
200
|
* and cannot be compiled again. If the original template must be preserved,
|
|
212
201
|
* it is recommended that you clone the original and pass the clone to this API.
|
|
213
202
|
* @public
|
|
214
203
|
*/
|
|
215
|
-
compile(html,
|
|
204
|
+
compile(html, factories, policy = DOM.policy) {
|
|
216
205
|
let template;
|
|
217
206
|
if (isString(html)) {
|
|
218
207
|
template = document.createElement(templateTag);
|
|
219
|
-
template.innerHTML =
|
|
208
|
+
template.innerHTML = policy.createHTML(html);
|
|
220
209
|
const fec = template.content.firstElementChild;
|
|
221
210
|
if (fec !== null && fec.tagName === templateTag) {
|
|
222
211
|
template = fec;
|
|
@@ -227,18 +216,18 @@ export const Compiler = {
|
|
|
227
216
|
}
|
|
228
217
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1111864
|
|
229
218
|
const fragment = document.adoptNode(template.content);
|
|
230
|
-
const context = new CompilationContext(fragment,
|
|
219
|
+
const context = new CompilationContext(fragment, factories, policy);
|
|
231
220
|
compileAttributes(context, "", template, /* host */ "h", 0, true);
|
|
232
221
|
if (
|
|
233
222
|
// If the first node in a fragment is a marker, that means it's an unstable first node,
|
|
234
223
|
// because something like a when, repeat, etc. could add nodes before the marker.
|
|
235
224
|
// To mitigate this, we insert a stable first node. However, if we insert a node,
|
|
236
225
|
// that will alter the result of the TreeWalker. So, we also need to offset the target index.
|
|
237
|
-
isMarker(fragment.firstChild,
|
|
226
|
+
isMarker(fragment.firstChild, factories) ||
|
|
238
227
|
// Or if there is only one node and a directive, it means the template's content
|
|
239
228
|
// is *only* the directive. In that case, HTMLView.dispose() misses any nodes inserted by
|
|
240
229
|
// the directive. Inserting a new node ensures proper disposal of nodes added by the directive.
|
|
241
|
-
(fragment.childNodes.length === 1 && Object.keys(
|
|
230
|
+
(fragment.childNodes.length === 1 && Object.keys(factories).length > 0)) {
|
|
242
231
|
fragment.insertBefore(document.createComment(""), fragment.firstChild);
|
|
243
232
|
}
|
|
244
233
|
compileChildren(context, fragment, /* root */ "r");
|
|
@@ -257,15 +246,17 @@ export const Compiler = {
|
|
|
257
246
|
* Aggregates an array of strings and directives into a single directive.
|
|
258
247
|
* @param parts - A heterogeneous array of static strings interspersed with
|
|
259
248
|
* directives.
|
|
249
|
+
* @param policy - The security policy to use with the aggregated bindings.
|
|
260
250
|
* @returns A single inline directive that aggregates the behavior of all the parts.
|
|
261
251
|
*/
|
|
262
|
-
aggregate(parts) {
|
|
252
|
+
aggregate(parts, policy = DOM.policy) {
|
|
263
253
|
if (parts.length === 1) {
|
|
264
254
|
return parts[0];
|
|
265
255
|
}
|
|
266
256
|
let sourceAspect;
|
|
267
257
|
let binding;
|
|
268
258
|
let isVolatile = false;
|
|
259
|
+
let bindingPolicy = void 0;
|
|
269
260
|
const partCount = parts.length;
|
|
270
261
|
const finalParts = parts.map((x) => {
|
|
271
262
|
if (isString(x)) {
|
|
@@ -274,6 +265,7 @@ export const Compiler = {
|
|
|
274
265
|
sourceAspect = x.sourceAspect || sourceAspect;
|
|
275
266
|
binding = x.dataBinding || binding;
|
|
276
267
|
isVolatile = isVolatile || x.dataBinding.isVolatile;
|
|
268
|
+
bindingPolicy = bindingPolicy || x.dataBinding.policy;
|
|
277
269
|
return x.dataBinding.evaluate;
|
|
278
270
|
});
|
|
279
271
|
const expression = (scope, context) => {
|
|
@@ -285,8 +277,9 @@ export const Compiler = {
|
|
|
285
277
|
};
|
|
286
278
|
binding.evaluate = expression;
|
|
287
279
|
binding.isVolatile = isVolatile;
|
|
280
|
+
binding.policy = bindingPolicy !== null && bindingPolicy !== void 0 ? bindingPolicy : policy;
|
|
288
281
|
const directive = new HTMLBindingDirective(binding);
|
|
289
|
-
|
|
282
|
+
HTMLDirective.assignAspect(directive, sourceAspect);
|
|
290
283
|
return directive;
|
|
291
284
|
},
|
|
292
285
|
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HTMLDirective } from "./html-directive.js";
|
|
2
|
+
/**
|
|
3
|
+
* A directive capable of injecting static HTML platform runtime protection.
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export class DangerousHTMLDirective {
|
|
7
|
+
constructor(html) {
|
|
8
|
+
this.html = html;
|
|
9
|
+
}
|
|
10
|
+
createHTML() {
|
|
11
|
+
return this.html;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
HTMLDirective.define(DangerousHTMLDirective);
|
|
15
|
+
/**
|
|
16
|
+
* Injects static HTML without platform protection.
|
|
17
|
+
* @param html - The html to injection.
|
|
18
|
+
* @returns A DangerousHTMLDirective.
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export function dangerousHTML(html) {
|
|
22
|
+
return new DangerousHTMLDirective(html);
|
|
23
|
+
}
|
|
@@ -1,67 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DOMAspect } from "../dom.js";
|
|
2
|
+
import { noop } from "../interfaces.js";
|
|
2
3
|
import { createTypeRegistry } from "../platform.js";
|
|
3
|
-
import { Markup
|
|
4
|
-
/**
|
|
5
|
-
* Bridges between ViewBehaviors and HostBehaviors, enabling a host to
|
|
6
|
-
* control ViewBehaviors.
|
|
7
|
-
* @public
|
|
8
|
-
*/
|
|
9
|
-
export const ViewBehaviorOrchestrator = Object.freeze({
|
|
10
|
-
/**
|
|
11
|
-
* Creates a ViewBehaviorOrchestrator.
|
|
12
|
-
* @param source - The source to to associate behaviors with.
|
|
13
|
-
* @returns A ViewBehaviorOrchestrator.
|
|
14
|
-
*/
|
|
15
|
-
create(source) {
|
|
16
|
-
const behaviors = [];
|
|
17
|
-
const targets = {};
|
|
18
|
-
let unbindables = null;
|
|
19
|
-
let isConnected = false;
|
|
20
|
-
return {
|
|
21
|
-
source,
|
|
22
|
-
context: ExecutionContext.default,
|
|
23
|
-
targets,
|
|
24
|
-
get isBound() {
|
|
25
|
-
return isConnected;
|
|
26
|
-
},
|
|
27
|
-
addBehaviorFactory(factory, target) {
|
|
28
|
-
const nodeId = factory.nodeId || (factory.nodeId = nextId());
|
|
29
|
-
factory.id || (factory.id = nextId());
|
|
30
|
-
this.addTarget(nodeId, target);
|
|
31
|
-
this.addBehavior(factory.createBehavior());
|
|
32
|
-
},
|
|
33
|
-
addTarget(nodeId, target) {
|
|
34
|
-
targets[nodeId] = target;
|
|
35
|
-
},
|
|
36
|
-
addBehavior(behavior) {
|
|
37
|
-
behaviors.push(behavior);
|
|
38
|
-
if (isConnected) {
|
|
39
|
-
behavior.bind(this);
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
onUnbind(unbindable) {
|
|
43
|
-
if (unbindables === null) {
|
|
44
|
-
unbindables = [];
|
|
45
|
-
}
|
|
46
|
-
unbindables.push(unbindable);
|
|
47
|
-
},
|
|
48
|
-
connectedCallback(controller) {
|
|
49
|
-
if (!isConnected) {
|
|
50
|
-
isConnected = true;
|
|
51
|
-
behaviors.forEach(x => x.bind(this));
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
disconnectedCallback(controller) {
|
|
55
|
-
if (isConnected) {
|
|
56
|
-
isConnected = false;
|
|
57
|
-
if (unbindables !== null) {
|
|
58
|
-
unbindables.forEach(x => x.unbind(this));
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
},
|
|
64
|
-
});
|
|
4
|
+
import { Markup } from "./markup.js";
|
|
65
5
|
const registry = createTypeRegistry();
|
|
66
6
|
/**
|
|
67
7
|
* Instructs the template engine to apply behavior to a node.
|
|
@@ -89,67 +29,6 @@ export const HTMLDirective = Object.freeze({
|
|
|
89
29
|
registry.register(options);
|
|
90
30
|
return type;
|
|
91
31
|
},
|
|
92
|
-
});
|
|
93
|
-
/**
|
|
94
|
-
* Decorator: Defines an HTMLDirective.
|
|
95
|
-
* @param options - Provides options that specify the directive's application.
|
|
96
|
-
* @public
|
|
97
|
-
*/
|
|
98
|
-
export function htmlDirective(options) {
|
|
99
|
-
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
100
|
-
return function (type) {
|
|
101
|
-
HTMLDirective.define(type, options);
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Captures a binding expression along with related information and capabilities.
|
|
106
|
-
*
|
|
107
|
-
* @public
|
|
108
|
-
*/
|
|
109
|
-
export class Binding {
|
|
110
|
-
/**
|
|
111
|
-
* Creates a binding.
|
|
112
|
-
* @param evaluate - Evaluates the binding.
|
|
113
|
-
* @param isVolatile - Indicates whether the binding is volatile.
|
|
114
|
-
*/
|
|
115
|
-
constructor(evaluate, isVolatile = false) {
|
|
116
|
-
this.evaluate = evaluate;
|
|
117
|
-
this.isVolatile = isVolatile;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* The type of HTML aspect to target.
|
|
122
|
-
* @public
|
|
123
|
-
*/
|
|
124
|
-
export const Aspect = Object.freeze({
|
|
125
|
-
/**
|
|
126
|
-
* Not aspected.
|
|
127
|
-
*/
|
|
128
|
-
none: 0,
|
|
129
|
-
/**
|
|
130
|
-
* An attribute.
|
|
131
|
-
*/
|
|
132
|
-
attribute: 1,
|
|
133
|
-
/**
|
|
134
|
-
* A boolean attribute.
|
|
135
|
-
*/
|
|
136
|
-
booleanAttribute: 2,
|
|
137
|
-
/**
|
|
138
|
-
* A property.
|
|
139
|
-
*/
|
|
140
|
-
property: 3,
|
|
141
|
-
/**
|
|
142
|
-
* Content
|
|
143
|
-
*/
|
|
144
|
-
content: 4,
|
|
145
|
-
/**
|
|
146
|
-
* A token list.
|
|
147
|
-
*/
|
|
148
|
-
tokenList: 5,
|
|
149
|
-
/**
|
|
150
|
-
* An event.
|
|
151
|
-
*/
|
|
152
|
-
event: 6,
|
|
153
32
|
/**
|
|
154
33
|
*
|
|
155
34
|
* @param directive - The directive to assign the aspect to.
|
|
@@ -157,9 +36,9 @@ export const Aspect = Object.freeze({
|
|
|
157
36
|
* @remarks
|
|
158
37
|
* If a falsy value is provided, then the content aspect will be assigned.
|
|
159
38
|
*/
|
|
160
|
-
|
|
39
|
+
assignAspect(directive, value) {
|
|
161
40
|
if (!value) {
|
|
162
|
-
directive.aspectType =
|
|
41
|
+
directive.aspectType = DOMAspect.content;
|
|
163
42
|
return;
|
|
164
43
|
}
|
|
165
44
|
directive.sourceAspect = value;
|
|
@@ -168,24 +47,53 @@ export const Aspect = Object.freeze({
|
|
|
168
47
|
directive.targetAspect = value.substring(1);
|
|
169
48
|
directive.aspectType =
|
|
170
49
|
directive.targetAspect === "classList"
|
|
171
|
-
?
|
|
172
|
-
:
|
|
50
|
+
? DOMAspect.tokenList
|
|
51
|
+
: DOMAspect.property;
|
|
173
52
|
break;
|
|
174
53
|
case "?":
|
|
175
54
|
directive.targetAspect = value.substring(1);
|
|
176
|
-
directive.aspectType =
|
|
55
|
+
directive.aspectType = DOMAspect.booleanAttribute;
|
|
177
56
|
break;
|
|
178
57
|
case "@":
|
|
179
58
|
directive.targetAspect = value.substring(1);
|
|
180
|
-
directive.aspectType =
|
|
59
|
+
directive.aspectType = DOMAspect.event;
|
|
181
60
|
break;
|
|
182
61
|
default:
|
|
183
62
|
directive.targetAspect = value;
|
|
184
|
-
directive.aspectType =
|
|
63
|
+
directive.aspectType = DOMAspect.attribute;
|
|
185
64
|
break;
|
|
186
65
|
}
|
|
187
66
|
},
|
|
188
67
|
});
|
|
68
|
+
/**
|
|
69
|
+
* Decorator: Defines an HTMLDirective.
|
|
70
|
+
* @param options - Provides options that specify the directive's application.
|
|
71
|
+
* @public
|
|
72
|
+
*/
|
|
73
|
+
export function htmlDirective(options) {
|
|
74
|
+
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
75
|
+
return function (type) {
|
|
76
|
+
HTMLDirective.define(type, options);
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Captures a binding expression along with related information and capabilities.
|
|
81
|
+
*
|
|
82
|
+
* @public
|
|
83
|
+
*/
|
|
84
|
+
export class Binding {
|
|
85
|
+
/**
|
|
86
|
+
* Creates a binding.
|
|
87
|
+
* @param evaluate - Evaluates the binding.
|
|
88
|
+
* @param policy - The security policy to associate with this binding.
|
|
89
|
+
* @param isVolatile - Indicates whether the binding is volatile.
|
|
90
|
+
*/
|
|
91
|
+
constructor(evaluate, policy, isVolatile = false) {
|
|
92
|
+
this.evaluate = evaluate;
|
|
93
|
+
this.policy = policy;
|
|
94
|
+
this.isVolatile = isVolatile;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
189
97
|
/**
|
|
190
98
|
* A base class used for attribute directives that don't need internal state.
|
|
191
99
|
* @public
|
|
@@ -198,9 +106,10 @@ export class StatelessAttachedAttributeDirective {
|
|
|
198
106
|
constructor(options) {
|
|
199
107
|
this.options = options;
|
|
200
108
|
/**
|
|
201
|
-
*
|
|
109
|
+
* Opts out of JSON stringification.
|
|
110
|
+
* @internal
|
|
202
111
|
*/
|
|
203
|
-
this.
|
|
112
|
+
this.toJSON = noop;
|
|
204
113
|
}
|
|
205
114
|
/**
|
|
206
115
|
* Creates a placeholder string based on the directive's index within the template.
|
|
@@ -16,9 +16,15 @@ export const elements = (selector) => selector
|
|
|
16
16
|
* Internally used by the SlottedDirective and the ChildrenDirective.
|
|
17
17
|
*/
|
|
18
18
|
export class NodeObservationDirective extends StatelessAttachedAttributeDirective {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
/**
|
|
20
|
+
* The unique id of the factory.
|
|
21
|
+
*/
|
|
22
|
+
get id() {
|
|
23
|
+
return this._id;
|
|
24
|
+
}
|
|
25
|
+
set id(value) {
|
|
26
|
+
this._id = value;
|
|
27
|
+
this._controllerProperty = `${value}-c`;
|
|
22
28
|
}
|
|
23
29
|
/**
|
|
24
30
|
* Bind this behavior to the source.
|
|
@@ -27,8 +33,8 @@ export class NodeObservationDirective extends StatelessAttachedAttributeDirectiv
|
|
|
27
33
|
* @param targets - The targets that behaviors in a view can attach to.
|
|
28
34
|
*/
|
|
29
35
|
bind(controller) {
|
|
30
|
-
const target = controller.targets[this.
|
|
31
|
-
target[this.
|
|
36
|
+
const target = controller.targets[this.targetNodeId];
|
|
37
|
+
target[this._controllerProperty] = controller;
|
|
32
38
|
this.updateTarget(controller.source, this.computeNodes(target));
|
|
33
39
|
this.observe(target);
|
|
34
40
|
controller.onUnbind(this);
|
|
@@ -40,10 +46,10 @@ export class NodeObservationDirective extends StatelessAttachedAttributeDirectiv
|
|
|
40
46
|
* @param targets - The targets that behaviors in a view can attach to.
|
|
41
47
|
*/
|
|
42
48
|
unbind(controller) {
|
|
43
|
-
const target = controller.targets[this.
|
|
49
|
+
const target = controller.targets[this.targetNodeId];
|
|
44
50
|
this.updateTarget(controller.source, emptyArray);
|
|
45
51
|
this.disconnect(target);
|
|
46
|
-
target[this.
|
|
52
|
+
target[this._controllerProperty] = null;
|
|
47
53
|
}
|
|
48
54
|
/**
|
|
49
55
|
* Gets the data source for the target.
|
|
@@ -51,7 +57,7 @@ export class NodeObservationDirective extends StatelessAttachedAttributeDirectiv
|
|
|
51
57
|
* @returns The source.
|
|
52
58
|
*/
|
|
53
59
|
getSource(target) {
|
|
54
|
-
return target[this.
|
|
60
|
+
return target[this._controllerProperty].source;
|
|
55
61
|
}
|
|
56
62
|
/**
|
|
57
63
|
* Updates the source property with the computed nodes.
|