@cocreate/render 1.43.0 → 1.43.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/index.js +994 -850
package/src/index.js
CHANGED
|
@@ -21,17 +21,22 @@
|
|
|
21
21
|
// For details, visit <https://cocreate.app/licenses/> or contact us at sales@cocreate.app.
|
|
22
22
|
|
|
23
23
|
/*globals CustomEvent*/
|
|
24
|
-
import Actions from
|
|
25
|
-
import Observer from
|
|
26
|
-
import uuid from
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
import Actions from "@cocreate/actions";
|
|
25
|
+
import Observer from "@cocreate/observer";
|
|
26
|
+
import uuid from "@cocreate/uuid";
|
|
27
|
+
import {
|
|
28
|
+
queryElements,
|
|
29
|
+
getValueFromObject,
|
|
30
|
+
dotNotationToObject,
|
|
31
|
+
ObjectId
|
|
32
|
+
} from "@cocreate/utils";
|
|
33
|
+
import "@cocreate/element-prototype";
|
|
34
|
+
import "./index.css";
|
|
35
|
+
|
|
36
|
+
const sources = new Map();
|
|
37
|
+
const renderedNodes = new Map();
|
|
38
|
+
const elementSelector =
|
|
39
|
+
"[render-selector], [render-closest], [render-parent], [render-next], [render-previous]";
|
|
35
40
|
|
|
36
41
|
/**
|
|
37
42
|
* Initializes elements based on specified rendering attributes. If a specific element is provided, it initializes that element.
|
|
@@ -50,19 +55,23 @@ const elementSelector = '[render-selector], [render-closest], [render-parent], [
|
|
|
50
55
|
* - If null or omitted, the function queries and initializes all elements matching the 'elementSelector'.
|
|
51
56
|
*/
|
|
52
57
|
function init(element) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
if (
|
|
59
|
+
element &&
|
|
60
|
+
!(element instanceof HTMLCollection) &&
|
|
61
|
+
!Array.isArray(element)
|
|
62
|
+
)
|
|
63
|
+
element = [element];
|
|
64
|
+
else if (!element) element = document.querySelectorAll(elementSelector);
|
|
65
|
+
|
|
66
|
+
for (let i = 0; i < element.length; i++) {
|
|
67
|
+
let source = sources.get(element[i]);
|
|
68
|
+
if (!source) {
|
|
69
|
+
sources.set(element[i], { element: element[i] });
|
|
70
|
+
element[i].renderValue = async (data) =>
|
|
71
|
+
await render({ source: element[i], data });
|
|
72
|
+
element[i].getData = () => sources.get(element[i]).data;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
/**
|
|
@@ -80,850 +89,985 @@ function init(element) {
|
|
|
80
89
|
* @param {boolean} [options.update] - Flag to indicate if the rendering should update existing content.
|
|
81
90
|
* @param {boolean} [options.remove] - Flag to indicate if the rendering should remove elements instead of updating or appending.
|
|
82
91
|
*/
|
|
83
|
-
async function render({
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
92
|
+
async function render({
|
|
93
|
+
source,
|
|
94
|
+
element,
|
|
95
|
+
selector,
|
|
96
|
+
data,
|
|
97
|
+
key,
|
|
98
|
+
index,
|
|
99
|
+
currentIndex,
|
|
100
|
+
update,
|
|
101
|
+
remove
|
|
102
|
+
}) {
|
|
103
|
+
let Data = { ...data };
|
|
104
|
+
if (!element) {
|
|
105
|
+
if (source) {
|
|
106
|
+
element = queryElements({ element: source, prefix: "render" });
|
|
107
|
+
if (!element && source.children.length > 0) {
|
|
108
|
+
for (const child of source.children) {
|
|
109
|
+
if (
|
|
110
|
+
child.matches(
|
|
111
|
+
"template, [template], .template, [render]"
|
|
112
|
+
)
|
|
113
|
+
) {
|
|
114
|
+
element = child;
|
|
115
|
+
break; // Found the desired element, no need to continue the loop
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!element) {
|
|
121
|
+
element = source.querySelector(
|
|
122
|
+
"template, [template], .template, [render]"
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
} else if (selector) element = queryElements({ selector });
|
|
126
|
+
|
|
127
|
+
if (!element) return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (source) {
|
|
131
|
+
if (!key) {
|
|
132
|
+
key = source.getAttribute("render") || source.getAttribute("key");
|
|
133
|
+
if (!key) {
|
|
134
|
+
key = data.type;
|
|
135
|
+
if (key == "key") key = "object";
|
|
136
|
+
else if (!key && data.method) key = data.method.split(".")[0];
|
|
137
|
+
else if (!key) return;
|
|
138
|
+
} else if (key == "{}") key = "object";
|
|
139
|
+
}
|
|
140
|
+
let sourceData = sources.get(source);
|
|
141
|
+
if (!sourceData) {
|
|
142
|
+
sourceData = { element: source, Data };
|
|
143
|
+
sources.set(source, sourceData);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
source = sourceData;
|
|
147
|
+
if (!source.data) source.data = Data;
|
|
148
|
+
} else if (data) source = { Data };
|
|
149
|
+
|
|
150
|
+
if (data.$filter) {
|
|
151
|
+
index = index || data.$filter.startingIndex || data.$filter.index;
|
|
152
|
+
update = update || data.$filter.update;
|
|
153
|
+
remove = remove || data.$filter.remove;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (
|
|
157
|
+
!Array.isArray(element) &&
|
|
158
|
+
!(element instanceof HTMLCollection) &&
|
|
159
|
+
!(element instanceof NodeList)
|
|
160
|
+
)
|
|
161
|
+
element = [element];
|
|
162
|
+
|
|
163
|
+
for (let i = 0; i < element.length; i++) {
|
|
164
|
+
key = element[i].getAttribute("render") || key;
|
|
165
|
+
|
|
166
|
+
let renderedNode = renderedNodes.get(element[i]);
|
|
167
|
+
if (
|
|
168
|
+
renderedNode &&
|
|
169
|
+
renderedNode.clones &&
|
|
170
|
+
renderedNode.source &&
|
|
171
|
+
renderedNode.source.element
|
|
172
|
+
) {
|
|
173
|
+
let limit =
|
|
174
|
+
renderedNode.source.element.getAttribute("render-limit");
|
|
175
|
+
if (limit && renderedNode.clones.size >= parseInt(limit)) continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (source) {
|
|
179
|
+
if (!renderedNode) {
|
|
180
|
+
renderedNode = {
|
|
181
|
+
element: element[i],
|
|
182
|
+
source,
|
|
183
|
+
clones: new Map(),
|
|
184
|
+
renderAs: new Map()
|
|
185
|
+
};
|
|
186
|
+
renderedNodes.set(element[i], renderedNode);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (remove) {
|
|
191
|
+
for (let j = 0; j < data[key].length; j++) {
|
|
192
|
+
let cloneKey;
|
|
193
|
+
if (key === "object") {
|
|
194
|
+
cloneKey = data[key][j]._id;
|
|
195
|
+
} else {
|
|
196
|
+
cloneKey = data[key][j].name;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
let clone = renderedNode.clones.get(cloneKey);
|
|
200
|
+
if (!clone) return;
|
|
201
|
+
|
|
202
|
+
renderedNode.clones.delete(cloneKey);
|
|
203
|
+
renderedNodes.delete(clone);
|
|
204
|
+
clone.remove();
|
|
205
|
+
}
|
|
206
|
+
} else if ((key && Array.isArray(data[key])) || Array.isArray(data)) {
|
|
207
|
+
if (update) {
|
|
208
|
+
for (let j = 0; j < data[key].length; j++) {
|
|
209
|
+
let clone;
|
|
210
|
+
if (key === "object") {
|
|
211
|
+
clone = renderedNode.clones.get(data[key][j]._id);
|
|
212
|
+
} else {
|
|
213
|
+
clone = renderedNode.clones.get(data[key][j].name);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (!currentIndex) currentIndex = data.$filter.currentIndex;
|
|
217
|
+
|
|
218
|
+
if (!clone) return;
|
|
219
|
+
|
|
220
|
+
await renderValues(clone, { object: data[key][j] });
|
|
221
|
+
if (currentIndex >= 0)
|
|
222
|
+
insertElement(renderedNode, clone, index, currentIndex);
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
// TODO: if $auto here every subsequent clone will have same value, not replacing here will apply unique value to each clone
|
|
226
|
+
if (key === "$auto")
|
|
227
|
+
key = key.replace(/\$auto/g, uuid.generate(6));
|
|
228
|
+
|
|
229
|
+
if (key) element[i].setAttribute("render", key);
|
|
230
|
+
|
|
231
|
+
await renderTemplate(element[i], data, key, index);
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
let renderAs = element[i].getAttribute("render-as") || key;
|
|
235
|
+
await renderValues(element[i], data, key, renderAs);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
212
238
|
}
|
|
213
239
|
|
|
214
240
|
async function renderTemplate(template, data, key, index, keyPath) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
await renderValues(clone.element, object, key, renderAs, null, null, index);
|
|
371
|
-
insertElement(template, clone.element, index, '', data, renderReverse);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
241
|
+
// if (!key)
|
|
242
|
+
// key = template.getAttribute('render')
|
|
243
|
+
|
|
244
|
+
let templateData = renderedNodes.get(template);
|
|
245
|
+
if (!templateData) {
|
|
246
|
+
templateData = { element: template, clones: new Map() };
|
|
247
|
+
renderedNodes.set(template, templateData);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
templateData.parent = template.parentElement.closest("[render]");
|
|
251
|
+
if (templateData.parent)
|
|
252
|
+
templateData.parent = renderedNodes.get(templateData.parent);
|
|
253
|
+
|
|
254
|
+
if (!templateData.keyPath) {
|
|
255
|
+
if (keyPath) templateData.keyPath = keyPath;
|
|
256
|
+
else if (templateData.parent && templateData.parent.keyPath)
|
|
257
|
+
templateData.keyPath = templateData.parent.keyPath;
|
|
258
|
+
else if (key) templateData.keyPath = key;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
template = templateData;
|
|
262
|
+
|
|
263
|
+
let renderData;
|
|
264
|
+
if (key) renderData = getRenderValue(template.element, data, key);
|
|
265
|
+
else if (Array.isArray(data)) renderData = data;
|
|
266
|
+
|
|
267
|
+
if (!renderData && data)
|
|
268
|
+
if (Array.isArray(data)) renderData = data;
|
|
269
|
+
else renderData = [data];
|
|
270
|
+
else if (!renderData) return;
|
|
271
|
+
|
|
272
|
+
let isInsert = data.$filter && (data.$filter.create || data.$filter.update);
|
|
273
|
+
if ((!isInsert && !index) || data.$filter.overwrite) {
|
|
274
|
+
if (!template.clones) template = template.template;
|
|
275
|
+
for (const [key, element] of template.clones) {
|
|
276
|
+
renderedNodes.delete(element);
|
|
277
|
+
element.remove();
|
|
278
|
+
template.clones.delete(key);
|
|
279
|
+
}
|
|
280
|
+
// if (renderedNodes.size) {
|
|
281
|
+
// for (let [element] of renderedNodes) {
|
|
282
|
+
// element.remove()
|
|
283
|
+
// }
|
|
284
|
+
// renderedNodes.clear();
|
|
285
|
+
// }
|
|
286
|
+
|
|
287
|
+
// template.data = renderData
|
|
288
|
+
}
|
|
289
|
+
// else if (index) {
|
|
290
|
+
// updates data that has already been rendered
|
|
291
|
+
// template.data = dotNotationToObject(renderData, template.data)
|
|
292
|
+
// }
|
|
293
|
+
|
|
294
|
+
let renderAs = template.element.getAttribute("render-as") || key;
|
|
295
|
+
template.renderAs = renderAs;
|
|
296
|
+
|
|
297
|
+
let renderType;
|
|
298
|
+
if (templateData.source && templateData.source.element)
|
|
299
|
+
renderType = templateData.source.element.getAttribute("render-type");
|
|
300
|
+
|
|
301
|
+
let renderReverse;
|
|
302
|
+
if (templateData.source && templateData.source.element) {
|
|
303
|
+
renderReverse =
|
|
304
|
+
templateData.source.element.getAttribute("render-reverse");
|
|
305
|
+
if (!renderReverse)
|
|
306
|
+
renderReverse = template.element.getAttribute("render-reverse");
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if ((key && !Array.isArray(renderData)) || renderType === "object") {
|
|
310
|
+
if (renderType && Array.isArray(renderData) && renderData.length === 1)
|
|
311
|
+
renderData = renderData[0];
|
|
312
|
+
|
|
313
|
+
let exclude = template.element.getAttribute("render-exclude") || "";
|
|
314
|
+
if (exclude) {
|
|
315
|
+
exclude = exclude.replace(/ /g, "").split(",");
|
|
316
|
+
if (!Array.isArray(exclude)) exclude = [exclude];
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const keys = Object.keys(renderData);
|
|
320
|
+
for (let i = 0; i < keys.length; i++) {
|
|
321
|
+
if (exclude.includes(keys[i])) continue;
|
|
322
|
+
|
|
323
|
+
let value = renderData[keys[i]];
|
|
324
|
+
let type = "string";
|
|
325
|
+
|
|
326
|
+
if (Array.isArray(value)) type = "array";
|
|
327
|
+
else if (typeof value == "object") type = "object";
|
|
328
|
+
|
|
329
|
+
let Data = { [renderAs]: { key: keys[i], value, type } };
|
|
330
|
+
|
|
331
|
+
let clone = cloneTemplate(template);
|
|
332
|
+
let renderedKey = key.split(".");
|
|
333
|
+
renderedKey = renderedKey[renderedKey.length - 1];
|
|
334
|
+
//renderedKey needs to remove the parent.renderAs/key
|
|
335
|
+
|
|
336
|
+
clone.key = keys[i];
|
|
337
|
+
clone.keyPath = template.keyPath + "." + renderedKey;
|
|
338
|
+
clone.parentKey = renderedKey;
|
|
339
|
+
clone.renderKey = key;
|
|
340
|
+
clone.element.setAttribute("renderedKey", keys[i]);
|
|
341
|
+
await renderValues(clone.element, Data, keys[i], renderAs);
|
|
342
|
+
insertElement(template, clone.element, index);
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
if (!key && !Array.isArray(renderData)) {
|
|
346
|
+
key = "data";
|
|
347
|
+
renderData = getValueFromObject(renderData, key);
|
|
348
|
+
if (!renderAs) renderAs = key;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (!renderData) {
|
|
352
|
+
let clone = cloneTemplate(template);
|
|
353
|
+
clone.keyPath = template.keyPath;
|
|
354
|
+
await renderValues(clone.element, data, key, renderAs);
|
|
355
|
+
insertElement(template, clone.element, index);
|
|
356
|
+
} else {
|
|
357
|
+
if (!Array.isArray(renderData)) renderData = [renderData];
|
|
358
|
+
|
|
359
|
+
for (let i = 0; i < renderData.length; i++) {
|
|
360
|
+
let clone = cloneTemplate(template);
|
|
361
|
+
|
|
362
|
+
let test = clone.element.getAttribute("render-as");
|
|
363
|
+
if (test) renderAs = test;
|
|
364
|
+
|
|
365
|
+
clone.keyPath = template.keyPath || "" + `[${i}]`;
|
|
366
|
+
|
|
367
|
+
let object;
|
|
368
|
+
if (renderAs) {
|
|
369
|
+
object = { [renderAs]: renderData[i] };
|
|
370
|
+
if (renderAs.includes("."))
|
|
371
|
+
object = dotNotationToObject(object);
|
|
372
|
+
} else object = renderData[i];
|
|
373
|
+
|
|
374
|
+
let index;
|
|
375
|
+
if (key !== "data") index = i;
|
|
376
|
+
await renderValues(
|
|
377
|
+
clone.element,
|
|
378
|
+
object,
|
|
379
|
+
key,
|
|
380
|
+
renderAs,
|
|
381
|
+
null,
|
|
382
|
+
null,
|
|
383
|
+
index
|
|
384
|
+
);
|
|
385
|
+
insertElement(
|
|
386
|
+
template,
|
|
387
|
+
clone.element,
|
|
388
|
+
index,
|
|
389
|
+
"",
|
|
390
|
+
data,
|
|
391
|
+
renderReverse
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
375
396
|
}
|
|
376
397
|
|
|
377
398
|
function cloneTemplate(template) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
renderedNodes.set(clone, renderedNode)
|
|
413
|
-
return renderedNode;
|
|
399
|
+
let clone = template.element.cloneNode(true);
|
|
400
|
+
let cloneTagName = clone.tagName;
|
|
401
|
+
|
|
402
|
+
if (clone.tagName == "TEMPLATE") {
|
|
403
|
+
clone = template.element.content.firstElementChild;
|
|
404
|
+
for (let attribute of template.element.attributes) {
|
|
405
|
+
clone.setAttribute(attribute.name, attribute.value || "");
|
|
406
|
+
}
|
|
407
|
+
} else {
|
|
408
|
+
clone.classList.remove("template");
|
|
409
|
+
clone.removeAttribute("template");
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
clone.setAttribute("render-clone", "");
|
|
413
|
+
|
|
414
|
+
let renderAs = clone.getAttribute("render-as");
|
|
415
|
+
if (renderAs === "$auto") {
|
|
416
|
+
renderAs = uuid.generate(6);
|
|
417
|
+
clone = clone.outerHTML.replace(/\$auto/g, renderAs);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (typeof clone === "string") {
|
|
421
|
+
// TODO: Some elements are only allowed a specific element, need to find these elements and confirm proper rendering.
|
|
422
|
+
let container;
|
|
423
|
+
if (cloneTagName === "TR") container = document.createElement("tbody");
|
|
424
|
+
else container = document.createElement("div");
|
|
425
|
+
|
|
426
|
+
container.innerHTML = clone;
|
|
427
|
+
clone = container.firstChild;
|
|
428
|
+
container.remove();
|
|
429
|
+
}
|
|
430
|
+
let renderedNode = { template, element: clone };
|
|
431
|
+
renderedNodes.set(clone, renderedNode);
|
|
432
|
+
return renderedNode;
|
|
414
433
|
}
|
|
415
434
|
|
|
416
|
-
function insertElement(
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
435
|
+
function insertElement(
|
|
436
|
+
template,
|
|
437
|
+
element,
|
|
438
|
+
index,
|
|
439
|
+
currentIndex,
|
|
440
|
+
data,
|
|
441
|
+
renderReverse
|
|
442
|
+
) {
|
|
443
|
+
let eid = element.getAttribute("eid");
|
|
444
|
+
if (!eid) {
|
|
445
|
+
eid = uuid.generate(6);
|
|
446
|
+
element.setAttribute("eid", eid);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (index !== null && index >= 0) {
|
|
450
|
+
if (!template.clones) template = template.template;
|
|
451
|
+
// const clones = Array.from(template.clones);
|
|
452
|
+
|
|
453
|
+
let item;
|
|
454
|
+
if (!currentIndex && currentIndex !== 0) {
|
|
455
|
+
if (template.clones.has(eid)) return;
|
|
456
|
+
item = [eid, element];
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const clones = Array.from(template.clones);
|
|
460
|
+
|
|
461
|
+
if (currentIndex || currentIndex === 0) {
|
|
462
|
+
item = clones.splice(currentIndex, 1)[0];
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (data && data.$filter && data.$filter.startingIndex)
|
|
466
|
+
index += data.$filter.startingIndex;
|
|
467
|
+
clones.splice(index, 0, item); // Insert item into clones at the specified index
|
|
468
|
+
|
|
469
|
+
if (renderReverse) {
|
|
470
|
+
// Chat-specific logic: reverse rendering but still inserting based on sorting
|
|
471
|
+
|
|
472
|
+
// If we're rendering in reverse order, we want to respect the insertion index
|
|
473
|
+
if (clones[index + 1] && clones[index + 1][1] !== element) {
|
|
474
|
+
// Insert before the next element (reverse order means newer items come before older ones)
|
|
475
|
+
clones[index + 1][1].insertAdjacentElement("afterend", element);
|
|
476
|
+
} else if (clones[index] && clones[index][1] !== element) {
|
|
477
|
+
// Insert after the current element if there's no next element
|
|
478
|
+
clones[index][1].insertAdjacentElement("beforeend", element);
|
|
479
|
+
} else {
|
|
480
|
+
// Fallback: insert before the template if clones are empty or undefined
|
|
481
|
+
template.element.insertAdjacentElement("afterend", element);
|
|
482
|
+
}
|
|
483
|
+
} else {
|
|
484
|
+
// Non-chat logic: handle ascending or descending order as usual
|
|
485
|
+
if (clones[index + 1] && clones[index + 1][1] !== element) {
|
|
486
|
+
// Insert before the next element
|
|
487
|
+
clones[index + 1][1].insertAdjacentElement(
|
|
488
|
+
"beforebegin",
|
|
489
|
+
element
|
|
490
|
+
);
|
|
491
|
+
} else if (clones[index] && clones[index][1] !== element) {
|
|
492
|
+
// Insert after the current element if there's no next element
|
|
493
|
+
clones[index][1].insertAdjacentElement("afterend", element);
|
|
494
|
+
} else {
|
|
495
|
+
// Fallback: insert before the template if clones are empty or undefined
|
|
496
|
+
template.element.insertAdjacentElement("beforebegin", element);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
template.clones = new Map(clones);
|
|
501
|
+
} else {
|
|
502
|
+
template.clones.set(eid, element);
|
|
503
|
+
template.element.insertAdjacentElement("beforebegin", element);
|
|
504
|
+
}
|
|
479
505
|
}
|
|
480
506
|
|
|
481
507
|
async function renderValues(node, data, key, renderAs, keyPath, parent, index) {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
508
|
+
if (!data) return;
|
|
509
|
+
|
|
510
|
+
let renderedNode = renderedNodes.get(node);
|
|
511
|
+
if (!renderedNode) renderedNode = { key, renderAs };
|
|
512
|
+
|
|
513
|
+
if (!renderedNode.key) renderedNode.key = key;
|
|
514
|
+
else if (!key) key = renderedNode.key;
|
|
515
|
+
|
|
516
|
+
if (!renderedNode.renderAs) renderedNode.renderAs = renderAs;
|
|
517
|
+
else if (!renderAs) renderAs = renderedNode.renderAs;
|
|
518
|
+
|
|
519
|
+
if (keyPath) renderedNode.keyPath = keyPath;
|
|
520
|
+
else if (renderedNode.keyPath) keyPath = renderedNode.keyPath;
|
|
521
|
+
|
|
522
|
+
if (parent) renderedNode.parent = parent;
|
|
523
|
+
|
|
524
|
+
if (node.nodeType == 1) {
|
|
525
|
+
if (node.hasAttribute("render-clone")) {
|
|
526
|
+
parent = renderedNode;
|
|
527
|
+
|
|
528
|
+
for (let eid of ["_id", "name", "key"]) {
|
|
529
|
+
if (renderAs) eid = data[renderAs][eid];
|
|
530
|
+
else eid = data[eid];
|
|
531
|
+
|
|
532
|
+
if (!eid) continue;
|
|
533
|
+
|
|
534
|
+
let oldEid = renderedNode.eid;
|
|
535
|
+
let temp = renderedNode.template;
|
|
536
|
+
if (!temp) {
|
|
537
|
+
console.log("temp could not be found");
|
|
538
|
+
} else if (!temp.clones) {
|
|
539
|
+
if (temp.template) temp = temp.template;
|
|
540
|
+
else console.log(temp);
|
|
541
|
+
|
|
542
|
+
if (oldEid && oldEid !== eid) temp.clones.delete(oldEid);
|
|
543
|
+
|
|
544
|
+
temp.clones.set(eid, node);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
renderedNode.eid = eid;
|
|
548
|
+
|
|
549
|
+
node.setAttribute("eid", eid);
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Array.from(node.attributes).forEach(attr => {
|
|
555
|
+
for (let attr of node.attributes) {
|
|
556
|
+
let name = attr.name;
|
|
557
|
+
let value = attr.value;
|
|
558
|
+
|
|
559
|
+
let renderedAttribute = renderedNodes.get(attr);
|
|
560
|
+
if (!renderedAttribute) {
|
|
561
|
+
renderedAttribute = {
|
|
562
|
+
placeholder: { name, value },
|
|
563
|
+
key,
|
|
564
|
+
renderAs,
|
|
565
|
+
parent: renderedNode
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
let namePlaceholder = renderedAttribute.placeholder.name || name;
|
|
570
|
+
let valuePlaceholder = renderedAttribute.placeholder.value || value;
|
|
571
|
+
|
|
572
|
+
name = await renderValue(
|
|
573
|
+
attr,
|
|
574
|
+
data,
|
|
575
|
+
namePlaceholder,
|
|
576
|
+
renderAs,
|
|
577
|
+
renderedAttribute,
|
|
578
|
+
index
|
|
579
|
+
);
|
|
580
|
+
value = await renderValue(
|
|
581
|
+
attr,
|
|
582
|
+
data,
|
|
583
|
+
valuePlaceholder,
|
|
584
|
+
renderAs,
|
|
585
|
+
renderedAttribute,
|
|
586
|
+
index
|
|
587
|
+
);
|
|
588
|
+
if (namePlaceholder.includes("{{") && name) {
|
|
589
|
+
const attributes = name.match(/([^\s]+="[^"]*"|[^\s]+)/g) || [];
|
|
590
|
+
attributes.forEach((attr) => {
|
|
591
|
+
let [attributeName, attributeValue] = attr.split("=");
|
|
592
|
+
attributeValue = attributeValue
|
|
593
|
+
? attributeValue.replace(/"/g, "")
|
|
594
|
+
: "";
|
|
595
|
+
node.setAttribute(attributeName, attributeValue);
|
|
596
|
+
});
|
|
597
|
+
} else if (name === undefined || name === null || name === "") {
|
|
598
|
+
renderedNodes.delete(attr);
|
|
599
|
+
node.removeAttribute(attr.name);
|
|
600
|
+
} else if (
|
|
601
|
+
name &&
|
|
602
|
+
(value || value === "") &&
|
|
603
|
+
(name !== attr.name || value !== attr.value)
|
|
604
|
+
)
|
|
605
|
+
node.setAttribute(name, value);
|
|
606
|
+
}
|
|
607
|
+
// });
|
|
608
|
+
|
|
609
|
+
if (CoCreate.state) {
|
|
610
|
+
if (node.hasAttribute("[state_id]"))
|
|
611
|
+
CoCreate.state.initElement(node);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
if (node.tagName === "SCRIPT" && node.src) {
|
|
615
|
+
if (
|
|
616
|
+
node.src.includes("CoCreate.js") ||
|
|
617
|
+
node.src.includes("CoCreate.min.js")
|
|
618
|
+
) {
|
|
619
|
+
node.remove();
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
if (node.tagName === "LINK" && node.href) {
|
|
625
|
+
if (
|
|
626
|
+
node.href.includes("CoCreate.css") ||
|
|
627
|
+
node.href.includes("CoCreate.min.css")
|
|
628
|
+
) {
|
|
629
|
+
node.remove();
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if (node.getAttribute("render") && !node.hasAttribute("render-clone")) {
|
|
634
|
+
renderTemplate(node, data);
|
|
635
|
+
} else if (node.childNodes.length > 0) {
|
|
636
|
+
// Array.from(node.childNodes).forEach(childNode => {
|
|
637
|
+
for (let childNode of node.childNodes) {
|
|
638
|
+
await renderValues(
|
|
639
|
+
childNode,
|
|
640
|
+
data,
|
|
641
|
+
key,
|
|
642
|
+
renderAs,
|
|
643
|
+
keyPath,
|
|
644
|
+
parent,
|
|
645
|
+
index
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
// });
|
|
649
|
+
}
|
|
650
|
+
} else if (node.nodeType == 3) {
|
|
651
|
+
let valueType = node.parentElement.getAttribute("value-type");
|
|
652
|
+
|
|
653
|
+
let textContent, text;
|
|
654
|
+
|
|
655
|
+
if (!renderedNode.placeholder && node.textContent.match(/{{(.*?)}}/))
|
|
656
|
+
renderedNode.placeholder = node.textContent;
|
|
657
|
+
|
|
658
|
+
if (!renderedNode.placeholder) return;
|
|
659
|
+
textContent = renderedNode.placeholder || node.textContent;
|
|
660
|
+
|
|
661
|
+
text = await renderValue(
|
|
662
|
+
node,
|
|
663
|
+
data,
|
|
664
|
+
textContent,
|
|
665
|
+
renderAs,
|
|
666
|
+
renderedNode,
|
|
667
|
+
index
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
if (text || text == "") {
|
|
671
|
+
if (text != renderedNode.text) {
|
|
672
|
+
renderedNode.text = text;
|
|
673
|
+
|
|
674
|
+
if (
|
|
675
|
+
valueType == "text" ||
|
|
676
|
+
valueType == "string" ||
|
|
677
|
+
valueType != "html"
|
|
678
|
+
) {
|
|
679
|
+
node.textContent = text;
|
|
680
|
+
} else {
|
|
681
|
+
const newNode = document.createElement("div");
|
|
682
|
+
newNode.innerHTML = text;
|
|
683
|
+
let parentElement = node.parentElement;
|
|
684
|
+
|
|
685
|
+
let renderedParent = renderedNodes.get(parentElement);
|
|
686
|
+
if (!renderedParent) {
|
|
687
|
+
renderedParent = {
|
|
688
|
+
placeholder: textContent,
|
|
689
|
+
key,
|
|
690
|
+
renderAs
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
renderedParent.text = text;
|
|
694
|
+
for (let newChild of newNode.childNodes) {
|
|
695
|
+
renderedNode.element = newChild;
|
|
696
|
+
renderedNodes.set(newChild, renderedNode);
|
|
697
|
+
}
|
|
698
|
+
renderedNodes.delete(node);
|
|
699
|
+
node.replaceWith(...newNode.childNodes);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
if (node.childNodes.length > 0) {
|
|
703
|
+
// Array.from(node.childNodes).forEach(childNode => {
|
|
704
|
+
for (let childNode of node.childNodes) {
|
|
705
|
+
await renderValues(
|
|
706
|
+
childNode,
|
|
707
|
+
data,
|
|
708
|
+
key,
|
|
709
|
+
renderAs,
|
|
710
|
+
keyPath,
|
|
711
|
+
parent,
|
|
712
|
+
index
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
// });
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
648
720
|
}
|
|
649
721
|
|
|
650
|
-
async function renderValue(
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
722
|
+
async function renderValue(
|
|
723
|
+
node,
|
|
724
|
+
data,
|
|
725
|
+
placeholder,
|
|
726
|
+
renderAs,
|
|
727
|
+
renderedNode,
|
|
728
|
+
index
|
|
729
|
+
) {
|
|
730
|
+
let output = placeholder;
|
|
731
|
+
|
|
732
|
+
// Updated regex to match {{ }}, {[ ]}, {( )}
|
|
733
|
+
let regex = /\{\{([^{}]+?)\}\}|\{\[([^{}\[\]]+?)\]\}|\{\(([^{}()]+?)\)\}/;
|
|
734
|
+
let omitted = {};
|
|
735
|
+
|
|
736
|
+
let match;
|
|
737
|
+
do {
|
|
738
|
+
match = output.match(regex);
|
|
739
|
+
if (match) {
|
|
740
|
+
let value;
|
|
741
|
+
let placeholderContent;
|
|
742
|
+
let placeholderType;
|
|
743
|
+
|
|
744
|
+
try {
|
|
745
|
+
// Initialize placeholderContent and placeholderType for each match
|
|
746
|
+
if (match[1] !== undefined) {
|
|
747
|
+
// Matched {{ }}
|
|
748
|
+
placeholderContent = match[1];
|
|
749
|
+
placeholderType = "doubleCurly";
|
|
750
|
+
} else if (match[2] !== undefined) {
|
|
751
|
+
// Matched {[ ]}
|
|
752
|
+
placeholderContent = match[2];
|
|
753
|
+
placeholderType = "squareBrackets";
|
|
754
|
+
} else if (match[3] !== undefined) {
|
|
755
|
+
// Matched {( )}
|
|
756
|
+
placeholderContent = match[3];
|
|
757
|
+
placeholderType = "parentheses";
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// Process based on the placeholder type
|
|
761
|
+
if (placeholderContent === "index" && index >= 0) {
|
|
762
|
+
// Handle {{index}} - index
|
|
763
|
+
value = index;
|
|
764
|
+
} else if (placeholderType === "squareBrackets") {
|
|
765
|
+
// {[ ]} - Dot-notation
|
|
766
|
+
value = getRenderValue(
|
|
767
|
+
node,
|
|
768
|
+
data,
|
|
769
|
+
placeholderContent,
|
|
770
|
+
renderAs
|
|
771
|
+
);
|
|
772
|
+
} else if (placeholderType === "parentheses") {
|
|
773
|
+
// If using JSON Structure:
|
|
774
|
+
try {
|
|
775
|
+
let Data = JSON.parse(
|
|
776
|
+
placeholderContent.replace(/'/g, '"')
|
|
777
|
+
);
|
|
778
|
+
if (
|
|
779
|
+
Data.storage ||
|
|
780
|
+
Data.database ||
|
|
781
|
+
Data.array ||
|
|
782
|
+
Data.object ||
|
|
783
|
+
Data.index
|
|
784
|
+
) {
|
|
785
|
+
Data.method = "object.read";
|
|
786
|
+
let response = await CoCreate.crud.send(Data);
|
|
787
|
+
value = response.object[0][Data.key];
|
|
788
|
+
}
|
|
789
|
+
} catch (error) {
|
|
790
|
+
// If parsing fails, you can handle it as needed
|
|
791
|
+
// {( )} - CSS Selector and JSON Structure
|
|
792
|
+
// For CSS Selector handling, implement your logic here
|
|
793
|
+
// Example:
|
|
794
|
+
|
|
795
|
+
let valueElement = queryElements({
|
|
796
|
+
selector: placeholderContent
|
|
797
|
+
});
|
|
798
|
+
if (valueElement && valueElement[0])
|
|
799
|
+
value = valueElement[0].getValue();
|
|
800
|
+
|
|
801
|
+
// For now, we'll omit the placeholder
|
|
802
|
+
omitted[`<|${placeholderContent}|>`] = match[0];
|
|
803
|
+
}
|
|
804
|
+
} else if (placeholderType === "doubleCurly") {
|
|
805
|
+
// {{ }} - Dot-notation and JSON Structure
|
|
806
|
+
try {
|
|
807
|
+
let Data = JSON.parse(
|
|
808
|
+
placeholderContent.replace(/'/g, '"')
|
|
809
|
+
);
|
|
810
|
+
if (
|
|
811
|
+
Data.storage ||
|
|
812
|
+
Data.database ||
|
|
813
|
+
Data.array ||
|
|
814
|
+
Data.object ||
|
|
815
|
+
Data.index
|
|
816
|
+
) {
|
|
817
|
+
Data.method = "object.read";
|
|
818
|
+
let response = await CoCreate.crud.send(Data);
|
|
819
|
+
value = response.object[0][Data.key];
|
|
820
|
+
}
|
|
821
|
+
} catch (error) {
|
|
822
|
+
// Treat as dot-notation
|
|
823
|
+
value = getRenderValue(
|
|
824
|
+
node,
|
|
825
|
+
data,
|
|
826
|
+
placeholderContent,
|
|
827
|
+
renderAs
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
} else {
|
|
831
|
+
// If none of the conditions match, store for omission
|
|
832
|
+
omitted[`<|${placeholderContent}|>`] = match[0];
|
|
833
|
+
}
|
|
834
|
+
} catch (error) {
|
|
835
|
+
console.error(error);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// Replace the placeholder with the resolved value
|
|
839
|
+
if (value !== undefined && value !== null) {
|
|
840
|
+
if (typeof value === "object") {
|
|
841
|
+
value = JSON.stringify(value, null, 2);
|
|
842
|
+
}
|
|
843
|
+
output = output.replaceAll(match[0], value);
|
|
844
|
+
} else if (renderAs) {
|
|
845
|
+
if (match[0].startsWith(`{{${renderAs}.`)) {
|
|
846
|
+
output = output.replaceAll(match[0], "");
|
|
847
|
+
} else if (placeholderContent) {
|
|
848
|
+
output = output.replaceAll(
|
|
849
|
+
match[0],
|
|
850
|
+
`<|${placeholderContent}|>`
|
|
851
|
+
);
|
|
852
|
+
omitted[`<|${placeholderContent}|>`] = match[0];
|
|
853
|
+
}
|
|
854
|
+
} else {
|
|
855
|
+
// If no value is found and no renderAs, exit the loop
|
|
856
|
+
match = null;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
} while (match);
|
|
860
|
+
|
|
861
|
+
// Restore any omitted placeholders
|
|
862
|
+
for (let key of Object.keys(omitted)) {
|
|
863
|
+
output = output.replaceAll(key, omitted[key]);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
return output;
|
|
729
867
|
}
|
|
730
868
|
|
|
731
|
-
|
|
732
869
|
function getRenderValue(node, data, key, renderAs) {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
return value
|
|
870
|
+
// TODO: handle operators directly from render placholders
|
|
871
|
+
// <span>{{ $toLocaleDateString.object.created.on }}</span>
|
|
872
|
+
|
|
873
|
+
let operator;
|
|
874
|
+
if (key.startsWith("$")) {
|
|
875
|
+
let keys = key.split(".");
|
|
876
|
+
operator = keys.shift();
|
|
877
|
+
if (keys.length > 0) {
|
|
878
|
+
key = keys.join(".");
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
let value = getValueFromObject(data, key);
|
|
883
|
+
|
|
884
|
+
if (!value && value !== "" && node) {
|
|
885
|
+
let parentTemplate = node;
|
|
886
|
+
do {
|
|
887
|
+
let parentNode = renderedNodes.get(parentTemplate);
|
|
888
|
+
if (parentNode) {
|
|
889
|
+
if (!value && (parentNode.parent || parentNode.template)) {
|
|
890
|
+
let Data,
|
|
891
|
+
eid,
|
|
892
|
+
parent = parentNode.parent || parentNode.template;
|
|
893
|
+
do {
|
|
894
|
+
if (key.includes("keyPath"))
|
|
895
|
+
value = parentNode.keyPath || parent.keyPath;
|
|
896
|
+
else if (key.includes("parentKey")) {
|
|
897
|
+
value =
|
|
898
|
+
parentNode.parentKey ||
|
|
899
|
+
parent.parentKey ||
|
|
900
|
+
parent.parent.parentKey;
|
|
901
|
+
} else if (key.includes("renderAs")) {
|
|
902
|
+
value = renderAs;
|
|
903
|
+
} else if (key === "object" || key === "_id")
|
|
904
|
+
value = ObjectId().toString();
|
|
905
|
+
else if (key === "uuid") value = uuid.generate(6);
|
|
906
|
+
else if (parent.source) Data = parent.source.data;
|
|
907
|
+
else if (parent.parent) parent = parent.parent;
|
|
908
|
+
else if (parent.template) parent = parent.template;
|
|
909
|
+
else parent = undefined;
|
|
910
|
+
|
|
911
|
+
if (!Data && parent && parent.eid) eid = parent.eid;
|
|
912
|
+
} while (!value && parent && !Data);
|
|
913
|
+
|
|
914
|
+
if (!value && Data) value = getValueFromObject(Data, key);
|
|
915
|
+
|
|
916
|
+
if (!value && key.includes(".")) {
|
|
917
|
+
let renderedData = getValueFromObject(
|
|
918
|
+
Data,
|
|
919
|
+
key.split(".")[0]
|
|
920
|
+
);
|
|
921
|
+
if (renderedData) {
|
|
922
|
+
let index;
|
|
923
|
+
if (!parent.clones.size || parent.clones.size === 1)
|
|
924
|
+
index = 0;
|
|
925
|
+
else if (eid)
|
|
926
|
+
index = Array.from(
|
|
927
|
+
parent.clones.keys()
|
|
928
|
+
).indexOf(eid);
|
|
929
|
+
else console.log("eid not found");
|
|
930
|
+
|
|
931
|
+
if (index >= 0)
|
|
932
|
+
Data = {
|
|
933
|
+
[key.split(".")[0]]: renderedData[index]
|
|
934
|
+
};
|
|
935
|
+
|
|
936
|
+
value = getValueFromObject(Data, key);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
if (!value && parentTemplate.parentElement)
|
|
943
|
+
parentTemplate =
|
|
944
|
+
parentTemplate.parentElement.closest("[render]");
|
|
945
|
+
else parentTemplate = undefined;
|
|
946
|
+
} while (!value && parentTemplate);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
if (operator) {
|
|
950
|
+
if (value) {
|
|
951
|
+
console.log("return processed render value using operator", value);
|
|
952
|
+
} else {
|
|
953
|
+
console.log("return render operator", operator);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return value;
|
|
824
958
|
}
|
|
825
959
|
|
|
826
960
|
async function renderKey(action) {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
961
|
+
// TODO: custom render-keys
|
|
962
|
+
let element = action.element;
|
|
963
|
+
let form = action.form || document;
|
|
964
|
+
let params = action.params;
|
|
965
|
+
|
|
966
|
+
if (!params) params = "render-key";
|
|
967
|
+
|
|
968
|
+
let data = {};
|
|
969
|
+
let selector = `[${params}]`;
|
|
970
|
+
let elements = form.querySelectorAll(selector);
|
|
971
|
+
for (let el of elements) {
|
|
972
|
+
let attribute = el.getAttribute(params);
|
|
973
|
+
if (attribute) data[attribute] = await el.getValue();
|
|
974
|
+
}
|
|
975
|
+
data = dotNotationToObject(data);
|
|
976
|
+
let renderData = { data: { [params]: data } };
|
|
977
|
+
|
|
978
|
+
let renderSelector = element.getAttribute("render-selector");
|
|
979
|
+
if (!renderSelector) return;
|
|
980
|
+
|
|
981
|
+
renderData.selector = renderSelector;
|
|
982
|
+
render(renderData);
|
|
983
|
+
|
|
984
|
+
document.dispatchEvent(
|
|
985
|
+
new CustomEvent("renderKey", {
|
|
986
|
+
detail: { data }
|
|
987
|
+
})
|
|
988
|
+
);
|
|
855
989
|
}
|
|
856
990
|
|
|
857
991
|
Actions.init({
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
992
|
+
name: "renderKey",
|
|
993
|
+
callback: (action) => {
|
|
994
|
+
renderKey(action);
|
|
995
|
+
}
|
|
862
996
|
});
|
|
863
997
|
|
|
864
998
|
Actions.init({
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
999
|
+
name: "render",
|
|
1000
|
+
callback: async (action) => {
|
|
1001
|
+
if (!action.form) return;
|
|
1002
|
+
|
|
1003
|
+
let elements;
|
|
1004
|
+
if (action.params)
|
|
1005
|
+
elements = queryElements({
|
|
1006
|
+
element: action.element,
|
|
1007
|
+
selector: action.params,
|
|
1008
|
+
type: "selector"
|
|
1009
|
+
});
|
|
1010
|
+
else
|
|
1011
|
+
elements = queryElements({
|
|
1012
|
+
element: action.element,
|
|
1013
|
+
prefix: "render"
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
let data = await action.form.getData();
|
|
1017
|
+
for (let i = 0; i < elements.length; i++)
|
|
1018
|
+
render({ source: elements[i], data: data[0] });
|
|
1019
|
+
|
|
1020
|
+
document.dispatchEvent(
|
|
1021
|
+
new CustomEvent("render", {
|
|
1022
|
+
detail: {}
|
|
1023
|
+
})
|
|
1024
|
+
);
|
|
1025
|
+
}
|
|
884
1026
|
});
|
|
885
1027
|
|
|
886
1028
|
Observer.init({
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
})
|
|
1029
|
+
name: "render",
|
|
1030
|
+
observe: ["addedNodes"],
|
|
1031
|
+
selector: elementSelector,
|
|
1032
|
+
callback: function (mutation) {
|
|
1033
|
+
init(mutation.target);
|
|
1034
|
+
}
|
|
1035
|
+
});
|
|
894
1036
|
|
|
895
1037
|
Observer.init({
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1038
|
+
name: "fileRender",
|
|
1039
|
+
observe: ["attributes"],
|
|
1040
|
+
attributeName: [
|
|
1041
|
+
"render-selector",
|
|
1042
|
+
"render-closest",
|
|
1043
|
+
"render-parent",
|
|
1044
|
+
"render-next",
|
|
1045
|
+
"render-previous"
|
|
1046
|
+
],
|
|
1047
|
+
callback: async function (mutation) {
|
|
1048
|
+
render({
|
|
1049
|
+
element: mutation.target,
|
|
1050
|
+
data: await mutation.target.getValue()
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
904
1053
|
});
|
|
905
1054
|
|
|
906
|
-
|
|
907
1055
|
Observer.init({
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
render({ element: mutation.target, data });
|
|
925
|
-
|
|
926
|
-
}
|
|
1056
|
+
name: "render",
|
|
1057
|
+
observe: ["addedNodes"],
|
|
1058
|
+
selector: "[render]",
|
|
1059
|
+
callback: function (mutation) {
|
|
1060
|
+
if (mutation.target.hasAttribute("render-clone")) return;
|
|
1061
|
+
let parentElement = mutation.target.parentElement.closest("[render]");
|
|
1062
|
+
if (!parentElement) return;
|
|
1063
|
+
return;
|
|
1064
|
+
let renderedNode = renderedNodes.get(parentElement);
|
|
1065
|
+
let data;
|
|
1066
|
+
if (renderedNode.source) data = renderedNode.source.data;
|
|
1067
|
+
if (renderedNode.template) data = renderedNode.template.source.data;
|
|
1068
|
+
|
|
1069
|
+
render({ element: mutation.target, data });
|
|
1070
|
+
}
|
|
927
1071
|
});
|
|
928
1072
|
|
|
929
1073
|
// Observer.init({
|
|
@@ -960,18 +1104,18 @@ Observer.init({
|
|
|
960
1104
|
// })
|
|
961
1105
|
|
|
962
1106
|
Observer.init({
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
})
|
|
974
|
-
|
|
975
|
-
init()
|
|
976
|
-
|
|
977
|
-
export { render, renderValue, sources, renderedNodes }
|
|
1107
|
+
name: "renderNodesRemoved",
|
|
1108
|
+
observe: ["removedNodes"],
|
|
1109
|
+
selector: "[render-clone]",
|
|
1110
|
+
callback: function (mutation) {
|
|
1111
|
+
if (mutation.target.parentElement) return;
|
|
1112
|
+
let renderedNode = renderedNodes.get(mutation.target);
|
|
1113
|
+
if (!renderedNode) return;
|
|
1114
|
+
renderedNode.template.clones.delete(renderedNode.eid);
|
|
1115
|
+
renderedNodes.delete(mutation.target);
|
|
1116
|
+
}
|
|
1117
|
+
});
|
|
1118
|
+
|
|
1119
|
+
init();
|
|
1120
|
+
|
|
1121
|
+
export { render, renderValue, sources, renderedNodes };
|