@cocreate/elements 1.38.0 → 1.39.0

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