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