@cocreate/elements 1.42.8 → 1.42.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/package.json +1 -1
  3. package/src/index.js +1349 -1492
package/src/index.js CHANGED
@@ -26,14 +26,14 @@ import Observer from "@cocreate/observer";
26
26
  import Actions from "@cocreate/actions";
27
27
  import CRUD from "@cocreate/crud-client";
28
28
  import {
29
- dotNotationToObject,
30
- queryElements,
31
- queryData,
32
- sortData,
33
- getAttributes,
34
- getAttributeNames,
35
- checkValue,
36
- getValueFromObject
29
+ dotNotationToObject,
30
+ queryElements,
31
+ queryData,
32
+ sortData,
33
+ getAttributes,
34
+ getAttributeNames,
35
+ checkValue,
36
+ getValueFromObject
37
37
  } from "@cocreate/utils";
38
38
  import filter from "@cocreate/filter";
39
39
  import { render, renderValue, renderedNodes } from "@cocreate/render";
@@ -43,9 +43,9 @@ import { reset } from "./form";
43
43
  import "./value.js";
44
44
 
45
45
  const selector = "[storage], [database], [array], [render-json]";
46
- const elements = new Map();
46
+ const elements = new WeakMap();
47
+ const forms = new WeakMap();
47
48
  const keys = new Map();
48
- const forms = new Map();
49
49
  const debounce = new Map();
50
50
 
51
51
  /**
@@ -59,1579 +59,1436 @@ const debounce = new Map();
59
59
  * - render-json: Determines how JSON data is rendered.
60
60
  *
61
61
  * @param {(Element|Element[])} [elements] - Optional. A single element or an array of elements to initialize.
62
- * If omitted, the function queries and initializes all elements containing
63
- * any of these CRUD attributes: "storage", "database", "array", "render-json".
62
+ * If omitted, the function queries and initializes all elements containing
63
+ * any of these CRUD attributes: "storage", "database", "array", "render-json".
64
64
  */
65
65
  async function init(element) {
66
- if (
67
- element &&
68
- !(element instanceof HTMLCollection) &&
69
- !(element instanceof NodeList) &&
70
- !Array.isArray(element)
71
- ) {
72
- element = [element];
73
- } else if (!element) {
74
- element = document.querySelectorAll(selector);
75
- initSocket();
76
- }
77
-
78
- let dataObjects = new Map();
79
- for (let i = 0; i < element.length; i++) {
80
- if (
81
- elements.has(element[i]) ||
82
- element[i].tagName === "FORM" ||
83
- element[i].getAttribute("crud") === "false"
84
- )
85
- continue;
86
-
87
- let data = await initElement(element[i]);
88
- if (data) {
89
- let dataKey = initDataKey(element[i], data);
90
- dataObjects.set(dataKey.string, data);
91
- }
92
- }
93
-
94
- if (dataObjects && dataObjects.size > 0) {
95
- for (let key of dataObjects.keys()) {
96
- let { data, elements } = keys.get(key);
97
- read(Array.from(elements.keys()), data, { string: key });
98
- }
99
- }
100
-
101
- // const evt = new CustomEvent('elementsInitialized', { bubbles: true });
102
- // document.dispatchEvent(evt);
66
+ if (
67
+ element &&
68
+ !(element instanceof HTMLCollection) &&
69
+ !(element instanceof NodeList) &&
70
+ !Array.isArray(element)
71
+ ) {
72
+ element = [element];
73
+ } else if (!element) {
74
+ element = document.querySelectorAll(selector);
75
+ initSocket();
76
+ }
77
+
78
+ let promises = [];
79
+ for (let i = 0; i < element.length; i++) {
80
+ if (
81
+ elements.has(element[i]) ||
82
+ element[i].tagName === "FORM" ||
83
+ element[i].getAttribute("crud") === "false"
84
+ )
85
+ continue;
86
+
87
+ promises.push(
88
+ (async () => {
89
+ let data = await initElement(element[i]);
90
+ if (data) {
91
+ let dataKey = initDataKey(element[i], data);
92
+ return { string: dataKey.string, data };
93
+ }
94
+ })()
95
+ );
96
+ }
97
+
98
+ let results = await Promise.all(promises);
99
+ let dataObjects = new Map();
100
+
101
+ for (let res of results) {
102
+ if (res) dataObjects.set(res.string, res.data);
103
+ }
104
+
105
+ if (dataObjects && dataObjects.size > 0) {
106
+ for (let key of dataObjects.keys()) {
107
+ let { data, elements: mappedElements } = keys.get(key);
108
+ read(Array.from(mappedElements.keys()), data, { string: key });
109
+ }
110
+ }
103
111
  }
104
112
 
