@cocreate/render 1.45.6 → 1.46.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/package.json +1 -1
  3. package/src/index.js +1077 -1169
package/src/index.js CHANGED
@@ -25,10 +25,12 @@ import Actions from "@cocreate/actions";
25
25
  import Observer from "@cocreate/observer";
26
26
  import uuid from "@cocreate/uuid";
27
27
  import {
28
- queryElements,
29
- getValueFromObject,
30
- dotNotationToObject,
31
- ObjectId
28
+ queryElements,
29
+ getValueFromObject,
30
+ dotNotationToObject,
31
+ ObjectId,
32
+ safeParse,
33
+ processOperatorsAsync
32
34
  } from "@cocreate/utils";
33
35
  import "@cocreate/element-prototype";
34
36
  import "./index.css";
@@ -45,44 +47,44 @@ const elementSelector = "[render-query]";
45
47
  * - render-query: [Describe what this attribute does]
46
48
  *
47
49
  * @param {(Element|Element[]|HTMLCollection|null)} [element] - Optional. A single element, an array of elements, an HTMLCollection, or null.
48
- * - If an HTMLCollection or an array of elements is provided, each element in the collection/array is initialized.
49
- * - If a single element is provided, only that element is initialized.
50
- * - If null or omitted, the function queries and initializes all elements matching the 'elementSelector'.
50
+ * - If an HTMLCollection or an array of elements is provided, each element in the collection/array is initialized.
51
+ * - If a single element is provided, only that element is initialized.
52
+ * - If null or omitted, the function queries and initializes all elements matching the 'elementSelector'.
51
53
  */
52
54
  function init(element) {
53
- if (
54
- element &&
55
- !(element instanceof HTMLCollection) &&
56
- !Array.isArray(element)
57
- )
58
- element = [element];
59
- else if (!element) element = document.querySelectorAll(elementSelector);
60
-
61
- for (let i = 0; i < element.length; i++) {
62
- let source = sources.get(element[i]);
63
- if (!source) {
64
- sources.set(element[i], { element: element[i] });
65
- element[i].renderValue = async (data) =>
66
- await render({ source: element[i], data });
67
- element[i].getData = () => sources.get(element[i]).data;
68
- }
69
-
70
- let dataAttr = element[i].getAttribute("render-data");
71
-
72
- if (dataAttr) {
73
- try {
74
- // Parse the string into a usable object
75
- const parsedData = JSON.parse(dataAttr);
76
-
77
- // Ensure the method exists before calling it
78
- if (typeof element[i].renderValue === "function") {
79
- element[i].renderValue(parsedData);
80
- }
81
- } catch (error) {
82
- console.error("Failed to parse render-data:", error);
83
- }
84
- }
85
- }
55
+ if (
56
+ element &&
57
+ !(element instanceof HTMLCollection) &&
58
+ !Array.isArray(element)
59
+ )
60
+ element = [element];
61
+ else if (!element) element = document.querySelectorAll(elementSelector);
62
+
63
+ for (let i = 0; i < element.length; i++) {
64
+ let source = sources.get(element[i]);
65
+ if (!source) {
66
+ sources.set(element[i], { element: element[i] });
67
+ element[i].renderValue = async (data) =>
68
+ await render({ source: element[i], data });
69
+ element[i].getData = () => sources.get(element[i]).data;
70
+ }
71
+
72
+ let dataAttr = element[i].getAttribute("render-data");
73
+
74
+ if (dataAttr) {
75
+ try {
76
+ // Parse the string into a usable object
77
+ const parsedData = JSON.parse(dataAttr);
78
+
79
+ // Ensure the method exists before calling it
80
+ if (typeof element[i].renderValue === "function") {
81
+ element[i].renderValue(parsedData);
82
+ }
83
+ } catch (error) {
84
+ console.error("Failed to parse render-data:", error);
85
+ }
86
+ }
87
+ }
86
88
  }
87
89
 
88
90
  /**
@@ -101,1178 +103,1084 @@ function init(element) {
101
103
  * @param {boolean} [options.remove] - Flag to indicate if the rendering should remove elements instead of updating or appending.
102
104
  */
