@cocreate/events 1.24.0 → 1.26.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 (3) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/package.json +1 -1
  3. package/src/index.js +833 -622
package/src/index.js CHANGED
@@ -20,465 +20,663 @@
20
20
  // you must obtain a commercial license from CoCreate LLC.
21
21
  // For details, visit <https://cocreate.app/licenses/> or contact us at sales@cocreate.app.
22
22
 
23
- import { queryElements, queryData } from '@cocreate/utils';
24
- import action from '@cocreate/actions';
25
- import observer from '@cocreate/observer';
26
- import '@cocreate/element-prototype';
23
+ import { queryElements, queryData } from "@cocreate/utils";
24
+ import action from "@cocreate/actions";
25
+ import observer from "@cocreate/observer";
26
+ import "@cocreate/element-prototype";
27
27
 
28
28
  const CoCreateEvents = {
29
- elements2: new Map(),
30
- init: function (prefix, events) {
31
- if (prefix && events)
32
- this.initPrefix(prefix, events);
33
- else {
34
- this.initPrefix('toggle', ['click']);
35
- this.initPrefix('click', ['click']);
36
- this.initPrefix('hover', ['mouseover', 'mouseout']);
37
- this.initPrefix('mouseover', ['mouseover']);
38
- this.initPrefix('mouseout', ['mouseout']);
39
- this.initPrefix('input', ['input']);
40
- this.initPrefix('change', ['change']);
41
- this.initPrefix('selected', ['click']);
42
- this.initPrefix('onload', ['onload']);
43
- this.initPrefix('observe', ['observer']);
44
- this.initPrefix('resize', ['onload', 'resize']);
45
- this.initPrefix('localstorage', ['onload', 'observer']);
46
- }
47
-
48
- let customEventEls = document.querySelectorAll('[event-name]')
49
- let names = {}
50
- for (let customEventEl of customEventEls) {
51
- let name = customEventEl.getAttribute('event-name')
52
- name = name.split(',')
53
- for (let i = 0; i < name.length; i++) {
54
- name[i].trim()
55
- if (!names[name]) {
56
- names[name] = name
57
- this.initPrefix(name);
58
- }
59
- }
60
- }
61
-
62
- const self = this
63
- observer.init({
64
- name: 'CoCreateEventName',
65
- observe: ['addedNodes'],
66
- selector: `[event-name]`,
67
- callback: function (mutation) {
68
- let name = mutation.target.getAttribute('event-name')
69
- self.initPrefix(name);
70
- }
71
- });
72
-
73
- },
74
-
75
- initPrefix: function (prefix, events) {
76
- const self = this;
77
-
78
- action.init({
79
- name: prefix,
80
- endEvent: `${prefix}End`,
81
- callback: (data) => {
82
- this.__updateElements(data.element, prefix)
83
- }
84
- });
85
-
86
- let selector = `[${prefix}], [${prefix}-key], [${prefix}-attribute], [${prefix}-value], [${prefix}-selector], [${prefix}-closest], [${prefix}-parent], [${prefix}-next], [${prefix}-previous]`
87
-
88
- observer.init({
89
- name: 'CoCreateEventattributes',
90
- observe: ['attributes', 'addedNodes'],
91
- attributeName: [`${prefix}-events`],
92
- selector: selector,
93
- callback: function (mutation) {
94
- self.initElements([mutation.target], prefix, events)
95
- }
96
- });
97
-
98
- if (events && events.includes('observer')) {
99
- observer.init({
100
- name: 'observerAttributes',
101
- observe: ['attributes'],
102
- attributeName: [`${prefix}-key`, `${prefix}-value`, `${prefix}-selector`, `${prefix}-closest`, `${prefix}-parent`, `${prefix}-next`, `${prefix}-previous`],
103
- callback: function (mutation) {
104
- // remove previous observer
105
- self.initElements([mutation.target], prefix, events)
106
- }
107
- });
108
- }
109
-
110
- let elements = document.querySelectorAll(selector)
111
- this.initElements(elements, prefix, events);
112
- },
113
-
114
- elements: new Map(),
115
- initElements: function (elements, prefix, events = []) {
116
- const self = this
117
- for (const el of elements) {
118
- let isEventable = true
119
- let prefixes = this.elements.get(el)
120
- if (!prefixes) {
121
- prefixes = { [prefix]: { events } }
122
- this.elements.set(el, prefixes)
123
- } else if (!prefixes[prefix]) {
124
- prefixes[prefix] = { events }
125
- } else
126
- isEventable = false
127
-
128
- let customEvents = el.getAttribute(`${prefix}-events`)
129
- if (customEvents) {
130
- customEvents = customEvents.split(',')
131
- for (let i = 0; i < customEvents.length; i++)
132
- customEvents[i] = customEvents[i].trim()
133
-
134
- for (let i = 0; i < events.length; i++)
135
- el.removeEventListener(events[i], eventFunction)
136
-
137
- events = customEvents
138
- prefixes[prefix].events = events
139
- isEventable = true
140
- }
141
- if (!events || !isEventable)
142
- continue
143
- if (events.includes('onload'))
144
- this.__updateElements(el, prefix);
145
-
146
- if (events.includes('observer')) {
147
- let target;
148
- for (let attribute of el.attributes) {
149
- if (attribute.name === 'observe-target') {
150
- target = attribute.value
151
- break;
152
- } else if ([`${prefix}-selector`, `${prefix}-closest`, `${prefix}-parent`, `${prefix}-next`, `${prefix}-previous`].includes(attribute.name)) {
153
- target = attribute.value
154
- break;
155
- }
156
- }
157
- if (target)
158
- observer.init({
159
- observe: ['addedNodes'],
160
- selector: target,
161
- callback: function (mutation) {
162
- self.__updateElements(el, prefix, mutation.target);
163
- }
164
- });
165
- }
166
-
167
- if (events.includes('resize')) {
168
- const resizeObserver = new ResizeObserver((entries) => {
169
- const lastEntry = entries[entries.length - 1];
170
- const { width, height } = lastEntry.contentRect;
171
- el.setAttribute(`${prefix}-if-value`, width + 'px')
172
- self.__updateElements(el, prefix)
173
- });
174
- resizeObserver.observe(el);
175
- }
176
-
177
- for (let i = 0; i < events.length; i++) {
178
- if (events[i] !== 'onload' && events[i] !== 'observer' && events[i] !== 'resize') {
179
- el.removeEventListener(events[i], eventFunction)
180
- el.addEventListener(events[i], eventFunction);
181
- }
182
- }
183
-
184
- function eventFunction(event) {
185
- // TODO: apply debounce
186
- // let debounce;
187
- // clearTimeout(debounce);
188
- // debounce = setTimeout(function() {
189
- const target = event.currentTarget
190
- if (target) {
191
- let prefixes = self.elements.get(target)
192
- if (prefixes[prefix].prev === event.type && ['mouseover', 'mouseout'].includes(event.type))
193
- return
194
- else
195
- prefixes[prefix].prev = event.type
196
-
197
- let attribute = target.getAttribute('actions') || ""
198
- if (attribute.includes(prefix))
199
- return;
200
- // if (target.closest(`[actions*="${prefix}"]`))
201
- // return;
202
- self.__updateElements(target, prefix, null, prefixes[prefix].events);
203
-
204
- // let selector = `[${prefix}], [${prefix}-key], [${prefix}-value], [${prefix}-selector], [${prefix}-closest], [${prefix}-parent], [${prefix}-next], [${prefix}-previous]`
205
-
206
- // let parentElement = target.parentElement;
207
- // if (parentElement) {
208
- // do {
209
- // parentElement = parentElement.closest(selector)
210
- // if (parentElement) {
211
- // self.__updateElements(parentElement, prefix, null, prefixes[prefix].events);
212
- // parentElement = parentElement.parentElement
213
- // }
214
- // }
215
- // while (parentElement)
216
-
217
- // }
218
-
219
- }
220
- // }, 500);
221
- }
222
-
223
-
224
- }
225
- },
226
-
227
- __updateElements: async function (el, prefix, target, events) {
228
- const self = this;
229
- let elements = [el]
230
- let targetGroup = el.getAttribute(`${prefix}-group`);
231
- if (targetGroup) {
232
- document.querySelectorAll(`[${prefix}-group="${targetGroup}"]`).forEach((element) => {
233
- if (element !== el)
234
- elements.push(element)
235
- })
236
- }
237
-
238
- for (let element of elements) {
239
- // TODO: support empty value when prefix-attribute defined, add and remove the attribute
240
- let targetAttribute = element.getAttribute(`${prefix}-attribute`);
241
- let targetPosition = element.getAttribute(`${prefix}-insert-adjacent`);
242
- // targetAttribute = checkMediaQueries(targetAttribute)
243
- // if (targetAttribute === false)
244
- // return
245
-
246
- let onEvent = element.getAttribute(`${prefix}-on`)
247
- if (onEvent) {
248
- await new Promise((resolve, reject) => {
249
- const handleEvent = () => {
250
- document.removeEventListener(onEvent, handleEvent);
251
- resolve();
252
- };
253
- document.addEventListener(onEvent, handleEvent);
254
- });
255
- }
256
-
257
- let values
258
- if (prefix === 'localstorage') {
259
- let key = element.getAttribute('localstorage-get')
260
- if (key) {
261
- values = localStorage.getItem(key)
262
- } else if (key = element.getAttribute('localstorage-set')) {
263
- values = await element.getValue()
264
- if (values)
265
- localStorage.setItem(key, values)
266
- }
267
-
268
- // if (!key || !values)
269
- if (!key)
270
- return
271
- } else {
272
-
273
- values = element.getAttribute(`${prefix}-value`)
274
-
275
- if (values === null) {
276
- let valueElements = queryElements({ element, prefix: `${prefix}-value` });
277
- if (valueElements) {
278
- let elementValues = []
279
- for (let i = 0; i < valueElements.length; i++)
280
- elementValues.push(valueElements[i].getValue())
281
-
282
- if (elementValues.length)
283
- values = elementValues
284
- }
285
- }
286
-
287
- if (values === null)
288
- values = element.getAttribute(`${prefix}-if-value`)
289
- if (values === null)
290
- values = element.getAttribute(prefix);
291
-
292
- }
293
-
294
- if (values || values === '') {
295
- if (typeof values === 'string')
296
- values = values.split(',');
297
- else if (!Array.isArray(values))
298
- values = [values]
299
- } else {
300
- values = await element.getValue()
301
- if (!Array.isArray(values))
302
- values = [values]
303
- }
304
-
305
- if (targetAttribute && !values || values.length === 0)
306
- return;
307
-
308
- let ifCondition = element.getAttribute(`${prefix}-if`);
309
- let elseCondition = element.getAttribute(`${prefix}-else`);
310
-
311
- let ifValue = element.getAttribute(`${prefix}-if-value`)
312
- if (!ifValue && ifValue !== "")
313
- ifValue = await element.getValue() || values //values // await element.getValue()
314
- else if (ifValue || ifValue === "")
315
- ifValue = [ifValue]
316
- else
317
- ifValue = values
318
-
319
- if (!Array.isArray(ifValue))
320
- ifValue = [ifValue]
321
-
322
- //TODO: improved resize toggling of values
323
- // let hasCondition = this.elements2.get(element)
324
- if (ifCondition && evaluateCondition(ifCondition, ifValue)) {
325
-
326
- // if (hasCondition && hasCondition.condition === ifCondition) {
327
- // return
328
- // } else
329
- // this.elements2.set(element, { condition: ifCondition })
330
- } else if (elseCondition && evaluateCondition(elseCondition, ifValue)) {
331
- // if (hasCondition && hasCondition.condition === elseCondition) {
332
- // return
333
- // } else
334
- // this.elements2.set(element, { condition: elseCondition })
335
- } else if (ifCondition || elseCondition) {
336
- return
337
- }
338
-
339
- let targetText = element.getAttribute(`${prefix}-text`);
340
- let targetHtml = element.getAttribute(`${prefix}-html`);
341
- let targetKey = element.getAttribute(`${prefix}-key`);
342
-
343
- if (prefix === 'selected') {
344
- if (el !== element)
345
- element.removeAttribute('selected')
346
- else
347
- element.setAttribute('selected', '')
348
- }
349
-
350
- let deactivate = false
351
- if (el !== element)
352
- deactivate = true
353
- // values = values.map(x => x.trim());
354
-
355
- values = values.map(x => {
356
- if (typeof x === 'string')
357
- x = x.trim(); // Update x with the trimmed value
358
- let prop = element.getAttribute(`${prefix}-property`);
359
- if (prop) {
360
- x = `${prop}:${x}`; // Update x with prop if it exists
361
- }
362
- return x; // Return the updated x
363
- });
364
-
365
- let targetElements = queryElements({ element, prefix });
366
- if (targetElements === false)
367
- targetElements = [element]
368
- let action = element.getAttribute(`${prefix}-action`)
369
- for (let i = 0; i < targetElements.length; i++) {
370
- if (action) {
371
- targetElements[i][action]()
372
- } else if (!targetAttribute && targetAttribute !== '' && ['click', 'focus', 'blur'].includes(prefix)) {
373
- targetElements[i][prefix]()
374
- } else {
375
- this.setValue(prefix, targetElements[i], targetAttribute, values, targetKey, deactivate, events, targetPosition)
376
- }
377
- }
378
- }
379
-
380
- document.dispatchEvent(new CustomEvent(`${prefix}End`, {
381
- detail: {}
382
- }))
383
-
384
- },
385
-
386
- setValue: async function (prefix, element, attrName, values, key, deactivate, events, targetPosition) {
387
- if (events && events.includes('mouseout')) {
388
- if (element.matches(':hover')) {
389
- element.addEventListener('mouseout', () => {
390
- this.setValue(prefix, element, attrName, values, key, deactivate, events, targetPosition);
391
- }, { once: true });
392
- return;
393
- }
394
- }
395
-
396
- let attrValues, oldValue;
397
- if (key) {
398
- key = `{{${key}}}`;
399
- // let value = values[0]
400
- replaceKey(prefix, element, key, values)
401
- } else {
402
- if (attrName === 'style') {
403
- if (element.getAttribute(attrName)) {
404
- attrValues = element.getAttribute(attrName).split(';').map(x => x.trim());
405
- attrValues = attrValues.map(function (item, index) {
406
- return item.replace(' ', '');
407
- });
408
- oldValue = values.filter(x => attrValues.includes(x))[0] || '';
409
- }
410
- let newValue = this.__getNextValue(values, oldValue);
411
-
412
- if (oldValue) {
413
- let [property, value] = oldValue.split(":");
414
- element.style[property] = '';
415
- }
416
-
417
- if (newValue != '') {
418
- newValue = newValue.split(';').map(x => x.trim())
419
- for (let style of newValue) {
420
- let [property, value] = style.split(":");
421
- element.style[property] = value;
422
- }
423
- }
424
- } else {
425
- if (attrName === 'value') {
426
- oldValue = await element.getValue()
427
- } else if (attrName === 'text' || attrName === 'html' || element.getAttribute(attrName)) {
428
- attrValues = element.getAttribute(attrName).split(' ').map(x => x.trim());
429
- oldValue = values.filter(x => attrValues.includes(x))[0] || '';
430
- }
431
-
432
- let newValue = this.__getNextValue(values, oldValue);
433
- if (deactivate)
434
- newValue = ""
435
- if (attrName === 'class') {
436
- if (oldValue) {
437
- element.classList.remove(oldValue);
438
- if (values.length === 1) {
439
- return;
440
- }
441
- }
442
-
443
- if (newValue) {
444
- element.classList.add(newValue);
445
- }
446
- } else if (attrName === 'value') {
447
- element.setValue(newValue);
448
- } else if (['$click', '$focus', '$blur', '$save', '$read'].includes(attrName)) {
449
- element[attrName.substring(1)]()
450
- } else if (attrName) {
451
- // TODO: removeAttribute vs setting empty value, how best to define. operator $remove ???
452
- if (newValue === '' && element.hasAttribute(attrName))
453
- element.removeAttribute(attrName);
454
- else
455
- element.setAttribute(attrName, newValue);
456
- } else if (targetPosition) {
457
- if (targetPosition === 'replace') {
458
- element.insertAdjacentHTML('beforebegin', newValue); // Insert before oldElement
459
- element.remove(); // Remove oldElement
460
- } else
461
- element.insertAdjacentHTML(targetPosition, newValue);
462
- } else {
463
- if (!attrName && ['click', 'focus', 'blur'].includes(newValue)) {
464
- element[newValue]()
465
- } else if (['click', 'focus', 'blur'].includes(attrName)) {
466
- element[attrName]()
467
- }
468
- }
469
- }
470
- }
471
- },
472
-
473
- __getNextValue: function (values, val) {
474
- let size = values.length;
475
- let nn = values.indexOf(val);
476
- if (nn == -1) {
477
- return values[0];
478
- } else {
479
- return values[(nn + 1) % size];
480
- }
481
- }
29
+ elements2: new Map(),
30
+ init: function (prefix, events) {
31
+ if (prefix && events) this.initPrefix(prefix, events);
32
+ else {
33
+ this.initPrefix("toggle", ["click"]);
34
+ this.initPrefix("click", ["click"]);
35
+ this.initPrefix("hover", ["mouseover", "mouseout"]);
36
+ this.initPrefix("mouseover", ["mouseover"]);
37
+ this.initPrefix("mouseout", ["mouseout"]);
38
+ this.initPrefix("input", ["input"]);
39
+ this.initPrefix("change", ["change"]);
40
+ this.initPrefix("selected", ["click"]);
41
+ this.initPrefix("onload", ["onload"]);
42
+ this.initPrefix("observe", ["observer"]);
43
+ this.initPrefix("intersection", ["intersection"]);
44
+ this.initPrefix("resize", ["onload", "resize"]);
45
+ this.initPrefix("localstorage", ["onload"]);
46
+ this.initPrefix("focus", ["focus"]);
47
+ }
48
+
49
+ let customEventEls = document.querySelectorAll("[event-name]");
50
+ let names = {};
51
+ for (let customEventEl of customEventEls) {
52
+ let name = customEventEl.getAttribute("event-name");
53
+ name = name.split(",");
54
+ for (let i = 0; i < name.length; i++) {
55
+ name[i].trim();
56
+ if (!names[name]) {
57
+ names[name] = name;
58
+ this.initPrefix(name);
59
+ }
60
+ }
61
+ }
62
+
63
+ const self = this;
64
+ observer.init({
65
+ name: "CoCreateEventName",
66
+ observe: ["addedNodes"],
67
+ selector: `[event-name]`,
68
+ callback: function (mutation) {
69
+ let name = mutation.target.getAttribute("event-name");
70
+ self.initPrefix(name);
71
+ }
72
+ });
73
+ },
74
+
75
+ initPrefix: function (prefix, events) {
76
+ const self = this;
77
+
78
+ action.init({
79
+ name: prefix,
80
+ endEvent: `${prefix}End`,
81
+ callback: (data) => {
82
+ this.__updateElements(
83
+ data.element,
84
+ prefix,
85
+ null,
86
+ null,
87
+ data.params
88
+ );
89
+ }
90
+ });
91
+
92
+ let selector = `[${prefix}], [${prefix}-key], [${prefix}-attribute], [${prefix}-value], [${prefix}-action], [${prefix}-selector], [${prefix}-closest], [${prefix}-parent], [${prefix}-next], [${prefix}-previous]`;
93
+
94
+ observer.init({
95
+ name: "CoCreateEventattributes",
96
+ observe: ["attributes", "addedNodes"],
97
+ attributeName: [
98
+ `${prefix}-key`,
99
+ `${prefix}-value`,
100
+ `${prefix}-selector`,
101
+ `${prefix}-closest`,
102
+ `${prefix}-parent`,
103
+ `${prefix}-next`,
104
+ `${prefix}-previous`,
105
+ `${prefix}-events`
106
+ ],
107
+ selector,
108
+ callback: function (mutation) {
109
+ self.initElements([mutation.target], prefix, events);
110
+ }
111
+ });
112
+
113
+ let elements = document.querySelectorAll(selector);
114
+ this.initElements(elements, prefix, events);
115
+ },
116
+
117
+ elements: new Map(),
118
+ initElements: function (elements, prefix, events = []) {
119
+ const self = this;
120
+ for (const el of elements) {
121
+ let isEventable = true;
122
+ let prefixes = this.elements.get(el);
123
+ if (!prefixes) {
124
+ prefixes = { [prefix]: { events } };
125
+ this.elements.set(el, prefixes);
126
+ } else if (!prefixes[prefix]) {
127
+ prefixes[prefix] = { events };
128
+ } else isEventable = false;
129
+
130
+ let customEvents = el.getAttribute(`${prefix}-events`);
131
+ if (customEvents) {
132
+ customEvents = customEvents.split(",");
133
+ for (let i = 0; i < customEvents.length; i++)
134
+ customEvents[i] = customEvents[i].trim();
135
+
136
+ for (let i = 0; i < events.length; i++)
137
+ el.removeEventListener(events[i], eventFunction);
138
+
139
+ events = customEvents;
140
+ prefixes[prefix].events = events;
141
+ isEventable = true;
142
+ }
143
+ if (!events || !isEventable) continue;
144
+ if (events.includes("onload")) this.__updateElements(el, prefix);
145
+
146
+ if (events.includes("observer")) {
147
+ let target;
148
+ for (let attribute of el.attributes) {
149
+ if (attribute.name === "observe-target") {
150
+ target = attribute.value;
151
+ break;
152
+ } else if (
153
+ [
154
+ `${prefix}-selector`,
155
+ `${prefix}-closest`,
156
+ `${prefix}-parent`,
157
+ `${prefix}-next`,
158
+ `${prefix}-previous`
159
+ ].includes(attribute.name)
160
+ ) {
161
+ target = attribute.value;
162
+ break;
163
+ }
164
+ }
165
+
166
+ let attributeName = (
167
+ el.getAttribute(`${prefix}-attributes`) || ""
168
+ )
169
+ .split(/\s*,\s*/)
170
+ .filter((item) => item);
171
+
172
+ let observeAttribute = (
173
+ el.getAttribute(`${prefix}-observe`) || ""
174
+ )
175
+ .split(/\s*,\s*/)
176
+ .filter((item) => item);
177
+
178
+ let observerConfig = {
179
+ observe: observeAttribute,
180
+ callback: function (mutation) {
181
+ self.__updateElements(el, prefix, mutation.target);
182
+ }
183
+ };
184
+
185
+ if (target) {
186
+ if (
187
+ target &&
188
+ !observeAttribute.length &&
189
+ !attributeName.length
190
+ ) {
191
+ observerConfig.observe.push("addedNodes");
192
+ }
193
+ observerConfig.target = target;
194
+ }
195
+
196
+ if (attributeName.length) {
197
+ observerConfig.observe.push("attributes");
198
+ observerConfig.attributeName = attributeName;
199
+ }
200
+
201
+ if (observerConfig.observe.length)
202
+ observer.init(observerConfig);
203
+ }
204
+
205
+ if (events.includes("resize")) {
206
+ const resizeObserver = new ResizeObserver((entries) => {
207
+ const lastEntry = entries[entries.length - 1];
208
+ const { width, height } = lastEntry.contentRect;
209
+ el.setAttribute(`${prefix}-if-value`, width + "px");
210
+ self.__updateElements(el, prefix);
211
+ });
212
+ resizeObserver.observe(el);
213
+ }
214
+
215
+ if (events.includes("intersection")) {
216
+ const rootSelector = el.getAttribute(`${prefix}-root`);
217
+ const rootMargin =
218
+ el.getAttribute(`${prefix}-root-margin`) || "0px";
219
+ const threshold = el.getAttribute(`${prefix}-threshold`)
220
+ ? JSON.parse(el.getAttribute(`${prefix}-threshold`))
221
+ : [0];
222
+ const trigger = el.getAttribute(`${prefix}-trigger`) || "both"; // Default to "both"
223
+
224
+ // Resolve root from the selector or use null for viewport
225
+ const root = rootSelector
226
+ ? document.querySelector(rootSelector)
227
+ : null;
228
+
229
+ // Validate and filter threshold values
230
+ const validThreshold = Array.isArray(threshold)
231
+ ? threshold.filter((value) => value >= 0 && value <= 1)
232
+ : [0];
233
+
234
+ // Create IntersectionObserver
235
+ const intersectionObserver = new IntersectionObserver(
236
+ (entries) => {
237
+ entries.forEach((entry) => {
238
+ const isVisible = entry.isIntersecting;
239
+
240
+ // Determine if __updateElements should be called based on trigger
241
+ // if (
242
+ // (trigger === "visible" && isVisible) ||
243
+ // (trigger === "not-visible" && !isVisible) ||
244
+ // trigger === "both"
245
+ // ) {
246
+ if (isVisible) {
247
+ // Set an attribute to reflect visibility state
248
+ el.setAttribute(
249
+ `${prefix}-is-visible`,
250
+ isVisible ? "true" : "false"
251
+ );
252
+
253
+ // Call __updateElements
254
+ self.__updateElements(
255
+ el,
256
+ prefix
257
+ // {
258
+ // isVisible,
259
+ // intersectionRatio:
260
+ // entry.intersectionRatio
261
+ // }
262
+ );
263
+ }
264
+ });
265
+ },
266
+ { root, rootMargin, threshold: validThreshold }
267
+ );
268
+
269
+ intersectionObserver.observe(el);
270
+ }
271
+
272
+ for (let i = 0; i < events.length; i++) {
273
+ if (
274
+ events[i] !== "onload" &&
275
+ events[i] !== "observer" &&
276
+ events[i] !== "intersection" &&
277
+ events[i] !== "resize"
278
+ ) {
279
+ el.removeEventListener(events[i], eventFunction);
280
+ el.addEventListener(events[i], eventFunction);
281
+ }
282
+ }
283
+
284
+ function eventFunction(event) {
285
+ // TODO: apply debounce
286
+ // let debounce;
287
+ // clearTimeout(debounce);
288
+ // debounce = setTimeout(function() {
289
+ const target = event.currentTarget;
290
+ if (target) {
291
+ let prefixes = self.elements.get(target);
292
+ if (
293
+ prefixes[prefix].prev === event.type &&
294
+ ["mouseover", "mouseout"].includes(event.type)
295
+ )
296
+ return;
297
+ else prefixes[prefix].prev = event.type;
298
+
299
+ let attribute = target.getAttribute("actions") || "";
300
+ if (attribute.includes(prefix)) return;
301
+ // if (target.closest(`[actions*="${prefix}"]`))
302
+ // return;
303
+ self.__updateElements(
304
+ target,
305
+ prefix,
306
+ null,
307
+ prefixes[prefix].events
308
+ );
309
+
310
+ // let selector = `[${prefix}], [${prefix}-key], [${prefix}-value], [${prefix}-selector], [${prefix}-closest], [${prefix}-parent], [${prefix}-next], [${prefix}-previous]`
311
+
312
+ // let parentElement = target.parentElement;
313
+ // if (parentElement) {
314
+ // do {
315
+ // parentElement = parentElement.closest(selector)
316
+ // if (parentElement) {
317
+ // self.__updateElements(parentElement, prefix, null, prefixes[prefix].events);
318
+ // parentElement = parentElement.parentElement
319
+ // }
320
+ // }
321
+ // while (parentElement)
322
+
323
+ // }
324
+ }
325
+ // }, 500);
326
+ }
327
+ }
328
+ },
329
+
330
+ __updateElements: async function (el, prefix, target, events, params) {
331
+ if (!el.isConnected) return;
332
+
333
+ let elements = [el];
334
+ let targetGroup = el.getAttribute(`${prefix}-group`);
335
+ if (targetGroup) {
336
+ document
337
+ .querySelectorAll(`[${prefix}-group="${targetGroup}"]`)
338
+ .forEach((element) => {
339
+ if (element !== el) elements.push(element);
340
+ });
341
+ }
342
+
343
+ for (let element of elements) {
344
+ let delay = element.getAttribute(`${prefix}-delay`);
345
+
346
+ if (delay) {
347
+ delay = parseInt(delay, 10) || 0;
348
+ if (delay > 0) {
349
+ await new Promise((resolve) => setTimeout(resolve, delay));
350
+ }
351
+ }
352
+
353
+ if (!element.isConnected) return;
354
+
355
+ let once = element.getAttribute(`${prefix}-once`);
356
+ if (once || once === "") {
357
+ if (!element.eventsOnce) {
358
+ element.eventsOnce = [prefix];
359
+ } else if (element.eventsOnce.includes(prefix)) {
360
+ continue;
361
+ } else {
362
+ element.eventsOnce.push(prefix);
363
+ }
364
+ }
365
+
366
+ // TODO: support empty value when prefix-attribute defined, add and remove the attribute
367
+ let targetAttribute = element.getAttribute(`${prefix}-attribute`);
368
+ let targetPosition = element.getAttribute(
369
+ `${prefix}-insert-adjacent`
370
+ );
371
+ // targetAttribute = checkMediaQueries(targetAttribute)
372
+ // if (targetAttribute === false)
373
+ // return
374
+
375
+ let onEvent = element.getAttribute(`${prefix}-on`);
376
+ if (onEvent) {
377
+ await new Promise((resolve, reject) => {
378
+ const handleEvent = () => {
379
+ document.removeEventListener(onEvent, handleEvent);
380
+ resolve();
381
+ };
382
+ document.addEventListener(onEvent, handleEvent);
383
+ });
384
+ }
385
+
386
+ let values;
387
+ if (prefix === "localstorage") {
388
+ let key = element.getAttribute("localstorage-get");
389
+ if (key) {
390
+ values = localStorage.getItem(key);
391
+ } else if ((key = element.getAttribute("localstorage-set"))) {
392
+ values = await element.getValue();
393
+ if (values) localStorage.setItem(key, values);
394
+ }
395
+
396
+ // if (!key || !values)
397
+ if (!key) return;
398
+ } else {
399
+ values = element.getAttribute(`${prefix}-value`);
400
+
401
+ if (values === null) {
402
+ let valueElements = queryElements({
403
+ element,
404
+ prefix: `${prefix}-value`
405
+ });
406
+ if (valueElements) {
407
+ let elementValues = [];
408
+ for (let i = 0; i < valueElements.length; i++)
409
+ elementValues.push(valueElements[i].getValue());
410
+
411
+ if (elementValues.length) values = elementValues;
412
+ }
413
+ }
414
+
415
+ if (values === null)
416
+ values = element.getAttribute(`${prefix}-if-value`);
417
+ if (values === null) values = element.getAttribute(prefix);
418
+ }
419
+
420
+ if (values || values === "") {
421
+ if (typeof values === "string") values = values.split(",");
422
+ else if (!Array.isArray(values)) values = [values];
423
+ } else {
424
+ values = await element.getValue();
425
+ if (!Array.isArray(values)) values = [values];
426
+ }
427
+
428
+ if ((targetAttribute && !values) || values.length === 0) return;
429
+
430
+ let ifCondition = element.getAttribute(`${prefix}-if`);
431
+ let elseCondition = element.getAttribute(`${prefix}-else`);
432
+
433
+ let ifValue = element.getAttribute(`${prefix}-if-value`);
434
+ if (!ifValue && ifValue !== "")
435
+ ifValue = (await element.getValue()) || values;
436
+ //values // await element.getValue()
437
+ else if (ifValue || ifValue === "") ifValue = [ifValue];
438
+ else ifValue = values;
439
+
440
+ if (!Array.isArray(ifValue)) ifValue = [ifValue];
441
+
442
+ //TODO: improved resize toggling of values
443
+ // let hasCondition = this.elements2.get(element)
444
+ if (ifCondition && evaluateCondition(ifCondition, ifValue)) {
445
+ // if (hasCondition && hasCondition.condition === ifCondition) {
446
+ // return
447
+ // } else
448
+ // this.elements2.set(element, { condition: ifCondition })
449
+ } else if (
450
+ elseCondition &&
451
+ evaluateCondition(elseCondition, ifValue)
452
+ ) {
453
+ // if (hasCondition && hasCondition.condition === elseCondition) {
454
+ // return
455
+ // } else
456
+ // this.elements2.set(element, { condition: elseCondition })
457
+ } else if (ifCondition || elseCondition) {
458
+ return;
459
+ }
460
+
461
+ let targetText = element.getAttribute(`${prefix}-text`);
462
+ let targetHtml = element.getAttribute(`${prefix}-html`);
463
+ let targetKey = element.getAttribute(`${prefix}-key`);
464
+
465
+ if (prefix === "selected") {
466
+ if (el !== element) element.removeAttribute("selected");
467
+ else element.setAttribute("selected", "");
468
+ }
469
+
470
+ let deactivate = false;
471
+ if (el !== element) deactivate = true;
472
+ // values = values.map(x => x.trim());
473
+
474
+ values = values.map((x) => {
475
+ if (typeof x === "string") x = x.trim(); // Update x with the trimmed value
476
+ let prop = element.getAttribute(`${prefix}-property`);
477
+ if (prop) {
478
+ x = `${prop}:${x}`; // Update x with prop if it exists
479
+ }
480
+ return x; // Return the updated x
481
+ });
482
+
483
+ let targetElements = queryElements({
484
+ element,
485
+ prefix,
486
+ selector: params
487
+ });
488
+ if (targetElements === false) targetElements = [element];
489
+ let action = element.getAttribute(`${prefix}-action`);
490
+ for (let i = 0; i < targetElements.length; i++) {
491
+ if (action) {
492
+ targetElements[i][action]();
493
+ } else if (
494
+ !targetAttribute &&
495
+ targetAttribute !== "" &&
496
+ !targetPosition &&
497
+ ["click", "focus", "blur"].includes(prefix)
498
+ ) {
499
+ // TODO: click causes an infinite loop if targetElement[i] is a child of element do to event propactaion
500
+ if (
501
+ (targetElements[i] === element &&
502
+ element.hasAttribute(prefix)) ||
503
+ (params &&
504
+ targetElements[i] !== element &&
505
+ !element.contains(targetElements[i]))
506
+ )
507
+ targetElements[i][prefix]();
508
+ } else {
509
+ this.setValue(
510
+ prefix,
511
+ targetElements[i],
512
+ targetAttribute,
513
+ values,
514
+ targetKey,
515
+ deactivate,
516
+ events,
517
+ targetPosition
518
+ );
519
+ }
520
+ }
521
+ }
522
+
523
+ document.dispatchEvent(
524
+ new CustomEvent(`${prefix}End`, {
525
+ detail: {}
526
+ })
527
+ );
528
+ },
529
+
530
+ setValue: async function (
531
+ prefix,
532
+ element,
533
+ attrName,
534
+ values,
535
+ key,
536
+ deactivate,
537
+ events,
538
+ targetPosition
539
+ ) {
540
+ if (events && events.includes("mouseout")) {
541
+ if (element.matches(":hover")) {
542
+ element.addEventListener(
543
+ "mouseout",
544
+ () => {
545
+ this.setValue(
546
+ prefix,
547
+ element,
548
+ attrName,
549
+ values,
550
+ key,
551
+ deactivate,
552
+ events,
553
+ targetPosition
554
+ );
555
+ },
556
+ { once: true }
557
+ );
558
+ return;
559
+ }
560
+ }
561
+
562
+ let attrValues, oldValue;
563
+ if (key) {
564
+ key = `{{${key}}}`;
565
+ // let value = values[0]
566
+ replaceKey(prefix, element, key, values);
567
+ } else {
568
+ // TODo: if html in iframe
569
+ let domTextEditor;
570
+ if (element.parentElement) {
571
+ domTextEditor =
572
+ element.parentElement.closest("[contenteditable]");
573
+ }
574
+
575
+ if (attrName === "style") {
576
+ if (element.getAttribute(attrName)) {
577
+ attrValues = element
578
+ .getAttribute(attrName)
579
+ .split(";")
580
+ .map((x) => x.trim());
581
+ attrValues = attrValues.map(function (item, index) {
582
+ return item.replace(" ", "");
583
+ });
584
+ oldValue =
585
+ values.filter((x) => attrValues.includes(x))[0] || "";
586
+ }
587
+ let newValue = this.__getNextValue(values, oldValue);
588
+
589
+ if (oldValue) {
590
+ let [property, value] = oldValue.split(":");
591
+ element.style[property] = "";
592
+ }
593
+
594
+ if (newValue != "") {
595
+ newValue = newValue.split(";").map((x) => x.trim());
596
+ for (let style of newValue) {
597
+ let [property, value] = style.split(":");
598
+ element.style[property] = value;
599
+ }
600
+ }
601
+ } else {
602
+ if (attrName === "value") {
603
+ oldValue = await element.getValue();
604
+ } else if (
605
+ attrName === "text" ||
606
+ attrName === "html" ||
607
+ element.getAttribute(attrName)
608
+ ) {
609
+ attrValues = element
610
+ .getAttribute(attrName)
611
+ .split(" ")
612
+ .map((x) => x.trim());
613
+ oldValue =
614
+ values.filter((x) => attrValues.includes(x))[0] || "";
615
+ }
616
+
617
+ let newValue = this.__getNextValue(values, oldValue);
618
+ if (deactivate) newValue = "";
619
+ if (attrName === "class") {
620
+ if (oldValue) {
621
+ element.classList.remove(oldValue);
622
+ if (values.length === 1) {
623
+ return;
624
+ }
625
+ }
626
+
627
+ if (newValue) {
628
+ element.classList.add(newValue);
629
+ }
630
+ } else if (attrName === "value") {
631
+ element.setValue(newValue);
632
+ } else if (
633
+ ["$click", "$focus", "$blur", "$save", "$read"].includes(
634
+ attrName
635
+ )
636
+ ) {
637
+ element[attrName.substring(1)]();
638
+ } else if (attrName) {
639
+ // TODO: removeAttribute vs setting empty value, how best to define. operator $remove ???
640
+ if (newValue === "" && element.hasAttribute(attrName))
641
+ element.removeAttribute(attrName);
642
+ else element.setAttribute(attrName, newValue);
643
+ } else if (targetPosition) {
644
+ if (domTextEditor) {
645
+ CoCreate.text.insertAdjacentElement({
646
+ domTextEditor,
647
+ position: targetPosition,
648
+ target: element,
649
+ elementValue: newValue
650
+ });
651
+ } else if (targetPosition === "replace") {
652
+ element.insertAdjacentHTML("beforebegin", newValue); // Insert before oldElement
653
+ element.remove(); // Remove oldElement
654
+ } else {
655
+ element.insertAdjacentHTML(targetPosition, newValue);
656
+ }
657
+ } else {
658
+ if (
659
+ !attrName &&
660
+ ["click", "focus", "blur"].includes(newValue)
661
+ ) {
662
+ element[newValue]();
663
+ } else if (["click", "focus", "blur"].includes(attrName)) {
664
+ element[attrName]();
665
+ }
666
+ }
667
+ }
668
+ }
669
+ },
670
+
671
+ __getNextValue: function (values, val) {
672
+ let size = values.length;
673
+ let nn = values.indexOf(val);
674
+ if (nn == -1) {
675
+ return values[0];
676
+ } else {
677
+ return values[(nn + 1) % size];
678
+ }
679
+ }
482
680
  };