105
113
  async function initElement(el) {
106
- let data = getObject(el);
107
- if (!data || !data.type) return;
108
-
109
- if (
110
- data.object &&
111
- data.object !== "pending" &&
112
- !/^[0-9a-fA-F]{24}$/.test(data.object)
113
- )
114
- return;
115
-
116
- if (!elements.has(el)) {
117
- elements.set(el, "");
118
-
119
- if (!el.elementsInputEvent) {
120
- el.elementsInputEvent = true;
121
-
122
- if (
123
- ["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName) ||
124
- (el.hasAttribute("contenteditable") &&
125
- el.getAttribute("contenteditable") !== "false") ||
126
- el.contenteditable || el.value !== undefined || el.hasAttribute("value")
127
- ) {
128
- if (el.tagName == "IFRAME") {
129
- // ToDo: saving on contenteditable elements when an objectId does not exist in order to crud or crdt
130
- el = el.contentDocument.documentElement;
131
- el.setAttribute("contenteditable", "true");
132
- }
133
-
134
- el.addEventListener("input", function (e) {
135
- if (el.pendingObject) return;
136
-
137
- const { object, key, isRealtime, isCrdt } =
138
- getAttributes(el);
139
- if (!isRealtime || isRealtime === "false" || key === "_id")
140
- return;
141
- if (isCrdt == "true" && object && object !== "pending")
142
- return;
143
- if (e.detail && e.detail.skip == true) return;
144
- if (data.type !== "object" && data[data.type] === "pending")
145
- return;
146
- if (!el.value && !el.hasAttribute("value") && el.contenteditable && !el.hasAttribute("contenteditable")) return;
147
- save(el);
148
- });
149
- }
150
- }
151
- }
152
- // let attributes = ['filter-key', 'filter-search', 'filter-sort-key', 'filter-on', 'filter-limit']
153
- // if (el.getFilter || attributes.some(attr => el.hasAttribute(attr))) {
154
-
155
- await filter.init(el);
156
-
157
- if (el.getFilter) {
158
- data.$filter = await el.getFilter();
159
-
160
- el.setFilter = (filter) => {
161
- data.$filter = filter;
162
- el.hasRead = false;
163
- // let dataKey = initDataKey(el, data)
164
- read(el, data);
165
- };
166
- }
167
-
168
- return data;
114
+ let data = getObject(el);
115
+ if (!data || !data.type) return;
116
+
117
+ if (
118
+ data.object &&
119
+ data.object !== "pending" &&
120
+ !/^[0-9a-fA-F]{24}$/.test(data.object)
121
+ )
122
+ return;
123
+
124
+ if (!elements.has(el)) {
125
+ elements.set(el, "");
126
+
127
+ if (!el.elementsInputEvent) {
128
+ el.elementsInputEvent = true;
129
+
130
+ if (
131
+ ["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName) ||
132
+ (el.hasAttribute("contenteditable") &&
133
+ el.getAttribute("contenteditable") !== "false") ||
134
+ el.contenteditable || el.value !== undefined || el.hasAttribute("value")
135
+ ) {
136
+ if (el.tagName == "IFRAME") {
137
+ // ToDo: saving on contenteditable elements when an objectId does not exist in order to crud or crdt
138
+ el = el.contentDocument.documentElement;
139
+ el.setAttribute("contenteditable", "true");
140
+ }
141
+
142
+ el.addEventListener("input", function (e) {
143
+ if (el.pendingObject) return;
144
+
145
+ const { object, key, isRealtime, isCrdt } =
146
+ getAttributes(el);
147
+ if (!isRealtime || isRealtime === "false" || key === "_id")
148
+ return;
149
+ if (isCrdt == "true" && object && object !== "pending")
150
+ return;
151
+ if (e.detail && e.detail.skip == true) return;
152
+ if (data.type !== "object" && data[data.type] === "pending")
153
+ return;
154
+ if (!el.value && !el.hasAttribute("value") && el.contenteditable && !el.hasAttribute("contenteditable")) return;
155
+ save(el);
156
+ });
157
+ }
158
+ }
159
+ }
160
+
161
+ await filter.init(el);
162
+
163
+ if (el.getFilter) {
164
+ data.$filter = await el.getFilter();
165
+
166
+ el.setFilter = (filter) => {
167
+ data.$filter = filter;
168
+ el.hasRead = false;
169
+ read(el, data);
170
+ };
171
+ }
172
+
173
+ return data;
169
174
  }
170
175
 
171
176
  function getObject(element) {
172
- const data = getAttributes(element);
173
- const crudType = ["storage", "database", "array", "index", "object"];
174
-
175
- for (let i = 0; i < crudType.length; i++) {
176
- if (!checkValue(data[crudType[i]])) return;
177
-
178
- if (data[crudType[i]] && data[crudType[i]].includes(",")) {
179
- const array = data[crudType[i]].split(",");
180
- data[crudType[i]] = [];
181
-
182
- for (let j = 0; j < array.length; j++) {
183
- array[j].trim();
184
- if (crudType[i] === "object") {
185
- data[crudType[i]].push({ _id: array[j] });
186
- } else {
187
- data[crudType[i]].push(array[j]);
188
- }
189
- }
190
- }
191
- }
192
-
193
- if (data.object || data.object === "" || data.key || data.key === "") {
194
- if (!data.array || (data.array && !data.array.length)) return;
195
- data.type = "object";
196
- } else if (data.index || data.index === "") {
197
- if (!data.array || (data.array && !data.array.length)) return;
198
- data.type = "index";
199
- } else if (data.array || data.array === "") data.type = "array";
200
- else if (data.database || data.database === "") data.type = "database";
201
- else if (data.storage || data.storage === "") data.type = "storage";
202
- else if (data.data) data.type = "data";
203
-
204
- delete data.isRealtime;
205
- return data;
177
+ const data = getAttributes(element);
178
+ const crudType = ["storage", "database", "array", "index", "object"];
179
+
180
+ for (let i = 0; i < crudType.length; i++) {
181
+ if (!checkValue(data[crudType[i]])) return;
182
+
183
+ if (data[crudType[i]] && data[crudType[i]].includes(",")) {
184
+ const array = data[crudType[i]].split(",");
185
+ data[crudType[i]] = [];
186
+
187
+ for (let j = 0; j < array.length; j++) {
188
+ array[j].trim();
189
+ if (crudType[i] === "object") {
190
+ data[crudType[i]].push({ _id: array[j] });
191
+ } else {
192
+ data[crudType[i]].push(array[j]);
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ if (data.object || data.object === "" || data.key || data.key === "") {
199
+ if (!data.array || (data.array && !data.array.length)) return;
200
+ data.type = "object";
201
+ } else if (data.index || data.index === "") {
202
+ if (!data.array || (data.array && !data.array.length)) return;
203
+ data.type = "index";
204
+ } else if (data.array || data.array === "") data.type = "array";
205
+ else if (data.database || data.database === "") data.type = "database";
206
+ else if (data.storage || data.storage === "") data.type = "storage";
207
+ else if (data.data) data.type = "data";
208
+
209
+ delete data.isRealtime;
210
+ return data;
206
211
  }
207
212
 
208
213
  function initDataKey(element, data) {
209
- let dataKey = getDataKey(data);
210
- if (keys.has(dataKey.string))
211
- keys.get(dataKey.string).elements.set(element, "");
212
- else
213
- keys.set(dataKey.string, {
214
- elements: new Map([[element, ""]]),
215
- data,
216
- dataKey
217
- });
218
-
219
- elements.set(element, dataKey.string);
220
-
221
- if (element.parentElement) {
222
- let form = element.closest("form");
223
- if (form) {
224
- if (!form.save) form.save = () => save(form);
225
-
226
- if (!form.getData) form.getData = () => getData(form);
227
-
228
- let formObject = forms.get(form);
229
- if (formObject) {
230
- formObject.elements.set(element, data);
231
- if (formObject.types.has(data.type))
232
- formObject.types.get(data.type).set(element, data);
233
- else
234
- formObject.types.set(data.type, new Map([[element, data]]));
235
- } else
236
- forms.set(form, {
237
- elements: new Map([[element, data]]),
238
- types: new Map([[data.type, new Map([[element, data]])]])
239
- });
240
- }
241
- }
242
-
243
- if (!element.read) element.read = () => read(element);
244
- if (!element.save) element.save = () => save(element);
245
-
246
- return dataKey;
214
+ let dataKey = getDataKey(data);
215
+ if (keys.has(dataKey.string))
216
+ keys.get(dataKey.string).elements.set(element, "");
217
+ else
218
+ keys.set(dataKey.string, {
219
+ elements: new Map([[element, ""]]),
220
+ data,
221
+ dataKey
222
+ });
223
+
224
+ elements.set(element, dataKey.string);
225
+
226
+ if (element.parentElement) {
227
+ let form = element.closest("form");
228
+ if (form) {
229
+ if (!form.save) form.save = () => save(form);
230
+
231
+ if (!form.getData) form.getData = () => getData(form);
232
+
233
+ let formObject = forms.get(form);
234
+ if (formObject) {
235
+ formObject.elements.set(element, data);
236
+ if (formObject.types.has(data.type))
237
+ formObject.types.get(data.type).set(element, data);
238
+ else
239
+ formObject.types.set(data.type, new Map([[element, data]]));
240
+ } else
241
+ forms.set(form, {
242
+ elements: new Map([[element, data]]),
243
+ types: new Map([[data.type, new Map([[element, data]])]])
244
+ });
245
+ }
246
+ }
247
+
248
+ if (!element.read) element.read = () => read(element);
249
+ if (!element.save) element.save = () => save(element);
250
+
251
+ return dataKey;
247
252
  }
248
253
 
249
254
  async function read(element, data, dataKey) {
250
- if (!dataKey) dataKey = { string: elements.get(element) };
251
- if (!data) {
252
- let existingData = keys.get(dataKey.string);
253
- if (existingData && existingData.dataKey && existingData.dataKey.object)
254
- data = { ...existingData.dataKey.object };
255
- }
256
-
257
- if (!dataKey || !data.type) return;
258
- if (!data.$filter && (!data[data.type] || !data[data.type].length)) return;
259
-
260
- if (!(element instanceof HTMLCollection) && !Array.isArray(element))
261
- element = [element];
262
-
263
- let delay = debounce.get(dataKey.string);
264
- if (!delay) debounce.set(dataKey.string, (delay = {}));
265
-
266
- if (!delay.elements) delay.elements = new Map();
267
-
268
- for (let el of element) {
269
- const isRead = el.getAttribute("read");
270
- if (
271
- isRead !== "false" &&
272
- !el.hasRead &&
273
- (!data.$filter || (data.$filter && data.$filter.isFilter !== false))
274
- ) {
275
- el.hasRead = true;
276
- delay.elements.set(el, true);
277
- } else {
278
- // console.log("read skipped", el);
279
- }
280
- }
281
-
282
- if (!delay.elements.size) return;
283
-
284
- clearTimeout(delay.timer);
285
- delay.timer = setTimeout(function () {
286
- // TODO: should server support string and string array for type object, methods create, read, delete
287
- if (!data.$filter && data.type === "object") {
288
- if (!data.object) return;
289
- else if (typeof data.object === "string")
290
- data.object = { _id: data.object };
291
- else if (Array.isArray(data.object)) {
292
- if (data.object.length)
293
- data.object = { _id: data.object[0]._id };
294
- } else if (!data.object._id.match(/^[0-9a-fA-F]{24}$/)) return;
295
- // if (data.object._id.startsWith('$'))
296
- // return
297
- }
298
-
299
- // if (data.object && !Array.isArray(data.object) && data.object._id.startsWith('$'))
300
- // return
301
-
302
- // if (data.$filter && data.$filter.query) {
303
- // if (!Object.keys(data.$filter.query).length)
304
- // return
305
- // }
306
-
307
- data.method = data.type + ".read";
308
-
309
- CRUD.send(data).then((Data) => {
310
- debounce.delete(dataKey.string);
311
- let els = Array.from(delay.elements.keys());
312
- clearTimeout(delay.timer);
313
- delete delay.elements;
314
- delete delay.timer;
315
-
316
- setData(els, Data);
317
- });
318
- }, 500);
255
+ if (!dataKey) dataKey = { string: elements.get(element) };
256
+ if (!data) {
257
+ let existingData = keys.get(dataKey.string);
258
+ if (existingData && existingData.dataKey && existingData.dataKey.object)
259
+ data = { ...existingData.dataKey.object };
260
+ }
261
+
262
+ if (!dataKey || !data.type) return;
263
+ if (!data.$filter && (!data[data.type] || !data[data.type].length)) return;
264
+
265
+ if (!(element instanceof HTMLCollection) && !Array.isArray(element))
266
+ element = [element];
267
+
268
+ let delay = debounce.get(dataKey.string);
269
+ if (!delay) debounce.set(dataKey.string, (delay = {}));
270
+
271
+ if (!delay.elements) delay.elements = new Map();
272
+
273
+ for (let el of element) {
274
+ const isRead = el.getAttribute("read");
275
+ if (
276
+ isRead !== "false" &&
277
+ !el.hasRead &&
278
+ (!data.$filter || (data.$filter && data.$filter.isFilter !== false))
279
+ ) {
280
+ el.hasRead = true;
281
+ delay.elements.set(el, true);
282
+ } else {
283
+ // console.log("read skipped", el);
284
+ }
285
+ }
286
+
287
+ if (!delay.elements.size) return;
288
+
289
+ clearTimeout(delay.timer);
290
+ delay.timer = setTimeout(function () {
291
+ // TODO: should server support string and string array for type object, methods create, read, delete
292
+ if (!data.$filter && data.type === "object") {
293
+ if (!data.object) return;
294
+ else if (typeof data.object === "string")
295
+ data.object = { _id: data.object };
296
+ else if (Array.isArray(data.object)) {
297
+ if (data.object.length)
298
+ data.object = { _id: data.object[0]._id };
299
+ } else if (!data.object._id.match(/^[0-9a-fA-F]{24}$/)) return;
300
+ // if (data.object._id.startsWith('$'))
301
+ // return
302
+ }
303
+
304
+ data.method = data.type + ".read";
305
+
306
+ CRUD.send(data).then((responseData) => {
307
+ debounce.delete(dataKey.string);
308
+ let els = Array.from(delay.elements.keys());
309
+ clearTimeout(delay.timer);
310
+ delete delay.elements;
311
+ delete delay.timer;
312
+
313
+ setData(els, responseData);
314
+ });
315
+ }, 500);
319
316
  }
320
317
 
321
318
  function get$in(query, mergedValues = []) {
322
- for (let key of Object.keys(query)) {
323
- if (key === "$and" || key === "$or" || key === "$nor") {
324
- for (let i = 0; i < query[key].length; i++) {
325
- sort$in(query[key][i], mergedValues);
326
- }
327
- } else if (
328
- typeof query[key] === "object" &&
329
- !Array.isArray(query[key])
330
- ) {
331
- if (query[key].$in)
332
- mergedValues = [...mergedValues, ...query[key].$in];
333
- }
334
- }
335
- return mergedValues;
319
+ for (let key of Object.keys(query)) {
320
+ if (key === "$and" || key === "$or" || key === "$nor") {
321
+ for (let i = 0; i < query[key].length; i++) {
322
+ sort$in(query[key][i], mergedValues);
323
+ }
324
+ } else if (
325
+ typeof query[key] === "object" &&
326
+ !Array.isArray(query[key])
327
+ ) {
328
+ if (query[key].$in)
329
+ mergedValues = [...mergedValues, ...query[key].$in];
330
+ }
331
+ }
332
+ return mergedValues;
336
333
  }
337
334
 
338
335
  function sort$in(data, query) {
339
- let mergedValues = get$in(query);
340
-
341
- if (mergedValues.length) {
342
- const sorted = mergedValues
343
- .map((name) => data.find((career) => career.name === name))
344
- .filter((career) => career !== undefined);
345
- return sorted;
346
- }
336
+ let mergedValues = get$in(query);
337
+
338
+ if (mergedValues.length) {
339
+ const sorted = mergedValues
340
+ .map((name) => data.find((career) => career.name === name))
341
+ .filter((career) => career !== undefined);
342
+ return sorted;
343
+ }
347
344
  }
348
345
 
349
346
  async function setData(element, data) {
350
- if (!element) {
351
- element = getDataElements(data);
352
- if (!element.length) return;
353
- }
354
- if (!(element instanceof HTMLCollection) && !Array.isArray(element))
355
- element = [element];
356
-
357
- let type = data.type;
358
- if (!type && data.method) {
359
- type = data.method.split(".")[0];
360
- } else if (type == "key") type = "object";
361
-
362
- if (data.$filter && data.$filter.query) {
363
- let sortedData = sort$in(data[type], data.$filter.query);
364
- if (sortedData && sortedData.length) data[type] = sortedData;
365
- }
366
-
367
- for (let el of element) {
368
- // if rendered in server side skip
369
- if (el.hasAttribute("rendered")) return el.removeAttribute("rendered");
370
- if (el.hasAttribute("render-json")) {
371
- // TODO find the json template in the text or attributes
372
- // if found add the node as an element, if the element has crud attributes also add as the element
373
- // for (let attribute of el.attributes) {
374
- // if (attribute.value.match(/{{(.*?)}}/)) {
375
- // let value = await renderValue(attribute, data[type][0], attribute.value)
376
- // if (value)
377
- // attribute.value = value
378
- // }
379
- // }
380
- // if (el.innerHTML.match(/{{(.*?)}}/)) {
381
- // let value = renderValue(el, data[type], el.innerHTML)
382
- // if (value)
383
- // el.innerHTML = value
384
- // }
385
-
386
- // if (el.textContent.match(/{{(.*?)}}/)) {
387
- // let value = renderValue(el, undefined, el.textContent)
388
- // if (value)
389
- // attribute.value = value
390
- // }
391
-
392
- // let Data = JSON.parse(match[1]);
393
- // Data.method = object.read
394
- // CRUD.send(Data)
395
- console.log("render-json", "");
396
- }
397
-
398
- let reference = el.getAttribute("reference");
399
- let action = el.getAttribute("actions");
400
- if (action && ["database", "array", "object", "key"].includes(action))
401
- continue;
402
-
403
- if (data.array.includes("aiConversations")) {
404
- console.log("testing ai conversations");
405
- }
406
-
407
- const { key, isRead, isUpdate, isListen, isCrdt } = getAttributes(el);
408
- let elementType = el.getAttribute("type");
409
- if (elementType !== "file" && (el.getFilter || el.renderValue))
410
- await filterData(el, data, type, key);
411
- else {
412
- if (!data[type] || !data[type].length) {
413
- if (el.hasAttribute("value-dispatch")) el.setValue("");
414
- continue;
415
- }
416
-
417
- if (key && checkValue(key)) {
418
- let value;
419
- if (key.includes("$length")) {
420
- value = CRUD.getValueFromObject(
421
- data[type][0],
422
- key.replace(/\.\$length$/, "")
423
- );
424
- if (value) value = value.length;
425
- else value = 0;
426
- } else {
427
- let $update = data[type][0].$update;
428
- if ($update) {
429
- delete data[type][0].$update;
430
- data[type][0] = { ...data[type][0], ...$update };
431
- } else if (key === "$data") {
432
- value = data;
433
- } else if (key && key.startsWith("$data")) {
434
- value = CRUD.getValueFromObject(data, key.slice(1));
435
- } else if (key === `$${type}`) {
436
- value = data[type];
437
- } else if (key && key.startsWith(`$${type}`)) {
438
- value = CRUD.getValueFromObject(data, key.slice(1));
439
- } else if (key === "{}") {
440
- value = data[type][0];
441
- if (reference === "false") {
442
- delete data[type][0].$storage;
443
- delete data[type][0].$database;
444
- delete data[type][0].$array;
445
- }
446
- } else {
447
- value = CRUD.getValueFromObject(data[type][0], key);
448
- }
449
- }
450
-
451
- if (!data[type].length) continue;
452
- if (isRead === "false" || isCrdt === "true") continue;
453
- if (
454
- isUpdate === "false" ||
455
- (isListen === "false" && !data.method.endsWith(".read"))
456
- )
457
- continue;
458
-
459
- // TODO: object.update data returned from server will not include $operator
460
- el.setValue(value);
461
- }
462
- }
463
- }
347
+ if (!element) {
348
+ element = getDataElements(data);
349
+ if (!element.length) return;
350
+ }
351
+ if (!(element instanceof HTMLCollection) && !Array.isArray(element))
352
+ element = [element];
353
+
354
+ let type = data.type;
355
+ if (!type && data.method) {
356
+ type = data.method.split(".")[0];
357
+ } else if (type == "key") type = "object";
358
+
359
+ if (data.$filter && data.$filter.query) {
360
+ let sortedData = sort$in(data[type], data.$filter.query);
361
+ if (sortedData && sortedData.length) data[type] = sortedData;
362
+ }
363
+
364
+ for (let el of element) {
365
+ // if rendered in server side skip
366
+ if (el.hasAttribute("rendered")) return el.removeAttribute("rendered");
367
+ if (el.hasAttribute("render-json")) {
368
+ console.log("render-json", "");
369
+ }
370
+
371
+ let reference = el.getAttribute("reference");
372
+ let action = el.getAttribute("actions");
373
+ if (action && ["database", "array", "object", "key"].includes(action))
374
+ continue;
375
+
376
+ if (data.array.includes("aiConversations")) {
377
+ console.log("testing ai conversations");
378
+ }
379
+
380
+ const { key, isRead, isUpdate, isListen, isCrdt } = getAttributes(el);
381
+ let elementType = el.getAttribute("type");
382
+ if (elementType !== "file" && (el.getFilter || el.renderValue))
383
+ await filterData(el, data, type, key);
384
+ else {
385
+ if (!data[type] || !data[type].length) {
386
+ if (el.hasAttribute("value-dispatch")) el.setValue("");
387
+ continue;
388
+ }
389
+
390
+ if (key && checkValue(key)) {
391
+ let value;
392
+ if (key.includes("$length")) {
393
+ value = CRUD.getValueFromObject(
394
+ data[type][0],
395
+ key.replace(/\.\$length$/, "")
396
+ );
397
+ if (value) value = value.length;
398
+ else value = 0;
399
+ } else {
400
+ let $update = data[type][0].$update;
401
+ if ($update) {
402
+ delete data[type][0].$update;
403
+ data[type][0] = { ...data[type][0], ...$update };
404
+ } else if (key === "$data") {
405
+ value = data;
406
+ } else if (key && key.startsWith("$data")) {
407
+ value = CRUD.getValueFromObject(data, key.slice(1));
408
+ } else if (key === `$${type}`) {
409
+ value = data[type];
410
+ } else if (key && key.startsWith(`$${type}`)) {
411
+ value = CRUD.getValueFromObject(data, key.slice(1));
412
+ } else if (key === "{}") {
413
+ value = data[type][0];
414
+ if (reference === "false") {
415
+ delete data[type][0].$storage;
416
+ delete data[type][0].$database;
417
+ delete data[type][0].$array;
418
+ }
419
+ } else {
420
+ value = CRUD.getValueFromObject(data[type][0], key);
421
+ }
422
+ }
423
+
424
+ if (!data[type].length) continue;
425
+ if (isRead === "false" || isCrdt === "true") continue;
426
+ if (
427
+ isUpdate === "false" ||
428
+ (isListen === "false" && !data.method.endsWith(".read"))
429
+ )
430
+ continue;
431
+
432
+ // TODO: object.update data returned from server will not include $operator
433
+ el.setValue(value);
434
+ }
435
+ }
436
+ }
464
437
  }
465
438
 
466
439
  async function filterData(element, data, type, key) {
467
- let operator = "",
468
- value;
469
-
470
- if (key && !key.includes("$length") && key !== "{}") {
471
- if (!data || !type) return;
472
-
473
- if (key.startsWith("$")) {
474
- operator = key.split(".")[0] || "";
475
- }
476
-
477
- let property = key;
478
- if (operator) {
479
- property = property.replace(operator + ".", "");
480
- if (operator === "$sum") {
481
- value = 0;
482
- }
483
- }
484
- if (Array.isArray(data[type])) {
485
- let Data = [],
486
- isObject;
487
- for (let doc of data[type]) {
488
- if (!doc.$storage) continue;
489
- // TODO: should have been handled by getDataElements()
490
- if (type === "object") {
491
- let _id = element.getAttribute("object");
492
- if (_id && doc._id !== _id) continue;
493
- let $update = doc.$update;
494
- if ($update) {
495
- delete doc.$update;
496
- doc = { ...doc, ...$update };
497
- }
498
- }
499
- let docValue = getValueFromObject(doc, property);
500
- if (docValue) {
501
- if (operator === "$sum" && typeof docValue === "number") {
502
- if (typeof value !== "number") value = 0;
503
- value += docValue || 0;
504
- } else if (Array.isArray(docValue)) {
505
- Data.push(...docValue);
506
- } else {
507
- isObject = true;
508
- Data.push(docValue);
509
- }
510
- } else continue;
511
- }
512
-
513
- if (isObject && Data.length === 1) {
514
- Data = Data[0];
515
- }
516
-
517
- // if (isObject && Data.length === 1) {
518
- // data = { [property]: Data[0] }
519
- // } else
520
- if (!operator) data = Data;
521
- // else if (operator === "$sum") {
522
- // value = data[type].reduce((accumulator, currentValue) => {
523
- // return accumulator + currentValue;
524
- // }, 0);
525
- // }
526
- } else {
527
- data = { [property]: data[type][property] };
528
- }
529
- }
530
-
531
- let isRendered = element.querySelector("[render-clone]");
532
- if (operator) {
533
- element.setValue(value);
534
- } else if (
535
- element.renderValue &&
536
- data.method &&
537
- data.method.endsWith(".read") &&
538
- data.$filter &&
539
- (data.$filter.overwrite || !isRendered)
540
- ) {
541
- await element.renderValue(data);
542
- } else if (
543
- (data.$filter && data.$filter.loadmore) ||
544
- (data.method && data.method.endsWith(".read") && isRendered)
545
- ) {
546
- await loadMore(element, data, type);
547
- } else if (
548
- element.getFilter &&
549
- data.method &&
550
- !data.method.endsWith(".read")
551
- ) {
552
- await checkFilters(element, data, type);
553
- } else if (element.renderValue) {
554
- if (key)
555
- data = {[key]: data}
556
- await element.renderValue(data);
557
- } else if (key === "$length") {
558
- element.setValue(data[type].length);
559
- } else if (key && key.includes("$length")) {
560
- let value = CRUD.getValueFromObject(
561
- data[type][0],
562
- key.replace(/\.\$length$/, "")
563
- );
564
- element.setValue(value.length);
565
- } else if (key === "$data") {
566
- value = data;
567
- } else if (key && key.startsWith("$data")) {
568
- value = CRUD.getValueFromObject(data, key.slice(1));
569
- } else if (key === `$${type}`) {
570
- value = data[type];
571
- } else if (key && key.startsWith(`$${type}`)) {
572
- value = CRUD.getValueFromObject(data, key.slice(1));
573
- } else if (key === "{}") {
574
- value = data[type][0];
575
- // if (reference === "false") {
576
- // delete data[type][0].$storage;
577
- // delete data[type][0].$database;
578
- // delete data[type][0].$array;
579
- // }
580
- } else if (data) element.setValue(data);
581
-
582
- if (data.$filter) {
583
- let filterElement = filter.filters.get(element);
584
- if (filterElement) filterElement.index = data.$filter.index;
585
- }
586
-
587
- if (!data[type] || !Array.isArray(data[type]) || !data[type].length) return;
588
-
589
- const evt = new CustomEvent("fetchedData", { bubbles: true });
590
- element.dispatchEvent(evt);
440
+ let operator = "",
441
+ value;
442
+
443
+ if (key && !key.includes("$length") && key !== "{}") {
444
+ if (!data || !type) return;
445
+
446
+ if (key.startsWith("$")) {
447
+ operator = key.split(".")[0] || "";
448
+ }
449
+
450
+ let property = key;
451
+ if (operator) {
452
+ property = property.replace(operator + ".", "");
453
+ if (operator === "$sum") {
454
+ value = 0;
455
+ }
456
+ }
457
+ if (Array.isArray(data[type])) {
458
+ let filteredItems = [],
459
+ isObject;
460
+ for (let doc of data[type]) {
461
+ if (!doc.$storage) continue;
462
+ // TODO: should have been handled by getDataElements()
463
+ if (type === "object") {
464
+ let _id = element.getAttribute("object");
465
+ if (_id && doc._id !== _id) continue;
466
+ let $update = doc.$update;
467
+ if ($update) {
468
+ delete doc.$update;
469
+ doc = { ...doc, ...$update };
470
+ }
471
+ }
472
+ let docValue = getValueFromObject(doc, property);
473
+ if (docValue) {
474
+ if (operator === "$sum" && typeof docValue === "number") {
475
+ if (typeof value !== "number") value = 0;
476
+ value += docValue || 0;
477
+ } else if (Array.isArray(docValue)) {
478
+ filteredItems.push(...docValue);
479
+ } else {
480
+ isObject = true;
481
+ filteredItems.push(docValue);
482
+ }
483
+ } else continue;
484
+ }
485
+
486
+ if (isObject && filteredItems.length === 1) {
487
+ filteredItems = filteredItems[0];
488
+ }
489
+ if (!operator) data = filteredItems;
490
+ } else {
491
+ data = { [property]: data[type][property] };
492
+ }
493
+ }
494
+
495
+ let isRendered = element.querySelector("[render-clone]");
496
+ if (operator) {
497
+ element.setValue(value);
498
+ } else if (
499
+ element.renderValue &&
500
+ data.method &&
501
+ data.method.endsWith(".read") &&
502
+ data.$filter &&
503
+ (data.$filter.overwrite || !isRendered)
504
+ ) {
505
+ await element.renderValue(data);
506
+ } else if (
507
+ (data.$filter && data.$filter.loadmore) ||
508
+ (data.method && data.method.endsWith(".read") && isRendered)
509
+ ) {
510
+ await loadMore(element, data, type);
511
+ } else if (
512
+ element.getFilter &&
513
+ data.method &&
514
+ !data.method.endsWith(".read")
515
+ ) {
516
+ await checkFilters(element, data, type);
517
+ } else if (element.renderValue) {
518
+ if (key)
519
+ data = {[key]: data}
520
+ await element.renderValue(data);
521
+ } else if (key === "$length") {
522
+ element.setValue(data[type].length);
523
+ } else if (key && key.includes("$length")) {
524
+ let value = CRUD.getValueFromObject(
525
+ data[type][0],
526
+ key.replace(/\.\$length$/, "")
527
+ );
528
+ element.setValue(value.length);
529
+ } else if (key === "$data") {
530
+ value = data;
531
+ } else if (key && key.startsWith("$data")) {
532
+ value = CRUD.getValueFromObject(data, key.slice(1));
533
+ } else if (key === `$${type}`) {
534
+ value = data[type];
535
+ } else if (key && key.startsWith(`$${type}`)) {
536
+ value = CRUD.getValueFromObject(data, key.slice(1));
537
+ } else if (key === "{}") {
538
+ value = data[type][0];
539
+ } else if (data) element.setValue(data);
540
+
541
+ if (data.$filter) {
542
+ let filterElement = filter.filters.get(element);
543
+ if (filterElement) filterElement.index = data.$filter.index;
544
+ }
545
+
546
+ if (!data[type] || !Array.isArray(data[type]) || !data[type].length) return;
547
+
548
+ const evt = new CustomEvent("fetchedData", { bubbles: true });
549
+ element.dispatchEvent(evt);
591
550
  }
592
551
 
593
552
  async function loadMore(element, data, type, sort) {
594
- let Data = { ...data };
595
- let renderedData = await element.getData();
596
- if (!renderedData || !renderedData[type]) {
597
- return;
598
- }
599
- for (let i = 0; i < Data[type].length; i++) {
600
- let index;
601
- if (type === "object") {
602
- index = renderedData[type].findIndex(
603
- (obj) => obj._id === Data[type][i]._id
604
- );
605
- } else {
606
- index = renderedData[type].findIndex(
607
- (obj) => obj.name === Data[type][i].name
608
- );
609
- }
610
-
611
- if (index >= 0) {
612
- Data[type].splice(i, 1);
613
- i--; // Adjust the index to account for the removed item
614
- }
615
- }
616
- if (Data[type].length > 0) {
617
- await element.renderValue(Data);
618
- }
553
+ let clonedData = { ...data };
554
+ let renderedData = await element.getData();
555
+ if (!renderedData || !renderedData[type]) {
556
+ return;
557
+ }
558
+ for (let i = 0; i < clonedData[type].length; i++) {
559
+ let index;
560
+ if (type === "object") {
561
+ index = renderedData[type].findIndex(
562
+ (obj) => obj._id === clonedData[type][i]._id
563
+ );
564
+ } else {
565
+ index = renderedData[type].findIndex(
566
+ (obj) => obj.name === clonedData[type][i].name
567
+ );
568
+ }
569
+
570
+ if (index >= 0) {
571
+ clonedData[type].splice(i, 1);
572
+ i--; // Adjust the index to account for the removed item
573
+ }
574
+ }
575
+ if (clonedData[type].length > 0) {
576
+ await element.renderValue(clonedData);
577
+ }
619
578
  }
620
579
 
621
580
  async function checkFilters(element, data, type) {
622
- let Data;
623
- if (!element.getData) {
624
- // TODO: fix: getObject as this is related to render or form, but filter could exist on an input which does not have getObject
625
- // TODO: generate an object of current element key: value to use with filter. because filter is used object is not defined
626
- Data = getObject(element);
627
- if (Array.isArray(Data[type])) Data = Data[type][0];
628
- } else Data = await element.getData();
629
-
630
- if (!Data) return;
631
-
632
- let newData;
633
- if (type) {
634
- Data = Data[type];
635
- newData = data[type];
636
- } else newData = data;
637
-
638
- let filter = await element.getFilter();
639
- if (filter && filter.query) {
640
- for (let i = 0; i < newData.length; i++) {
641
- let isMatch = queryData(newData[i], filter.query);
642
- if (!isMatch) newData.slice(i, 1);
643
- }
644
- }
645
-
646
- if (!newData || !newData.length) return;
647
-
648
- if (Array.isArray(Data)) {
649
- if (Array.isArray(newData)) {
650
- for (let i = 0; i < newData.length; i++) {
651
- checkIndex(element, data, Data, newData[i], type, filter);
652
- }
653
- } else {
654
- checkIndex(element, data, Data, newData, type, filter);
655
- }
656
- } else {
657
- let primaryKey;
658
- if (type === "object") {
659
- primaryKey = "_id";
660
- } else {
661
- primaryKey = "name";
662
- }
663
-
664
- if (Array.isArray(newData)) {
665
- for (let i = 0; i < newData.length; i++) {
666
- if (
667
- typeof Data === "string" &&
668
- Data === newData[i][primaryKey]
669
- ) {
670
- Data = newData[i];
671
- } else if (Data[primaryKey] === newData[i][primaryKey]) {
672
- Data = dotNotationToObject(newData[i], Data);
673
- }
674
- }
675
- } else if (typeof Data === "string" && Data === newData[primaryKey]) {
676
- Data = newData;
677
- } else if (Data[primaryKey] === newData[primaryKey]) {
678
- Data = dotNotationToObject(newData, Data);
679
- }
680
-
681
- if (element.renderValue) element.renderValue(data);
682
- // render({ element, data, key: type });
683
- else if (data) element.setValue(data);
684
- }
581
+ let localData;
582
+ if (!element.getData) {
583
+ // TODO: fix: getObject as this is related to render or form, but filter could exist on an input which does not have getObject
584
+ // TODO: generate an object of current element key: value to use with filter. because filter is used object is not defined
585
+ localData = getObject(element);
586
+ if (Array.isArray(localData[type])) localData = localData[type][0];
587
+ } else localData = await element.getData();
588
+
589
+ if (!localData) return;
590
+
591
+ let newData;
592
+ if (type) {
593
+ localData = localData[type];
594
+ newData = data[type];
595
+ } else newData = data;
596
+
597
+ let filter = await element.getFilter();
598
+ if (filter && filter.query) {
599
+ newData = newData.filter(item => queryData(item, filter.query));
600
+ }
601
+
602
+ if (!newData || !newData.length) return;
603
+
604
+ if (Array.isArray(localData)) {
605
+ if (Array.isArray(newData)) {
606
+ for (let i = 0; i < newData.length; i++) {
607
+ checkIndex(element, data, localData, newData[i], type, filter);
608
+ }
609
+ } else {
610
+ checkIndex(element, data, localData, newData, type, filter);
611
+ }
612
+ } else {
613
+ let primaryKey;
614
+ if (type === "object") {
615
+ primaryKey = "_id";
616
+ } else {
617
+ primaryKey = "name";
618
+ }
619
+
620
+ if (Array.isArray(newData)) {
621
+ for (let i = 0; i < newData.length; i++) {
622
+ if (
623
+ typeof localData === "string" &&
624
+ localData === newData[i][primaryKey]
625
+ ) {
626
+ localData = newData[i];
627
+ } else if (localData[primaryKey] === newData[i][primaryKey]) {
628
+ localData = dotNotationToObject(newData[i], localData);
629
+ }
630
+ }
631
+ } else if (typeof localData === "string" && localData === newData[primaryKey]) {
632
+ localData = newData;
633
+ } else if (localData[primaryKey] === newData[primaryKey]) {
634
+ localData = dotNotationToObject(newData, localData);
635
+ }
636
+
637
+ if (element.renderValue) element.renderValue(data);
638
+ // render({ element, data, key: type });
639
+ else if (data) element.setValue(localData);
640
+ }
685
641
  }
686
642
 
687
- function checkIndex(element, data, Data, newData, type, filter) {
688
- let index;
689
- if (type === "object") {
690
- index = Data.findIndex((obj) => obj._id === newData._id);
691
- } else {
692
- index = Data.findIndex((obj) => obj.name === newData.name);
693
- }
694
-
695
- if (!data.$filter) data.$filter = {};
696
-
697
- if (data.method.endsWith(".delete")) {
698
- if (!index && index !== 0) return;
699
- data.$filter.remove = true;
700
- } else {
701
- if (data.method.endsWith(".create")) {
702
- if (index === -1) {
703
- data.$filter.create = true;
704
- if (filter && filter.sort) newData.isNewData = true;
705
- else index = Data.length;
706
- Data.push(newData);
707
- }
708
- } else {
709
- data.$filter.update = true;
710
- data.$filter.currentIndex = index;
711
- Data[index] = dotNotationToObject(newData, Data[index]);
712
- if (filter && filter.sort) {
713
- Data[index].isNewData = true;
714
- }
715
- }
716
-
717
- if (filter && filter.sort) {
718
- Data = sortData(Data, filter.sort);
719
- index = Data.findIndex((obj) => obj.isNewData);
720
- }
721
- }
722
-
723
- if (index >= 0) {
724
- if (data.$filter.currentIndex === index)
725
- delete data.$filter.currentIndex;
726
- data.$filter.index = index;
727
- if (element.renderValue) element.renderValue(data);
728
- else if (data) element.setValue(data);
729
- }
643
+ function checkIndex(element, data, localData, newData, type, filter) {
644
+ let index;
645
+ if (type === "object") {
646
+ index = localData.findIndex((obj) => obj._id === newData._id);
647
+ } else {
648
+ index = localData.findIndex((obj) => obj.name === newData.name);
649
+ }
650
+
651
+ if (!data.$filter) data.$filter = {};
652
+
653
+ if (data.method.endsWith(".delete")) {
654
+ if (index === -1) return;
655
+ data.$filter.remove = true;
656
+ localData.splice(index, 1);
657
+ } else {
658
+ if (data.method.endsWith(".create")) {
659
+ if (index === -1) {
660
+ data.$filter.create = true;
661
+ if (filter && filter.sort) newData.isNewData = true;
662
+ else index = localData.length;
663
+ localData.push(newData);
664
+ }
665
+ } else {
666
+ if (index === -1) return;
667
+ data.$filter.update = true;
668
+ data.$filter.currentIndex = index;
669
+ localData[index] = dotNotationToObject(newData, localData[index]);
670
+ if (filter && filter.sort) {
671
+ localData[index].isNewData = true;
672
+ }
673
+ }
674
+
675
+ if (filter && filter.sort) {
676
+ localData = sortData(localData, filter.sort);
677
+ index = localData.findIndex((obj) => obj.isNewData);
678
+ }
679
+ }
680
+
681
+ if (index >= 0) {
682
+ if (data.$filter.currentIndex === index)
683
+ delete data.$filter.currentIndex;
684
+ data.$filter.index = index;
685
+ if (element.renderValue) element.renderValue(data);
686
+ else if (data) element.setValue(localData);
687
+ }
730
688
  }
731
689
 
732
690
  function getDataKey(data) {
733
- let dataKey = {};
734
- let attributes = [
735
- "host",
736
- "organization_id",
737
- "apikey",
738
- "method",
739
- "type",
740
- "storage",
741
- "database",
742
- "array",
743
- "index",
744
- "object",
745
- "key",
746
- "updateKey",
747
- "$filter",
748
- "upsert",
749
- "namespace",
750
- "room",
751
- "broadcast",
752
- "broadcastSender",
753
- "broadcastBrowser"
754
- ];
755
-
756
- for (let attribute of attributes) {
757
- if (attribute === "key" && data.type === "object") continue;
758
- let value = data[attribute];
759
- if (value) {
760
- if (Array.isArray(value)) {
761
- dataKey[attribute] = [...value];
762
- if (typeof value[0] === "string") dataKey[attribute].sort(); // Sort the values alphabetically
763
- } else {
764
- dataKey[attribute] = value;
765
- }
766
- }
767
- }
768
-
769
- const object = Object.fromEntries(
770
- Object.entries(dataKey).sort(([a], [b]) => a.localeCompare(b))
771
- );
772
- const string = JSON.stringify(object);
773
-
774
- return { string, object };
691
+ let dataKey = {};
692
+ let attributes = [
693
+ "host",
694
+ "organization_id",
695
+ "apikey",
696
+ "method",
697
+ "type",
698
+ "storage",
699
+ "database",
700
+ "array",
701
+ "index",
702
+ "object",
703
+ "key",
704
+ "updateKey",
705
+ "$filter",
706
+ "upsert",
707
+ "namespace",
708
+ "room",
709
+ "broadcast",
710
+ "broadcastSender",
711
+ "broadcastBrowser"
712
+ ];
713
+
714
+ for (let attribute of attributes) {
715
+ if (attribute === "key" && data.type === "object") continue;
716
+ let value = data[attribute];
717
+ if (value) {
718
+ if (Array.isArray(value)) {
719
+ dataKey[attribute] = [...value];
720
+ if (typeof value[0] === "string") dataKey[attribute].sort(); // Sort the values alphabetically
721
+ } else {
722
+ dataKey[attribute] = value;
723
+ }
724
+ }
725
+ }
726
+
727
+ const object = Object.fromEntries(
728
+ Object.entries(dataKey).sort(([a], [b]) => a.localeCompare(b))
729
+ );
730
+ const string = JSON.stringify(object);
731
+
732
+ return { string, object };
775
733
  }
776
734
 
777
735
  function getDataElements(data) {
778
- let element = [];
779
- let matchingKeys = getDataKeys(data);
780
- for (let i = 0; i < matchingKeys.length; i++) {
781
- let matchingElements = keys.get(matchingKeys[i]);
782
- if (
783
- matchingElements &&
784
- matchingElements.elements &&
785
- matchingElements.elements.size
786
- )
787
- element.push(...matchingElements.elements.keys());
788
- }
789
- return element;
736
+ let element = [];
737
+ let matchingKeys = getDataKeys(data);
738
+ for (let i = 0; i < matchingKeys.length; i++) {
739
+ let matchingElements = keys.get(matchingKeys[i]);
740
+ if (matchingElements?.elements?.size)
741
+ element.push(...matchingElements.elements.keys());
742
+ }
743
+ return element;
790
744
  }
791
745
 
792
746
  // TODO: Correctly check for matches
793
747
  function getDataKeys(data) {
794
- const matchingKeyStrings = [];
795
- const targetKeys = [
796
- "type",
797
- "storage",
798
- "database",
799
- "array",
800
- "index",
801
- "object",
802
- "$filter"
803
- ];
804
-
805
- for (const [keyString, sortedKey] of keys.entries()) {
806
- let hasMatch = true;
807
-
808
- for (const key of targetKeys) {
809
- if (
810
- !data.$filter &&
811
- key === "$filter" &&
812
- sortedKey.data.hasOwnProperty(key)
813
- )
814
- hasMatch = true;
815
- else if (data.hasOwnProperty(key)) {
816
- if (!sortedKey.data.hasOwnProperty(key)) {
817
- hasMatch = false;
818
- break;
819
- }
820
- if (
821
- Array.isArray(sortedKey.data[key]) &&
822
- Array.isArray(data[key])
823
- ) {
824
- // if key is object check _id
825
- if (key === "object" && sortedKey.data.$filter)
826
- hasMatch = true;
827
- else {
828
- const matches = sortedKey.data[key].some((value) => {
829
- if (key === "object") {
830
- return data[key].some((obj) => {
831
- return obj._id === value._id;
832
- });
833
- } else {
834
- return data[key].includes(value);
835
- }
836
- });
837
-
838
- if (!matches) {
839
- hasMatch = false;
840
- break;
841
- }
842
- }
843
- } else if (sortedKey.data[key] !== data[key]) {
844
- hasMatch = false;
845
- break;
846
- }
847
- }
848
- }
849
-
850
- if (hasMatch) {
851
- matchingKeyStrings.push(keyString);
852
- }
853
- }
854
-
855
- return matchingKeyStrings;
748
+ const matchingKeyStrings = [];
749
+ const targetKeys = [
750
+ "type",
751
+ "storage",
752
+ "database",
753
+ "array",
754
+ "index",
755
+ "object",
756
+ "$filter"
757
+ ];
758
+
759
+ for (const [keyString, sortedKey] of keys.entries()) {
760
+ let hasMatch = true;
761
+
762
+ for (const key of targetKeys) {
763
+ if (
764
+ !data.$filter &&
765
+ key === "$filter" &&
766
+ sortedKey.data.hasOwnProperty(key)
767
+ )
768
+ hasMatch = true;
769
+ else if (data.hasOwnProperty(key)) {
770
+ if (!sortedKey.data.hasOwnProperty(key)) {
771
+ hasMatch = false;
772
+ break;
773
+ }
774
+ if (
775
+ Array.isArray(sortedKey.data[key]) &&
776
+ Array.isArray(data[key])
777
+ ) {
778
+ // if key is object check _id
779
+ if (key === "object" && sortedKey.data.$filter)
780
+ hasMatch = true;
781
+ else {
782
+ const matches = sortedKey.data[key].some((value) => {
783
+ if (key === "object") {
784
+ return data[key].some((obj) => {
785
+ return obj._id === value._id;
786
+ });
787
+ } else {
788
+ return data[key].includes(value);
789
+ }
790
+ });
791
+
792
+ if (!matches) {
793
+ hasMatch = false;
794
+ break;
795
+ }
796
+ }
797
+ } else if (sortedKey.data[key] !== data[key]) {
798
+ hasMatch = false;
799
+ break;
800
+ }
801
+ }
802
+ }
803
+
804
+ if (hasMatch) {
805
+ matchingKeyStrings.push(keyString);
806
+ }
807
+ }
808
+
809
+ return matchingKeyStrings;
810
+ }
811
+
812
+ function formatPayload(payload, value, element) {
813
+ if (!payload[payload.type] && payload.key) {
814
+ payload.method = payload.type + ".create";
815
+ if (payload.type === "object") {
816
+ if (!payload.object) payload.object = {};
817
+ else if (typeof payload.object === "string")
818
+ payload.object = { _id: payload.object };
819
+
820
+ if (payload.key) {
821
+ if (payload.key == "{}") {
822
+ if (Array.isArray(value)) {
823
+ payload.object = value;
824
+ } else payload.object = { ...payload.object, ...value };
825
+ } else payload.object[payload.key] = value;
826
+ }
827
+ if (payload.isUpsert && payload.$filter)
828
+ payload.method = "object.update";
829
+ } else payload[payload.type] = value;
830
+ } else if (payload[payload.type] && payload.key) {
831
+ let attributes = element.attributes;
832
+ if (payload.key.startsWith("$")) {
833
+ const operators = ["$rename", "$inc", "$push", "$each", "$splice", "$unset", "$delete", "$slice", "$pop", "$shift", "$addToSet", "$pull"];
834
+ const matchedAttr = Array.from(attributes).find(attr => operators.includes(attr.name));
835
+ if (matchedAttr) {
836
+ payload.key = matchedAttr.name + "." + payload.key;
837
+ }
838
+ }
839
+
840
+ if (payload.type === "object") {
841
+ if (typeof payload[payload.type] === "string")
842
+ if (payload.key == "{}") {
843
+ if (Array.isArray(value))
844
+ payload[payload.type] = {
845
+ _id: payload[payload.type],
846
+ ...value[0]
847
+ };
848
+ else
849
+ payload[payload.type] = {
850
+ _id: payload[payload.type],
851
+ ...value
852
+ };
853
+ } else
854
+ payload[payload.type] = {
855
+ _id: payload[payload.type],
856
+ [payload.key]: value
857
+ };
858
+ else if (Array.isArray(payload[payload.type]))
859
+ if (payload.key == "{}")
860
+ payload[payload.type][0] = {
861
+ ...payload[payload.type][0],
862
+ ...value
863
+ };
864
+ else {
865
+ if (payload[payload.type][0]) {
866
+ payload[payload.type][0][payload.key] = value;
867
+ }
868
+ if (!payload[payload.type][0]._id)
869
+ payload.method = payload.type + ".create";
870
+ }
871
+ else if (typeof payload[payload.type] === "object")
872
+ if (payload.key == "{}")
873
+ payload[payload.type] = { ...payload[payload.type], ...value };
874
+ else {
875
+ payload[payload.type][payload.key] = value;
876
+ if (!payload[payload.type]._id)
877
+ payload.method = payload.type + ".create";
878
+ }
879
+ } else {
880
+ payload[payload.type] = { [payload[payload.type]]: value };
881
+ }
882
+
883
+ if (payload.isUpdate || payload.isUpdate === "") {
884
+ if (!payload.key) return false;
885
+ delete payload.isUpdate;
886
+ payload.updateKey = { [payload.key]: value };
887
+ payload.method = payload.type + ".update";
888
+ } else if (payload.isDelete || payload.isDelete === "") {
889
+ delete payload.isDelete;
890
+ if (payload.type == "object" && payload.key) {
891
+ payload.method = payload.type + ".update";
892
+ if (typeof payload[payload.type] === "string")
893
+ payload[payload.type] = {
894
+ _id: payload[payload.type],
895
+ [payload.key]: undefined
896
+ };
897
+ else if (Array.isArray(payload[payload.type])) {
898
+ console.log(
899
+ "payload.type is an array function incomplete"
900
+ );
901
+ } else if (typeof payload[payload.type] === "object")
902
+ payload[payload.type][payload.key] = undefined;
903
+ } else {
904
+ payload.method = payload.type + ".delete";
905
+ }
906
+ }
907
+ }
908
+ return true;
856
909
  }
857
910
 
858
911
  async function getData(form) {
859
- let dataKeys = new Map();
860
- let formObject = forms.get(form);
861
- if (!formObject) {
862
- let elements = form.querySelectorAll(selector);
863
- await init(elements);
864
- return await getData(form);
865
- }
866
-
867
- for (let type of formObject.types.values()) {
868
- for (let [element, data] of type.entries()) {
869
- if (
870
- !element.hasAttribute("key") ||
871
- element.getAttribute("save") === "false"
872
- )
873
- continue;
874
-
875
- if (element.hasAttribute("actions")) {
876
- let attribute = element.getAttribute("actions");
877
- if (attribute.includes("save", "delete")) continue;
878
- }
879
-
880
- if (element.matches("[render-query]")) {
881
- let type = element.getAttribute("type");
882
- if (type !== "file") continue;
883
- }
884
-
885
- let value = await element.getValue();
886
- if (value === undefined) continue;
887
-
888
- let Data = { ...data };
889
- let dataKey = elements.get(element);
890
-
891
- // console.log(type, value, data)
892
- if (!Data[Data.type] && Data.key) {
893
- // if (!value && value !== "") continue;
894
- // else if (Array.isArray(value) && !value.length) continue;
895
-
896
- Data.method = Data.type + ".create";
897
- if (Data.type === "object") {
898
- if (!Data.object) Data.object = {};
899
- else if (typeof Data.object === "string")
900
- Data.object = { _id: Data.object };
901
-
902
- if (Data.key) {
903
- if (Data.key == "{}") {
904
- if (Array.isArray(value)) {
905
- Data.object = value;
906
- } else Data.object = { ...Data.object, ...value };
907
- } else Data.object[Data.key] = value;
908
- }
909
- if (Data.isUpsert && Data.$filter)
910
- Data.method = "object.update";
911
- } else Data[Data.type] = value;
912
- } else if (Data[Data.type] && Data.key) {
913
- let attributes = element.attributes;
914
- if (Data.key.startsWith("$")) {
915
- for (let i = 0; i < attributes.length; i++) {
916
- let operators = [
917
- "$rename",
918
- "$inc",
919
- "$push",
920
- "$each",
921
- "$splice",
922
- "$unset",
923
- "$delete",
924
- "$slice",
925
- "$pop",
926
- "$shift",
927
- "$addToSet",
928
- "$pull"
929
- ];
930
- if (operators.includes(attributes[i].name)) {
931
- Data.key = attributes[i].name + "." + Data.key;
932
- break;
933
- }
934
- }
935
- }
936
-
937
- if ((Data.type = "object")) {
938
- // if (Data.key == "{}") {
939
- // if (!value && value !== "") continue;
940
- // else if (Array.isArray(value) && !value.length)
941
- // continue;
942
- // }
943
-
944
- if (typeof Data[Data.type] === "string")
945
- if (Data.key == "{}") {
946
- // TODO: handle if array length more than 1
947
- if (Array.isArray(value))
948
- Data[Data.type] = {
949
- _id: Data[Data.type],
950
- ...value[0]
951
- };
952
- else
953
- Data[Data.type] = {
954
- _id: Data[Data.type],
955
- ...value
956
- };
957
- } else
958
- Data[Data.type] = {
959
- _id: Data[Data.type],
960
- [Data.key]: value
961
- };
962
- else if (Array.isArray(Data[Data.type]))
963
- if (Data.key == "{}")
964
- Data[Data.type][0] = {
965
- ...Data[Data.type][0],
966
- ...value
967
- };
968
- else {
969
- if (Data[Data.type][0]) {
970
- Data[Data.type][0][Data.key] = value;
971
- }
972
- if (!Data[Data.type][0]._id)
973
- Data.method = Data.type + ".create";
974
- }
975
- else if (typeof Data[Data.type] === "object")
976
- if (Data.key == "{}")
977
- Data[Data.type] = { ...Data[Data.type], ...value };
978
- else {
979
- Data[Data.type][Data.key] = value;
980
- if (!Data[Data.type]._id)
981
- Data.method = Data.type + ".create";
982
- }
983
- } else {
984
- Data[Data.type] = { [Data[Data.type]]: value };
985
- }
986
-
987
- if (Data.isUpdate || Data.isUpdate === "") {
988
- if (!Data.key) return;
989
- delete Data.isUpdate;
990
- Data.updateKey = { [Data.key]: value };
991
- Data.method = Data.type + ".update";
992
- } else if (Data.isDelete || Data.isDelete === "") {
993
- delete Data.isDelete;
994
- if (Data.type == "object" && Data.key) {
995
- Data.method = Data.type + ".update";
996
- // TODO: Data.type can be a string _id or an array for string _id needs to be converted to object
997
- if (typeof Data[Data.type] === "string")
998
- Data[Data.type] = {
999
- _id: Data[Data.type],
1000
- [Data.key]: undefined
1001
- };
1002
- else if (Array.isArray(Data[Data.type])) {
1003
- console.log(
1004
- "Data.type is an array function incomplete"
1005
- );
1006
- } else if (typeof Data[Data.type] === "object")
1007
- Data[Data.type][Data.key] = undefined;
1008
- } else {
1009
- Data.method = Data.type + ".delete";
1010
- }
1011
- } else if (Data.type !== "object" && Data[Data.type] === "") {
1012
- // if (!Data.key)
1013
- // Data.method = Data.type + '.read'
1014
- // else if (Data.key === 'name')
1015
- // Data.method = Data.type + '.create'
1016
- } else if (Data.type !== "object" && Data[Data.type]) {
1017
- // if (Data.key)
1018
- // Data.method = Data.type + '.update'
1019
- }
1020
- }
1021
-
1022
- //dataKey should be used to group
1023
- let key = dataKey; //+ Data.method;
1024
- if (dataKeys.has(key)) {
1025
- let storedData = dataKeys.get(key)[Data.type];
1026
- dataKeys.get(key)[Data.type] = {
1027
- ...storedData,
1028
- ...Data[Data.type]
1029
- };
1030
- } else {
1031
- dataKeys.set(key, Data);
1032
- }
1033
- }
1034
- }
1035
-
1036
- // TODO: group by methods so we can make one crud request per method
1037
- let dataArray = Array.from(dataKeys.values());
1038
-
1039
- return dataArray;
912
+ let dataKeys = new Map();
913
+ let formObject = forms.get(form);
914
+ if (!formObject) {
915
+ let elements = form.querySelectorAll(selector);
916
+ await init(elements);
917
+ return await getData(form);
918
+ }
919
+
920
+ for (let type of formObject.types.values()) {
921
+ for (let [element, data] of type.entries()) {
922
+ if (
923
+ !element.hasAttribute("key") ||
924
+ element.getAttribute("save") === "false"
925
+ )
926
+ continue;
927
+
928
+ if (element.hasAttribute("actions")) {
929
+ let attribute = element.getAttribute("actions");
930
+ if (attribute.includes("save") || attribute.includes("delete")) continue;
931
+ }
932
+
933
+ if (element.matches("[render-query]")) {
934
+ let type = element.getAttribute("type");
935
+ if (type !== "file") continue;
936
+ }
937
+
938
+ let value = await element.getValue();
939
+ if (value === undefined) continue;
940
+
941
+ let payload = { ...data };
942
+ let dataKey = elements.get(element);
943
+
944
+ let success = formatPayload(payload, value, element);
945
+ if (!success) continue;
946
+
947
+ //dataKey should be used to group
948
+ let key = dataKey; //+ payload.method;
949
+ if (dataKeys.has(key)) {
950
+ let storedData = dataKeys.get(key)[payload.type];
951
+ dataKeys.get(key)[payload.type] = {
952
+ ...storedData,
953
+ ...payload[payload.type]
954
+ };
955
+ } else {
956
+ dataKeys.set(key, payload);
957
+ }
958
+ }
959
+ }
960
+
961
+ // TODO: group by methods so we can make one crud request per method
962
+ let dataArray = Array.from(dataKeys.values());
963
+
964
+ return dataArray;
1040
965
  }
1041
966
 
1042
967
  async function save(element, action) {
1043
- if (!element) return;
1044
- let data, value, form;
1045
- let upsert = element.getAttribute("upsert");
1046
- if (upsert && upsert !== "false") upsert = true;
1047
- if (element.tagName === "FORM") {
1048
- data = await element.getData();
1049
- } else {
1050
- let isSave = element.getAttribute("save");
1051
- if (isSave === "false") return;
1052
- if (action) {
1053
- form = element.closest("form");
1054
- if (form) {
1055
- return save(form);
1056
- }
1057
- }
1058
-
1059
- let dataKey = elements.get(element);
1060
- data = { ...keys.get(dataKey).dataKey.object };
1061
-
1062
- value = await element.getValue();
1063
- let key = element.getAttribute("key");
1064
-
1065
- if (typeof data[data.type] === "string")
1066
- if (key == "{}")
1067
- data[data.type] = { _id: data[data.type], ...value };
1068
- else data[data.type] = { _id: data[data.type], [key]: value };
1069
- else if (typeof data[data.type] === "object")
1070
- if (key == "{}") data[data.type] = { ...data[data.type], ...value };
1071
- else data[data.type][key] = value;
1072
-
1073
- if (/\.([0-9]*)/g.test(data.key)) {
1074
- let splice = element.getAttribute("splice");
1075
- let slice = element.getAttribute("slice");
1076
- let update = element.getAttribute("update");
1077
-
1078
- if (splice || splice === "") {
1079
- data[data.type][key] = { $splice: value };
1080
- } else if (slice) {
1081
- data[data.type][key] = "$delete";
1082
- } else if (update) {
1083
- value = data.key.replace(/\[.*?\]/, "[" + value + "]");
1084
- data.updateKey[key] = value;
1085
- data[data.type][key] = { $update: value }; // $update is string use the value as the key name
1086
-
1087
- // data[data.type][key] = { $update: {[value]: value} } // $update is an object use the key as the value to use for the new key
1088
- }
1089
- }
1090
-
1091
- data = [data];
1092
- }
1093
-
1094
- let Data = [];
1095
- for (let i = 0; i < data.length; i++) {
1096
- if (data[i].type === "object") {
1097
- if (!data[i].object) {
1098
- data[i].method = "object.create";
1099
- } else if (typeof data[i].object === "string") {
1100
- if (!data[i]._id) data[i].method = "object.create";
1101
- else {
1102
- data[i].method = "object.update";
1103
- if (upsert) data[i].upsert = true;
1104
- }
1105
- } else if (Array.isArray(data[i].object)) {
1106
- if (!data[i].object[0]._id) {
1107
- data[i].method = "object.create";
1108
- } else {
1109
- data[i].method = "object.update";
1110
- if (upsert) data[i].upsert = true;
1111
- }
1112
- } else if (typeof data[i].object === "object") {
1113
- if (!data[i].object._id) {
1114
- data[i].method = "object.create";
1115
- } else {
1116
- data[i].method = "object.update";
1117
- if (upsert) data[i].upsert = true;
1118
- }
1119
- }
1120
- }
1121
-
1122
- if (data[i].isUpsert) {
1123
- data[i].upsert = true;
1124
- delete data[i].isUpsert;
1125
- }
1126
-
1127
- if (data[i].method && data[i].method.endsWith(".create")) {
1128
- element.setAttribute(data[i].type, "pending");
1129
- } else if (
1130
- data[i].method &&
1131
- data[i].method.endsWith(".update") &&
1132
- data[i].type == "object" &&
1133
- typeof value == "string" &&
1134
- window.CoCreate.crdt &&
1135
- !"crdt"
1136
- ) {
1137
- return window.CoCreate.crdt.replaceText({
1138
- array: data[i].array,
1139
- key: data[i].key,
1140
- object: data[i].object._id,
1141
- value
1142
- });
1143
- }
1144
-
1145
- data[i] = await CRUD.send(data[i]);
1146
-
1147
- Data.push(data[i]);
1148
-
1149
- if (
1150
- data[i] &&
1151
- (data[i].method.endsWith(".create") ||
1152
- (data[i].type !== "object" &&
1153
- data[i].method.endsWith(".update")))
1154
- ) {
1155
- setTypeValue(element, data[i], action);
1156
- } else if (data[i]) {
1157
- if (action) {
1158
- action.element.dispatchEvent(
1159
- new CustomEvent("saved", {
1160
- detail: data
1161
- })
1162
- );
1163
- } else {
1164
- document.dispatchEvent(
1165
- new CustomEvent("saved", {
1166
- detail: data
1167
- })
1168
- );
1169
- }
1170
- }
1171
- }
1172
-
1173
- return Data;
968
+ if (!element) return;
969
+ let data, value, form;
970
+ let upsert = element.getAttribute("upsert");
971
+ if (upsert && upsert !== "false") upsert = true;
972
+ if (element.tagName === "FORM") {
973
+ data = await element.getData();
974
+ } else {
975
+ let isSave = element.getAttribute("save");
976
+ if (isSave === "false") return;
977
+ if (action) {
978
+ form = element.closest("form");
979
+ if (form) {
980
+ return save(form);
981
+ }
982
+ }
983
+
984
+ let dataKey = elements.get(element);
985
+ data = { ...keys.get(dataKey).dataKey.object };
986
+
987
+ value = await element.getValue();
988
+ let key = element.getAttribute("key");
989
+
990
+ if (typeof data[data.type] === "string")
991
+ if (key == "{}")
992
+ data[data.type] = { _id: data[data.type], ...value };
993
+ else data[data.type] = { _id: data[data.type], [key]: value };
994
+ else if (typeof data[data.type] === "object")
995
+ if (key == "{}") data[data.type] = { ...data[data.type], ...value };
996
+ else data[data.type][key] = value;
997
+
998
+ if (/\.([0-9]*)/g.test(data.key)) {
999
+ let splice = element.getAttribute("splice");
1000
+ let slice = element.getAttribute("slice");
1001
+ let update = element.getAttribute("update");
1002
+
1003
+ if (splice || splice === "") {
1004
+ data[data.type][key] = { $splice: value };
1005
+ } else if (slice) {
1006
+ data[data.type][key] = "$delete";
1007
+ } else if (update) {
1008
+ value = data.key.replace(/\[.*?\]/, "[" + value + "]");
1009
+ data.updateKey[key] = value;
1010
+ data[data.type][key] = { $update: value }; // $update is string use the value as the key name
1011
+
1012
+ // data[data.type][key] = { $update: {[value]: value} } // $update is an object use the key as the value to use for the new key
1013
+ }
1014
+ }
1015
+
1016
+ data = [data];
1017
+ }
1018
+
1019
+ let responseDataList = [];
1020
+ for (let i = 0; i < data.length; i++) {
1021
+ if (data[i].type === "object") {
1022
+ let hasId = false;
1023
+
1024
+ // 1. Check your three scenarios just like before
1025
+ if (typeof data[i].object === "string") {
1026
+ hasId = !!data[i]._id;
1027
+ } else if (Array.isArray(data[i].object)) {
1028
+ hasId = !!data[i].object[0]?._id;
1029
+ } else if (typeof data[i].object === "object" && data[i].object !== null) {
1030
+ hasId = !!data[i].object?._id;
1031
+ }
1032
+
1033
+ // 2. Apply the method based on what we found
1034
+ if (!data[i].object || !hasId) {
1035
+ data[i].method = "object.create";
1036
+ } else {
1037
+ data[i].method = "object.update";
1038
+ if (upsert) data[i].upsert = true;
1039
+ }
1040
+ }
1041
+
1042
+ if (data[i].isUpsert) {
1043
+ data[i].upsert = true;
1044
+ delete data[i].isUpsert;
1045
+ }
1046
+
1047
+ if (data[i].method && data[i].method.endsWith(".create")) {
1048
+ element.setAttribute(data[i].type, "pending");
1049
+ } else if (
1050
+ data[i].method &&
1051
+ data[i].method.endsWith(".update") &&
1052
+ data[i].type == "object" &&
1053
+ typeof value == "string" &&
1054
+ window.CoCreate.crdt &&
1055
+ !"crdt"
1056
+ ) {
1057
+ return window.CoCreate.crdt.replaceText({
1058
+ array: data[i].array,
1059
+ key: data[i].key,
1060
+ object: data[i].object._id,
1061
+ value
1062
+ });
1063
+ }
1064
+
1065
+ data[i] = await CRUD.send(data[i]);
1066
+
1067
+ responseDataList.push(data[i]);
1068
+
1069
+ if (
1070
+ data[i] &&
1071
+ (data[i].method.endsWith(".create") ||
1072
+ (data[i].type !== "object" &&
1073
+ data[i].method.endsWith(".update")))
1074
+ ) {
1075
+ setTypeValue(element, data[i], action);
1076
+ } else if (data[i]) {
1077
+ if (action) {
1078
+ action.element.dispatchEvent(
1079
+ new CustomEvent("saved", {
1080
+ detail: data
1081
+ })
1082
+ );
1083
+ } else {
1084
+ document.dispatchEvent(
1085
+ new CustomEvent("saved", {
1086
+ detail: data
1087
+ })
1088
+ );
1089
+ }
1090
+ }
1091
+ }
1092
+
1093
+ return responseDataList;
1174
1094
  }
1175
1095
 
1176
1096
  function setTypeValue(element, data, action) {
1177
- // TODO: if an array name is updated, the attibute array="" needs to be updated.
1178
-
1179
- if (!data) return;
1180
-
1181
- let form;
1182
- if (element.tagName === "FORM") form = element;
1183
- else if (element.parentElement)
1184
- form = element.parentElement.closest("form");
1185
-
1186
- if (!form) {
1187
- if (data.type === "object") {
1188
- if (data.object && data.object[0] && data.object[0]._id) {
1189
- element.setAttribute("object", data.object[0]._id);
1190
- }
1191
- } else {
1192
- element.setAttribute(data.type, data[data.type].name);
1193
- }
1194
- } else {
1195
- let formObject = forms.get(form);
1196
- if (form.getAttribute("object") === "pending")
1197
- form.setAttribute("object", data.object[0]._id);
1198
-
1199
- let elements = formObject.types.get(data.type);
1200
-
1201
- for (let [el, Data] of elements.entries()) {
1202
- if (data.type === "object") {
1203
- if (!Data.object || Data.object === "pending") {
1204
- Data.object = data.object[0]._id;
1205
- el.setAttribute("object", data.object[0]._id);
1206
- }
1207
- } else if (!Data[data.type]) {
1208
- Data[data.type] = data[data.type].name;
1209
- el.setAttribute(data.type, data[data.type].name);
1210
- }
1211
- }
1212
- setData(Array.from(elements.keys()), data);
1213
-
1214
- // const state_ids = new Map()
1215
-
1216
- // let state_id = form.getAttribute('state_id');
1217
- // if (state_id) {
1218
- // // Set state_ids to state_ids if array is not set
1219
- // if (form.getAttribute('array') == array)
1220
- // state_ids.set(state_id, '');
1221
- // }
1222
-
1223
- // let objectId = el.getAttribute('object');
1224
- // let key = el.getAttribute('key')
1225
- // // set object and state_id attributes to the object id if the object id is pending
1226
- // if (key && (objectId == '' || objectId == 'pending')) {
1227
- // el.setAttribute('object', id);
1228
- // // Set the id attribute of the element
1229
- // if (key == '_id')
1230
- // el.setValue(id)
1231
- // let state_id = el.getAttribute('state_id');
1232
- // // Set the state id to the state_ids.
1233
- // if (state_id) {
1234
- // state_ids.set(state_id, '');
1235
- // }
1236
-
1237
- // if (el.hasAttribute('state-object')) {
1238
- // let stateObjectId = el.getAttribute('state-object');
1239
- // // Set the state object id if not set.
1240
- // if (stateObjectId == '') {
1241
- // el.setAttribute('state-object', id);
1242
- // let state_id = el.getAttribute('state_id');
1243
- // // Set the state id to the state_ids.
1244
- // if (state_id) {
1245
- // state_ids.set(state_id, '');
1246
- // }
1247
- // }
1248
- // }
1249
-
1250
- // // Set the object attribute of all state_ids to the object attribute of all state_ids
1251
- // if (state_ids.size > 0) {
1252
- // for (let key of state_ids.keys()) {
1253
- // let stateEls = document.querySelectorAll(`[state_id="${key}"]`)
1254
- // for (let stateEl of stateEls) {
1255
- // // if (stateEl.getAttribute('array') == array){
1256
- // // Set the object id attribute to the stateEl s object if it is not set.
1257
- // if (stateEl.getAttribute('object') == '') {
1258
- // stateEl.setAttribute('object', id);
1259
- // }
1260
- // // }
1261
- // }
1262
- // }
1263
- // }
1264
- // }
1265
- }
1266
-
1267
- if (action) {
1268
- action.element.dispatchEvent(
1269
- new CustomEvent("saved", {
1270
- detail: data
1271
- })
1272
- );
1273
- } else {
1274
- document.dispatchEvent(
1275
- new CustomEvent("saved", {
1276
- detail: data
1277
- })
1278
- );
1279
- }
1097
+ // TODO: if an array name is updated, the attibute array="" needs to be updated.
1098
+
1099
+ if (!data) return;
1100
+
1101
+ let form;
1102
+ if (element.tagName === "FORM") form = element;
1103
+ else if (element.parentElement)
1104
+ form = element.parentElement.closest("form");
1105
+
1106
+ if (!form) {
1107
+ if (data.type === "object") {
1108
+ if (data.object?.[0]?._id) {
1109
+ element.setAttribute("object", data.object[0]._id);
1110
+ }
1111
+ } else {
1112
+ element.setAttribute(data.type, data[data.type].name);
1113
+ }
1114
+ } else {
1115
+ let formObject = forms.get(form);
1116
+ if (form.getAttribute("object") === "pending")
1117
+ form.setAttribute("object", data.object[0]._id);
1118
+
1119
+ let elements = formObject.types.get(data.type);
1120
+
1121
+ for (let [el, elData] of elements.entries()) {
1122
+ if (data.type === "object") {
1123
+ if (!elData.object || elData.object === "pending") {
1124
+ elData.object = data.object[0]._id;
1125
+ el.setAttribute("object", data.object[0]._id);
1126
+ }
1127
+ } else if (!elData[data.type]) {
1128
+ elData[data.type] = data[data.type].name;
1129
+ el.setAttribute(data.type, data[data.type].name);
1130
+ }
1131
+ }
1132
+ setData(Array.from(elements.keys()), data);
1133
+ }
1134
+
1135
+ if (action) {
1136
+ action.element.dispatchEvent(
1137
+ new CustomEvent("saved", {
1138
+ detail: data
1139
+ })
1140
+ );
1141
+ } else {
1142
+ document.dispatchEvent(
1143
+ new CustomEvent("saved", {
1144
+ detail: data
1145
+ })
1146
+ );
1147
+ }
1280
1148
  }
1281
1149
 
1282
1150
  async function remove(element) {
1283
- if (
1284
- element &&
1285
- !(element instanceof HTMLCollection) &&
1286
- !Array.isArray(element)
1287
- )
1288
- element = [element];
1289
- for (let i = 0; i < element.length; i++) {
1290
- delete element[i].hasRead;
1291
- if (element[i].tagName === "FORM") {
1292
- let form = forms.get(element[i]);
1293
- if (!form) return;
1294
-
1295
- form = form.elements;
1296
- for (let el of form.keys()) {
1297
- let key = elements.get(el);
1298
- if (key) {
1299
- keys.get(key).elements.delete(el);
1300
- elements.delete(el);
1301
- // debounce.delete(key)
1302
- }
1303
- }
1304
- let key = elements.get(element[i]);
1305
- if (key) {
1306
- keys.get(key).elements.delete(element[i]);
1307
- if (!keys.get(key).elements.size) keys.delete(key);
1308
- }
1309
- elements.delete(element[i]);
1310
- forms.delete(element[i]);
1311
- } else {
1312
- let key = elements.get(element[i]);
1313
- if (key) {
1314
- if (element[i].getFilter) filter.filters.delete(element[i]);
1315
- keys.get(key).elements.delete(element[i]);
1316
- elements.delete(element[i]);
1317
- if (!keys.get(key).elements.size) keys.delete(key);
1318
-
1319
- // debounce.delete(key)
1320
- let form = element[i].closest("form");
1321
- form = forms.get(form);
1322
- if (form) {
1323
- form.elements.delete(element[i]);
1324
- if (!form.elements.size) forms.delete(form);
1325
- }
1326
- } else elements.delete(element[i]);
1327
- }
1328
- }
1151
+ if (
1152
+ element &&
1153
+ !(element instanceof HTMLCollection) &&
1154
+ !Array.isArray(element)
1155
+ )
1156
+ element = [element];
1157
+ for (let i = 0; i < element.length; i++) {
1158
+ delete element[i].hasRead;
1159
+ if (element[i].tagName === "FORM") {
1160
+ let form = forms.get(element[i]);
1161
+ if (!form) return;
1162
+
1163
+ form = form.elements;
1164
+ for (let el of form.keys()) {
1165
+ let key = elements.get(el);
1166
+ if (key) {
1167
+ keys.get(key).elements.delete(el);
1168
+ elements.delete(el);
1169
+ // debounce.delete(key)
1170
+ }
1171
+ }
1172
+ let key = elements.get(element[i]);
1173
+ if (key) {
1174
+ keys.get(key).elements.delete(element[i]);
1175
+ if (!keys.get(key).elements.size) keys.delete(key);
1176
+ }
1177
+ elements.delete(element[i]);
1178
+ forms.delete(element[i]);
1179
+ } else {
1180
+ let key = elements.get(element[i]);
1181
+ if (key) {
1182
+ if (element[i].getFilter) filter.filters.delete(element[i]);
1183
+ keys.get(key).elements.delete(element[i]);
1184
+ elements.delete(element[i]);
1185
+ if (!keys.get(key).elements.size) keys.delete(key);
1186
+
1187
+ // debounce.delete(key)
1188
+ let form = element[i].closest("form");
1189
+ form = forms.get(form);
1190
+ if (form) {
1191
+ form.elements.delete(element[i]);
1192
+ if (!form.elements.size) forms.delete(form);
1193
+ }
1194
+ } else elements.delete(element[i]);
1195
+ }
1196
+ }
1329
1197
  }
1330
1198
 
1331
1199
  function initSocket() {
1332
- const type = ["storage", "database", "array", "index", "object", "filter"];
1333
- const method = ["create", "update", "delete"];
1334
-
1335
- for (let i = 0; i < type.length; i++) {
1336
- for (let j = 0; j < method.length; j++) {
1337
- const action = type[i] + "." + method[j];
1338
-
1339
- CRUD.listen(action, function (data) {
1340
- if (
1341
- data.resolved &&
1342
- data.status === "received" &&
1343
- CRUD.socket.clientId === data.clientId
1344
- )
1345
- return;
1346
- if (data.rendered) return;
1347
-
1348
- data.rendered = true;
1349
-
1350
- setData(null, data);
1351
- });
1352
- }
1353
- }
1200
+ const type = ["storage", "database", "array", "index", "object", "filter"];
1201
+ const method = ["create", "update", "delete"];
1202
+
1203
+ for (let i = 0; i < type.length; i++) {
1204
+ for (let j = 0; j < method.length; j++) {
1205
+ const action = type[i] + "." + method[j];
1206
+
1207
+ CRUD.listen(action, function (data) {
1208
+ if (
1209
+ data.resolved &&
1210
+ data.status === "received" &&
1211
+ CRUD.socket.clientId === data.clientId
1212
+ )
1213
+ return;
1214
+ if (data.rendered) return;
1215
+
1216
+ data.rendered = true;
1217
+
1218
+ setData(null, data);
1219
+ });
1220
+ }
1221
+ }
1354
1222
  }
1355
1223
 
1356
1224
  Observer.init({
1357
- name: "render",
1358
- types: ["addedNodes"],
1359
- selector: "[render-clone]",
1360
- callback: function (mutation) {
1361
- if (
1362
- mutation.parentElement &&
1363
- !mutation.parentElement.hasAttribute("dnd")
1364
- )
1365
- return;
1366
- let delayTimer = debounce.get(mutation);
1367
- clearTimeout(delayTimer);
1368
- debounce.delete(mutation.target);
1369
-
1370
- let renderedNode = renderedNodes.get(mutation.target);
1371
- if (!renderedNode) return;
1372
-
1373
- if (!mutation.movedFrom) return;
1374
- let draggedEl = mutation.target;
1375
- let draggedFrom = mutation.movedFrom.parentElement;
1376
- let droppedEl =
1377
- mutation.target.nextElementSibling ||
1378
- mutation.target.previousElementSibling;
1379
- let droppedIn = mutation.parentElement;
1380
-
1381
- if (!draggedFrom || !droppedIn) return;
1382
- dndCrud(draggedEl, draggedFrom, droppedEl, droppedIn);
1383
- }
1225
+ name: "render",
1226
+ types: ["addedNodes"],
1227
+ selector: "[render-clone]",
1228
+ callback: function (mutation) {
1229
+ if (
1230
+ mutation.parentElement &&
1231
+ !mutation.parentElement.hasAttribute("dnd")
1232
+ )
1233
+ return;
1234
+ let delayTimer = debounce.get(mutation);
1235
+ clearTimeout(delayTimer);
1236
+ debounce.delete(mutation.target);
1237
+
1238
+ let renderedNode = renderedNodes.get(mutation.target);
1239
+ if (!renderedNode) return;
1240
+
1241
+ if (!mutation.movedFrom) return;
1242
+ let draggedEl = mutation.target;
1243
+ let draggedFrom = mutation.movedFrom.parentElement;
1244
+ let droppedEl =
1245
+ mutation.target.nextElementSibling ||
1246
+ mutation.target.previousElementSibling;
1247
+ let droppedIn = mutation.parentElement;
1248
+
1249
+ if (!draggedFrom || !droppedIn) return;
1250
+ dndCrud(draggedEl, draggedFrom, droppedEl, droppedIn);
1251
+ }
1384
1252
  });
1385
1253
 
1386
1254
  // TODO: has the potential to work on most of the crud elements specifically if the value is an object or an array
1387
1255
  async function dndCrud(draggedEl, draggedFrom, droppedEl, droppedIn) {
1388
- let from = await dndCrudData(draggedEl, draggedFrom, "remove");
1389
- let to = await dndCrudData(droppedEl, droppedIn, "add");
1390
-
1391
- if (from && to && !draggedFrom.isSameNode(droppedIn)) {
1392
- let element = getDataElements(from.data);
1393
- if (!element.length) return;
1394
-
1395
- let match = element.find((obj) => obj === droppedIn);
1396
- if (!match) {
1397
- if (from.keyPath.includes(".")) {
1398
- let test = { [from.keyPath]: undefined };
1399
-
1400
- from.newData = dotNotationToObject(test, from.newData);
1401
- dndCrudSend(from.newData, "update");
1402
- } else {
1403
- const index = from.keyPath.match(/\[(\d+)\]/);
1404
- let removeData = from.newData[from.newData.type].splice(
1405
- index,
1406
- 1
1407
- )[0];
1408
- if (removeData) {
1409
- removeData.type = from.newData.type;
1410
- removeData[removeData.type] = removeData;
1411
- dndCrudSend(removeData, "delete");
1412
- }
1413
-
1414
- if (from.newData[from.newData.type].length)
1415
- dndCrudSend(from.newData, "update");
1416
- }
1417
- }
1418
- }
1419
-
1420
- if (to) dndCrudSend(to.newData, "update");
1256
+ let from = await dndCrudData(draggedEl, draggedFrom, "remove");
1257
+ let to = await dndCrudData(droppedEl, droppedIn, "add");
1258
+
1259
+ if (from && to && !draggedFrom.isSameNode(droppedIn)) {
1260
+ let element = getDataElements(from.data);
1261
+ if (!element.length) return;
1262
+
1263
+ if (!element.includes(droppedIn)) {
1264
+ if (from.keyPath.includes(".")) {
1265
+ let test = { [from.keyPath]: undefined };
1266
+
1267
+ from.clonedParentData = dotNotationToObject(test, from.clonedParentData);
1268
+ dndCrudSend(from.clonedParentData, "update");
1269
+ } else {
1270
+ const index = from.keyPath.match(/\[(\d+)\]/);
1271
+ let removeData = from.clonedParentData[from.clonedParentData.type].splice(
1272
+ index,
1273
+ 1
1274
+ )[0];
1275
+ if (removeData) {
1276
+ removeData.type = from.clonedParentData.type;
1277
+ removeData[removeData.type] = removeData;
1278
+ dndCrudSend(removeData, "delete");
1279
+ }
1280
+
1281
+ if (from.clonedParentData[from.clonedParentData.type].length)
1282
+ dndCrudSend(from.clonedParentData, "update");
1283
+ }
1284
+ }
1285
+ }
1286
+
1287
+ if (to) dndCrudSend(to.clonedParentData, "update");
1421
1288
  }
1422
1289
 
1423
1290
  async function dndCrudData(element, parent, operator) {
1424
- if (!elements.has(parent)) return;
1425
- let data = await parent.getData();
1426
- let newData = getObject(parent);
1427
-
1428
- let { Data, sortName, sortDirection, keyPath, clones, index } = dndNewData(
1429
- element,
1430
- data
1431
- );
1432
- newData[newData.type] = [];
1433
-
1434
- if (sortName) {
1435
- for (let i = 0; i < clones.length; i++) {
1436
- if (i > index) {
1437
- let previousData = data[data.type][index];
1438
- if (operator === "add") Data[sortName] = i + 1;
1439
- else if (operator === "remove") Data[sortName] = i - 1;
1440
-
1441
- newData[newData.type].push({ ...previousData, ...Data });
1442
- }
1443
- }
1444
- } else {
1445
- newData[newData.type] = [{ ...data[data.type][index], ...Data }];
1446
- }
1447
-
1448
- return { data, newData, keyPath, clones, index };
1291
+ if (!elements.has(parent)) return;
1292
+ let data = await parent.getData();
1293
+ let clonedParentData = getObject(parent);
1294
+
1295
+ let { dragData, sortName, sortDirection, keyPath, clones, index } = dndNewData(
1296
+ element,
1297
+ data
1298
+ );
1299
+ clonedParentData[clonedParentData.type] = [];
1300
+
1301
+ if (sortName) {
1302
+ for (let i = 0; i < clones.length; i++) {
1303
+ if (i > index) {
1304
+ let previousData = data[data.type][index];
1305
+ dragData[sortName] = operator === "add" ? i + 1 : i - 1;
1306
+
1307
+ clonedParentData[clonedParentData.type].push({ ...previousData, ...dragData });
1308
+ }
1309
+ }
1310
+ } else {
1311
+ clonedParentData[clonedParentData.type] = [{ ...data[data.type][index], ...dragData }];
1312
+ }
1313
+
1314
+ return { data, clonedParentData, keyPath, clones, index };
1449
1315
  }
1450
1316
 
1451
1317
  function dndNewData(element, data) {
1452
- let Data = {};
1453
- if (data.$filter.query) {
1454
- dndNewDataUpdate(Data, data.$filter.query);
1455
- }
1456
-
1457
- let sortName, sortDirection;
1458
- let sort = data.$filter.sort;
1459
- if (sort && sort.length) {
1460
- // for (let i = 0; i < sort.length; i++) {
1461
- for (let i = sort.length - 1; i >= 0; i--) {
1462
- if (typeof data[sort.key] === "number") {
1463
- sortName = sort.key;
1464
- sortDirection = sort.direction;
1465
- break;
1466
- }
1467
- }
1468
- }
1469
-
1470
- let keyPath, clonesMap, clones, index;
1471
-
1472
- let renderedNode = renderedNodes.get(element);
1473
- if (renderedNode) {
1474
- keyPath = renderedNode.keyPath;
1475
- clonesMap = renderedNode.template.clones;
1476
- clones = Array.from(clonesMap.values());
1477
- index = clones.indexOf(element);
1478
- }
1479
-
1480
- return { Data, sortName, sortDirection, keyPath, clones, index };
1318
+ let dragData = {};
1319
+ if (data.$filter.query) {
1320
+ dndNewDataUpdate(dragData, data.$filter.query);
1321
+ }
1322
+
1323
+ let sortName, sortDirection;
1324
+ let sort = data.$filter.sort;
1325
+ if (sort && sort.length) {
1326
+ for (let i = sort.length - 1; i >= 0; i--) {
1327
+ if (typeof data[sort.key] === "number") {
1328
+ sortName = sort.key;
1329
+ sortDirection = sort.direction;
1330
+ break;
1331
+ }
1332
+ }
1333
+ }
1334
+
1335
+ let keyPath, clonesMap, clones, index;
1336
+
1337
+ let renderedNode = renderedNodes.get(element);
1338
+ if (renderedNode) {
1339
+ keyPath = renderedNode.keyPath;
1340
+ clonesMap = renderedNode.template.clones;
1341
+ clones = Array.from(clonesMap.values());
1342
+ index = clones.indexOf(element);
1343
+ }
1344
+
1345
+ return { dragData, sortName, sortDirection, keyPath, clones, index };
1481
1346
  }
1482
1347
 
1483
- function dndNewDataUpdate(Data, query) {
1484
- for (let key of Object.keys(query)) {
1485
- if (key === "$and" || key === "$or" || key === "$nor") {
1486
- for (let i = 0; i < query[key].length; i++) {
1487
- dndNewDataUpdate(Data, query[key][i]);
1488
- }
1489
- } else if (
1490
- typeof query[key] === "object" &&
1491
- !Array.isArray(query[key])
1492
- ) {
1493
- if (query[key].$eq) Data[key] = query[key].$eq;
1494
- if (query[key].$ne) Data[key] = query[key].$ne;
1495
- } else {
1496
- Data[key] = query[key];
1497
- }
1498
- }
1348
+ function dndNewDataUpdate(dragData, query) {
1349
+ for (let key of Object.keys(query)) {
1350
+ if (key === "$and" || key === "$or" || key === "$nor") {
1351
+ for (let i = 0; i < query[key].length; i++) {
1352
+ dndNewDataUpdate(dragData, query[key][i]);
1353
+ }
1354
+ } else if (
1355
+ typeof query[key] === "object" &&
1356
+ !Array.isArray(query[key])
1357
+ ) {
1358
+ if (query[key].$eq) dragData[key] = query[key].$eq;
1359
+ if (query[key].$ne) dragData[key] = query[key].$ne;
1360
+ } else {
1361
+ dragData[key] = query[key];
1362
+ }
1363
+ }
1499
1364
  }
1500
1365
 
1501
1366
  function dndCrudSend(data, crudType) {
1502
- if (CRUD) {
1503
- let action = data.type;
1504
- action = action.charAt(0).toUpperCase() + action.slice(1);
1505
- CRUD[crudType + action](data);
1506
- } else console.log("dnd reordered data set as crud is unavailable");
1367
+ if (CRUD) {
1368
+ let action = data.type;
1369
+ action = action.charAt(0).toUpperCase() + action.slice(1);
1370
+ CRUD[crudType + action](data);
1371
+ } else console.log("dnd reordered data set as crud is unavailable");
1507
1372
  }
1508
1373
 
1509
1374
  Observer.init({
1510
- name: "CoCreateElementsChildList",
1511
- types: ["addedNodes"],
1512
- selector: selector,
1513
- callback: function (mutation) {
1514
- init([mutation.target]);
1515
- }
1375
+ name: "CoCreateElementsChildList",
1376
+ types: ["addedNodes"],
1377
+ selector: selector,
1378
+ callback: function (mutation) {
1379
+ init([mutation.target]);
1380
+ }
1516
1381
  });
1517
1382
 
1518
1383
  Observer.init({
1519
- name: "CoCreateElementsRemovedNodes",
1520
- types: ["removedNodes"],
1521
- selector: selector,
1522
- callback: function (mutation) {
1523
- // if (mutation.target.parentElement) return
1524
- // if (mutation.target.parentElement) {
1525
- // let delayTimer = setTimeout(function () {
1526
- // debounce.delete(mutation.target)
1527
- // remove(mutation.target)
1528
- // }, 3000);
1529
- // debounce.set(mutation.target, delayTimer)
1530
- // } else
1531
- if (mutation.target.hasAttribute("render-clone")) return;
1532
- remove(mutation.target);
1533
- }
1384
+ name: "CoCreateElementsRemovedNodes",
1385
+ types: ["removedNodes"],
1386
+ selector: selector,
1387
+ callback: function (mutation) {
1388
+ if (mutation.target.hasAttribute("render-clone")) return;
1389
+ remove(mutation.target);
1390
+ }
1534
1391
  });
1535
1392
 
1536
1393
  Observer.init({
1537
- name: "CoCreateElementsAttributes",
1538
- types: ["attributes"],
1539
- attributeFilter: [
1540
- "organization_id",
1541
- "host",
1542
- "storage",
1543
- "database",
1544
- "array",
1545
- "index",
1546
- "object",
1547
- "key"
1548
- ],
1549
- // target: selector, // blocks mutations when applied
1550
- callback: function (mutation) {
1551
- let currentValue = mutation.target.getAttribute(mutation.attributeName);
1552
- if (currentValue !== mutation.oldValue) {
1553
- if (mutation.target.tagName === "FORM") return;
1554
- remove(mutation.target);
1555
- init([mutation.target]);
1556
- }
1557
- }
1394
+ name: "CoCreateElementsAttributes",
1395
+ types: ["attributes"],
1396
+ attributeFilter: [
1397
+ "organization_id",
1398
+ "host",
1399
+ "storage",
1400
+ "database",
1401
+ "array",
1402
+ "index",
1403
+ "object",
1404
+ "key"
1405
+ ],
1406
+ // target: selector, // blocks mutations when applied
1407
+ callback: function (mutation) {
1408
+ let currentValue = mutation.target.getAttribute(mutation.attributeName);
1409
+ if (currentValue !== mutation.oldValue) {
1410
+ if (mutation.target.tagName === "FORM") return;
1411
+ remove(mutation.target);
1412
+ init([mutation.target]);
1413
+ }
1414
+ }
1558
1415
  });
1559
1416
 
1560
1417
  Actions.init([
1561
- {
1562
- name: "save",
1563
- endEvent: "saved",
1564
- callback: (action) => {
1565
- if ((action.form, action)) save(action.form, action);
1566
- }
1567
- },
1568
- {
1569
- name: "delete",
1570
- endEvent: "deleted",
1571
- callback: async (action) => {
1572
- // TODO: use selector to target elements for deletion if element is apart of render get render get rendering element for more crud detils
1573
- // this way any selector can be used to target crud deletions not just .selected
1574
- let elements = [];
1575
- if (action.element.hasAttribute("delete-query")) {
1576
- elements = queryElements({
1577
- element: action.element,
1578
- prefix: "delete"
1579
- });
1580
- } else {
1581
- elements = [action.element];
1582
- }
1583
-
1584
- for (let i = 0; i < elements.length; i++) {
1585
- const data = getObject(elements[i]);
1586
- if (!data) return;
1587
- data.method = data.type + ".delete";
1588
-
1589
- if (elements[i].renderValue) {
1590
- let selected = elements[i].querySelectorAll(".selected");
1591
- data[data.type] = [];
1592
- for (let j = 0; j < selected.length; j++) {
1593
- let attribute = selected[j].getAttribute(data.type);
1594
- if (attribute) {
1595
- attribute = attribute.split(",");
1596
- for (let k = 0; k < attribute.length; k++) {
1597
- if (data.type === "object")
1598
- data[data.type].push({ _id: attribute[k] });
1599
- else {
1600
- data[data.type].push(attribute[k]);
1601
- }
1602
- }
1603
- }
1604
- }
1605
- } else if (
1606
- data.type === "object" &&
1607
- typeof data[data.type] === "string"
1608
- )
1609
- data[data.type] = { _id: data[data.type] };
1610
-
1611
- let response = await CRUD.send(data);
1612
- action.element.dispatchEvent(
1613
- new CustomEvent("deleted", {
1614
- detail: response
1615
- })
1616
- );
1617
- }
1618
- }
1619
- }
1418
+ {
1419
+ name: "save",
1420
+ endEvent: "saved",
1421
+ callback: (action) => {
1422
+ if ((action.form, action)) save(action.form, action);
1423
+ }
1424
+ },
1425
+ {
1426
+ name: "delete",
1427
+ endEvent: "deleted",
1428
+ callback: async (action) => {
1429
+ // TODO: use selector to target elements for deletion if element is apart of render get render get rendering element for more crud detils
1430
+ // this way any selector can be used to target crud deletions not just .selected
1431
+ let elements = [];
1432
+ if (action.element.hasAttribute("delete-query")) {
1433
+ elements = queryElements({
1434
+ element: action.element,
1435
+ prefix: "delete"
1436
+ });
1437
+ } else {
1438
+ elements = [action.element];
1439
+ }
1440
+
1441
+ for (let i = 0; i < elements.length; i++) {
1442
+ const data = getObject(elements[i]);
1443
+ if (!data) return;
1444
+ data.method = data.type + ".delete";
1445
+
1446
+ if (elements[i].renderValue) {
1447
+ let selected = elements[i].querySelectorAll(".selected");
1448
+ data[data.type] = [];
1449
+ for (let j = 0; j < selected.length; j++) {
1450
+ let attribute = selected[j].getAttribute(data.type);
1451
+ if (attribute) {
1452
+ attribute = attribute.split(",");
1453
+ for (let k = 0; k < attribute.length; k++) {
1454
+ if (data.type === "object")
1455
+ data[data.type].push({ _id: attribute[k] });
1456
+ else {
1457
+ data[data.type].push(attribute[k]);
1458
+ }
1459
+ }
1460
+ }
1461
+ }
1462
+ } else if (
1463
+ data.type === "object" &&
1464
+ typeof data[data.type] === "string"
1465
+ )
1466
+ data[data.type] = { _id: data[data.type] };
1467
+
1468
+ let response = await CRUD.send(data);
1469
+ action.element.dispatchEvent(
1470
+ new CustomEvent("deleted", {
1471
+ detail: response
1472
+ })
1473
+ );
1474
+ }
1475
+ }
1476
+ }
1620
1477
  ]);
1621
1478
 
1622
1479
  init();
1623
1480
 
1624
1481
  export default {
1625
- init,
1626
- read,
1627
- save,
1628
- getData,
1629
- getObject,
1630
- reset,
1631
- elements,
1632
- keys,
1633
- forms,
1634
- debounce,
1635
- getAttributes,
1636
- setTypeValue
1637
- };
1482
+ init,
1483
+ read,
1484
+ save,
1485
+ getData,
1486
+ getObject,
1487
+ reset,
1488
+ elements,
1489
+ keys,
1490
+ forms,
1491
+ debounce,
1492
+ getAttributes,
1493
+ setTypeValue
1494
+ };