103
105
  async function render({
104
- source,
105
- element,
106
- selector,
107
- data,
108
- key,
109
- index,
110
- currentIndex,
111
- update,
112
- remove
106
+ source,
107
+ element,
108
+ selector,
109
+ data,
110
+ key,
111
+ index,
112
+ currentIndex,
113
+ update,
114
+ remove
113
115
  }) {
114
- if (!data || (!source && !data)) {
115
- return;
116
- }
117
-
118
- if (!element) {
119
- if (source instanceof HTMLElement) {
120
- if (selector || (selector = source.getAttribute("render-query"))) {
121
- element = queryElements({
122
- element: source,
123
- selector
124
- });
125
- } else if (source.children.length > 0) {
126
- element = Array.from(source.children).find((child) =>
127
- child.matches("template, [template], .template, [render]")
128
- );
129
- if (!element) {
130
- element = source.querySelector(
131
- "template, [template], .template, [render]"
132
- );
133
- }
134
- }
135
- } else if (selector) {
136
- element = queryElements({
137
- selector
138
- });
139
- }
140
-
141
- if (!element || (Array.isArray(element) && !element.length)) {
142
- return;
143
- }
144
- }
145
-
146
- if (!key) {
147
- if (source instanceof HTMLElement) {
148
- key =
149
- source.getAttribute("render") ||
150
- source.getAttribute("key") ||
151
- data.type;
152
- } else {
153
- key = data.type;
154
- }
155
- if (!key || key === "key") {
156
- key = "object";
157
- } else if (key === "{}" || (!key && data.method)) {
158
- key = data.method ? data.method.split(".")[0] : undefined;
159
- }
160
- if (!key) {
161
- return;
162
- }
163
- }
164
-
165
- let sourceData = sources.get(source);
166
- if (!sourceData) {
167
- sourceData = { element: source, data: { ...data } };
168
- sources.set(source, sourceData);
169
- } else if (sourceData.data) {
170
- sourceData.data = { ...data };
171
- } else {
172
- // TODO: Most effiecientway to comapre too objects or array of objects
173
- if (data === sourceData.data) return;
174
- sourceData.data = { ...data };
175
- }
176
-
177
- if (data.$filter) {
178
- index = index || data.$filter.startingIndex || data.$filter.index;
179
- update = update || data.$filter.update;
180
- remove = remove || data.$filter.remove;
181
- }
182
-
183
- if (
184
- !Array.isArray(element) &&
185
- !(element instanceof HTMLCollection) &&
186
- !(element instanceof NodeList)
187
- ) {
188
- element = [element];
189
- }
190
-
191
- for (let i = 0; i < element.length; i++) {
192
- let renderedNode = renderedNodes.get(element[i]);
193
- if (renderedNode) {
194
- if (
195
- renderedNode.clones &&
196
- renderedNode.source &&
197
- renderedNode.source.element
198
- ) {
199
- let limit =
200
- renderedNode.source.element.getAttribute("render-limit");
201
- if (limit && renderedNode.clones.size >= parseInt(limit))
202
- continue;
203
- }
204
- } else {
205
- renderedNode = {
206
- element: element[i],
207
- source: sourceData,
208
- clones: new Map()
209
- };
210
- renderedNodes.set(element[i], renderedNode);
211
- }
212
-
213
- let clones = renderedNode.clones; // || renderedNode.template.clones..
214
- if (!clones && renderedNode.template) {
215
- clones = renderedNode.template.clones;
216
- console.log("renderedNode.template.clones", clones);
217
- }
218
-
219
- key = element[i].getAttribute("render") || key;
220
- let renderedSource = renderedNode.source;
221
- if (!renderedSource) {
222
- if (renderedNode.parent && renderedNode.parent.template) {
223
- renderedSource = renderedNode.parent.template.source;
224
- }
225
- }
226
- let renderType;
227
- if (renderedSource && renderedSource.element) {
228
- renderType = renderedSource.element.getAttribute("render-type");
229
- }
230
-
231
- let clone;
232
- if (remove) {
233
- for (let j = 0; j < data[key].length; j++) {
234
- let cloneKey;
235
- if (key === "object") {
236
- cloneKey = data[key][j]._id;
237
- } else {
238
- cloneKey = data[key][j].name;
239
- }
240
-
241
- clone = clones.get(cloneKey);
242
- if (!clone) return;
243
-
244
- clones.delete(cloneKey);
245
- renderedNodes.delete(clone);
246
- clone.remove();
247
- }
248
- } else if (
249
- (key && (Array.isArray(data[key]) || renderType)) ||
250
- Array.isArray(data)
251
- ) {
252
- if (update) {
253
- for (let j = 0; j < data[key].length; j++) {
254
- if (key === "object") {
255
- clone = clones.get(data[key][j]._id);
256
- } else {
257
- clone = clones.get(data[key][j].name);
258
- }
259
-
260
- if (!currentIndex) currentIndex = data.$filter.currentIndex;
261
-
262
- if (!clone) return;
263
-
264
- await renderValues(clone, { object: data[key][j] });
265
- if (currentIndex >= 0)
266
- insertElement(renderedNode, clone, index, currentIndex);
267
- }
268
- } else {
269
- // TODO: if $auto here every subsequent clone will have same value, not replacing here will apply unique value to each clone
270
- if (key === "$auto")
271
- key = key.replace(/\$auto/g, uuid.generate(6));
272
-
273
- if (key) element[i].setAttribute("render", key);
274
-
275
- await renderTemplate(element[i], data, key, index);
276
- }
277
- } else {
278
- let renderAs = element[i].getAttribute("render-as") || key;
279
- await renderValues(element[i], data, key, renderAs);
280
- }
281
- }
282
- // Dispatch input and change events after rendering is complete
283
- if (source instanceof HTMLElement) {
284
- source.dispatchEvent(new Event("input"));
285
- source.dispatchEvent(new Event("change"));
286
- }
116
+ if (!data || (!source && !data)) {
117
+ return;
118
+ }
119
+
120
+ if (!element) {
121
+ if (source instanceof HTMLElement) {
122
+ if (selector || (selector = source.getAttribute("render-query"))) {
123
+ element = queryElements({
124
+ element: source,
125
+ selector
126
+ });
127
+ } else if (source.children.length > 0) {
128
+ element = Array.from(source.children).find((child) =>
129
+ child.matches("template, [template], .template, [render]")
130
+ );
131
+ if (!element) {
132
+ element = source.querySelector(
133
+ "template, [template], .template, [render]"
134
+ );
135
+ }
136
+ }
137
+ } else if (selector) {
138
+ element = queryElements({
139
+ selector
140
+ });
141
+ }
142
+
143
+ if (!element || (Array.isArray(element) && !element.length)) {
144
+ return;
145
+ }
146
+ }
147
+
148
+ if (!key) {
149
+ if (source instanceof HTMLElement) {
150
+ key =
151
+ source.getAttribute("render") ||
152
+ source.getAttribute("key") ||
153
+ data.type;
154
+ } else {
155
+ key = data.type;
156
+ }
157
+ if (!key || key === "key") {
158
+ key = "object";
159
+ } else if (key === "{}" || (!key && data.method)) {
160
+ key = data.method ? data.method.split(".")[0] : undefined;
161
+ }
162
+ if (!key) {
163
+ return;
164
+ }
165
+ }
166
+
167
+ let sourceData = sources.get(source);
168
+ if (!sourceData) {
169
+ sourceData = { element: source, data: { ...data } };
170
+ sources.set(source, sourceData);
171
+ } else if (sourceData.data) {
172
+ sourceData.data = { ...data };
173
+ } else {
174
+ // TODO: Most effiecientway to comapre too objects or array of objects
175
+ if (data === sourceData.data) return;
176
+ sourceData.data = { ...data };
177
+ }
178
+
179
+ if (data.$filter) {
180
+ index = index || data.$filter.startingIndex || data.$filter.index;
181
+ update = update || data.$filter.update;
182
+ remove = remove || data.$filter.remove;
183
+ }
184
+
185
+ if (
186
+ !Array.isArray(element) &&
187
+ !(element instanceof HTMLCollection) &&
188
+ !(element instanceof NodeList)
189
+ ) {
190
+ element = [element];
191
+ }
192
+
193
+ for (let i = 0; i < element.length; i++) {
194
+ let renderedNode = renderedNodes.get(element[i]);
195
+ if (renderedNode) {
196
+ if (
197
+ renderedNode.clones &&
198
+ renderedNode.source &&
199
+ renderedNode.source.element
200
+ ) {
201
+ let limit =
202
+ renderedNode.source.element.getAttribute("render-limit");
203
+ if (limit && renderedNode.clones.size >= parseInt(limit))
204
+ continue;
205
+ }
206
+ } else {
207
+ renderedNode = {
208
+ element: element[i],
209
+ source: sourceData,
210
+ clones: new Map()
211
+ };
212
+ renderedNodes.set(element[i], renderedNode);
213
+ }
214
+
215
+ let clones = renderedNode.clones; // || renderedNode.template.clones..
216
+ if (!clones && renderedNode.template) {
217
+ clones = renderedNode.template.clones;
218
+ console.log("renderedNode.template.clones", clones);
219
+ }
220
+
221
+ key = element[i].getAttribute("render") || key;
222
+ let renderedSource = renderedNode.source;
223
+ if (!renderedSource) {
224
+ if (renderedNode.parent && renderedNode.parent.template) {
225
+ renderedSource = renderedNode.parent.template.source;
226
+ }
227
+ }
228
+ let renderType;
229
+ if (renderedSource && renderedSource.element) {
230
+ renderType = renderedSource.element.getAttribute("render-type");
231
+ }
232
+
233
+ let clone;
234
+ if (remove) {
235
+ for (let j = 0; j < data[key].length; j++) {
236
+ let cloneKey;
237
+ if (key === "object") {
238
+ cloneKey = data[key][j]._id;
239
+ } else {
240
+ cloneKey = data[key][j].name;
241
+ }
242
+
243
+ clone = clones.get(cloneKey);
244
+ if (!clone) return;
245
+
246
+ clones.delete(cloneKey);
247
+ renderedNodes.delete(clone);
248
+ clone.remove();
249
+ }
250
+ } else if (
251
+ (key && (Array.isArray(data[key]) || renderType)) ||
252
+ Array.isArray(data)
253
+ ) {
254
+ if (update) {
255
+ for (let j = 0; j < data[key].length; j++) {
256
+ if (key === "object") {
257
+ clone = clones.get(data[key][j]._id);
258
+ } else {
259
+ clone = clones.get(data[key][j].name);
260
+ }
261
+
262
+ if (!currentIndex) currentIndex = data.$filter.currentIndex;
263
+
264
+ if (!clone) return;
265
+
266
+ await renderValues(clone, { object: data[key][j] });
267
+ if (currentIndex >= 0)
268
+ insertElement(renderedNode, clone, index, currentIndex);
269
+ }
270
+ } else {
271
+ // TODO: if $auto here every subsequent clone will have same value, not replacing here will apply unique value to each clone
272
+ if (key === "$auto")
273
+ key = key.replace(/\$auto/g, uuid.generate(6));
274
+
275
+ if (key) element[i].setAttribute("render", key);
276
+
277
+ await renderTemplate(element[i], data, key, index);
278
+ }
279
+ } else {
280
+ let renderAs = element[i].getAttribute("render-as") || key;
281
+ await renderValues(element[i], data, key, renderAs);
282
+ }
283
+ }
284
+ // Dispatch input and change events after rendering is complete
285
+ if (source instanceof HTMLElement) {
286
+ source.dispatchEvent(new Event("input"));
287
+ source.dispatchEvent(new Event("change"));
288
+ }
287
289
  }
288
290
 
