@cocreate/elements 1.23.3 → 1.23.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ ## [1.23.5](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.23.4...v1.23.5) (2023-10-14)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * added other crud types to attribute queries ([513472c](https://github.com/CoCreate-app/CoCreate-elements/commit/513472c768412e8b7ed5b205a48d16a49349cfaa))
7
+ * attribute mutation not firing when selector applied. temporarily removed selector ([3b5551f](https://github.com/CoCreate-app/CoCreate-elements/commit/3b5551ff0e7c3838b7079e6d14574831ad6a7ba5))
8
+ * bump dependencies ([1aa9443](https://github.com/CoCreate-app/CoCreate-elements/commit/1aa944336afdcd38b4f0915c6146d89d0ea56b1c))
9
+ * data.filter updated to data$filter ([5a64fbf](https://github.com/CoCreate-app/CoCreate-elements/commit/5a64fbfe0d5e580633aa0deed131619c070e0fac))
10
+ * getData ([e74675e](https://github.com/CoCreate-app/CoCreate-elements/commit/e74675ea5ed0f9b800fb18874864c93e8a8a5353))
11
+ * improved setting method conditions ([013753a](https://github.com/CoCreate-app/CoCreate-elements/commit/013753a541eca3f88b4d5350763f52f38bef2932))
12
+ * replaced action with data.method ([bfe513c](https://github.com/CoCreate-app/CoCreate-elements/commit/bfe513c5c498c84d2f11ce7d07ce71095dd232bf))
13
+ * save and delete action ([f32e9b6](https://github.com/CoCreate-app/CoCreate-elements/commit/f32e9b6e661211b8fb0548aaa03ffd28b4bd1edd))
14
+
15
+ ## [1.23.4](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.23.3...v1.23.4) (2023-10-09)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * bump dependencies ([6adac76](https://github.com/CoCreate-app/CoCreate-elements/commit/6adac767eb93127a7c27bb80791121a2f748406d))
21
+
1
22
  ## [1.23.3](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.23.2...v1.23.3) (2023-10-09)
2
23
 
3
24
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/elements",
3
- "version": "1.23.3",
3
+ "version": "1.23.5",
4
4
  "description": "Fetch content into any html element by using html5 attributes to query data stored in CoCreate headless CMS. If data is changed it will instantly reflect in html tags as changes are broadcasted in realtime",
5
5
  "keywords": [
6
6
  "elements",
@@ -58,12 +58,12 @@
58
58
  "webpack-log": "^3.0.1"
59
59
  },
60
60
  "dependencies": {
61
- "@cocreate/actions": "^1.11.4",
62
- "@cocreate/crud-client": "^1.28.2",
63
- "@cocreate/element-prototype": "^1.11.3",
64
- "@cocreate/filter": "^1.23.1",
65
- "@cocreate/observer": "^1.11.3",
66
- "@cocreate/render": "^1.28.1",
67
- "@cocreate/utils": "^1.25.1"
61
+ "@cocreate/actions": "^1.11.6",
62
+ "@cocreate/crud-client": "^1.28.4",
63
+ "@cocreate/element-prototype": "^1.11.5",
64
+ "@cocreate/filter": "^1.23.3",
65
+ "@cocreate/observer": "^1.11.5",
66
+ "@cocreate/render": "^1.28.3",
67
+ "@cocreate/utils": "^1.25.3"
68
68
  }
69
69
  }
package/src/form.js CHANGED
@@ -48,7 +48,7 @@ function runObjectId(form) {
48
48
  * @param form
49
49
  */
50
50
  function setAttribute(form) {
51
- let elements = form.querySelectorAll('[key]');
51
+ let elements = form.querySelectorAll('[storage], [database], [array], [index], [object], [key]');
52
52
 
53
53
  for (let attribute of form.attributes) {
54
54
  let variable = window.CoCreateConfig.attributes[attribute.name]
package/src/index.js CHANGED
@@ -27,8 +27,8 @@ import Observer from '@cocreate/observer';
27
27
  import Actions from '@cocreate/actions';
28
28
  import CRUD from '@cocreate/crud-client';
29
29
  import { dotNotationToObject, queryData, sortData, getAttributes, getAttributeNames, checkValue } from '@cocreate/utils';
30
- import '@cocreate/filter';
31
- import { render } from '@cocreate/render';
30
+ import filter from '@cocreate/filter';
31
+ import render from '@cocreate/render';
32
32
  import '@cocreate/element-prototype';
33
33
  import './fetchSrc';
34
34
  import { reset } from './form'
@@ -39,7 +39,7 @@ const keys = new Map();
39
39
  const forms = new Map(); // form, [elements]
40
40
  const debounce = new Map();
41
41
 
42
- function init(element) {
42
+ async function init(element) {
43
43
  if (element && !(element instanceof HTMLCollection) && !Array.isArray(element))
44
44
  element = [element]
45
45
  else if (!element) {
@@ -52,7 +52,7 @@ function init(element) {
52
52
  if (elements.has(element[i]) || element.tagName === 'FORM')
53
53
  continue
54
54
 
55
- let data = initElement(element[i]);
55
+ let data = await initElement(element[i]);
56
56
  if (data) {
57
57
  let dataKey = initDataKey(element[i], data)
58
58
  dataObjects.set(dataKey.string, data)
@@ -67,7 +67,7 @@ function init(element) {
67
67
  }
68
68
  }
69
69
 
70
- function initElement(el) {
70
+ async function initElement(el) {
71
71
  if (el.hasAttribute('render-json')) {
72
72
  // TODO find the json template in the text or attributes
73
73
  // if found add the node as an element, if the element has crud attributes also add as the element
@@ -119,9 +119,12 @@ function initElement(el) {
119
119
  });
120
120
  }
121
121
  }
122
-
122
+ // let attributes = ['filter-key', 'filter-search', 'filter-sort-key', 'filter-on', 'filter-limit']
123
+ // if (el.getFilter || attributes.some(attr => el.hasAttribute(attr))) {
124
+ await filter.init()
123
125
  if (el.getFilter) {
124
126
  data.$filter = el.getFilter();
127
+
125
128
  el.setFilter = (filter) => {
126
129
  data.$filter = filter
127
130
  let dataKey = initDataKey(el, data)
@@ -227,10 +230,13 @@ async function read(element, data, dataKey) {
227
230
  delayTimer = setTimeout(function () {
228
231
  debounce.delete(dataKey.string)
229
232
  // TODO: should server support string and string array for type object, methods create, read, delete
230
- if (data.type === 'object') {
233
+ if (!data.$filter && data.type === 'object') {
231
234
  if (typeof data.object === 'string')
232
235
  data.object = { _id: data.object }
233
236
 
237
+ if (Array.isArray(data.object))
238
+ data.object = { _id: data.object[0]._id }
239
+
234
240
  if (!data.object._id.match(/^[0-9a-fA-F]{24}$/))
235
241
  return
236
242
  }
@@ -272,7 +278,7 @@ function setData(element, data) {
272
278
 
273
279
  const { key, isRead, isListen, isCrdt } = getAttributes(el);
274
280
  if (el.getFilter || el.renderValue)
275
- filterData(el, data, type, key, action)
281
+ filterData(el, data, type, key)
276
282
  else {
277
283
  let value = CRUD.getValueFromObject(data[type][0], key);
278
284
  if (key) {
@@ -286,7 +292,7 @@ function setData(element, data) {
286
292
  }
287
293
  }
288
294
 
289
- function filterData(element, data, type, key, action) {
295
+ function filterData(element, data, type, key) {
290
296
  if (key) {
291
297
  if (!data.type) return
292
298
  if (Array.isArray(data[type])) {
@@ -305,8 +311,8 @@ function filterData(element, data, type, key, action) {
305
311
  }
306
312
  }
307
313
 
308
- if (element.getFilter && action && !action.startsWith('read'))
309
- checkFilters(element, data, type, action)
314
+ if (element.getFilter && data.method && !data.method.startsWith('read'))
315
+ checkFilters(element, data, type)
310
316
  else if (element.renderValue)
311
317
  element.renderValue(data);
312
318
  // render({ element, data, key: type });
@@ -317,7 +323,7 @@ function filterData(element, data, type, key, action) {
317
323
  element.dispatchEvent(evt);
318
324
  }
319
325
 
320
- function checkFilters(element, data, type, action) {
326
+ function checkFilters(element, data, type) {
321
327
  let Data = element.getData()
322
328
  if (!Data) return
323
329
 
@@ -329,25 +335,31 @@ function checkFilters(element, data, type, action) {
329
335
  newData = data
330
336
 
331
337
  let filter = element.getFilter()
332
- if (filter && filter.query)
333
- newData = queryData(newData, filter.query)
334
- if (!newData.length)
338
+ if (filter && filter.query) {
339
+ for (let i = 0; i < newData.length; i++) {
340
+ let isMatch = queryData(newData[i], filter.query)
341
+ if (!isMatch)
342
+ newData.slice(i, 1)
343
+ }
344
+ }
345
+
346
+ if (!newData || !newData.length)
335
347
  return
336
348
 
337
349
  if (Array.isArray(Data)) {
338
350
  if (Array.isArray(newData)) {
339
351
  for (let i = 0; i < newData.length; i++) {
340
- checkIndex(element, data, Data, newData[i], type, filter, action)
352
+ checkIndex(element, data, Data, newData[i], type, filter)
341
353
  }
342
354
  } else {
343
- checkIndex(element, data, Data, newData, type, filter, action)
355
+ checkIndex(element, data, Data, newData, type, filter)
344
356
  }
345
357
  } else {
346
358
  let primaryKey
347
359
  if (type === 'object') {
348
360
  primaryKey = '_id';
349
361
  } else {
350
- primaryKey = 'key';
362
+ primaryKey = 'name';
351
363
  }
352
364
 
353
365
  if (Data[primaryKey] === newData[primaryKey]) {
@@ -361,7 +373,7 @@ function checkFilters(element, data, type, action) {
361
373
  }
362
374
  }
363
375
 
364
- function checkIndex(element, data, Data, newData, type, filter, action) {
376
+ function checkIndex(element, data, Data, newData, type, filter) {
365
377
  let index
366
378
  if (type === 'object') {
367
379
  index = Data.findIndex(obj => obj._id === newData._id);
@@ -372,7 +384,7 @@ function checkIndex(element, data, Data, newData, type, filter, action) {
372
384
  if (!data.$filter)
373
385
  data.$filter = {}
374
386
 
375
- if (action.startsWith('delete')) {
387
+ if (data.method.startsWith('delete')) {
376
388
  if (!index && index !== 0)
377
389
  return
378
390
  data.$filter.remove = true
@@ -387,7 +399,7 @@ function checkIndex(element, data, Data, newData, type, filter, action) {
387
399
  }
388
400
 
389
401
  if (filter && filter.sort) {
390
- newData.isNewData = true
402
+ Data[index].isNewData = true
391
403
  Data = sortData(Data, filter.sort)
392
404
  index = Data.findIndex(obj => obj.isNewData);
393
405
  }
@@ -408,7 +420,7 @@ function checkIndex(element, data, Data, newData, type, filter, action) {
408
420
 
409
421
  function getDataKey(data) {
410
422
  let dataKey = {};
411
- let attributes = ["host", "organization_id", "apikey", "method", "type", "storage", "database", "array", "index", "object", "key", "updateKey", "filter", "upsert", "namespace", "room", "broadcast", "broadcastSender", "broadcastBrowser"];
423
+ let attributes = ["host", "organization_id", "apikey", "method", "type", "storage", "database", "array", "index", "object", "key", "updateKey", "$filter", "upsert", "namespace", "room", "broadcast", "broadcastSender", "broadcastBrowser"];
412
424
 
413
425
  for (let attribute of attributes) {
414
426
  if (attribute === 'key' && data.type === 'object')
@@ -444,7 +456,7 @@ function getDataElements(data) {
444
456
 
445
457
  function getDataKeys(data) {
446
458
  const matchingKeyStrings = [];
447
- const targetKeys = ["type", "storage", "database", "array", "index", "object", 'filter'];
459
+ const targetKeys = ["type", "storage", "database", "array", "index", "object", '$filter'];
448
460
 
449
461
  for (const [keyString, sortedKey] of keys.entries()) {
450
462
  let hasMatch = true;
@@ -488,10 +500,17 @@ function getData(form) {
488
500
  let formObject = forms.get(form)
489
501
  for (let type of formObject.types.values()) {
490
502
  for (let [element, data] of type.entries()) {
503
+ if (!element.hasAttribute('key'))
504
+ continue
505
+ if (element.hasAttribute('actions')) {
506
+ let attribute = element.getAttribute('actions')
507
+ if (attribute.includes('save', 'delete'))
508
+ continue
509
+ }
491
510
  let Data = { ...data }
492
511
  let dataKey = elements.get(element)
493
512
  let value = element.getValue()
494
- console.log(type, value, data)
513
+ // console.log(type, value, data)
495
514
 
496
515
  if (!Data[Data.type] && Data.key) {
497
516
  Data.method = 'create.' + Data.type
@@ -507,19 +526,29 @@ function getData(form) {
507
526
 
508
527
  } else if (Data[Data.type] && Data.key) {
509
528
  let attributes = element.attributes
510
- if (!Data.key.startsWith('$')) {
529
+ if (Data.key.startsWith('$')) {
511
530
  for (let i = 0; i < attributes.length; i++) {
512
531
  let operators = ['$rename', '$inc', '$push', '$each', '$splice', '$unset', '$delete', '$slice', '$pop', '$shift', '$addToSet', '$pull']
513
- if (!operators.includes(attributes[i].name)) {
532
+ if (operators.includes(attributes[i].name)) {
514
533
  Data.key = attributes[i].name + '.' + Data.key
515
534
  break;
516
535
  }
517
536
  }
518
537
  }
519
538
 
520
- if (Data.type = 'object')
521
- Data.object[Data.key] = value
522
- else {
539
+
540
+ if (Data.type = 'object') {
541
+ if (typeof Data[Data.type] === 'string')
542
+ if (Data.key == '{}')
543
+ Data[Data.type] = { _id: Data[Data.type], ...value }
544
+ else
545
+ Data[Data.type] = { _id: Data[Data.type], [Data.key]: value }
546
+ else if (typeof Data[Data.type] === 'object')
547
+ if (Data.key == '{}')
548
+ Data[Data.type] = { ...Data[Data.type], ...value }
549
+ else
550
+ Data[Data.type][Data.key] = value
551
+ } else {
523
552
  Data[Data.type] = { [Data[Data.type]]: value }
524
553
  }
525
554
 
@@ -556,22 +585,27 @@ function getData(form) {
556
585
 
557
586
  //dataKey should be used to group
558
587
  let key = dataKey + Data.method
559
- if (dataKeys.has(key))
560
- dataKeys.get(key).push(Data)
561
- else
562
- dataKeys.set(key, [Data])
563
-
588
+ if (dataKeys.has(key)) {
589
+ let storedData = dataKeys.get(key)[Data.type]
590
+ dataKeys.get(key)[Data.type] = { ...storedData, ...Data[Data.type] }
591
+ } else {
592
+ dataKeys.set(key, Data)
593
+ }
564
594
  }
565
595
  }
566
596
 
567
597
  // TODO: group by methods so we can make one crud request per method
568
- let dataArray = []
598
+ let dataArray = Array.from(dataKeys.values())
599
+
569
600
  return dataArray
570
601
  }
571
602
 
572
603
  async function save(element) {
573
604
  if (!element) return;
574
605
  let data, value
606
+ let upsert = element.getAttribute('upsert')
607
+ if (upsert !== undefined || upsert !== null)
608
+ upsert = true
575
609
  if (element.tagName === "FORM") {
576
610
  data = element.getData()
577
611
  } else {
@@ -623,11 +657,37 @@ async function save(element) {
623
657
  }
624
658
 
625
659
  for (let i = 0; i < data.length; i++) {
626
- data[i].method = 'update.' + data[i].type
660
+ if (data[i].type === 'object' && !data[i]) {
661
+ if (typeof data[i].object === 'string') {
662
+ if (!data[i]._id)
663
+ data[i].method = 'create.object'
664
+ else {
665
+ data[i].method = 'update.object'
666
+ if (upsert)
667
+ data[i].upsert = true
668
+ }
669
+ } else if (Array.isArray(data[i].object)) {
670
+ if (!data[i].object[0]._id)
671
+ data[i].method = 'create.object'
672
+ else {
673
+ data[i].method = 'update.object'
674
+ if (upsert)
675
+ data[i].upsert = true
676
+ }
677
+ } else if (typeof data[i].object === 'object') {
678
+ if (!data[i].object._id)
679
+ data[i].method = 'create.object'
680
+ else {
681
+ data[i].method = 'update.object'
682
+ if (upsert)
683
+ data[i].upsert = true
684
+ }
685
+ }
686
+ }
627
687
 
628
- if (data[i].method && data[i].method.startsWith('create'))
688
+ if (data[i].method && data[i].method.startsWith('create')) {
629
689
  element.setAttribute(data[i].type, 'pending');
630
- else if (data[i].method && data[i].method.startsWith('update') && data[i].type == 'object' && typeof value == 'string' && window.CoCreate.crdt && !'crdt') {
690
+ } else if (data[i].method && data[i].method.startsWith('update') && data[i].type == 'object' && typeof value == 'string' && window.CoCreate.crdt && !'crdt') {
631
691
  return window.CoCreate.crdt.replaceText({
632
692
  array: data[i].array,
633
693
  key: data[i].key,
@@ -640,7 +700,10 @@ async function save(element) {
640
700
 
641
701
  if (data[i] && (data[i].method.startsWith('create') || data[i].type !== 'object' && data[i].method.startsWith('update'))) {
642
702
  setTypeValue(element, data[i])
643
- }
703
+ } else if (data[i])
704
+ document.dispatchEvent(new CustomEvent('saved', {
705
+ detail: data[i]
706
+ }));
644
707
 
645
708
  }
646
709
 
@@ -731,19 +794,46 @@ function setTypeValue(element, data) {
731
794
  // }
732
795
  // }
733
796
  }
797
+
798
+ document.dispatchEvent(new CustomEvent('saved', {
799
+ detail: data
800
+ }));
801
+
734
802
  }
735
803
 
736
804
  async function remove(element) {
737
805
  if (element && !(element instanceof HTMLCollection) && !Array.isArray(element))
738
806
  element = [element]
739
807
  for (let i = 0; i < element.length; i++) {
740
- let key = elements.get(element[i])
741
- if (key) {
742
- let els = keys.get(key).elements
743
- els.delete(element[i])
744
- elements.delete(key)
745
- debounce.delete(element[i])
746
- // TODO: delete element from forms map
808
+ if (element[i].tagName === 'FORM') {
809
+ let form = forms.get(element[i]).elements
810
+ for (let el of form.keys()) {
811
+ let key = elements.get(el)
812
+ if (key) {
813
+ keys.get(key).elements.delete(el)
814
+ elements.delete(el)
815
+ // debounce.delete(key)
816
+ }
817
+ }
818
+ let key = elements.get(element[i])
819
+ if (key) {
820
+ keys.get(key).elements.delete(element[i])
821
+ }
822
+ elements.delete(element[i])
823
+ forms.delete(element[i])
824
+ } else {
825
+
826
+ let key = elements.get(element[i])
827
+ if (key) {
828
+ keys.get(key).elements.delete(element[i])
829
+ elements.delete(element[i])
830
+ // debounce.delete(key)
831
+ let form = element[i].closest('form')
832
+ form = forms.get(form)
833
+ if (form) {
834
+ form.elements.delete(element[i])
835
+ }
836
+ }
747
837
  }
748
838
  }
749
839
  }
@@ -768,7 +858,11 @@ Observer.init({
768
858
  observe: ['addedNodes'],
769
859
  target: '[render-clone]',
770
860
  callback: function (mutation) {
771
- let renderedNode = CoCreate.render.renderedNodes.get(mutation.target)
861
+ let delayTimer = debounce.get(mutation)
862
+ clearTimeout(delayTimer);
863
+ debounce.delete(mutation.target)
864
+
865
+ let renderedNode = render.renderedNodes.get(mutation.target)
772
866
  if (!renderedNode) return
773
867
 
774
868
  if (!mutation.movedFrom) return
@@ -911,7 +1005,15 @@ Observer.init({
911
1005
  observe: ['removedNodes'],
912
1006
  target: selector,
913
1007
  callback: function (mutation) {
914
- if (mutation.target.parentElement) return
1008
+ // if (mutation.target.parentElement) return
1009
+ // if (mutation.target.parentElement) {
1010
+ // let delayTimer = setTimeout(function () {
1011
+ // debounce.delete(mutation.target)
1012
+ // remove(mutation.target)
1013
+ // }, 3000);
1014
+ // debounce.set(mutation.target, delayTimer)
1015
+ // } else
1016
+ if (mutation.target.hasAttribute('render-clone')) return
915
1017
  remove(mutation.target)
916
1018
  }
917
1019
  });
@@ -919,8 +1021,8 @@ Observer.init({
919
1021
  Observer.init({
920
1022
  name: 'CoCreateElementsAttributes',
921
1023
  observe: ['attributes'],
922
- attributeName: getAttributeNames(['storage', 'database', 'array', 'object', 'key']),
923
- target: selector,
1024
+ attributeName: ['storage', 'database', 'array', 'index', 'object', 'key'],
1025
+ // target: selector, // blocks mutations when applied
924
1026
  callback: function (mutation) {
925
1027
  remove(mutation.target)
926
1028
  init([mutation.target]);
@@ -936,6 +1038,24 @@ Actions.init({
936
1038
  }
937
1039
  });
938
1040
 
1041
+ Actions.init({
1042
+ name: "delete",
1043
+ endEvent: "deleted",
1044
+ callback: async (action) => {
1045
+ const data = getObject(action.element);
1046
+ if (data) {
1047
+ data.method = 'delete.' + data.type
1048
+ if (data.type === 'object' && typeof data[data.type] === 'string')
1049
+ data[data.type] = { _id: data[data.type] }
1050
+
1051
+ let response = await CRUD.send(data)
1052
+ document.dispatchEvent(new CustomEvent('deleted', {
1053
+ detail: response
1054
+ }));
1055
+ }
1056
+ }
1057
+ });
1058
+
939
1059
  init();
940
1060
 
941
1061
  export default { init, read, save, getData, reset, elements, keys, forms, debounce, getAttributes };