@schukai/monster 2.2.1 → 3.1.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/README.md CHANGED
@@ -73,7 +73,7 @@ We do try to work around some browser bugs, but on the whole we don't use polyfi
73
73
  However, many functions can be mapped via [polyfill.io](https://polyfill.io/) and thus the compatibility can be increased.
74
74
 
75
75
  ```html
76
- <script id="polyfill" src="https://polyfill.io/v3/polyfill.min.js?features=Array.from,Array.isArray,Array.prototype.entries,Array.prototype.fill,Array.prototype.filter,Array.prototype.forEach,Array.prototype.indexOf,Array.prototype.keys,Array.prototype.lastIndexOf,Array.prototype.map,Array.prototype.reduce,Array.prototype.sort,ArrayBuffer,atob,CustomEvent,DataView,document,Document,DocumentFragment,Element,Event,fetch,globalThis,HTMLDocument,HTMLTemplateElement,Intl,JSON,Map,Math.log2,Number.isInteger,Object.assign,Object.defineProperty,Object.entries,Object.freeze,Object.getOwnPropertyDescriptor,Object.getOwnPropertyNames,Object.getOwnPropertySymbols,Object.getPrototypeOf,Object.keys,Promise,Reflect,Reflect.defineProperty,Reflect.get,Reflect.getOwnPropertyDescriptor,Reflect.setPrototypeOf,Set,String.prototype.endsWith,String.prototype.matchAll,String.prototype.padStart,String.prototype.startsWith,String.prototype.trim,Symbol,Symbol.for,Symbol.hasInstance,Symbol.iterator,Uint16Array,Uint8Array,URL,WeakMap,WeakSet"
76
+ <script id="polyfill" src="https://polyfill.io/v3/polyfill.min.js?features=Array.from,Array.isArray,Array.prototype.entries,Array.prototype.fill,Array.prototype.filter,Array.prototype.forEach,Array.prototype.indexOf,Array.prototype.keys,Array.prototype.lastIndexOf,Array.prototype.map,Array.prototype.reduce,Array.prototype.sort,ArrayBuffer,atob,CustomEvent,DataView,document,Document,DocumentFragment,Element,Event,fetch,globalThis,HTMLDocument,HTMLTemplateElement,Intl,JSON,Map,Math.log2,Number.isInteger,Object.assign,Object.defineProperty,Object.entries,Object.freeze,Object.getOwnPropertyDescriptor,Object.getOwnPropertyNames,Object.getPrototypeOf,Object.keys,Promise,Reflect,Reflect.defineProperty,Reflect.get,Reflect.getOwnPropertyDescriptor,Reflect.setPrototypeOf,Set,String.prototype.endsWith,String.prototype.matchAll,String.prototype.padStart,String.prototype.startsWith,String.prototype.trim,Symbol,Symbol.for,Symbol.hasInstance,Symbol.iterator,Uint16Array,Uint8Array,URL,WeakMap,WeakSet"
77
77
  crossorigin="anonymous"
78
78
  referrerpolicy="no-referrer"></script>
79
79
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schukai/monster",
3
- "version": "2.2.1",
3
+ "version": "3.1.0",
4
4
  "description": "Monster is a simple library for creating fast, robust and lightweight websites.",
5
5
  "keywords": [
6
6
  "framework",
@@ -22,7 +22,7 @@ export {RestAPI}
22
22
  * @since 1.22.0
23
23
  * @copyright schukai GmbH
24
24
  * @memberOf Monster.Data.Datasource
25
- * @summary The LocalStorage class encapsulates the access to data objects.
25
+ * @summary The RestAPI is a class that binds a REST API server.
26
26
  */
27
27
  class RestAPI extends Datasource {
28
28
 
@@ -30,7 +30,6 @@ class RestAPI extends Datasource {
30
30
  *
31
31
  * @param {Object} [readDefinition] An options object containing any custom settings that you want to apply to the read request.
32
32
  * @param {Object} [writeDefinition] An options object containing any custom settings that you want to apply to the write request.
33
- * @throws {TypeError} value is not a string
34
33
  */
35
34
  constructor(readDefinition, writeDefinition) {
36
35
  super();
@@ -54,17 +53,21 @@ class RestAPI extends Datasource {
54
53
  }
55
54
 
56
55
  /**
57
- * @property {string} url=undefined Defines the resource that you wish to fetch.
58
56
  * @property {Object} write={} Options
59
57
  * @property {Object} write.init={} An options object containing any custom settings that you want to apply to the request. The parameters are identical to those of the {@link https://developer.mozilla.org/en-US/docs/Web/API/Request/Request|Request constructor}
60
58
  * @property {string} write.init.method=POST
59
+ * @property {Object} write.init.headers Object containing any custom headers that you want to apply to the request.
61
60
  * @property {string} write.acceptedStatus=[200,201]
62
61
  * @property {string} write.url URL
63
62
  * @property {Object} write.mapping the mapping is applied before writing.
64
63
  * @property {String} write.mapping.transformer Transformer to select the appropriate entries
64
+ * @property {Monster.Data.Datasource~exampleCallback[]} write.mapping.callback with the help of the callback, the structures can be adjusted before writing.
65
65
  * @property {Object} write.report
66
66
  * @property {String} write.report.path Path to validations
67
- * @property {Monster.Data.Datasource~exampleCallback[]} write.mapping.callback with the help of the callback, the structures can be adjusted before writing.
67
+ * @property {Object} write.sheathing
68
+ * @property {Object} write.sheathing.object Object to be wrapped
69
+ * @property {string} write.sheathing.path Path to the data
70
+ * @property {Object} read={} Options
68
71
  * @property {Object} read.init={} An options object containing any custom settings that you want to apply to the request. The parameters are identical to those of the {@link https://developer.mozilla.org/en-US/docs/Web/API/Request/Request|Request constructor}
69
72
  * @property {string} read.init.method=GET
70
73
  * @property {string} read.acceptedStatus=[200]
@@ -85,6 +88,10 @@ class RestAPI extends Datasource {
85
88
  transformer: undefined,
86
89
  callbacks: []
87
90
  },
91
+ sheathing: {
92
+ object: undefined,
93
+ path: undefined,
94
+ },
88
95
  report: {
89
96
  path: undefined
90
97
  }
@@ -146,6 +153,11 @@ class RestAPI extends Datasource {
146
153
  let transformation = self.getOption('read.mapping.transformer');
147
154
  if (transformation !== undefined) {
148
155
  const pipe = new Pipe(transformation);
156
+
157
+ for (const callback of self.getOption('read.mapping.callbacks')) {
158
+ pipe.setCallback(callback.constructor.name, callback);
159
+ }
160
+
149
161
  obj = pipe.run(obj);
150
162
  }
151
163
 
@@ -174,6 +186,11 @@ class RestAPI extends Datasource {
174
186
  let transformation = self.getOption('write.mapping.transformer');
175
187
  if (transformation !== undefined) {
176
188
  const pipe = new Pipe(transformation);
189
+
190
+ for (const callback of self.getOption('write.mapping.callbacks')) {
191
+ pipe.setCallback(callback.constructor.name, callback);
192
+ }
193
+
177
194
  obj = pipe.run(obj);
178
195
  }
179
196
 
@@ -234,12 +251,3 @@ class RestAPI extends Datasource {
234
251
  }
235
252
 
236
253
 
237
- /**
238
- * This callback can be passed to a datasource and is used to adapt data structures.
239
- *
240
- * @callback Monster.Data.Datasource~exampleCallback
241
- * @param {*} value Value
242
- * @param {string} key Key
243
- * @memberOf Monster.Data
244
- * @see Monster.Data.Datasource
245
- */
@@ -0,0 +1,337 @@
1
+ /**
2
+ * Copyright schukai GmbH and contributors 2022. All Rights Reserved.
3
+ * Node module: @schukai/monster
4
+ * This file is licensed under the AGPLv3 License.
5
+ * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
6
+ */
7
+
8
+ import {internalSymbol, instanceSymbol} from "../../constants.mjs";
9
+ import {isInteger, isString, isObject} from "../../types/is.mjs";
10
+ import {Queue} from "../../types/queue.mjs";
11
+ import {Datasource} from "../datasource.mjs";
12
+ import {Pathfinder} from "../pathfinder.mjs";
13
+ import {Pipe} from "../pipe.mjs";
14
+
15
+ export {WebSocketDatasource}
16
+
17
+ /**
18
+ * @private
19
+ * @type {symbol}
20
+ */
21
+ const receiveQueueSymbol = Symbol("queue");
22
+
23
+
24
+ /**
25
+ * @private
26
+ * @type {symbol}
27
+ *
28
+ * hint: this name is used in the tests. if you want to change it, please change it in the tests as well.
29
+ */
30
+ const connectionSymbol = Symbol("connection");
31
+
32
+ /**
33
+ * @private
34
+ * @type {symbol}
35
+ */
36
+ const manualCloseSymbol = Symbol("manualClose");
37
+
38
+ /**
39
+ * @see https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1
40
+ * @type {{"1000": string, "1011": string, "1010": string, "1008": string, "1007": string, "1006": string, "1005": string, "1004": string, "1015": string, "1003": string, "1002": string, "1001": string, "1009": string}}
41
+ */
42
+ const connectionStatusCode = {
43
+ 1000: "Normal closure",
44
+ 1001: "Going away",
45
+ 1002: "Protocol error",
46
+ 1003: "Unsupported data",
47
+ 1004: "Reserved",
48
+ 1005: "No status code",
49
+ 1006: "Connection closed abnormally",
50
+ 1007: "Invalid frame payload data",
51
+ 1008: "Policy violation",
52
+ 1009: "Message too big",
53
+ 1010: "Mandatory extension",
54
+ 1011: "Internal server error",
55
+ 1015: "TLS handshake"
56
+ };
57
+
58
+ /**
59
+ * The RestAPI is a class that enables a REST API server.
60
+ *
61
+ * @externalExample ../../../example/data/storage/restapi.mjs
62
+ * @license AGPLv3
63
+ * @since 3.1.0
64
+ * @copyright schukai GmbH
65
+ * @memberOf Monster.Data.Datasource
66
+ * @summary The LocalStorage class encapsulates the access to data objects.
67
+ */
68
+ class WebSocketDatasource extends Datasource {
69
+
70
+ /**
71
+ *
72
+ * @param {Object} [options] options contains definitions for the datasource.
73
+ */
74
+ constructor(options) {
75
+ super();
76
+
77
+ if (isString(options)) {
78
+ options = {url: options};
79
+ }
80
+
81
+ if (!isObject(options)) options = {};
82
+ this.setOptions(options);
83
+ this[receiveQueueSymbol] = new Queue();
84
+
85
+ this[connectionSymbol] = {};
86
+ this[connectionSymbol].socket = null;
87
+ this[connectionSymbol].reconnectCounter = 0;
88
+ this[manualCloseSymbol]=false;
89
+ }
90
+
91
+ /**
92
+ *
93
+ * @returns {Websocketdatasource}
94
+ * @throws {Error} No url defined for websocket datasource.
95
+ */
96
+ connect() {
97
+ const self = this;
98
+
99
+ let connected = false;
100
+ let reconnectTimeout = self.getOption('reconnect.timeout');
101
+ if (!isInteger(reconnectTimeout) || reconnectTimeout < 1000) reconnectTimeout = 1000;
102
+ let reconnectAttempts = self.getOption('reconnect.attempts');
103
+ if (!isInteger(reconnectAttempts) || reconnectAttempts < 1) reconnectAttempts = 1;
104
+ let reconnectEnabled = self.getOption('reconnect.enabled');
105
+ if (reconnectEnabled !== true) reconnectEnabled = false;
106
+
107
+ self[manualCloseSymbol] = false;
108
+ self[connectionSymbol].reconnectCounter++;
109
+
110
+ if (self[connectionSymbol].socket && self[connectionSymbol].socket.readyState < 2) {
111
+ self[connectionSymbol].socket.close();
112
+ }
113
+ self[connectionSymbol].socket = null;
114
+
115
+ const url = self.getOption('url');
116
+ if (!url) throw new Error('No url defined for websocket datasource.');
117
+
118
+ self[connectionSymbol].socket = new WebSocket(url);
119
+
120
+ self[connectionSymbol].socket.onmessage = function (event) {
121
+ self[receiveQueueSymbol].add(event);
122
+ setTimeout(function () {
123
+ self.read();
124
+ }, 0);
125
+ };
126
+
127
+ self[connectionSymbol].socket.onopen = function () {
128
+ connected = true;
129
+ self[connectionSymbol].reconnectCounter = 0;
130
+ };
131
+
132
+ self[connectionSymbol].socket.close = function (event) {
133
+
134
+ if (self[manualCloseSymbol]) {
135
+ self[manualCloseSymbol] = false;
136
+ return;
137
+ }
138
+
139
+ if (reconnectEnabled && this[connectionSymbol].reconnectCounter < reconnectAttempts) {
140
+ setTimeout(() => {
141
+ self.connect();
142
+ }, reconnectTimeout * this[connectionSymbol].reconnectCounter);
143
+ }
144
+
145
+ };
146
+
147
+ self[connectionSymbol].socket.onerror = (error) => {
148
+
149
+ if (reconnectEnabled && self[connectionSymbol].reconnectCounter < reconnectAttempts) {
150
+ setTimeout(() => {
151
+ self.connect();
152
+ }, reconnectTimeout * this[connectionSymbol].reconnectCounter);
153
+ }
154
+
155
+ };
156
+ }
157
+
158
+ isConnected() {
159
+ return this[connectionSymbol].socket && this[connectionSymbol].socket.readyState === 1;
160
+ }
161
+
162
+ /**
163
+ * This method is called by the `instanceof` operator.
164
+ * @returns {symbol}
165
+ */
166
+ static get [instanceSymbol]() {
167
+ return Symbol.for("@schukai/monster/data/datasource/websocket");
168
+ }
169
+
170
+ /**
171
+ * @property {string} url=undefined Defines the resource that you wish to fetch.
172
+ * @property {Number} reconnect.timeout The timeout in milliseconds for the reconnect.
173
+ * @property {Number} reconnect.attempts The maximum number of reconnects.
174
+ * @property {Bool} reconnect.enabled If the reconnect is enabled.
175
+ * @property {Object} write={} Options
176
+ * @property {Object} write.mapping the mapping is applied before writing.
177
+ * @property {String} write.mapping.transformer Transformer to select the appropriate entries
178
+ * @property {Monster.Data.Datasource~exampleCallback[]} write.mapping.callback with the help of the callback, the structures can be adjusted before writing.
179
+ * @property {Object} write.report
180
+ * @property {String} write.report.path Path to validations
181
+ * @property {Object} write.sheathing
182
+ * @property {Object} write.sheathing.object Object to be wrapped
183
+ * @property {string} write.sheathing.path Path to the data
184
+ * @property {Object} read={} Options
185
+ * @property {Object} read.mapping the mapping is applied after reading.
186
+ * @property {String} read.mapping.transformer Transformer to select the appropriate entries
187
+ * @property {Monster.Data.Datasource~exampleCallback[]} read.mapping.callback with the help of the callback, the structures can be adjusted after reading.
188
+ */
189
+ get defaults() {
190
+ return Object.assign({}, super.defaults, {
191
+ url: undefined,
192
+ write: {
193
+ mapping: {
194
+ transformer: undefined,
195
+ callbacks: []
196
+ },
197
+ report: {
198
+ path: undefined
199
+ },
200
+ sheathing: {
201
+ object: undefined,
202
+ path: undefined,
203
+ },
204
+ },
205
+ read: {
206
+ mapping: {
207
+ transformer: undefined,
208
+ callbacks: []
209
+ },
210
+ },
211
+ reconnect: {
212
+ timeout: 1000,
213
+ attempts: 10,
214
+ enabled: true
215
+ }
216
+ });
217
+ }
218
+
219
+ /**
220
+ * This method closes the connection.
221
+ *
222
+ * @returns {Promise}
223
+ */
224
+ close() {
225
+ this[manualCloseSymbol]=true;
226
+ if (this[connectionSymbol].socket) {
227
+ this[connectionSymbol].socket.close();
228
+ }
229
+ return this;
230
+ }
231
+
232
+ /**
233
+ * @return {Promise}
234
+ * @throws {Error} the options does not contain a valid json definition
235
+ * @throws {Error} the data cannot be read
236
+ * @throws {TypeError} value is not an object
237
+ */
238
+ read() {
239
+ const self = this;
240
+ let response;
241
+
242
+ return new Promise((resolve, reject) => {
243
+ if (self[receiveQueueSymbol].isEmpty()) {
244
+ resolve();
245
+ }
246
+
247
+ while (!self[receiveQueueSymbol].isEmpty()) {
248
+
249
+ const event = self[receiveQueueSymbol].poll();
250
+ const body = event?.data;
251
+ if (!body) continue;
252
+
253
+ let obj;
254
+ try {
255
+ obj = JSON.parse(body);
256
+ } catch (e) {
257
+
258
+ let msg = 'the response does not contain a valid json (actual: ';
259
+
260
+ if (body.length > 100) {
261
+ msg += body.substring(0, 97) + '...';
262
+ } else {
263
+ msg += body;
264
+ }
265
+
266
+ msg += "; " + e.message + ')';
267
+
268
+ reject(msg);
269
+ }
270
+
271
+ let transformation = self.getOption('read.mapping.transformer');
272
+ if (transformation !== undefined) {
273
+ const pipe = new Pipe(transformation);
274
+
275
+ for (const callback of self.getOption('read.mapping.callbacks')) {
276
+ pipe.setCallback(callback.constructor.name, callback);
277
+ }
278
+
279
+ obj = pipe.run(obj);
280
+ }
281
+
282
+ self.set(obj);
283
+ return response;
284
+ }
285
+ })
286
+ }
287
+
288
+ /**
289
+ * @return {Promise}
290
+ */
291
+ write() {
292
+ const self = this;
293
+
294
+ let obj = self.get();
295
+ let transformation = self.getOption('write.mapping.transformer');
296
+ if (transformation !== undefined) {
297
+ const pipe = new Pipe(transformation);
298
+
299
+ for (const callback of self.getOption('write.mapping.callbacks')) {
300
+ pipe.setCallback(callback.constructor.name, callback);
301
+ }
302
+
303
+ obj = pipe.run(obj);
304
+ }
305
+
306
+ let sheathingObject = self.getOption('write.sheathing.object');
307
+ let sheathingPath = self.getOption('write.sheathing.path');
308
+ let reportPath = self.getOption('write.report.path');
309
+
310
+ if (sheathingObject && sheathingPath) {
311
+ const sub = obj;
312
+ obj = sheathingObject;
313
+ (new Pathfinder(obj)).setVia(sheathingPath, sub);
314
+ }
315
+
316
+ return new Promise((resolve, reject) => {
317
+
318
+ if (self[connectionSymbol].socket.readyState !== 1) {
319
+ reject('the socket is not ready');
320
+ }
321
+
322
+ self[connectionSymbol].socket.send(JSON.stringify(obj))
323
+ resolve();
324
+ });
325
+ }
326
+
327
+
328
+ /**
329
+ * @return {RestAPI}
330
+ */
331
+ getClone() {
332
+ const self = this;
333
+ return new Websocketdatasource(self[internalSymbol].getRealSubject()['options']);
334
+ }
335
+
336
+ }
337
+
@@ -17,6 +17,18 @@ import {Pathfinder} from "./pathfinder.mjs";
17
17
 
18
18
  export {Datasource}
19
19
 
20
+
21
+ /**
22
+ * This callback can be passed to a datasource and is used to adapt data structures.
23
+ *
24
+ * @callback Monster.Data.Datasource~exampleCallback
25
+ * @param {*} value Value
26
+ * @param {string} key Key
27
+ * @memberOf Monster.Data
28
+ * @see Monster.Data.Datasource
29
+ */
30
+
31
+
20
32
  /**
21
33
  * @private
22
34
  * @type {symbol}
@@ -59,6 +59,7 @@ export {
59
59
  ATTRIBUTE_EXPORTPARTS,
60
60
  ATTRIBUTE_HIDDEN,
61
61
  objectUpdaterLinkSymbol,
62
+ customElementUpdaterLinkSymbol
62
63
 
63
64
  }
64
65
 
@@ -223,6 +224,14 @@ const ATTRIBUTE_ERRORMESSAGE = ATTRIBUTE_PREFIX + 'error';
223
224
  */
224
225
  const objectUpdaterLinkSymbol = Symbol.for('@schukai/monster/dom/@@object-updater-link');
225
226
 
227
+ /**
228
+ * @memberOf Monster.DOM
229
+ * @type {symbol}
230
+ * @license AGPLv3
231
+ * @since 1.24.0
232
+ */
233
+ const customElementUpdaterLinkSymbol = Symbol.for('@schukai/monster/dom/custom-element@@options-updater-link');
234
+
226
235
  /**
227
236
  * @memberOf Monster.DOM
228
237
  * @type {string}
@@ -16,19 +16,26 @@ import {Observer} from "../types/observer.mjs";
16
16
  import {ProxyObserver} from "../types/proxyobserver.mjs";
17
17
  import {validateFunction, validateInstance, validateObject, validateString} from "../types/validate.mjs";
18
18
  import {clone} from "../util/clone.mjs";
19
- import {addAttributeToken, addToObjectLink, getLinkedObjects, hasObjectLink} from "./attributes.mjs";
19
+ import {addAttributeToken, getLinkedObjects, hasObjectLink} from "./attributes.mjs";
20
20
  import {
21
21
  ATTRIBUTE_DISABLED,
22
22
  ATTRIBUTE_ERRORMESSAGE,
23
23
  ATTRIBUTE_OPTIONS,
24
24
  ATTRIBUTE_OPTIONS_SELECTOR,
25
- objectUpdaterLinkSymbol
25
+ customElementUpdaterLinkSymbol
26
26
  } from "./constants.mjs";
27
27
  import {findDocumentTemplate, Template} from "./template.mjs";
28
- import {Updater} from "./updater.mjs";
28
+ import {addObjectWithUpdaterToElement} from "./updater.mjs";
29
29
  import {instanceSymbol} from '../constants.mjs';
30
30
 
31
- export {CustomElement, initMethodSymbol, assembleMethodSymbol, attributeObserverSymbol, registerCustomElement, assignUpdaterToElement, getSlottedElements}
31
+ export {
32
+ CustomElement,
33
+ initMethodSymbol,
34
+ assembleMethodSymbol,
35
+ attributeObserverSymbol,
36
+ registerCustomElement,
37
+ getSlottedElements
38
+ }
32
39
 
33
40
  /**
34
41
  * @memberOf Monster.DOM
@@ -460,7 +467,7 @@ class CustomElement extends HTMLElement {
460
467
  nodeList = elements
461
468
  }
462
469
 
463
- assignUpdaterToElement.call(self, nodeList, clone(self[internalSymbol].getRealSubject()['options']));
470
+ addObjectWithUpdaterToElement.call(self, nodeList, customElementUpdaterLinkSymbol, clone(self[internalSymbol].getRealSubject()['options']))
464
471
  return self;
465
472
  }
466
473
 
@@ -473,7 +480,7 @@ class CustomElement extends HTMLElement {
473
480
  */
474
481
  connectedCallback() {
475
482
  let self = this;
476
- if (!hasObjectLink(self, objectUpdaterLinkSymbol)) {
483
+ if (!hasObjectLink(self, customElementUpdaterLinkSymbol)) {
477
484
  self[assembleMethodSymbol]()
478
485
  }
479
486
  }
@@ -673,11 +680,11 @@ function initOptionObserver() {
673
680
  self.attachObserver(new Observer(function () {
674
681
 
675
682
  // not initialised
676
- if (!hasObjectLink(self, objectUpdaterLinkSymbol)) {
683
+ if (!hasObjectLink(self, customElementUpdaterLinkSymbol)) {
677
684
  return;
678
685
  }
679
686
  // inform every element
680
- const updaters = getLinkedObjects(self, objectUpdaterLinkSymbol);
687
+ const updaters = getLinkedObjects(self, customElementUpdaterLinkSymbol);
681
688
 
682
689
  for (const list of updaters) {
683
690
  for (const updater of list) {
@@ -935,44 +942,3 @@ function registerCustomElement(element) {
935
942
  getGlobalObject('customElements').define(element.getTag(), element);
936
943
  }
937
944
 
938
-
939
- /**
940
- *
941
- * @param element
942
- * @param object
943
- * @return {Promise[]}
944
- * @license AGPLv3
945
- * @since 1.23.0
946
- * @memberOf Monster.DOM
947
- */
948
- function assignUpdaterToElement(elements, object) {
949
-
950
- const updaters = new Set;
951
-
952
- if (elements instanceof NodeList) {
953
- elements = new Set([
954
- ...elements
955
- ])
956
- }
957
-
958
- let result = [];
959
-
960
- elements.forEach((element) => {
961
- if (!(element instanceof HTMLElement)) return;
962
- if ((element instanceof HTMLTemplateElement)) return;
963
-
964
- const u = new Updater(element, object)
965
- updaters.add(u);
966
-
967
- result.push(u.run().then(() => {
968
- return u.enableEventProcessing();
969
- }));
970
-
971
- });
972
-
973
- if (updaters.size > 0) {
974
- addToObjectLink(this, objectUpdaterLinkSymbol, updaters);
975
- }
976
-
977
- return result;
978
- }