289
291
  async function renderTemplate(template, data, key, index, keyPath) {
290
- // if (!key)
291
- // key = template.getAttribute('render')
292
- if (!(template instanceof HTMLElement)) {
293
- console.log("template not an element but should be")
294
- }
295
- let templateData = renderedNodes.get(template);
296
- if (!templateData) {
297
- templateData = {element: template, clones: new Map() };
298
- renderedNodes.set(template, templateData);
299
- }
300
-
301
- if (!templateData.parent && !templateData.source) {
302
- let parentRender = template.parentElement.closest("[render]")
303
- if (parentRender || template.source)
304
- templateData.parent = renderedNodes.get(parentRender) || template.source
305
- else
306
- console.log("template parent missing is there no parent or is this an error? and source is", templateData.source)
307
- }
308
-
309
- if(!templateData.source && templateData.parent && templateData.parent.source){
310
- templateData.source = templateData.parent.source
311
- }
312
-
313
- if (!templateData.keyPath) {
314
- if (keyPath) {
315
- templateData.keyPath = keyPath;
316
- } else if (templateData.parent && templateData.parent.keyPath) {
317
- templateData.keyPath = templateData.parent.keyPath;
318
- } else if (key) {
319
- templateData.keyPath = key;
320
- }
321
- }
322
-
323
- let renderData;
324
- if (key) {
325
- renderData = getRenderValue(templateData.element, data, key);
326
- }
327
-
328
- if (!renderData) {
329
- renderData = data;
330
- }
331
-
332
- // else if (Array.isArray(data)) {
333
- // renderData = data;
334
- // }
335
-
336
- // if (!renderData && data) {
337
- // if (Array.isArray(data)) {
338
- // renderData = data;
339
- // } else {
340
- // renderData = [data];
341
- // }
342
- // } else return;
343
-
344
- templateData.renderData = renderData;
345
- let el = templateData.element;
346
- if (el.nodeType !== 1) {
347
- el = templateData.parent.element;
348
- }
349
-
350
- let renderAs = templateData.renderAs
351
- if (!templateData.renderAs) {
352
- renderAs =
353
- el.getAttribute("render-as") ||
354
- el.getAttribute("render") ||
355
- key;
356
- templateData.renderAs = renderAs;
357
- }
358
-
359
- let renderType;
360
- if (templateData.source && templateData.source.element)
361
- renderType = templateData.source.element.getAttribute("render-type");
362
-
363
- let renderReverse;
364
- if (templateData.source && templateData.source.element) {
365
- renderReverse =
366
- templateData.source.element.getAttribute("render-reverse");
367
- if (!renderReverse)
368
- renderReverse = el.getAttribute("render-reverse");
369
- }
370
-
371
- let exclude = el.getAttribute("render-exclude") || "";
372
- if (exclude) {
373
- exclude = exclude.replace(/ /g, "").split(",");
374
- }
375
- let reference = el.getAttribute("render-reference");
376
-
377
- let isInsert = data.$filter && (data.$filter.create || data.$filter.update);
378
- if (renderType !== "object") {
379
- if ((!isInsert && !index) || data.$filter.overwrite) {
380
- if (!templateData.clones) {
381
- return
382
- if (templateData.template) {
383
- templateData.clones = templateData.template.clones
384
- } else if (templateData.parent && templateData.parent.template) {
385
- templateData.clones = templateData.parent.template.clones
386
- }
387
- }
388
-
389
- // if (!templateData.clones) {
390
- // templateData
391
- // templateData = templateData.templateData;
392
- // }
393
- for (const [key, element] of templateData.clones) {
394
- renderedNodes.delete(element);
395
- element.remove();
396
- templateData.clones.delete(key);
397
- }
398
- } //
399
- // else if (index) {
400
- // updates data that has already been rendered
401
- // templateData.data = dotNotationToObject(renderData, templateData.data)
402
- // }
403
- }
404
-
405
- if ((key && !Array.isArray(renderData)) || renderType === "object") {
406
- if (renderType && Array.isArray(renderData) && renderData.length === 1)
407
- renderData = renderData[0];
408
-
409
- const keys = Object.keys(renderData);
410
- for (let i = 0; i < keys.length; i++) {
411
- let clone = templateData.clones.get(keys[i]);
412
- clone = renderedNodes.get(clone);
413
-
414
- if (
415
- exclude.includes(keys[i]) ||
416
- (reference === "false" &&
417
- ["$storage", "$database", "$array"].includes(key))
418
- ) {
419
- if (clone) {
420
- renderedNodes.delete(clone.element);
421
- clone.element.remove();
422
- templateData.clones.delete(keys[i]);
423
- }
424
- continue;
425
- }
426
-
427
- let value = renderData[keys[i]];
428
- let type = "string";
429
-
430
- if (Array.isArray(value)) type = "array";
431
- else if (typeof value == "object") type = "object";
432
-
433
- let Data = { [renderAs]: { key: keys[i], value, type } };
434
-
435
- if (!clone) {
436
- clone = cloneTemplate(templateData);
437
- } else {
438
- if (clone.renderedValue === value) {
439
- continue;
440
- }
441
- }
442
- clone.renderedValue = value;
443
- // let clone = cloneTemplate(templateData);
444
-
445
- let renderedKey = key.split(".");
446
- renderedKey = renderedKey[renderedKey.length - 1];
447
- //renderedKey needs to remove the parent.renderAs/key
448
-
449
- clone.key = keys[i];
450
- clone.keyPath = templateData.keyPath + "." + renderedKey;
451
- clone.parentKey = renderedKey;
452
- clone.renderKey = key;
453
- clone.element.setAttribute("renderedKey", keys[i]);
454
- await renderValues(clone.element, Data, keys[i], renderAs);
455
- insertElement(templateData, clone.element, index);
456
- }
457
- } else {
458
- if (!key && !Array.isArray(renderData)) {
459
- key = "data";
460
- renderData = getValueFromObject(renderData, key);
461
- if (!renderAs) renderAs = key;
462
- }
463
-
464
- if (!renderData) {
465
- let clone = cloneTemplate(templateData);
466
- clone.keyPath = templateData.keyPath;
467
- await renderValues(clone.element, data, key, renderAs);
468
- insertElement(templateData, clone.element, index);
469
- } else {
470
- if (!Array.isArray(renderData)) renderData = [renderData];
471
-
472
- for (let i = 0; i < renderData.length; i++) {
473
- let clone = cloneTemplate(templateData);
474
-
475
- let test = clone.element.getAttribute("render-as");
476
- if (test) renderAs = test;
477
-
478
- clone.keyPath = templateData.keyPath || "" + `[${i}]`;
479
-
480
- let object;
481
- if (
482
- typeof renderData[i] === "object" &&
483
- renderData[i] !== null
484
- ) {
485
- object = { ...renderData[i] };
486
- } else {
487
- object = renderData[i];
488
- }
489
-
490
- for (let j = 0; j < exclude.length; j++)
491
- delete object[exclude[j]];
492
-
493
- if (reference === "false") {
494
- delete object.$storage;
495
- delete object.$database;
496
- delete object.$array;
497
- }
498
-
499
- if (renderAs) {
500
- object = { [renderAs]: object };
501
- if (renderAs.includes("."))
502
- object = dotNotationToObject(object);
503
- } else object = object;
504
-
505
- let index;
506
- if (key !== "data") index = i;
507
-
508
- clone.renderData = object
509
- clone.index = index
510
- await renderValues(
511
- clone.element,
512
- object,
513
- key,
514
- renderAs,
515
- null,
516
- null,
517
- index
518
- );
519
- insertElement(
520
- templateData,
521
- clone.element,
522
- index,
523
- "",
524
- data,
525
- renderReverse
526
- );
527
- }
528
- }
529
- }
292
+ if (!(template instanceof HTMLElement)) {
293
+ console.log("template not an element but should be")
294
+ }
295
+ let templateData = renderedNodes.get(template);
296
+ if (!templateData) {
297
+ templateData = {element: template, clones: new Map() };
298
+ renderedNodes.set(template, templateData);
299
+ }
300
+
301
+ if (!templateData.parent && !templateData.source) {
302
+ let parentRender = template.parentElement.closest("[render]")
303
+ if (parentRender || template.source)
304
+ templateData.parent = renderedNodes.get(parentRender) || template.source
305
+ else
306
+ console.log("template parent missing is there no parent or is this an error? and source is", templateData.source)
307
+ }
308
+
309
+ if(!templateData.source && templateData.parent && templateData.parent.source){
310
+ templateData.source = templateData.parent.source
311
+ }
312
+
313
+ if (!templateData.keyPath) {
314
+ if (keyPath) {
315
+ templateData.keyPath = keyPath;
316
+ } else if (templateData.parent && templateData.parent.keyPath) {
317
+ templateData.keyPath = templateData.parent.keyPath;
318
+ } else if (key) {
319
+ templateData.keyPath = key;
320
+ }
321
+ }
322
+
323
+ let renderData;
324
+ if (key) {
325
+ renderData = getRenderValue(templateData.element, data, key);
326
+ }
327
+
328
+ if (!renderData) {
329
+ renderData = data;
330
+ }
331
+
332
+ templateData.renderData = renderData;
333
+ let el = templateData.element;
334
+ if (el.nodeType !== 1) {
335
+ el = templateData.parent.element;
336
+ }
337
+
338
+ let renderAs = templateData.renderAs
339
+ if (!templateData.renderAs) {
340
+ renderAs =
341
+ el.getAttribute("render-as") ||
342
+ el.getAttribute("render") ||
343
+ key;
344
+ templateData.renderAs = renderAs;
345
+ }
346
+
347
+ let renderType;
348
+ if (templateData.source && templateData.source.element)
349
+ renderType = templateData.source.element.getAttribute("render-type");
350
+
351
+ let renderReverse;
352
+ if (templateData.source && templateData.source.element) {
353
+ renderReverse =
354
+ templateData.source.element.getAttribute("render-reverse");
355
+ if (renderReverse === null)
356
+ renderReverse = el.getAttribute("render-reverse");
357
+ }
358
+
359
+ let exclude = el.getAttribute("render-exclude") || "";
360
+ if (exclude) {
361
+ exclude = exclude.replace(/ /g, "").split(",");
362
+ }
363
+ let reference = el.getAttribute("render-reference");
364
+
365
+ let isInsert = data.$filter && (data.$filter.create || data.$filter.update);
366
+ if (renderType !== "object") {
367
+ if ((!isInsert && !index) || data.$filter.overwrite) {
368
+ if (!templateData.clones) {
369
+ return
370
+ if (templateData.template) {
371
+ templateData.clones = templateData.template.clones
372
+ } else if (templateData.parent && templateData.parent.template) {
373
+ templateData.clones = templateData.parent.template.clones
374
+ }
375
+ }
376
+
377
+ for (const [key, element] of templateData.clones) {
378
+ renderedNodes.delete(element);
379
+ element.remove();
380
+ templateData.clones.delete(key);
381
+ }
382
+ }
383
+ }
384
+
385
+ if ((key && !Array.isArray(renderData)) || renderType === "object") {
386
+ if (renderType && Array.isArray(renderData) && renderData.length === 1)
387
+ renderData = renderData[0];
388
+
389
+ const keys = Object.keys(renderData);
390
+ for (let i = 0; i < keys.length; i++) {
391
+ let clone = templateData.clones.get(keys[i]);
392
+ clone = renderedNodes.get(clone);
393
+
394
+ if (
395
+ exclude.includes(keys[i]) ||
396
+ (reference === "false" &&
397
+ ["$storage", "$database", "$array"].includes(key))
398
+ ) {
399
+ if (clone) {
400
+ renderedNodes.delete(clone.element);
401
+ clone.element.remove();
402
+ templateData.clones.delete(keys[i]);
403
+ }
404
+ continue;
405
+ }
406
+
407
+ let value = renderData[keys[i]];
408
+ let type = "string";
409
+
410
+ if (Array.isArray(value)) type = "array";
411
+ else if (typeof value == "object") type = "object";
412
+
413
+ let Data = { [renderAs]: { key: keys[i], value, type } };
414
+
415
+ if (!clone) {
416
+ clone = cloneTemplate(templateData);
417
+ } else {
418
+ if (clone.renderedValue === value) {
419
+ continue;
420
+ }
421
+ }
422
+ clone.renderedValue = value;
423
+
424
+ let renderedKey = key.split(".");
425
+ renderedKey = renderedKey[renderedKey.length - 1];
426
+
427
+ clone.key = keys[i];
428
+ clone.keyPath = templateData.keyPath + "." + renderedKey;
429
+ clone.parentKey = renderedKey;
430
+ clone.renderKey = key;
431
+ clone.element.setAttribute("renderedKey", keys[i]);
432
+ await renderValues(clone.element, Data, keys[i], renderAs);
433
+ insertElement(templateData, clone.element, index);
434
+ }
435
+ } else {
436
+ if (!key && !Array.isArray(renderData)) {
437
+ key = "data";
438
+ renderData = getValueFromObject(renderData, key);
439
+ if (!renderAs) renderAs = key;
440
+ }
441
+
442
+ if (!renderData) {
443
+ let clone = cloneTemplate(templateData);
444
+ clone.keyPath = templateData.keyPath;
445
+ await renderValues(clone.element, data, key, renderAs);
446
+ insertElement(templateData, clone.element, index);
447
+ } else {
448
+ if (!Array.isArray(renderData)) renderData = [renderData];
449
+
450
+ for (let i = 0; i < renderData.length; i++) {
451
+ let clone = cloneTemplate(templateData);
452
+
453
+ let test = clone.element.getAttribute("render-as");
454
+ if (test) renderAs = test;
455
+
456
+ clone.keyPath = templateData.keyPath || "" + `[${i}]`;
457
+
458
+ let object;
459
+ if (
460
+ typeof renderData[i] === "object" &&
461
+ renderData[i] !== null
462
+ ) {
463
+ object = { ...renderData[i] };
464
+ } else {
465
+ object = renderData[i];
466
+ }
467
+
468
+ for (let j = 0; j < exclude.length; j++)
469
+ delete object[exclude[j]];
470
+
471
+ if (reference === "false") {
472
+ delete object.$storage;
473
+ delete object.$database;
474
+ delete object.$array;
475
+ }
476
+
477
+ if (renderAs) {
478
+ object = { [renderAs]: object };
479
+ if (renderAs.includes("."))
480
+ object = dotNotationToObject(object);
481
+ } else object = object;
482
+
483
+ let index;
484
+ if (key !== "data") index = i;
485
+
486
+ clone.renderData = object
487
+ clone.index = index
488
+ await renderValues(
489
+ clone.element,
490
+ object,
491
+ key,
492
+ renderAs,
493
+ null,
494
+ null,
495
+ index
496
+ );
497
+ insertElement(
498
+ templateData,
499
+ clone.element,
500
+ index,
501
+ "",
502
+ data,
503
+ renderReverse
504
+ );
505
+ }
506
+ }
507
+ }
530
508
  }