483
681
 
484
682
  const eventElements = new Map();
@@ -486,180 +684,193 @@ const eventKeys = new Map();
486
684
  const elementAttributes = new Map();
487
685
 
488
686
  function replaceKey(prefix, element, key, values) {
489
- let currentValue = key
490
-
491
- if (eventElements.has(element)) {
492
- currentValue = eventElements.get(element).get(key);
493
- }
494
- let value = CoCreateEvents.__getNextValue(values, currentValue);
495
- eventKeys.set(key, value)
496
- eventElements.set(element, eventKeys)
497
-
498
- let attributes = elementAttributes.get(element)
499
- if (!attributes) {
500
- attributes = {}
501
- elementAttributes.set(element, attributes)
502
- }
503
-
504
-
505
- for (let attribute of element.attributes) {
506
- let newName = attribute.name;
507
- let newValue = attribute.value;
508
- let attrName = attribute.name;
509
- let attrValue = attribute.value;
510
- let setAttr = false;
511
-
512
- if (attrName === 'clone-data')
513
- console.log('clone-data')
514
- if (attrValue.includes(currentValue) || attributes[attrName] && attributes[attrName].valueKeys && attributes[attrName].valueKeys[key]) {
515
- if (!attributes[attrName])
516
- attributes[attrName] = { originalValue: attrValue }
517
- else if (!attributes[attrName].originalValue)
518
- attributes[attrName].originalValue = attrValue
519
- if (!attributes[attrName].valueKeys)
520
- attributes[attrName].valueKeys = { [key]: value }
521
- else
522
- attributes[attrName].valueKeys[key] = value;
523
-
524
- newValue = attributes[attrName].originalValue
525
- for (let valueKey of Object.keys(attributes[attrName].valueKeys)) {
526
- const valueKeyRegex = new RegExp(valueKey, "g");
527
- newValue = newValue.replace(valueKeyRegex, value);
528
- }
529
- setAttr = true;
530
- }
531
- // if (attrName.includes(currentValue) || attributes[attrName] && attributes[attrName].nameKeys && attributes[attrName].nameKeys[key]){
532
- // if (!attributes[attrName])
533
- // attributes[attrName] = { originalName: attrName }
534
- // else if (!attributes[attrName].originalName)
535
- // attributes[attrName].originalName = attrName
536
-
537
- // if (!attributes[attrName].nameKeys)
538
- // attributes[attrName].nameKeys = {[key]: value}
539
-
540
- // newName = attributes[attrName].originalName
541
- // for (let nameKey of Object.keys(attributes[attrName].nameKeys)) {
542
- // let r
543
- // if (attrName === nameKey)
544
- // r = nameKey
545
- // else
546
- // r = attributes[attrName].nameKeys[nameKey]
547
-
548
- // const nameKeyRegex = new RegExp(r, "g");
549
- // newName = newName.replace(nameKeyRegex, value);
550
- // }
551
-
552
- // attributes[attrName].nameKeys[key] = value;
553
-
554
-
555
- // element.removeAttribute(attrName);
556
- // setAttr = true;
557
-
558
- // }
559
- if (setAttr)
560
- element.setAttribute(newName, newValue);
561
- }
562
- let html = element.innerHTML;
563
- if (html.indexOf(currentValue) !== -1 || element.htmlKeys && element.htmlKeys[key]) {
564
- if (!element.originalHtml)
565
- element.originalHtml = html
566
- if (!element.htmlKeys)
567
- element.htmlKeys = { [key]: value }
568
- else
569
- element.htmlKeys[key] = value;
570
-
571
- let newHTML = element.originalHtml
572
- if (newHTML) {
573
- for (let elementKey of Object.keys(element.htmlKeys)) {
574
- const htmlKeyRegex = new RegExp(elementKey, "g");
575
- newHTML = newHTML.replace(htmlKeyRegex, value);
576
- }
577
-
578
- element.innerHTML = newHTML;
579
- }
580
- }
581
-
687
+ let currentValue = key;
688
+
689
+ if (eventElements.has(element)) {
690
+ currentValue = eventElements.get(element).get(key);
691
+ }
692
+ let value = CoCreateEvents.__getNextValue(values, currentValue);
693
+ eventKeys.set(key, value);
694
+ eventElements.set(element, eventKeys);
695
+
696
+ let attributes = elementAttributes.get(element);
697
+ if (!attributes) {
698
+ attributes = {};
699
+ elementAttributes.set(element, attributes);
700
+ }
701
+
702
+ for (let attribute of element.attributes) {
703
+ let newName = attribute.name;
704
+ let newValue = attribute.value;
705
+ let attrName = attribute.name;
706
+ let attrValue = attribute.value;
707
+ let setAttr = false;
708
+
709
+ if (attrName === "clone-data") console.log("clone-data");
710
+ if (
711
+ attrValue.includes(currentValue) ||
712
+ (attributes[attrName] &&
713
+ attributes[attrName].valueKeys &&
714
+ attributes[attrName].valueKeys[key])
715
+ ) {
716
+ if (!attributes[attrName])
717
+ attributes[attrName] = { originalValue: attrValue };
718
+ else if (!attributes[attrName].originalValue)
719
+ attributes[attrName].originalValue = attrValue;
720
+ if (!attributes[attrName].valueKeys)
721
+ attributes[attrName].valueKeys = { [key]: value };
722
+ else attributes[attrName].valueKeys[key] = value;
723
+
724
+ newValue = attributes[attrName].originalValue;
725
+ for (let valueKey of Object.keys(attributes[attrName].valueKeys)) {
726
+ const valueKeyRegex = new RegExp(valueKey, "g");
727
+ newValue = newValue.replace(valueKeyRegex, value);
728
+ }
729
+ setAttr = true;
730
+ }
731
+ // if (attrName.includes(currentValue) || attributes[attrName] && attributes[attrName].nameKeys && attributes[attrName].nameKeys[key]){
732
+ // if (!attributes[attrName])
733
+ // attributes[attrName] = { originalName: attrName }
734
+ // else if (!attributes[attrName].originalName)
735
+ // attributes[attrName].originalName = attrName
736
+
737
+ // if (!attributes[attrName].nameKeys)
738
+ // attributes[attrName].nameKeys = {[key]: value}
739
+
740
+ // newName = attributes[attrName].originalName
741
+ // for (let nameKey of Object.keys(attributes[attrName].nameKeys)) {
742
+ // let r
743
+ // if (attrName === nameKey)
744
+ // r = nameKey
745
+ // else
746
+ // r = attributes[attrName].nameKeys[nameKey]
747
+
748
+ // const nameKeyRegex = new RegExp(r, "g");
749
+ // newName = newName.replace(nameKeyRegex, value);
750
+ // }
751
+
752
+ // attributes[attrName].nameKeys[key] = value;
753
+
754
+ // element.removeAttribute(attrName);
755
+ // setAttr = true;
756
+
757
+ // }
758
+ if (setAttr) element.setAttribute(newName, newValue);
759
+ }
760
+ let html = element.innerHTML;
761
+ if (
762
+ html.indexOf(currentValue) !== -1 ||
763
+ (element.htmlKeys && element.htmlKeys[key])
764
+ ) {
765
+ if (!element.originalHtml) element.originalHtml = html;
766
+ if (!element.htmlKeys) element.htmlKeys = { [key]: value };
767
+ else element.htmlKeys[key] = value;
768
+
769
+ let newHTML = element.originalHtml;
770
+ if (newHTML) {
771
+ for (let elementKey of Object.keys(element.htmlKeys)) {
772
+ const htmlKeyRegex = new RegExp(elementKey, "g");
773
+ newHTML = newHTML.replace(htmlKeyRegex, value);
774
+ }
775
+
776
+ element.innerHTML = newHTML;
777
+ }
778
+ }
582
779
  }
