@webtides/element-js 1.0.0 → 1.1.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/CHANGELOG.md +147 -90
- package/README.md +3 -3
- package/docs/README.md +70 -89
- package/docs/concepts/classes.md +37 -66
- package/docs/concepts/hierarchy.md +29 -31
- package/docs/concepts/lifecycle.md +9 -23
- package/docs/concepts/reactivity.md +1 -3
- package/docs/features/computed-properties.md +13 -16
- package/docs/features/dependency-injection-context-protocol.md +75 -87
- package/docs/features/global-styles.md +1 -1
- package/docs/features/methods.md +14 -15
- package/docs/features/properties.md +21 -33
- package/docs/features/refs.md +23 -31
- package/docs/features/renderless.md +31 -37
- package/docs/features/store.md +63 -78
- package/docs/features/templates.md +4 -1
- package/docs/features/watch.md +28 -35
- package/docs/getting-started/upgrade-to-v1.md +16 -0
- package/docs/guide/guide.md +10 -22
- package/index.js +29 -2
- package/package.json +62 -62
- package/src/BaseElement.js +632 -631
- package/src/StyledElement.js +104 -104
- package/src/TemplateElement.js +53 -53
- package/src/dom-parts/AttributePart.js +116 -116
- package/src/dom-parts/ChildNodePart.js +288 -288
- package/src/dom-parts/NodePart.js +27 -27
- package/src/dom-parts/Part.js +6 -6
- package/src/dom-parts/TemplatePart.js +119 -119
- package/src/dom-parts/TemplateResult.js +270 -270
- package/src/dom-parts/directives.js +105 -48
- package/src/dom-parts/html.js +1 -1
- package/src/dom-parts/render.js +6 -6
- package/src/util/AttributeParser.js +47 -47
- package/src/util/DOMHelper.js +190 -190
- package/src/util/Directive.js +31 -31
- package/src/util/GlobalStylesStore.js +63 -53
- package/src/util/SerializeStateHelper.js +56 -56
- package/src/util/Store.js +175 -174
- package/src/util/crypto.js +13 -0
- package/src/util/defineElement.js +5 -5
- package/src/util/toString.js +5 -5
package/src/StyledElement.js
CHANGED
|
@@ -12,110 +12,110 @@ import { globalStylesStore } from './util/GlobalStylesStore.js';
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
class StyledElement extends BaseElement {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
15
|
+
/**
|
|
16
|
+
* @param {StyledElementOptions} options
|
|
17
|
+
*/
|
|
18
|
+
constructor(options) {
|
|
19
|
+
super({
|
|
20
|
+
deferUpdate: false,
|
|
21
|
+
shadowRender: false,
|
|
22
|
+
styles: [],
|
|
23
|
+
adoptGlobalStyles: true,
|
|
24
|
+
...options,
|
|
25
|
+
});
|
|
26
|
+
this._styles = [...this._options.styles, ...this.styles()];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Overrides the `connectedCallback` to adopt optional styles when the element is connected
|
|
31
|
+
*/
|
|
32
|
+
connectedCallback() {
|
|
33
|
+
super.connectedCallback();
|
|
34
|
+
|
|
35
|
+
if (!this.constructor['elementStyleSheets']) {
|
|
36
|
+
this.constructor['elementStyleSheets'] = this._styles.map((style) => {
|
|
37
|
+
const cssStyleSheet = new CSSStyleSheet();
|
|
38
|
+
cssStyleSheet.replaceSync(style);
|
|
39
|
+
return cssStyleSheet;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (supportsAdoptingStyleSheets() && this._options.shadowRender) {
|
|
44
|
+
// adopting does only make sense in shadow dom. Fall back to append for light elements
|
|
45
|
+
this.adoptStyleSheets();
|
|
46
|
+
|
|
47
|
+
if (this._options.adoptGlobalStyles !== false) {
|
|
48
|
+
globalStylesStore.subscribe(() => {
|
|
49
|
+
this.adoptStyleSheets();
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The styles method is another way to return a list of styles to be adopted when the element is connected.
|
|
57
|
+
* You can either provide a list in the constructor options or return it here.
|
|
58
|
+
* @returns {string[]}
|
|
59
|
+
*/
|
|
60
|
+
styles() {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Overrides the `update` method to adopt optional styles
|
|
66
|
+
* @param {PropertyUpdateOptions} options
|
|
67
|
+
*/
|
|
68
|
+
update(options) {
|
|
69
|
+
// We cannot do this in connectedCallback() since the whole template will be overridden in update/render afterward
|
|
70
|
+
if (!supportsAdoptingStyleSheets() || this._options.shadowRender === false) {
|
|
71
|
+
this.appendStyleSheets();
|
|
72
|
+
}
|
|
73
|
+
super.update(options);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Adopt stylesheets
|
|
78
|
+
*/
|
|
79
|
+
adoptStyleSheets() {
|
|
80
|
+
const adoptGlobalStyleSheets = this._options.shadowRender && this._options.adoptGlobalStyles !== false;
|
|
81
|
+
|
|
82
|
+
this.getRoot().adoptedStyleSheets = [
|
|
83
|
+
...(adoptGlobalStyleSheets ? globalStylesStore.getGlobalStyleSheets(this._options.adoptGlobalStyles) : []),
|
|
84
|
+
...this.constructor['elementStyleSheets'],
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Custom polyfill for constructable stylesheets by appending styles to the end of an element
|
|
90
|
+
*/
|
|
91
|
+
appendStyleSheets() {
|
|
92
|
+
const parentDocument = getShadowParentOrBody(this.getRoot());
|
|
93
|
+
|
|
94
|
+
const adoptGlobalStyleSheets =
|
|
95
|
+
this._options.shadowRender &&
|
|
96
|
+
this._options.adoptGlobalStyles !== false &&
|
|
97
|
+
parentDocument !== globalThis.document.body;
|
|
98
|
+
|
|
99
|
+
const appendableStyles = [
|
|
100
|
+
...(adoptGlobalStyleSheets ? globalStylesStore.getGlobalStyleSheets(this._options.adoptGlobalStyles) : []),
|
|
101
|
+
...this.constructor['elementStyleSheets'],
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
appendableStyles.forEach((styleSheet, index) => {
|
|
105
|
+
const identifier = this.tagName + index;
|
|
106
|
+
|
|
107
|
+
// only append stylesheet if not already appended to shadowRoot or document
|
|
108
|
+
if (!parentDocument.querySelector(`#${identifier}`)) {
|
|
109
|
+
const styleElement = globalThis.document?.createElement('style');
|
|
110
|
+
styleElement.id = identifier;
|
|
111
|
+
styleElement.style.display = 'none';
|
|
112
|
+
styleElement.textContent = Array.from(styleSheet.cssRules)
|
|
113
|
+
.map((rule) => rule.cssText)
|
|
114
|
+
.join('');
|
|
115
|
+
parentDocument.appendChild(styleElement);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
export { StyledElement };
|
package/src/TemplateElement.js
CHANGED
|
@@ -9,64 +9,64 @@ import { render } from './dom-parts/render.js';
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
class TemplateElement extends StyledElement {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
12
|
+
/**
|
|
13
|
+
* @param {TemplateElementOptions} options
|
|
14
|
+
*/
|
|
15
|
+
constructor(options) {
|
|
16
|
+
super({
|
|
17
|
+
deferUpdate: false,
|
|
18
|
+
shadowRender: false,
|
|
19
|
+
styles: [],
|
|
20
|
+
adoptGlobalStyles: true,
|
|
21
|
+
mutationObserverOptions: {
|
|
22
|
+
childList: false,
|
|
23
|
+
},
|
|
24
|
+
...options,
|
|
25
|
+
});
|
|
26
|
+
this._template = this._options.template;
|
|
27
|
+
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Overrides the native `connectedCallback` of the HTMLElement to set up and initialize our element.
|
|
31
|
+
* This will attach a shadow DOM if the element is supposed to render in shadow DOM.
|
|
32
|
+
*/
|
|
33
|
+
connectedCallback() {
|
|
34
|
+
if (this._options.shadowRender && !this.shadowRoot) this.attachShadow({ mode: 'open' });
|
|
35
|
+
super.connectedCallback();
|
|
36
|
+
}
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
/**
|
|
39
|
+
* The template method should be overridden in extending elements and return the template to be rendered to the root
|
|
40
|
+
* @returns {TemplateResult | string}
|
|
41
|
+
*/
|
|
42
|
+
template() {
|
|
43
|
+
return html``;
|
|
44
|
+
}
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Override update method to render the template to the root
|
|
48
|
+
* @param {PropertyUpdateOptions} options
|
|
49
|
+
*/
|
|
50
|
+
update(options) {
|
|
51
|
+
this.renderTemplate();
|
|
52
|
+
super.update(options);
|
|
53
|
+
}
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Render the template to the root
|
|
57
|
+
*/
|
|
58
|
+
renderTemplate() {
|
|
59
|
+
const template = this._template || this.template();
|
|
60
|
+
render(template, this.getRoot());
|
|
61
|
+
}
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Get the root element - either the element or the shadow root
|
|
65
|
+
* @returns {ShadowRoot | HTMLElement}
|
|
66
|
+
*/
|
|
67
|
+
getRoot() {
|
|
68
|
+
return this.shadowRoot !== null ? this.shadowRoot : this;
|
|
69
|
+
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
export { TemplateElement, html, render };
|
|
@@ -7,14 +7,14 @@ import { Part } from './Part.js';
|
|
|
7
7
|
* @return {(function(*): void)|*}
|
|
8
8
|
*/
|
|
9
9
|
const processBooleanAttribute = (node, name, oldValue) => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
// TODO: It would be better if the ?boolean= attribute would not be there in the first place...
|
|
11
|
+
node.removeAttribute(`?${name}`);
|
|
12
|
+
return (newValue) => {
|
|
13
|
+
const value = !!newValue?.valueOf() && newValue !== 'false';
|
|
14
|
+
if (oldValue !== value) {
|
|
15
|
+
node.toggleAttribute(name, (oldValue = !!value));
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -23,11 +23,11 @@ const processBooleanAttribute = (node, name, oldValue) => {
|
|
|
23
23
|
* @return {(function(*): void)|*}
|
|
24
24
|
*/
|
|
25
25
|
const processPropertyAttribute = (node, name) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
// TODO: It would be better if the .property= attribute would not be there in the first place...
|
|
27
|
+
node.removeAttribute(`.${name}`);
|
|
28
|
+
return (value) => {
|
|
29
|
+
node[name] = value;
|
|
30
|
+
};
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -36,18 +36,18 @@ const processPropertyAttribute = (node, name) => {
|
|
|
36
36
|
* @return {(function(*): void)|*}
|
|
37
37
|
*/
|
|
38
38
|
const processEventAttribute = (node, name) => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
// TODO: It would be better if the event attribute would not be there in the first place...
|
|
40
|
+
node.removeAttribute(name);
|
|
41
|
+
|
|
42
|
+
let oldValue = undefined;
|
|
43
|
+
let type = name.startsWith('@') ? name.slice(1) : name.toLowerCase().slice(2);
|
|
44
|
+
|
|
45
|
+
return (newValue) => {
|
|
46
|
+
if (oldValue !== newValue) {
|
|
47
|
+
if (oldValue) node.removeEventListener(type, oldValue);
|
|
48
|
+
if ((oldValue = newValue)) node.addEventListener(type, oldValue);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
/**
|
|
@@ -56,26 +56,26 @@ const processEventAttribute = (node, name) => {
|
|
|
56
56
|
* @return {(function(*): void)|*}
|
|
57
57
|
*/
|
|
58
58
|
const processAttribute = (node, name) => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
59
|
+
let oldValue,
|
|
60
|
+
orphan = true;
|
|
61
|
+
const attributeNode = globalThis.document?.createAttributeNS(null, name);
|
|
62
|
+
return (newValue) => {
|
|
63
|
+
const value = newValue?.valueOf();
|
|
64
|
+
if (oldValue !== value) {
|
|
65
|
+
if ((oldValue = value) == null) {
|
|
66
|
+
if (!orphan) {
|
|
67
|
+
node.removeAttributeNode(attributeNode);
|
|
68
|
+
orphan = true;
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
attributeNode.value = value;
|
|
72
|
+
if (orphan) {
|
|
73
|
+
node.setAttributeNodeNS(attributeNode);
|
|
74
|
+
orphan = false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
/** @type {Map<Element, AttributePart>} */
|
|
@@ -87,81 +87,81 @@ const attributePartsCache = new WeakMap();
|
|
|
87
87
|
* @return {(function(*): void)|*}
|
|
88
88
|
*/
|
|
89
89
|
export const processAttributePart = (node, name) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
90
|
+
// boolean attribute: ?boolean=${...}
|
|
91
|
+
if (name.startsWith('?')) {
|
|
92
|
+
return processBooleanAttribute(node, name.slice(1), false);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// property attribute: .property=${...}
|
|
96
|
+
if (name.startsWith('.')) {
|
|
97
|
+
return processPropertyAttribute(node, name.slice(1));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// event attribute: @event=${...} || "old school" event attribute: onevent=${...}
|
|
101
|
+
if (name.startsWith('@') || name.startsWith('on')) {
|
|
102
|
+
return processEventAttribute(node, name);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// normal "string" attribute: attribute=${...}
|
|
106
|
+
return processAttribute(node, name);
|
|
107
107
|
};
|
|
108
108
|
|
|
109
109
|
/**
|
|
110
110
|
* For updating a single attribute
|
|
111
111
|
*/
|
|
112
112
|
export class AttributePart extends Part {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
113
|
+
name = undefined;
|
|
114
|
+
interpolations = 1;
|
|
115
|
+
values = [];
|
|
116
|
+
currentValueIndex = 0;
|
|
117
|
+
initialValue = undefined;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @param {Comment} node
|
|
121
|
+
* @param {String} name
|
|
122
|
+
* @param {String} initialValue
|
|
123
|
+
*/
|
|
124
|
+
constructor(node, name, initialValue) {
|
|
125
|
+
// If we have multiple attribute parts with the same name, it means we have multiple
|
|
126
|
+
// interpolations inside that attribute. Instead of creating a new part, we will return the same
|
|
127
|
+
// as before and let it defer the update until the last interpolation gets updated
|
|
128
|
+
const attributePart = attributePartsCache.get(node.nextElementSibling);
|
|
129
|
+
if (attributePart && attributePart.name === name) {
|
|
130
|
+
attributePart.interpolations++;
|
|
131
|
+
node.__part = attributePart; // add Part to comment node for debugging in the browser
|
|
132
|
+
return attributePart;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
super();
|
|
136
|
+
this.name = name;
|
|
137
|
+
this.initialValue = initialValue;
|
|
138
|
+
this.processor = processAttributePart(node.nextElementSibling, this.name);
|
|
139
|
+
node.__part = this; // add Part to comment node for debugging in the browser
|
|
140
|
+
attributePartsCache.set(node.nextElementSibling, this);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {string | number | bigint | boolean | undefined | symbol | null} value
|
|
145
|
+
*/
|
|
146
|
+
update(value) {
|
|
147
|
+
// If we only have one sole interpolation, we can just apply the update
|
|
148
|
+
if (this.initialValue === '\x03') {
|
|
149
|
+
this.processor(value);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Instead of applying the update immediately, we check if the part has multiple interpolations
|
|
154
|
+
// and store the values for each interpolation in a list
|
|
155
|
+
this.values[this.currentValueIndex++] = value;
|
|
156
|
+
|
|
157
|
+
// Only the last call to update (for the last interpolation) will actually trigger the update
|
|
158
|
+
// on the DOM processor. Here we can reset everything before the next round of updates
|
|
159
|
+
if (this.interpolations === this.currentValueIndex) {
|
|
160
|
+
this.currentValueIndex = 0;
|
|
161
|
+
let replaceIndex = 0;
|
|
162
|
+
// Note: this will coarse the values into strings, but it's probably ok since there can only be multiple values in string attributes?!
|
|
163
|
+
const parsedValue = this.initialValue.replace(/\x03/g, () => this.values[replaceIndex++]);
|
|
164
|
+
this.processor(parsedValue);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
167
|
}
|