531
509
 
532
510
  function cloneTemplate(template) {
533
- let clone = template.element.cloneNode(true);
534
- let cloneTagName = clone.tagName;
535
-
536
- if (clone.tagName == "TEMPLATE") {
537
- clone = template.element.content.firstElementChild;
538
- for (let attribute of template.element.attributes) {
539
- clone.setAttribute(attribute.name, attribute.value || "");
540
- }
541
- } else {
542
- clone.classList.remove("template");
543
- clone.removeAttribute("template");
544
- }
545
-
546
- clone.setAttribute("render-clone", "");
547
-
548
- let renderAs = clone.getAttribute("render-as");
549
- if (renderAs === "$auto") {
550
- renderAs = uuid.generate(6);
551
- clone = clone.outerHTML.replace(/\$auto/g, renderAs);
552
- }
553
-
554
- if (typeof clone === "string") {
555
- // TODO: Some elements are only allowed a specific element, need to find these elements and confirm proper rendering.
556
- let container;
557
- if (cloneTagName === "TR") container = document.createElement("tbody");
558
- else container = document.createElement("div");
559
-
560
- container.innerHTML = clone;
561
- clone = container.firstChild;
562
- container.remove();
563
- }
564
-
565
- let renderedNode = { template, element: clone };
566
- renderedNodes.set(clone, renderedNode);
567
- return renderedNode;
511
+ let clone = template.element.cloneNode(true);
512
+ let cloneTagName = clone.tagName;
513
+
514
+ if (clone.tagName == "TEMPLATE") {
515
+ clone = template.element.content.firstElementChild;
516
+ for (let attribute of template.element.attributes) {
517
+ clone.setAttribute(attribute.name, attribute.value || "");
518
+ }
519
+ } else {
520
+ clone.classList.remove("template");
521
+ clone.removeAttribute("template");
522
+ }
523
+
524
+ clone.setAttribute("render-clone", "");
525
+
526
+ let renderAs = clone.getAttribute("render-as");
527
+ if (renderAs === "$auto") {
528
+ renderAs = uuid.generate(6);
529
+ clone = clone.outerHTML.replace(/\$auto/g, renderAs);
530
+ }
531
+
532
+ if (typeof clone === "string") {
533
+ // TODO: Some elements are only allowed a specific element, need to find these elements and confirm proper rendering.
534
+ let container;
535
+ if (cloneTagName === "TR") container = document.createElement("tbody");
536
+ else container = document.createElement("div");
537
+
538
+ container.innerHTML = clone;
539
+ clone = container.firstChild;
540
+ container.remove();
541
+ }
542
+
543
+ let renderedNode = { template, element: clone };
544
+ renderedNodes.set(clone, renderedNode);
545
+ return renderedNode;
568
546
  }
569
547
 
570
548
  function insertElement(
571
- template,
572
- element,
573
- index,
574
- currentIndex,
575
- data,
576
- renderReverse
549
+ template,
550
+ element,
551
+ index,
552
+ currentIndex,
553
+ data,
554
+ renderReverse
577
555
  ) {
578
- let eid = element.getAttribute("eid");
579
- if (!eid) {
580
- eid = uuid.generate(6);
581
- element.setAttribute("eid", eid);
582
- }
583
-
584
- if (index !== null && index >= 0) {
585
- if (!template.clones) template = template.template;
586
- // const clones = Array.from(template.clones);
587
-
588
- let item;
589
- if (!currentIndex && currentIndex !== 0) {
590
- if (template.clones.has(eid)) return;
591
- item = [eid, element];
592
- }
593
-
594
- const clones = Array.from(template.clones);
595
-
596
- if (currentIndex || currentIndex === 0) {
597
- item = clones.splice(currentIndex, 1)[0];
598
- }
599
-
600
- if (data && data.$filter && data.$filter.startingIndex)
601
- index += data.$filter.startingIndex;
602
- clones.splice(index, 0, item); // Insert item into clones at the specified index
603
-
604
- if (renderReverse) {
605
- // Chat-specific logic: reverse rendering but still inserting based on sorting
606
-
607
- // If we're rendering in reverse order, we want to respect the insertion index
608
- if (clones[index + 1] && clones[index + 1][1] !== element) {
609
- // Insert before the next element (reverse order means newer items come before older ones)
610
- clones[index + 1][1].insertAdjacentElement("afterend", element);
611
- } else if (clones[index] && clones[index][1] !== element) {
612
- // Insert after the current element if there's no next element
613
- clones[index][1].insertAdjacentElement("beforeend", element);
614
- } else {
615
- // Fallback: insert before the template if clones are empty or undefined
616
- template.element.insertAdjacentElement("afterend", element);
617
- }
618
- } else {
619
- // Non-chat logic: handle ascending or descending order as usual
620
- if (clones[index + 1] && clones[index + 1][1] !== element) {
621
- // Insert before the next element
622
- clones[index + 1][1].insertAdjacentElement(
623
- "beforebegin",
624
- element
625
- );
626
- } else if (clones[index] && clones[index][1] !== element) {
627
- // Insert after the current element if there's no next element
628
- clones[index][1].insertAdjacentElement("afterend", element);
629
- } else {
630
- // Fallback: insert before the template if clones are empty or undefined
631
- template.element.insertAdjacentElement("beforebegin", element);
632
- }
633
- }
634
-
635
- template.clones = new Map(clones);
636
- } else {
637
- template.clones.set(eid, element);
638
- template.element.insertAdjacentElement("beforebegin", element);
639
- }
556
+ let eid = element.getAttribute("eid");
557
+ if (!eid) {
558
+ eid = uuid.generate(6);
559
+ element.setAttribute("eid", eid);
560
+ }
561
+
562
+ if (index !== null && index >= 0) {
563
+ if (!template.clones) template = template.template;
564
+
565
+ let item;
566
+ if (!currentIndex && currentIndex !== 0) {
567
+ if (template.clones.has(eid)) return;
568
+ item = [eid, element];
569
+ }
570
+
571
+ const clones = Array.from(template.clones);
572
+
573
+ if (currentIndex || currentIndex === 0) {
574
+ item = clones.splice(currentIndex, 1)[0];
575
+ }
576
+
577
+ if (data && data.$filter && data.$filter.startingIndex)
578
+ index += data.$filter.startingIndex;
579
+ clones.splice(index, 0, item); // Insert item into clones at the specified index
580
+
581
+ if (renderReverse !== null && renderReverse !== "false" ) {
582
+ // Chat-specific logic: reverse rendering but still inserting based on sorting
583
+ if (clones[index + 1] && clones[index + 1][1] !== element) {
584
+ clones[index + 1][1].insertAdjacentElement("afterend", element);
585
+ } else if (clones[index] && clones[index][1] !== element) {
586
+ clones[index][1].insertAdjacentElement("beforeend", element);
587
+ } else {
588
+ template.element.insertAdjacentElement("afterend", element);
589
+ }
590
+ } else {
591
+ // Non-chat logic: handle ascending or descending order as usual
592
+ if (clones[index + 1] && clones[index + 1][1] !== element) {
593
+ clones[index + 1][1].insertAdjacentElement(
594
+ "beforebegin",
595
+ element
596
+ );
597
+ } else if (clones[index] && clones[index][1] !== element) {
598
+ clones[index][1].insertAdjacentElement("afterend", element);
599
+ } else {
600
+ template.element.insertAdjacentElement("beforebegin", element);
601
+ }
602
+ }
603
+
604
+ template.clones = new Map(clones);
605
+ } else {
606
+ template.clones.set(eid, element);
607
+ template.element.insertAdjacentElement("beforebegin", element);
608
+ }
640
609
  }
641
610
 