583
780
 
584
781
  function evaluateCondition(condition, values) {
585
- let orConditions = condition.split(/\s*\|\|\s*/);
586
-
587
- if (orConditions.length > 1) {
588
- return orConditions.some(cond => checkCondition(cond, values));
589
- } else {
590
- let andConditions = condition.split(/\s*&&\s*/);
591
- return andConditions.every(cond => checkCondition(cond, values));
592
- }
782
+ let orConditions = condition.split(/\s*\|\|\s*/);
783
+
784
+ if (orConditions.length > 1) {
785
+ return orConditions.some((cond) => checkCondition(cond, values));
786
+ } else {
787
+ let andConditions = condition.split(/\s*&&\s*/);
788
+ return andConditions.every((cond) => checkCondition(cond, values));
789
+ }
593
790
  }
594
791
 
595
792
  function checkCondition(condition, value) {
596
- let isNegated = condition.startsWith('!');
597
- if (isNegated) {
598
- condition = condition.substring(1);
599
- }
600
- const operatorMatch = condition.match(/(<=|>=|<|>)(.+)/);
601
- if (operatorMatch)
602
- condition = operatorMatch[2].trim()
603
-
604
- let parse = true
605
- if (condition === 'true') {
606
- return !!value[0];
607
- } else if (condition === 'false') {
608
- return !value[0];
609
- } else if (condition === '[]' && typeof value[0] === 'string') {
610
- parse = false
611
- }
612
-
613
-
614
-
615
- // TODO: why parse updated conditin to boolean false
616
- if (parse && condition !== 'false')
617
- condition = parseCondition(condition);
618
-
619
- let result;
620
-
621
- if (condition === '$template') {
622
- result = (/{{\s*([\w\W]+)\s*}}/g.test(value[0]))
623
- } else if (Array.isArray(value) && !(typeof condition === 'object')) {
624
- if (operatorMatch) {
625
- condition = parseFloat(condition)
626
- result = value.some(v => {
627
- v = parseFloat(v)
628
- switch (operatorMatch[1]) {
629
- case '<': return v < condition;
630
- case '>': return v > condition;
631
- case '<=': return v <= condition;
632
- case '>=': return v >= condition;
633
- default: return false;
634
- }
635
- });
636
- } else
637
- result = value.includes(condition);
638
- } else if (Array.isArray(value)) {
639
- // TODO: handle comparing array to array, vs querying the ayya items for a match
640
- result = queryData(value, condition)
641
- } else if (typeof value === 'object' && value !== null && typeof parsedCond === 'object') {
642
- result = queryData(value, condition)
643
- } else {
644
- result = value === condition;
645
- }
646
-
647
- result = isNegated ? !result : result;
648
- return result
649
-
793
+ let isNegated = condition.startsWith("!");
794
+ if (isNegated) {
795
+ condition = condition.substring(1);
796
+ }
797
+ const operatorMatch = condition.match(/(<=|>=|<|>)(.+)/);
798
+ if (operatorMatch) condition = operatorMatch[2].trim();
799
+
800
+ let parse = true;
801
+ if (condition === "true") {
802
+ return !!value[0];
803
+ } else if (condition === "false") {
804
+ return !value[0];
805
+ }
806
+ // else if (condition === "[]" && typeof value[0] === "string") {
807
+ // parse = false;
808
+ // }
809
+
810
+ // TODO: why parse updated conditin to boolean false
811
+ // if (parse && condition !== "false") condition = parseCondition(condition);
812
+
813
+ if (typeof value[0] === "number") {
814
+ condition = parseNumberCondition(condition);
815
+ } else if (typeof value[0] === "object" && typeof condition === "string") {
816
+ condition = parseJsonCondition(condition);
817
+ }
818
+
819
+ let result;
820
+
821
+ if (condition === "$template") {
822
+ result = /{{\s*([\w\W]+)\s*}}/g.test(value[0]);
823
+ } else if (Array.isArray(value) && !(typeof condition === "object")) {
824
+ if (operatorMatch) {
825
+ condition = parseFloat(condition);
826
+ result = value.some((v) => {
827
+ v = parseFloat(v);
828
+ switch (operatorMatch[1]) {
829
+ case "<":
830
+ return v < condition;
831
+ case ">":
832
+ return v > condition;
833
+ case "<=":
834
+ return v <= condition;
835
+ case ">=":
836
+ return v >= condition;
837
+ default:
838
+ return false;
839
+ }
840
+ });
841
+ } else result = value.includes(condition);
842
+ } else if (Array.isArray(value)) {
843
+ // TODO: handle comparing array to array, vs querying the array items for a match
844
+ result = queryData(value, condition);
845
+ } else if (
846
+ typeof value === "object" &&
847
+ value !== null &&
848
+ typeof parsedCond === "object"
849
+ ) {
850
+ result = queryData(value, condition);
851
+ } else {
852
+ result = value === condition;
853
+ }
854
+
855
+ result = isNegated ? !result : result;
856
+ return result;
650
857
  }
651
858
 
652
- function parseCondition(condition) {
653
- try {
654
- // Attempt to parse the condition as JSON
655
- let parsedJson = JSON.parse(condition);
656
- return parsedJson;
657
- } catch (e) {
658
- // If JSON parsing fails, check if the condition is a number
659
- return !isNaN(condition) && condition.trim() !== '' ? Number(condition) : condition;
660
- }
859
+ function parseJsonCondition(condition) {
860
+ try {
861
+ // Attempt to parse the condition as JSON
862
+ let parsedJson = JSON.parse(condition);
863
+ return parsedJson;
864
+ } catch (e) {
865
+ return condition;
866
+ }
867
+ }
868
+ function parseNumberCondition(condition) {
869
+ return !isNaN(condition) && condition.trim() !== ""
870
+ ? Number(condition)
871
+ : condition;
661
872
  }
662
873
 
663
874
  CoCreateEvents.init();
664
875
 
665
- export default CoCreateEvents;
876
+ export default CoCreateEvents;