642
611
  async function renderValues(node, data, key, renderAs, keyPath, parent, index) {
643
- if (!data) return;
644
-
645
- let renderedNode = renderedNodes.get(node);
646
- if (!renderedNode) renderedNode = { key, renderAs };
647
-
648
- if (!renderedNode.key) renderedNode.key = key;
649
- else if (!key) key = renderedNode.key;
650
-
651
- if (!renderedNode.renderAs) renderedNode.renderAs = renderAs;
652
- else if (!renderAs) renderAs = renderedNode.renderAs;
653
-
654
- if (keyPath) renderedNode.keyPath = keyPath;
655
- else if (renderedNode.keyPath) keyPath = renderedNode.keyPath;
656
-
657
- if (parent) renderedNode.parent = parent;
658
-
659
- if (node.nodeType == 1) {
660
- if (node.hasAttribute("render-clone")) {
661
- parent = renderedNode;
662
-
663
- for (let eid of ["_id", "name", "key"]) {
664
- if (renderAs) eid = data[renderAs][eid];
665
- else eid = data[eid];
666
-
667
- if (!eid) continue;
668
-
669
- let oldEid = renderedNode.eid;
670
- let temp = renderedNode.template;
671
- if (!temp) {
672
- console.log("temp could not be found");
673
- } else if (!temp.clones) {
674
- if (temp.template) temp = temp.template;
675
- else console.log(temp);
676
-
677
- if (oldEid && oldEid !== eid) temp.clones.delete(oldEid);
678
-
679
- temp.clones.set(eid, node);
680
- }
681
-
682
- renderedNode.eid = eid;
683
-
684
- node.setAttribute("eid", eid);
685
- break;
686
- }
687
- }
688
-
689
- // Array.from(node.attributes).forEach(attr => {
690
- for (let attr of node.attributes) {
691
- let name = attr.name;
692
- let value = attr.value;
693
-
694
- let renderedAttribute = renderedNodes.get(attr);
695
- if (!renderedAttribute) {
696
- renderedAttribute = {
697
- placeholder: { name, value },
698
- key,
699
- renderAs,
700
- parent: renderedNode
701
- };
702
- }
703
-
704
- let namePlaceholder = renderedAttribute.placeholder.name || name;
705
- let valuePlaceholder = renderedAttribute.placeholder.value || value;
706
-
707
- name = await renderValue(
708
- attr,
709
- data,
710
- namePlaceholder,
711
- renderAs,
712
- renderedAttribute,
713
- index
714
- );
715
- value = await renderValue(
716
- attr,
717
- data,
718
- valuePlaceholder,
719
- renderAs,
720
- renderedAttribute,
721
- index
722
- );
723
- if (namePlaceholder.includes("{{") && name) {
724
- const attributes = name.match(/([^\s]+="[^"]*"|[^\s]+)/g) || [];
725
- attributes.forEach((attr) => {
726
- let [attributeName, attributeValue] = attr.split("=");
727
- attributeValue = attributeValue
728
- ? attributeValue.replace(/"/g, "")
729
- : "";
730
- node.setAttribute(attributeName, attributeValue);
731
- });
732
- } else if (name === undefined || name === null || name === "") {
733
- renderedNodes.delete(attr);
734
- node.removeAttribute(attr.name);
735
- } else if (
736
- name &&
737
- (value || value === "") &&
738
- (name !== attr.name || value !== attr.value)
739
- )
740
- node.setAttribute(name, value);
741
- }
742
- // });
743
-
744
- if (CoCreate.state) {
745
- if (node.hasAttribute("[state_id]"))
746
- CoCreate.state.initElement(node);
747
- }
748
-
749
- if (node.tagName === "SCRIPT" && node.src) {
750
- if (
751
- node.src.includes("CoCreate.js") ||
752
- node.src.includes("CoCreate.min.js")
753
- ) {
754
- node.remove();
755
- return;
756
- }
757
- }
758
-
759
- if (node.tagName === "LINK" && node.href) {
760
- if (
761
- node.href.includes("CoCreate.css") ||
762
- node.href.includes("CoCreate.min.css")
763
- ) {
764
- node.remove();
765
- return;
766
- }
767
- }
768
- if (node.hasAttribute("render") && !node.hasAttribute("render-clone")) {
769
- let renderKey = node.getAttribute("render") || key
770
- renderTemplate(node, data, renderKey);
771
- } else if (node.childNodes.length > 0) {
772
- // Array.from(node.childNodes).forEach(childNode => {
773
- for (let childNode of node.childNodes) {
774
- await renderValues(
775
- childNode,
776
- data,
777
- key,
778
- renderAs,
779
- keyPath,
780
- parent,
781
- index
782
- );
783
- }
784
- // });
785
- }
786
- } else if (node.nodeType == 3) {
787
- let valueType = node.parentElement.getAttribute("value-type");
788
-
789
- let textContent, text;
790
-
791
- if (!renderedNode.placeholder && node.textContent.match(/{{(.*?)}}/))
792
- renderedNode.placeholder = node.textContent;
793
-
794
- if (!renderedNode.placeholder) return;
795
- textContent = renderedNode.placeholder || node.textContent;
796
-
797
- text = await renderValue(
798
- node,
799
- data,
800
- textContent,
801
- renderAs,
802
- renderedNode,
803
- index
804
- );
805
-
806
- if (text || text == "") {
807
- if (text != renderedNode.text) {
808
- renderedNode.text = text;
809
-
810
- if (
811
- valueType == "text" ||
812
- valueType == "string" ||
813
- valueType != "html"
814
- ) {
815
- node.textContent = text;
816
- } else {
817
- const newNode = document.createElement("div");
818
- newNode.innerHTML = text;
819
- let parentElement = node.parentElement;
820
-
821
- let renderedParent = renderedNodes.get(parentElement);
822
- if (!renderedParent) {
823
- renderedParent = {
824
- placeholder: textContent,
825
- key,
826
- renderAs
827
- };
828
- }
829
- renderedParent.text = text;
830
- for (let newChild of newNode.childNodes) {
831
- renderedNode.element = newChild;
832
- renderedNodes.set(newChild, renderedNode);
833
- }
834
- renderedNodes.delete(node);
835
- node.replaceWith(...newNode.childNodes);
836
- }
837
-
838
- if (node.childNodes.length > 0) {
839
- // Array.from(node.childNodes).forEach(childNode => {
840
- for (let childNode of node.childNodes) {
841
- await renderValues(
842
- childNode,
843
- data,
844
- key,
845
- renderAs,
846
- keyPath,
847
- parent,
848
- index
849
- );
850
- }
851
- // });
852
- }
853
- }
854
- }
855
- }
612
+ if (!data) return;
613
+
614
+ let renderedNode = renderedNodes.get(node);
615
+ if (!renderedNode) renderedNode = { key, renderAs };
616
+
617
+ if (!renderedNode.key) renderedNode.key = key;
618
+ else if (!key) key = renderedNode.key;
619
+
620
+ if (!renderedNode.renderAs) renderedNode.renderAs = renderAs;
621
+ else if (!renderAs) renderAs = renderedNode.renderAs;
622
+
623
+ if (keyPath) renderedNode.keyPath = keyPath;
624
+ else if (renderedNode.keyPath) keyPath = renderedNode.keyPath;
625
+
626
+ if (parent) renderedNode.parent = parent;
627
+
628
+ if (node.nodeType == 1) {
629
+ if (node.hasAttribute("render-clone")) {
630
+ parent = renderedNode;
631
+
632
+ for (let eid of ["_id", "name", "key"]) {
633
+ if (renderAs) eid = data[renderAs][eid];
634
+ else eid = data[eid];
635
+
636
+ if (!eid) continue;
637
+
638
+ let oldEid = renderedNode.eid;
639
+ let temp = renderedNode.template;
640
+ if (!temp) {
641
+ console.log("temp could not be found");
642
+ } else if (!temp.clones) {
643
+ if (temp.template) temp = temp.template;
644
+ else console.log(temp);
645
+
646
+ if (oldEid && oldEid !== eid) temp.clones.delete(oldEid);
647
+
648
+ temp.clones.set(eid, node);
649
+ }
650
+
651
+ renderedNode.eid = eid;
652
+
653
+ node.setAttribute("eid", eid);
654
+ break;
655
+ }
656
+ }
657
+
658
+ for (let attr of node.attributes) {
659
+ let name = attr.name;
660
+ let value = attr.value;
661
+
662
+ let renderedAttribute = renderedNodes.get(attr);
663
+ if (!renderedAttribute) {
664
+ renderedAttribute = {
665
+ placeholder: { name, value },
666
+ key,
667
+ renderAs,
668
+ parent: renderedNode
669
+ };
670
+ }
671
+
672
+ let namePlaceholder = renderedAttribute.placeholder.name || name;
673
+ let valuePlaceholder = renderedAttribute.placeholder.value || value;
674
+
675
+ name = await renderValue(
676
+ attr,
677
+ data,
678
+ namePlaceholder,
679
+ renderAs,
680
+ renderedAttribute,
681
+ index
682
+ );
683
+ value = await renderValue(
684
+ attr,
685
+ data,
686
+ valuePlaceholder,
687
+ renderAs,
688
+ renderedAttribute,
689
+ index
690
+ );
691
+ if (namePlaceholder.includes("{{") && name) {
692
+ const attributes = name.match(/([^\s]+="[^"]*"|[^\s]+)/g) || [];
693
+ attributes.forEach((attr) => {
694
+ let [attributeName, attributeValue] = attr.split("=");
695
+ attributeValue = attributeValue
696
+ ? attributeValue.replace(/"/g, "")
697
+ : "";
698
+ node.setAttribute(attributeName, attributeValue);
699
+ });
700
+ } else if (name === undefined || name === null || name === "") {
701
+ renderedNodes.delete(attr);
702
+ node.removeAttribute(attr.name);
703
+ } else if (
704
+ name &&
705
+ (value || value === "") &&
706
+ (name !== attr.name || value !== attr.value)
707
+ )
708
+ node.setAttribute(name, value);
709
+ }
710
+
711
+ if (CoCreate.state) {
712
+ if (node.hasAttribute("[state_id]"))
713
+ CoCreate.state.initElement(node);
714
+ }
715
+
716
+ if (node.tagName === "SCRIPT" && node.src) {
717
+ if (
718
+ node.src.includes("CoCreate.js") ||
719
+ node.src.includes("CoCreate.min.js")
720
+ ) {
721
+ node.remove();
722
+ return;
723
+ }
724
+ }
725
+
726
+ if (node.tagName === "LINK" && node.href) {
727
+ if (
728
+ node.href.includes("CoCreate.css") ||
729
+ node.href.includes("CoCreate.min.css")
730
+ ) {
731
+ node.remove();
732
+ return;
733
+ }
734
+ }
735
+ if (node.hasAttribute("render") && !node.hasAttribute("render-clone")) {
736
+ let renderKey = node.getAttribute("render") || key
737
+ renderTemplate(node, data, renderKey);
738
+ } else if (node.childNodes.length > 0) {
739
+ for (let childNode of node.childNodes) {
740
+ await renderValues(
741
+ childNode,
742
+ data,
743
+ key,
744
+ renderAs,
745
+ keyPath,
746
+ parent,
747
+ index
748
+ );
749
+ }
750
+ }
751
+ } else if (node.nodeType == 3) {
752
+ let valueType = node.parentElement.getAttribute("value-type");
753
+
754
+ let textContent, text;
755
+
756
+ if (!renderedNode.placeholder && node.textContent.match(/{{(.*?)}}/))
757
+ renderedNode.placeholder = node.textContent;
758
+
759
+ if (!renderedNode.placeholder) return;
760
+ textContent = renderedNode.placeholder || node.textContent;
761
+
762
+ text = await renderValue(
763
+ node,
764
+ data,
765
+ textContent,
766
+ renderAs,
767
+ renderedNode,
768
+ index
769
+ );
770
+
771
+ if (text || text == "") {
772
+ if (text != renderedNode.text) {
773
+ renderedNode.text = text;
774
+
775
+ if (
776
+ valueType == "text" ||
777
+ valueType == "string" ||
778
+ valueType != "html"
779
+ ) {
780
+ node.textContent = text;
781
+ } else {
782
+ const newNode = document.createElement("div");
783
+ newNode.innerHTML = text;
784
+ let parentElement = node.parentElement;
785
+
786
+ let renderedParent = renderedNodes.get(parentElement);
787
+ if (!renderedParent) {
788
+ renderedParent = {
789
+ placeholder: textContent,
790
+ key,
791
+ renderAs
792
+ };
793
+ }
794
+ renderedParent.text = text;
795
+ for (let newChild of newNode.childNodes) {
796
+ renderedNode.element = newChild;
797
+ renderedNodes.set(newChild, renderedNode);
798
+ }
799
+ renderedNodes.delete(node);
800
+ node.replaceWith(...newNode.childNodes);
801
+ }
802
+
803
+ if (node.childNodes.length > 0) {
804
+ for (let childNode of node.childNodes) {
805
+ await renderValues(
806
+ childNode,
807
+ data,
808
+ key,
809
+ renderAs,
810
+ keyPath,
811
+ parent,
812
+ index
813
+ );
814
+ }
815
+ }
816
+ }
817
+ }
818
+ }
856
819
  }
857
820
 
858
821
  async function renderValue(
859
- node,
860
- data,
861
- placeholder,
862
- renderAs,
863
- renderedNode,
864
- index
822
+ node,
823
+ data,
824
+ placeholder,
825
+ renderAs,
826
+ renderedNode,
827
+ index
865
828
  ) {
866
- let output = placeholder;
867
-
868
- // Updated regex to match {{ }}, {[ ]}, {( )}
869
- let regex = /\{\{([^{}]+?)\}\}|\{\[([^{}\[\]]+?)\]\}|\{\(([^{}()]+?)\)\}/;
870
- let omitted = {};
871
-
872
- let match;
873
- do {
874
- match = output.match(regex);
875
- if (match) {
876
- let value;
877
- let placeholderContent;
878
- let placeholderType;
879
-
880
- try {
881
- // Initialize placeholderContent and placeholderType for each match
882
- if (match[1] !== undefined) {
883
- // Matched {{ }}
884
- placeholderContent = match[1];
885
- placeholderType = "doubleCurly";
886
- } else if (match[2] !== undefined) {
887
- // Matched {[ ]}
888
- placeholderContent = match[2];
889
- placeholderType = "squareBrackets";
890
- } else if (match[3] !== undefined) {
891
- // Matched {( )}
892
- placeholderContent = match[3];
893
- placeholderType = "parentheses";
894
- }
895
-
896
- // Process based on the placeholder type
897
- if (placeholderContent === "index" && index >= 0) {
898
- // Handle {{index}} - index
899
- value = index;
900
- } else if (placeholderType === "squareBrackets") {
901
- // {[ ]} - Dot-notation
902
- value = getRenderValue(
903
- node,
904
- data,
905
- placeholderContent,
906
- renderAs
907
- );
908
- } else if (placeholderType === "parentheses") {
909
- // If using JSON Structure:
910
- try {
911
- let Data = JSON.parse(
912
- placeholderContent.replace(/'/g, '"')
913
- );
914
- if (
915
- Data.storage ||
916
- Data.database ||
917
- Data.array ||
918
- Data.object ||
919
- Data.index
920
- ) {
921
- Data.method = "object.read";
922
- let response = await CoCreate.crud.send(Data);
923
- value = response.object[0][Data.key];
924
- }
925
- } catch (error) {
926
- // If parsing fails, you can handle it as needed
927
- // {( )} - CSS Selector and JSON Structure
928
- // For CSS Selector handling, implement your logic here
929
- // Example:
930
-
931
- let valueElement = queryElements({
932
- selector: placeholderContent
933
- });
934
- if (valueElement && valueElement[0])
935
- value = valueElement[0].getValue();
936
-
937
- // For now, we'll omit the placeholder
938
- omitted[`<|${placeholderContent}|>`] = match[0];
939
- }
940
- } else if (placeholderType === "doubleCurly") {
941
- // {{ }} - Dot-notation and JSON Structure
942
- try {
943
- let Data = JSON.parse(
944
- placeholderContent.replace(/'/g, '"')
945
- );
946
- if (
947
- Data.storage ||
948
- Data.database ||
949
- Data.array ||
950
- Data.object ||
951
- Data.index
952
- ) {
953
- Data.method = "object.read";
954
- let response = await CoCreate.crud.send(Data);
955
- value = response.object[0][Data.key];
956
- }
957
- } catch (error) {
958
- // Treat as dot-notation
959
- value = getRenderValue(
960
- node,
961
- data,
962
- placeholderContent,
963
- renderAs
964
- );
965
- }
966
- } else {
967
- // If none of the conditions match, store for omission
968
- omitted[`<|${placeholderContent}|>`] = match[0];
969
- }
970
- } catch (error) {
971
- console.error(error);
972
- }
973
-
974
- // Replace the placeholder with the resolved value
975
- if (value !== undefined && value !== null) {
976
- if (typeof value === "object") {
977
- value = JSON.stringify(value, null, 2);
978
- }
979
- output = output.replaceAll(match[0], value);
980
- } else if (renderAs) {
981
- if (match[0].startsWith(`{{${renderAs}.`)) {
982
- output = output.replaceAll(match[0], "");
983
- } else if (placeholderContent) {
984
- output = output.replaceAll(
985
- match[0],
986
- `<|${placeholderContent}|>`
987
- );
988
- omitted[`<|${placeholderContent}|>`] = match[0];
989
- }
990
- } else {
991
- // If no value is found and no renderAs, exit the loop
992
- match = null;
993
- }
994
- }
995
- } while (match);
996
-
997
- // Restore any omitted placeholders
998
- for (let key of Object.keys(omitted)) {
999
- output = output.replaceAll(key, omitted[key]);
1000
- }
1001
-
1002
- return output;
829
+ let output = placeholder;
830
+
831
+ // Determine the actual HTMLElement for processOperatorsAsync
832
+ // If the node is not an Element (nodeType 1), get its owner or parent element.
833
+ // This safely covers Attributes (ownerElement), Text, Comments, etc. (parentElement)
834
+ let contextElement = node;
835
+ if (node && node.nodeType !== 1) {
836
+ contextElement = node.ownerElement || node.parentElement;
837
+ }
838
+
839
+ // DEPRECATED: {[ ]} and {( )}
840
+ // Matches ONLY the innermost {{ }} brackets.
841
+ let regex = /\{\{((?:(?!\{\{|\}\})[\s\S])+?)\}\}/;
842
+ let omitted = {};
843
+
844
+ let match;
845
+ do {
846
+ match = output.match(regex);
847
+ if (match) {
848
+ let value;
849
+ let placeholderContent = match[1].trim();
850
+
851
+ try {
852
+ if (placeholderContent === "index" && index >= 0) {
853
+ value = index;
854
+ } else {
855
+ // --- UNIFIED PARSING PROCESS ---
856
+ let preProcessed = placeholderContent;
857
+
858
+ // 1. PRE-PROCESSOR FOR QUOTED OPERATORS
859
+ let quoteRegex = /(['"])(.*?)\1/g;
860
+ let quoteMatch;
861
+ let replacements = [];
862
+ while ((quoteMatch = quoteRegex.exec(preProcessed)) !== null) {
863
+ let quoteType = quoteMatch[1];
864
+ let content = quoteMatch[2];
865
+ if (content.trim().startsWith('$')) {
866
+ let resolved = await processOperatorsAsync(contextElement, content);
867
+ if (resolved === null || resolved === undefined) resolved = "";
868
+ replacements.push({
869
+ original: quoteMatch[0],
870
+ replacement: `${quoteType}${resolved}${quoteType}`
871
+ });
872
+ }
873
+ }
874
+
875
+ for (let r of replacements) {
876
+ preProcessed = preProcessed.replace(r.original, r.replacement);
877
+ }
878
+
879
+ // 2. PRE-PROCESSOR: Resolve unquoted DOM selectors, custom operators, and CRUD JSON
880
+ preProcessed = await processOperatorsAsync(
881
+ contextElement,
882
+ preProcessed
883
+ );
884
+
885
+ // 3. DATA LOOKUP: Resolve simple keys from the provided data object
886
+ // Keep `node` here because getRenderValue needs to look up the attribute cache!
887
+ value = getRenderValue(
888
+ node,
889
+ data,
890
+ preProcessed,
891
+ renderAs
892
+ );
893
+
894
+ // 4. EXPRESSION EVALUATOR: Handle Math and Ternary logic
895
+ if (value === undefined || value === null) {
896
+ const dataProxy = new Proxy(data || {}, {
897
+ get(target, prop) {
898
+ if (typeof prop !== "string") return target[prop];
899
+ if (prop in target) return target[prop];
900
+ return getRenderValue(node, data, prop, renderAs);
901
+ },
902
+ has(target, prop) {
903
+ if (typeof prop !== "string") return prop in target;
904
+ return true;
905
+ }
906
+ });
907
+
908
+ const parsedValue = safeParse(preProcessed, dataProxy);
909
+
910
+ if (parsedValue !== null) {
911
+ value = parsedValue;
912
+ } else if (preProcessed !== placeholderContent) {
913
+ value = preProcessed;
914
+ }
915
+ }
916
+ }
917
+ } catch (error) {
918
+ console.error(error);
919
+ }
920
+
921
+ // Replace the placeholder with the resolved value
922
+ if (value !== undefined && value !== null) {
923
+ if (typeof value === "object") {
924
+ value = JSON.stringify(value, null, 2);
925
+ }
926
+ output = output.replaceAll(match[0], value);
927
+ } else if (renderAs) {
928
+ if (match[0].startsWith(`{{${renderAs}.`)) {
929
+ output = output.replaceAll(match[0], "");
930
+ } else if (placeholderContent) {
931
+ output = output.replaceAll(
932
+ match[0],
933
+ `<|${placeholderContent}|>`
934
+ );
935
+ omitted[`<|${placeholderContent}|>`] = match[0];
936
+ }
937
+ } else {
938
+ match = null;
939
+ }
940
+ }
941
+ } while (match);
942
+
943
+ for (let key of Object.keys(omitted)) {
944
+ output = output.replaceAll(key, omitted[key]);
945
+ }
946
+
947
+ return output;
1003
948
  }
1004
949
 
1005
950
  function getRenderValue(node, data, key, renderAs) {
1006
- // TODO: handle operators directly from render placholders
1007
- // <span>{{ $toLocaleDateString.object.created.on }}</span>
1008
-
1009
- let operator;
1010
- if (key.startsWith("$")) {
1011
- let keys = key.split(".");
1012
- operator = keys.shift();
1013
- if (keys.length > 0) {
1014
- key = keys.join(".");
1015
- }
1016
- }
1017
-
1018
- let value = getValueFromObject(data, key);
1019
-
1020
- if (!value && value !== "" && node) {
1021
- let parentTemplate = node;
1022
- do {
1023
- let parentNode = renderedNodes.get(parentTemplate);
1024
- if (parentNode) {
1025
- if (!value && (parentNode.parent || parentNode.template)) {
1026
- let Data,
1027
- eid,
1028
- parent = parentNode.parent || parentNode.template;
1029
- do {
1030
- if (key.includes("keyPath")) {
1031
- value = parentNode.keyPath || parent.keyPath;
1032
- } else if (key.includes("parentKey")) {
1033
- value =
1034
- parentNode.parentKey ||
1035
- parent.parentKey ||
1036
- parent.parent.parentKey;
1037
- } else if (key.includes("renderAs")) {
1038
- value = renderAs;
1039
- } else if (key === "object" || key === "_id")
1040
- value = ObjectId().toString();
1041
- else if (key === "uuid") {
1042
- value = uuid.generate(6);
1043
- } else if (parent.source) {
1044
- Data = parent.source.data;
1045
- } else if (parent.parent) {
1046
- parent = parent.parent;
1047
- } else if (parent.template) {
1048
- parent = parent.template;
1049
- } else {
1050
- parent = undefined;
1051
- }
1052
-
1053
- if (!Data && parent && parent.eid) eid = parent.eid;
1054
- } while (!value && parent && !Data);
1055
-
1056
- if (!value && Data) {
1057
- value = getValueFromObject(Data, key);
1058
- }
1059
- if (!value && key.includes(".")) {
1060
- let renderedData = getValueFromObject(
1061
- Data,
1062
- key.split(".")[0]
1063
- );
1064
- if (renderedData) {
1065
- let index;
1066
- if (
1067
- !parent.clones.size ||
1068
- parent.clones.size === 1
1069
- ) {
1070
- index = 0;
1071
- } else if (eid) {
1072
- index = Array.from(
1073
- parent.clones.keys()
1074
- ).indexOf(eid);
1075
- } else console.log("eid not found");
1076
-
1077
- if (index >= 0) {
1078
- Data = {
1079
- [key.split(".")[0]]: renderedData[index]
1080
- };
1081
- }
1082
- value = getValueFromObject(Data, key);
1083
- }
1084
- }
1085
- }
1086
- }
1087
-
1088
- if (!value && parentTemplate.parentElement) {
1089
- parentTemplate =
1090
- parentTemplate.parentElement.closest("[render]");
1091
- } else {
1092
- parentTemplate = undefined;
1093
- }
1094
- } while (!value && parentTemplate);
1095
- }
1096
-
1097
- if (operator) {
1098
- if (value) {
1099
- console.log("return processed render value using operator", value);
1100
- } else {
1101
- console.log("return render operator", operator);
1102
- }
1103
- }
1104
-
1105
- return value;
951
+ let operator;
952
+ if (key.startsWith("$")) {
953
+ let keys = key.split(".");
954
+ operator = keys.shift();
955
+ if (keys.length > 0) {
956
+ key = keys.join(".");
957
+ }
958
+ }
959
+
960
+ let value = getValueFromObject(data, key);
961
+
962
+ if (!value && value !== "" && node) {
963
+ let parentTemplate = node;
964
+ do {
965
+ let parentNode = renderedNodes.get(parentTemplate);
966
+ if (parentNode) {
967
+ if (!value && (parentNode.parent || parentNode.template)) {
968
+ let Data,
969
+ eid,
970
+ parent = parentNode.parent || parentNode.template;
971
+ do {
972
+ if (key.includes("keyPath")) {
973
+ value = parentNode.keyPath || parent.keyPath;
974
+ } else if (key.includes("parentKey")) {
975
+ value =
976
+ parentNode.parentKey ||
977
+ parent.parentKey ||
978
+ parent.parent.parentKey;
979
+ } else if (key.includes("renderAs")) {
980
+ value = renderAs;
981
+ } else if (key === "object" || key === "_id")
982
+ value = ObjectId().toString();
983
+ else if (key === "uuid") {
984
+ value = uuid.generate(6);
985
+ } else if (parent.source) {
986
+ Data = parent.source.data;
987
+ } else if (parent.parent) {
988
+ parent = parent.parent;
989
+ } else if (parent.template) {
990
+ parent = parent.template;
991
+ } else {
992
+ parent = undefined;
993
+ }
994
+
995
+ if (!Data && parent && parent.eid) eid = parent.eid;
996
+ } while (!value && parent && !Data);
997
+
998
+ if (!value && Data) {
999
+ value = getValueFromObject(Data, key);
1000
+ }
1001
+ if (!value && key.includes(".")) {
1002
+ let renderedData = getValueFromObject(
1003
+ Data,
1004
+ key.split(".")[0]
1005
+ );
1006
+ if (renderedData) {
1007
+ let index;
1008
+ if (
1009
+ !parent.clones.size ||
1010
+ parent.clones.size === 1
1011
+ ) {
1012
+ index = 0;
1013
+ } else if (eid) {
1014
+ index = Array.from(
1015
+ parent.clones.keys()
1016
+ ).indexOf(eid);
1017
+ } else console.log("eid not found");
1018
+
1019
+ if (index >= 0) {
1020
+ Data = {
1021
+ [key.split(".")[0]]: renderedData[index]
1022
+ };
1023
+ }
1024
+ value = getValueFromObject(Data, key);
1025
+ }
1026
+ }
1027
+ }
1028
+ }
1029
+
1030
+ if (!value && parentTemplate.parentElement) {
1031
+ parentTemplate =
1032
+ parentTemplate.parentElement.closest("[render]");
1033
+ } else {
1034
+ parentTemplate = undefined;
1035
+ }
1036
+ } while (!value && parentTemplate);
1037
+ }
1038
+
1039
+ if (operator) {
1040
+ if (value) {
1041
+ console.log("return processed render value using operator", value);
1042
+ } else {
1043
+ console.log("return render operator", operator);
1044
+ }
1045
+ }
1046
+
1047
+ return value;
1106
1048
  }
1107
1049
 
1108
1050
  async function renderKey(action) {
1109
- // TODO: custom render-keys
1110
- let element = action.element;
1111
- let form = action.form || document;
1112
- let params = action.params;
1113
-
1114
- if (!params) {
1115
- params = "render-key";
1116
- }
1117
-
1118
- let data = {};
1119
- let selector = `[${params}]`;
1120
- let elements = form.querySelectorAll(selector);
1121
- for (let el of elements) {
1122
- let attribute = el.getAttribute(params);
1123
- if (attribute) data[attribute] = await el.getValue();
1124
- }
1125
- data = dotNotationToObject(data);
1126
- let renderData = { data: { [params]: data } };
1127
-
1128
- let renderSelector = element.getAttribute("render-query");
1129
- if (!renderSelector) return;
1130
-
1131
- renderData.selector = renderSelector;
1132
- render(renderData);
1133
-
1134
- action.element.dispatchEvent(
1135
- new CustomEvent("renderKey", {
1136
- detail: { data }
1137
- })
1138
- );
1051
+ // TODO: custom render-keys
1052
+ let element = action.element;
1053
+ let form = action.form || document;
1054
+ let params = action.params;
1055
+
1056
+ if (!params) {
1057
+ params = "render-key";
1058
+ }
1059
+
1060
+ let data = {};
1061
+ let selector = `[${params}]`;
1062
+ let elements = form.querySelectorAll(selector);
1063
+ for (let el of elements) {
1064
+ let attribute = el.getAttribute(params);
1065
+ if (attribute) data[attribute] = await el.getValue();
1066
+ }
1067
+ data = dotNotationToObject(data);
1068
+ let renderData = { data: { [params]: data } };
1069
+
1070
+ let renderSelector = element.getAttribute("render-query");
1071
+ if (!renderSelector) return;
1072
+
1073
+ renderData.selector = renderSelector;
1074
+ render(renderData);
1075
+
1076
+ action.element.dispatchEvent(
1077
+ new CustomEvent("renderKey", {
1078
+ detail: { data }
1079
+ })
1080
+ );
1139
1081
  }
1140
1082
 
1141
1083
  Actions.init({
1142
- name: "renderKey",
1143
- callback: (action) => {
1144
- renderKey(action);
1145
- }
1084
+ name: "renderKey",
1085
+ callback: (action) => {
1086
+ renderKey(action);
1087
+ }
1146
1088
  });
1147
1089
 
1148
1090
  Actions.init({
1149
- name: "render",
1150
- callback: async (action) => {
1151
- if (!action.form) return;
1152
-
1153
- let elements;
1154
- if (action.params)
1155
- elements = queryElements({
1156
- element: action.element,
1157
- selector: action.params,
1158
- type: "selector"
1159
- });
1160
- else
1161
- elements = queryElements({
1162
- element: action.element,
1163
- prefix: "render"
1164
- });
1165
-
1166
- // TODO: data returned from form.getData() returns an array of objects each representing an storage, database and array in form. need a solution for handling what is the item to be rendered
1167
- let data = await action.form.getData();
1168
- let array = action.form.getAttribute("array");
1169
- if (array) data = data.find((obj) => obj.array === array);
1170
- for (let i = 0; i < elements.length; i++)
1171
- await render({ source: elements[i], data });
1172
-
1173
- action.element.dispatchEvent(
1174
- new CustomEvent("render", {
1175
- detail: {}
1176
- })
1177
- );
1178
- }
1091
+ name: "render",
1092
+ callback: async (action) => {
1093
+ if (!action.form) return;
1094
+
1095
+ let elements;
1096
+ if (action.params)
1097
+ elements = queryElements({
1098
+ element: action.element,
1099
+ selector: action.params,
1100
+ type: "selector"
1101
+ });
1102
+ else
1103
+ elements = queryElements({
1104
+ element: action.element,
1105
+ prefix: "render"
1106
+ });
1107
+
1108
+ let data = await action.form.getData();
1109
+ let array = action.form.getAttribute("array");
1110
+ if (array) data = data.find((obj) => obj.array === array);
1111
+ for (let i = 0; i < elements.length; i++)
1112
+ await render({ source: elements[i], data });
1113
+
1114
+ action.element.dispatchEvent(
1115
+ new CustomEvent("render", {
1116
+ detail: {}
1117
+ })
1118
+ );
1119
+ }
1179
1120
  });
1180
1121
 
1181
1122
  Observer.init({
1182
- name: "render",
1183
- types: ["addedNodes"],
1184
- selector: elementSelector,
1185
- callback: function (mutation) {
1186
- init(mutation.target);
1187
- }
1123
+ name: "render",
1124
+ types: ["addedNodes"],
1125
+ selector: elementSelector,
1126
+ callback: function (mutation) {
1127
+ init(mutation.target);
1128
+ }
1188
1129
  });
1189
1130
 
1190
1131
  Observer.init({
1191
- name: "fileRender",
1192
- types: ["attributes"],
1193
- attributeFilter: ["render-query"],
1194
- callback: async function (mutation) {
1195
- render({
1196
- element: mutation.target,
1197
- data: await mutation.target.getValue()
1198
- });
1199
- }
1132
+ name: "fileRender",
1133
+ types: ["attributes"],
1134
+ attributeFilter: ["render-query"],
1135
+ callback: async function (mutation) {
1136
+ render({
1137
+ element: mutation.target,
1138
+ data: await mutation.target.getValue()
1139
+ });
1140
+ }
1200
1141
  });
1201
1142
 
1202
1143
  Observer.init({
1203
- name: "render",
1204
- types: ["addedNodes"],
1205
- selector: "[render]",
1206
- callback: function (mutation) {
1207
- if (mutation.target.hasAttribute("render-clone")) return;
1208
- let parentElement = mutation.target.parentElement.closest("[render]");
1209
- if (!parentElement) return;
1210
-
1211
- let renderedNode = renderedNodes.get(parentElement);
1212
- let data;
1213
- if (renderedNode) {
1214
- if (renderedNode.renderData) {
1215
- data = renderedNode.renderData;
1216
- }
1217
- } else {
1218
- let sourceElement = mutation.target.parentElement.closest("[render-query]")
1219
- let sourceData = sources.get(sourceElement);
1220
- if (sourceData) {
1221
- data = sourceData.data;
1222
- }
1223
- }
1224
- if (data) {
1225
- // render({ element: mutation.target, data });
1226
- }
1227
- }
1144
+ name: "render",
1145
+ types: ["addedNodes"],
1146
+ selector: "[render-element]",
1147
+ callback: function (mutation) {
1148
+ if (mutation.target.hasAttribute("render-clone")) return;
1149
+ let parentElement = mutation.target.parentElement.closest("[render]");
1150
+ if (!parentElement) return;
1151
+
1152
+ let renderedNode = renderedNodes.get(parentElement);
1153
+ let data;
1154
+ if (renderedNode) {
1155
+ if (renderedNode.renderData) {
1156
+ data = renderedNode.renderData;
1157
+ }
1158
+ } else {
1159
+ let sourceElement = mutation.target.parentElement.closest("[render-query]")
1160
+ let sourceData = sources.get(sourceElement);
1161
+ if (sourceData) {
1162
+ data = sourceData.data;
1163
+ }
1164
+ }
1165
+ if (data) {
1166
+ render({ element: mutation.target, data });
1167
+ }
1168
+ }
1228
1169
  });
1229
1170
 
1230
- // Observer.init({
1231
- // name: 'render',
1232
- // types: ['addedNodes'],
1233
- // selector: '[render-clone]',
1234
- // callback: function (mutation) {
1235
- // let renderedNode = renderedNodes.get(mutation.target)
1236
- // if (!renderedNode) return
1237
-
1238
- // render({ source, element, data, key, index, currentIndex, update, remove })
1239
-
1240
- // let nextElement = mutation.target.nextElementSibling
1241
- // if (!nextElement) return
1242
-
1243
- // let nextRenderedNode = renderedNodes.get(nextElement)
1244
- // if (!nextRenderedNode) return
1245
-
1246
- // let clones
1247
- // if (nextRenderedNode.template)
1248
- // clones = nextRenderedNode.template.clones
1249
- // else if (nextRenderedNode.clones)
1250
- // clones = nextRenderedNode.clones
1251
-
1252
- // const cloneValueArray = Array.from(clones.values())
1253
- // let index = cloneValueArray.indexOf(nextElement);
1254
-
1255
- // const cloneArray = Array.from(clones)
1256
-
1257
- // cloneArray.splice(index, 0, [renderedNode.eid, mutation.target]);
1258
- // clones = new Map(cloneArray);
1259
-
1260
- // }
1261
- // })
1262
-
1263
1171
  Observer.init({
1264
- name: "renderNodesRemoved",
1265
- types: ["removedNodes"],
1266
- selector: "[render-clone]",
1267
- callback: function (mutation) {
1268
- if (mutation.target.parentElement) return;
1269
- let renderedNode = renderedNodes.get(mutation.target);
1270
- if (!renderedNode) return;
1271
- renderedNode.template.clones.delete(renderedNode.eid);
1272
- renderedNodes.delete(mutation.target);
1273
- }
1172
+ name: "renderNodesRemoved",
1173
+ types: ["removedNodes"],
1174
+ selector: "[render-clone]",
1175
+ callback: function (mutation) {
1176
+ if (mutation.target.parentElement) return;
1177
+ let renderedNode = renderedNodes.get(mutation.target);
1178
+ if (!renderedNode) return;
1179
+ renderedNode.template.clones.delete(renderedNode.eid);
1180
+ renderedNodes.delete(mutation.target);
1181
+ }
1274
1182
  });
1275
1183
 
1276
1184
  init();
1277
1185
 
1278
- export { render, renderValue, sources, renderedNodes };
1186
+ export { render, renderValue, sources, renderedNodes };