@cocreate/utils 1.36.0 → 1.37.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 +8 -0
  2. package/package.json +1 -1
  3. package/src/index.js +1121 -992
package/src/index.js CHANGED
@@ -1,993 +1,1122 @@
1
1
  (function (root, factory) {
2
- if (typeof define === 'function' && define.amd) {
3
- define([], function () {
4
- return factory(true)
5
- });
6
- } else if (typeof module === 'object' && module.exports) {
7
- module.exports = factory(false);
8
- } else {
9
- root.returnExports = factory(true);
10
- }
11
- }(typeof self !== 'undefined' ? self : this, function (isBrowser) {
12
-
13
- /*globals DOMParser*/
14
- function clickedElement() {
15
- document.addEventListener('click', e => {
16
- document.clickedElement = e.target;
17
- });
18
-
19
- try {
20
- let frames = document.querySelectorAll('iframe');
21
- for (let frame of frames) {
22
- try {
23
- let frameDocument = frame.contentDocument;
24
- if (!frameDocument.clickedElementListenerAdded) {
25
- frameDocument.addEventListener('click', e => {
26
- frameDocument.clickedElement = e.target;
27
- });
28
-
29
- // Mark the document to avoid adding duplicate listeners
30
- frameDocument.clickedElementListenerAdded = true;
31
- }
32
- } catch (iframeError) {
33
- console.log(`Cross-origin frame handling failed for: ${frame}`, iframeError);
34
- }
35
- }
36
- } catch (e) {
37
- console.log('Top-level frame document handling failed:', e);
38
- }
39
- }
40
-
41
- /**
42
- * Generates an ObjectId
43
- */
44
- let counter = 0;
45
- function ObjectId(inputId) {
46
- if (inputId && /^[0-9a-fA-F]{24}$/.test(inputId)) {
47
- // If a valid ObjectId is provided, return it as a custom ObjectId object
48
- return {
49
- timestamp: inputId.substring(0, 8),
50
- processId: inputId.substring(8, 20),
51
- counter: inputId.substring(20),
52
- toString: function () {
53
- return this.timestamp + this.processId + this.counter;
54
- }
55
- };
56
- } else if (inputId) {
57
- throw new Error('Invalid ObjectId provided.');
58
- }
59
-
60
- // Generate a new custom ObjectId
61
- const timestampHex = Math.floor(new Date(new Date().toISOString()).getTime() / 1000).toString(16).padStart(8, '0');
62
- const processIdHex = Math.floor(Math.random() * 0x100000000000).toString(16).padStart(12, '0');
63
-
64
- counter = (counter + 1) % 10000;
65
- if (counter < 2) {
66
- counter = Math.floor(Math.random() * (5000 - 100 + 1)) + 100;
67
- }
68
-
69
- const counterHex = counter.toString(16).padStart(4, '0');
70
-
71
- // Return the custom ObjectId object with a toString() method
72
- return {
73
- timestamp: timestampHex,
74
- processId: processIdHex,
75
- counter: counterHex,
76
- toString: function () {
77
- return this.timestamp + this.processId + this.counter;
78
- }
79
- };
80
- }
81
-
82
- function checkValue(value) {
83
- if (/{{\s*([\w\W]+)\s*}}/g.test(value))
84
- return false;
85
- else
86
- return true
87
- }
88
-
89
- function isValidDate(value) {
90
- if (typeof value === 'string' && value.length >= 20 && value.length <= 24) {
91
- // if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z$/i.test(value))
92
- if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?([-+]\d{2}:\d{2}|Z)?$/i.test(value)) {
93
- return true
94
- }
95
- }
96
-
97
- return false;
98
- }
99
-
100
- function dotNotationToObject(data, obj = {}) {
101
- try {
102
- let arrayGroup = {}; // Track groups by key paths (e.g., 'messages[a]')
103
-
104
- for (const key of Object.keys(data)) {
105
- let value = data[key];
106
- let newObject = obj;
107
- let oldObject = new Object(obj);
108
- let keys = key.split('.');
109
- let length = keys.length - 1;
110
-
111
- for (let i = 0; i < keys.length; i++) {
112
- // Check if the key ends with ']', indicating an array or grouping operation
113
- if (keys[i].endsWith(']')) {
114
- // Handle array push (e.g., messages[] -> push value)
115
- if (keys[i].endsWith('[]')) {
116
- let baseKey = keys[i].slice(0, -2); // Remove '[]'
117
-
118
- // Initialize newObject[baseKey] as an array if not an array or doesn't exist
119
- if (!Array.isArray(newObject[baseKey])) {
120
- newObject[baseKey] = [];
121
- }
122
-
123
- if (length == i) {
124
- // If value is an array, spread the array values into newObject[baseKey]
125
- if (Array.isArray(value)) {
126
- newObject[baseKey].push(...value);
127
- } else {
128
- // If value is not an array, just push the single value
129
- newObject[baseKey].push(value);
130
- }
131
- }
132
- }
133
- // Check for array index (e.g., messages[0])
134
- else if (/\[([0-9]+)\]/g.test(keys[i])) {
135
- let [k, index] = keys[i].split('[');
136
- index = index.slice(0, -1); // Get the index
137
-
138
- // Initialize newObject[k] as an array if it doesn't exist or is not an array
139
- if (!Array.isArray(newObject[k])) {
140
- newObject[k] = [];
141
- }
142
-
143
- if (length == i) {
144
- if (value === undefined) {
145
- newObject[k].splice(index, 1); // Remove element if value is undefined
146
- } else {
147
- newObject[k][index] = value; // Replace value at specified index
148
- }
149
- } else {
150
- newObject[k][index] = oldObject[k][index] || {}; // Initialize inner object
151
- newObject = newObject[k][index];
152
- oldObject = oldObject[k][index];
153
- }
154
- }
155
- // Handle letter-based groupings (e.g., messages[a].role)
156
- else if (/\[\w\]/g.test(keys[i])) {
157
- let [k, group] = keys[i].split('[');
158
- group = group.slice(0, -1); // Get the letter inside []
159
-
160
- // Initialize newObject[k] as an array if not an array or doesn't exist
161
- if (!Array.isArray(newObject[k])) {
162
- newObject[k] = [];
163
- }
164
-
165
- // If there's no object at this group index yet, push a new object
166
- let index;
167
- if (arrayGroup[keys.slice(0, i + 1).join('.')]) {
168
- // Reuse the existing index for the group
169
- index = arrayGroup[keys.slice(0, i + 1).join('.')];
170
- } else {
171
- // Create a new group and track the index
172
- index = newObject[k].length;
173
- arrayGroup[keys.slice(0, i + 1).join('.')] = index;
174
- newObject[k][index] = {};
175
- }
176
-
177
- // Move into the newly created or existing object for the group
178
- if (length == i) {
179
- newObject[k][index] = value; // Set value in the group
180
- } else {
181
- newObject = newObject[k][index]; // Continue with the group object
182
- }
183
- }
184
- }
185
- // Handle regular object keys (non-array keys)
186
- else {
187
- if (length == i) {
188
- if (value === undefined) {
189
- delete newObject[keys[i]]; // Delete key if value is undefined
190
- } else {
191
- newObject[keys[i]] = value; // Set value
192
- }
193
- } else {
194
- newObject[keys[i]] = oldObject[keys[i]] || {}; // Initialize inner object
195
- newObject = newObject[keys[i]];
196
- oldObject = oldObject[keys[i]];
197
- }
198
- }
199
- }
200
- }
201
- return obj;
202
- } catch (error) {
203
- console.log("Error converting dot notation to object", error);
204
- return false;
205
- }
206
- }
207
-
208
- function getValueFromObject(object = {}, path = '', throwError = false) {
209
- try {
210
- if (!Object.keys(object).length || !path) {
211
- if (throwError)
212
- throw new Error("Invalid input to getValueFromObject");
213
- return
214
-
215
- }
216
-
217
- path = path.replace(/\[(\d+)\]/g, '.$1');
218
-
219
- let data = object, subpath = path.split('.');
220
-
221
- for (let i = 0; i < subpath.length; i++) {
222
- if (throwError && !(subpath[i] in data))
223
- throw new Error("Key not found in object: " + subpath[i]);
224
-
225
- data = data[subpath[i]];
226
- if (!data)
227
- break;
228
- }
229
-
230
- return data;
231
- } catch (error) {
232
- // console.error("Error in getValueFromObject:", error);
233
- if (throwError)
234
- throw error;
235
- }
236
- }
237
-
238
- function createUpdate(update, data, globalOpertors) {
239
- let operatorKeys = {}
240
- if (globalOpertors)
241
- operatorKeys = { ...globalOpertors }
242
-
243
- Object.keys(data).forEach(key => {
244
- if (key.startsWith('$')) {
245
- if (!key.includes('.'))
246
- for (let oldkey of Object.keys(data[key]))
247
- operatorKeys[key + '.' + oldkey] = data[key][oldkey]
248
- else
249
- operatorKeys[key] = data[key]
250
- } else if (typeof data[key] === 'string' && data[key].startsWith('$')) {
251
- operatorKeys[data[key] + '.' + key] = data[key]
252
- } else if (key.endsWith(']')) {
253
- const regex = /^(.*(?:\[\d+\].*?)?)\[(.*?)\](?:\[\])?$/;
254
- const match = key.match(regex);
255
- if (match[2] === '')
256
- operatorKeys['$push.' + match[1]] = data[key]
257
- else {
258
- let index = parseInt(match[2], 10);
259
- if (index === NaN)
260
- operatorKeys[match[2] + '.' + match[1]] = data[key]
261
- else
262
- operatorKeys[key] = data[key]
263
- }
264
- } else if (key.includes('.')) {
265
- operatorKeys[key] = data[key]
266
- } else if (data[key] === undefined) {
267
- delete update[key]
268
- } else
269
- update[key] = data[key]
270
-
271
- })
272
-
273
- return dotNotationToObjectUpdate(operatorKeys, update)
274
- }
275
-
276
- function dotNotationToObjectUpdate(data, object = {}) {
277
- try {
278
- for (const key of Object.keys(data)) {
279
- let newObject = object
280
- let oldObject = new Object(newObject)
281
- let keys = key.replace(/\[(\d+)\]/g, '.$1').split('.');
282
- let value = data[key]
283
- let operator
284
- if (keys[0].startsWith('$'))
285
- operator = keys.shift()
286
-
287
- let length = keys.length - 1
288
- for (let i = 0; i < keys.length; i++) {
289
- if (/^\d+$/.test(keys[i]))
290
- keys[i] = parseInt(keys[i]);
291
-
292
- if (length == i) {
293
- if (operator) {
294
- let operators = ['$rename', '$inc', '$push', '$each', '$splice', '$unset', '$delete', '$slice', '$pop', '$shift', '$addToSet', '$pull']
295
- if (!operators.includes(operator))
296
- continue
297
- if (operator === '$rename') {
298
- newObject[value] = newObject[keys[i]]
299
- delete newObject[keys[i]]
300
- } else if (operator === '$delete' || operator === '$unset' || operator === '$slice') {
301
- if (typeof keys[i] === 'number')
302
- newObject.slice(keys[i], 1);
303
- else
304
- delete newObject[keys[i]]
305
- } else if (operator === '$shift') {
306
- newObject[keys[i]].shift();
307
- } else if (operator === '$pop') {
308
- newObject[keys[i]].pop();
309
- } else if (operator === '$addToSet') {
310
- if (!newObject[keys[i]])
311
- newObject[keys[i]] = []
312
- let exists
313
- if (Array.isArray(value)) {
314
- exists = newObject[keys[i]].some(item => Array.isArray(item) && isEqualArray(item, value));
315
- } else if (typeof value === 'object' && value !== null) {
316
- exists = newObject[keys[i]].some(item => typeof item === 'object' && isEqualObject(item, value));
317
- } else {
318
- exists = newObject[keys[i]].includes(value);
319
- }
320
- if (!exists)
321
- newObject[keys[i]].push(value)
322
- } else if (operator === '$pull') {
323
- if (!newObject[keys[i]])
324
- continue
325
- if (Array.isArray(value)) {
326
- newObject[keys[i]] = newObject[keys[i]].filter(item => !Array.isArray(item) || !isEqualArray(item, value));
327
- } else if (typeof value === 'object' && value !== null) {
328
- newObject[keys[i]] = newObject[keys[i]].filter(item => typeof item !== 'object' || !isEqualObject(item, value));
329
- } else {
330
- newObject[keys[i]] = newObject[keys[i]].filter(item => item !== value);
331
- }
332
- } else if (operator === '$push' || operator === '$splice') {
333
- if (typeof keys[i] === 'number' && newObject.length >= keys[i])
334
- newObject.splice(keys[i], 0, value);
335
- else if (newObject[keys[i]])
336
- newObject[keys[i]].push(value);
337
- else
338
- newObject[keys[i]] = [value];
339
- } else if (operator === '$each') {
340
- if (!Array.isArray(value))
341
- value = [value]
342
- if (typeof keys[i] === 'number')
343
- newObject.splice(keys[i], 0, ...value);
344
- else
345
- newObject[keys[i]].push(...value);
346
- } else if (operator === '$inc') {
347
- if (!newObject[keys[i]] || typeof newObject[keys[i]] !== "number")
348
- newObject[keys[i]] = value
349
- else
350
- newObject[keys[i]] += value
351
- }
352
- } else if (value === undefined) {
353
- if (typeof keys[i] === 'number')
354
- newObject.slice(keys[i], 1);
355
- else
356
- delete newObject[keys[i]]
357
- } else
358
- newObject[keys[i]] = value;
359
- } else {
360
- newObject[keys[i]] = oldObject[keys[i]] || {};
361
- newObject = newObject[keys[i]]
362
- oldObject = oldObject[keys[i]]
363
- }
364
- }
365
- }
366
- return object
367
- } catch (error) {
368
- console.log("Error converting dot notation to object", error);
369
- return false;
370
- }
371
- }
372
-
373
- function domParser(str) {
374
- try {
375
- var mainTag = str.match(/\<(?<tag>[a-z0-9]+)(.*?)?\>/).groups.tag;
376
- } catch (e) {
377
- // console.log(e, 'find position: can not find the main tag');
378
- }
379
- let doc;
380
- switch (mainTag) {
381
- case 'html':
382
- doc = new DOMParser().parseFromString(str, "text/html");
383
- return doc.documentElement;
384
- case 'body':
385
- doc = new DOMParser().parseFromString(str, "text/html");
386
- return doc.body;
387
- case 'head':
388
- doc = new DOMParser().parseFromString(str, "text/html");
389
- return doc.head;
390
-
391
- default:
392
- let con = document.createElement('dom-parser');
393
- con.innerHTML = str;
394
- return con;
395
- }
396
- }
397
-
398
- function parseTextToHtml(text) {
399
- let doc = new DOMParser().parseFromString(text, "text/html");
400
- if (doc.head.children[0]) return doc.head.children[0];
401
- else return doc.body.children[0];
402
- }
403
-
404
- function escapeHtml(html) {
405
- return html.replaceAll('&', '&amp').replaceAll('<', '&lt').replaceAll('>', '&gt;').replaceAll("'", '&#39;').replaceAll('"', '&quot;');
406
- }
407
-
408
- function cssPath(node, container) {
409
- let pathSplits = [];
410
- do {
411
- if (!node || !node.tagName) return false;
412
- let pathSplit = node.tagName.toLowerCase();
413
-
414
- if (node.id) {
415
- pathSplit += "#" + node.id;
416
- node = '';
417
- } else {
418
- let eid = node.getAttribute('eid');
419
- if (eid && !(/{{\s*([\w\W]+)\s*}}/g.test(eid))) {
420
- pathSplit += `[eid="${eid}"]`;
421
- node = '';
422
- } else
423
- // if (node.classList.length) {
424
- // node.classList.forEach((item) => {
425
- // if (item.indexOf(":") === -1) pathSplit += "." + item;
426
- // });
427
- // }
428
-
429
- if (node.parentNode && node.parentNode.children.length > 1) {
430
- // TODO: improve array logic so ignores javascript generated html??
431
- let children = []
432
- for (let child of node.parentNode.children) {
433
- if (child.tagName == node.tagName)
434
- children.push(child);
435
- }
436
- let index = Array.prototype.indexOf.call(
437
- children,
438
- node
439
- );
440
-
441
- pathSplit += `:nth-of-type(${index + 1})`;
442
- }
443
-
444
- node = node.parentNode;
445
- if (node == null || node.tagName == "HTML" || node.tagName == "BODY" || node.tagName == "DOM-PARSER" || node.nodeName == "#document" || node.hasAttribute('contenteditable'))
446
- node = '';
447
- }
448
-
449
- pathSplits.unshift(pathSplit);
450
- } while (node);
451
- let path = pathSplits.join(" > ")
452
- if (path && path.includes('<')) {
453
- let index = path.lastIndexOf(' >')
454
- if (index != -1)
455
- path = path.slice(0, index)
456
- else {
457
- index = path.lastIndexOf('<')
458
- path = path.slice(0, index)
459
- }
460
- }
461
-
462
- return path;
463
- }
464
-
465
- function queryElements({ element, prefix, type, selector }) {
466
- let elements = new Map()
467
- if (!element)
468
- element = document
469
- let hasAttribute = false
470
-
471
- if (selector) {
472
- if (!type)
473
- type = ['selector']
474
- else if (!Array.isArray(type))
475
- type = [type]
476
- } else
477
- type = ['selector', 'closest', 'parent', 'next', 'previous']
478
-
479
- for (let i = 0; i < type.length; i++) {
480
- let Selector = selector
481
- if (!Selector && element.nodeType !== 9) {
482
-
483
- let name = prefix + '-' + type[i]
484
- if (!element.hasAttribute(name))
485
- continue
486
- hasAttribute = true
487
- Selector = element.getAttribute(name);
488
- }
489
-
490
- if (Selector) {
491
- let selectors = Selector.split(/,(?![^()]*\))/g);
492
-
493
- for (let j = 0; j < selectors.length; j++) {
494
- if (selectors[j].includes('@')) {
495
- selectors[j] = checkMediaQueries(selectors[j])
496
- if (selectors[j] === false)
497
- continue
498
- }
499
-
500
- let queriedElement = element
501
- let specialSelectors = selectors[j].split(';')
502
- for (let k = 0; k < specialSelectors.length; k++) {
503
-
504
- // TODO: Support an array of queried elements and branch off to return matches for each
505
- // if (!Array.isArray(queriedElement)) {
506
- // queriedElement = [queriedElement]
507
- // }
508
- if (!specialSelectors[k])
509
- continue
510
- if (k === 0) {
511
- if (type[i] === 'parent')
512
- queriedElement = queriedElement.parentElement
513
- else if (type[i] === 'next')
514
- queriedElement = queriedElement.nextElementSibling
515
- else if (type[i] === 'previous')
516
- queriedElement = queriedElement.previousElementSibling
517
- }
518
-
519
- switch (specialSelectors[k] = specialSelectors[k].trim()) {
520
- case 'top':
521
- queriedElement = window.top.document
522
- break;
523
- case 'frame':
524
- if (queriedElement.nodeType === 9)
525
- queriedElement = queriedElement.window.frameElement;
526
- else if (queriedElement.contentDocument)
527
- queriedElement = queriedElement.contentDocument;
528
- break;
529
- case 'document':
530
- queriedElement = document
531
- break;
532
- case 'parent':
533
- queriedElement = queriedElement.parentElement
534
- break;
535
- case 'next':
536
- queriedElement = queriedElement.nextElementSibling
537
- break;
538
- case 'previous':
539
- queriedElement = queriedElement.previousElementSibling
540
- break;
541
- default:
542
- if (k === 0 && type[i] === 'closest')
543
- if (specialSelectors[k].includes(' ')) {
544
- let [firstSelector, ...restSelectors] = specialSelectors[k].split(/ (.+)/);
545
- queriedElement = queriedElement.closest(firstSelector);
546
- if (restSelectors.length > 0) {
547
- if (restSelectors[0].endsWith('[]'))
548
- queriedElement = queriedElement.querySelectorAll(restSelectors[0].slice(0, -2))
549
- else
550
- queriedElement = queriedElement.querySelector(restSelectors[0])
551
- }
552
- } else {
553
- // If no space, just use the selector with closest
554
- queriedElement = queriedElement.closest(specialSelectors[k]);
555
- }
556
- else if (specialSelectors[k].endsWith('[]'))
557
- queriedElement = queriedElement.querySelectorAll(specialSelectors[k].slice(0, -2))
558
- else
559
- queriedElement = queriedElement.querySelector(specialSelectors[k])
560
- }
561
- if (!queriedElement)
562
- break;
563
- }
564
-
565
- if (Array.isArray(queriedElement) || queriedElement instanceof HTMLCollection || queriedElement instanceof NodeList) {
566
- for (let el of queriedElement)
567
- elements.set(el, '')
568
- } else if (queriedElement) {
569
- elements.set(queriedElement, '')
570
- }
571
-
572
- }
573
- } else if (Selector === '') {
574
- if (type[i] === 'parent')
575
- elements.set(element.parentElement, '')
576
- else if (type[i] === 'next')
577
- elements.set(element.nextElementSibling, '')
578
- else if (type[i] === 'previous')
579
- elements.set(element.previousElementSibling, '')
580
- }
581
- }
582
-
583
- if (!hasAttribute && !selector)
584
- elements = false
585
- else
586
- elements = Array.from(elements.keys())
587
-
588
- return elements
589
- }
590
-
591
- const mediaRanges = {
592
- xs: [0, 575],
593
- sm: [576, 768],
594
- md: [769, 992],
595
- lg: [993, 1200],
596
- xl: [1201, 0],
597
- };
598
-
599
- function checkMediaQueries(selector) {
600
- if (selector && selector.includes('@')) {
601
- let screenSizes = selector.split('@')
602
- selector = screenSizes.shift();
603
- for (let screenSize of screenSizes) {
604
- const viewportWidth = window.innerWidth;
605
- let mediaViewport = false;
606
-
607
- // Check if screenSize is a valid range in the 'ranges' object
608
- if (mediaRanges.hasOwnProperty(screenSize)) {
609
- const [minWidth, maxWidth] = mediaRanges[screenSize];
610
- if (viewportWidth >= minWidth && viewportWidth <= maxWidth) {
611
- mediaViewport = true;
612
- break;
613
- }
614
- }
615
-
616
- if (!mediaViewport)
617
- return false
618
-
619
- }
620
- }
621
-
622
- return selector
623
- }
624
-
625
- function queryData(data, query) {
626
- if (query.$and) {
627
- for (let i = 0; i < query.$and.length; i++) {
628
- if (!queryData(data, query.$and[i]))
629
- return false
630
- }
631
- }
632
-
633
- if (query.$nor) {
634
- for (let i = 0; i < query.$nor.length; i++) {
635
- if (queryData(data, query.$nor[i]))
636
- return false;
637
- }
638
- }
639
-
640
- for (let key of Object.keys(query)) {
641
- if (key === '$and' || key === '$or')
642
- continue
643
- if (!queryMatch(data, { [key]: query[key] }))
644
- return false
645
- }
646
-
647
- if (query.$or) {
648
- for (let i = 0; i < query.$or.length; i++) {
649
- if (queryData(data, query.$or[i]))
650
- return true
651
- }
652
- }
653
-
654
- return true;
655
- }
656
-
657
- function queryMatch(data, query) {
658
- for (let key of Object.keys(query)) {
659
- // if (!data.hasOwnProperty(key))
660
- // return false
661
-
662
- let dataValue
663
- try {
664
- dataValue = getValueFromObject(data, key, true)
665
- } catch (error) {
666
- return false
667
- }
668
-
669
- if (typeof query[key] === 'string' || typeof query[key] === 'number' || typeof query[key] === 'boolean') {
670
- if (Array.isArray(dataValue))
671
- return dataValue.includes(query[key])
672
- else
673
- return dataValue === query[key]
674
- } else if (Array.isArray(query[key])) {
675
- if (Array.isArray(dataValue)) {
676
- return isEqualArray(dataValue, query[key]);
677
- } else {
678
- return false;
679
- }
680
- } else {
681
- for (let property of Object.keys(query[key])) {
682
- if (property === '$options')
683
- continue
684
- if (!property.startsWith('$')) {
685
- if (typeof dataValue !== 'object') {
686
- return false;
687
- } else
688
- return queryMatch({ [property]: getValueFromObject(dataValue, property) }, { [property]: query[key][property] })
689
- } else {
690
- let queryValue = query[key][property]
691
- if (isValidDate(queryValue) && isValidDate(dataValue)) {
692
- queryValue = new Date(queryValue)
693
- dataValue = new Date(dataValue)
694
- }
695
- let queryStatus = false
696
- switch (property) {
697
- case '$eq':
698
- if (Array.isArray(dataValue) && Array.isArray(queryValue)) {
699
- queryStatus = isEqualArray(dataValue, queryValue);
700
- } else {
701
- queryStatus = (dataValue === queryValue);
702
- }
703
- break;
704
- case '$ne':
705
- if (Array.isArray(dataValue) && Array.isArray(queryValue)) {
706
- queryStatus = !isEqualArray(dataValue, queryValue);
707
- } else {
708
- queryStatus = (dataValue !== queryValue);
709
- }
710
- break;
711
- case '$not':
712
- queryStatus = !queryMatch(data, { [key]: query[key]['$not'] });
713
- break;
714
- case '$lt':
715
- queryStatus = (dataValue < queryValue)
716
- break;
717
- case '$lte':
718
- queryStatus = (dataValue <= queryValue)
719
- break;
720
- case '$gt':
721
- queryStatus = (dataValue > queryValue)
722
- break;
723
- case '$gte':
724
- queryStatus = (dataValue >= queryValue)
725
- break;
726
- case '$in':
727
- if (Array.isArray(dataValue)) {
728
- queryStatus = dataValue.some(element => queryValue.includes(element));
729
- } else {
730
- queryStatus = queryValue.includes(dataValue);
731
- }
732
- break;
733
- case '$nin':
734
- if (Array.isArray(dataValue)) {
735
- queryStatus = !dataValue.some(element => queryValue.includes(element));
736
- } else {
737
- queryStatus = !queryValue.includes(dataValue);
738
- }
739
- break;
740
- case '$all':
741
- if (Array.isArray(dataValue) && Array.isArray(queryValue)) {
742
- queryStatus = queryValue.every(element => dataValue.includes(element));
743
- }
744
- break;
745
- case '$elemMatch':
746
- if (Array.isArray(data[key])) {
747
- queryStatus = data[key].some(element => queryMatch(element, query[key][property]));
748
- }
749
- break;
750
- case '$size':
751
- if (Array.isArray(dataValue)) {
752
- queryStatus = (dataValue.length === queryValue);
753
- }
754
- break;
755
- case '$exists':
756
- queryStatus = (queryValue ? data.hasOwnProperty(key) : !data.hasOwnProperty(key));
757
- break;
758
- case '$regex':
759
- if (typeof dataValue === 'string') {
760
- let regexFlag = query[key]['$options'] || ''
761
- let regex = new RegExp(queryValue, regexFlag)
762
- queryStatus = regex.test(dataValue);
763
- }
764
- break;
765
- case '$type':
766
- let dataType = typeof dataValue;
767
- if (Array.isArray(dataValue)) {
768
- dataType = 'array';
769
- }
770
- queryStatus = (dataType === queryValue);
771
- break;
772
- case '$mod':
773
- if (typeof dataValue === 'number' && Array.isArray(queryValue) && queryValue.length === 2) {
774
- const [divisor, remainder] = queryValue;
775
- queryStatus = (dataValue % divisor === remainder);
776
- }
777
- break;
778
- case '$where':
779
- if (typeof queryValue === 'function') {
780
- try {
781
- // queryStatus = queryValue.call(data);
782
- } catch (error) {
783
- console.error('Error in queryData $where function:', error);
784
- }
785
- }
786
- break;
787
-
788
- default:
789
- console.log('unknown operator')
790
- break;
791
-
792
- }
793
- if (!queryStatus)
794
- return false
795
-
796
- }
797
- }
798
- return true
799
- }
800
-
801
- }
802
- }
803
-
804
- function isEqualArray(arr1, arr2) {
805
- if (arr1.length !== arr2.length) {
806
- return false;
807
- }
808
- for (let i = 0; i < arr1.length; i++) {
809
- if (!isEqualObject(arr1[i], arr2[i])) {
810
- return false;
811
- }
812
- }
813
- return true;
814
- }
815
-
816
- function isEqualObject(obj1, obj2) {
817
- const keys1 = Object.keys(obj1);
818
- const keys2 = Object.keys(obj2);
819
-
820
- if (keys1.length !== keys2.length) {
821
- return false;
822
- }
823
-
824
- for (const key of keys1) {
825
- if (obj1[key] !== obj2[key]) {
826
- return false;
827
- }
828
- }
829
-
830
- return true;
831
- }
832
-
833
- function searchData(data, search) {
834
- if (!search)
835
- return true
836
- if (!Array.isArray(search))
837
- search = [search]
838
- for (let i = 0; i < search.length; i++) {
839
- let searchValue = search[i].value
840
- if (!Array.isArray(searchValue))
841
- searchValue = [searchValue]
842
- for (let key in data) {
843
- let value = data[key];
844
- let status = false;
845
- switch (typeof value) {
846
- case 'number':
847
- value = value.toString();
848
- break;
849
- case 'object':
850
- value = JSON.stringify(value)
851
- break;
852
- case 'function':
853
- value = value.toString();
854
- break;
855
- }
856
- if (search[i].caseSensitive != 'true' || search[i].caseSensitive != true)
857
- value = value.toLowerCase()
858
-
859
- for (let i = 0; i < searchValue.length; i++) {
860
- let searchString = searchValue[i]
861
- if (search[i].caseSensitive != 'true' || search[i].caseSensitive != true)
862
- searchString = searchString.toLowerCase()
863
-
864
- if (searchString === "" && search[i].operator === 'and') {
865
- if (value !== "")
866
- return false
867
- }
868
-
869
- if (value.indexOf(searchString) > -1)
870
- status = true;
871
-
872
- if (status)
873
- return true;
874
- else if (search[i].operator == 'and')
875
- return false;
876
-
877
-
878
- }
879
- }
880
- if (search[i].value.length && search[i].operator == 'or')
881
- return false
882
-
883
- }
884
- return true
885
- }
886
-
887
-
888
- function sortData(data, sort) {
889
- return data.sort((a, b) => {
890
- for (let i = 0; i < sort.length; i++) {
891
- let key = sort[i].key;
892
- if (a[key] == null && b[key] == null) continue;
893
- if (a[key] == null)
894
- return sort[i].direction === 'desc' ? -1 : 1;
895
- if (b[key] == null)
896
- return sort[i].direction === 'desc' ? 1 : -1;
897
-
898
- if (typeof a[key] !== typeof b[key]) {
899
- return typeof a[key] < typeof b[key] ? -1 : 1;
900
- }
901
-
902
- if (a[key] !== b[key]) {
903
- if (typeof a[key] === 'string') {
904
- return sort[i].direction === 'desc' ?
905
- b[key].localeCompare(a[key]) :
906
- a[key].localeCompare(b[key]);
907
- } else { // Assuming numeric or other comparable types
908
- return sort[i].direction === 'desc' ?
909
- (b[key] - a[key]) :
910
- (a[key] - b[key]);
911
- }
912
- }
913
- }
914
- return 0;
915
- });
916
- }
917
-
918
-
919
- function getAttributes(el) {
920
- if (!el) return;
921
-
922
- let attributes = window.CoCreateConfig.attributes;
923
- let object = {};
924
-
925
- for (let attribute of el.attributes) {
926
- let variable = attributes[attribute.name]
927
- if (variable) {
928
- object[variable] = el.getAttribute(attribute.name)
929
- }
930
- }
931
-
932
- return object
933
- }
934
-
935
- function getAttributeNames(variables) {
936
- let reversedObject = {}
937
- for (const key of Object.keys(CoCreateConfig.attributes)) {
938
- reversedObject[CoCreateConfig.attributes[key]] = key
939
- }
940
-
941
- let attributes = [];
942
- for (const variable of variables) {
943
- let attribute = reversedObject[variable]
944
- if (attribute)
945
- attributes.push(attribute)
946
- }
947
- return attributes
948
- }
949
-
950
- function setAttributeNames(attributes, overWrite) {
951
- let reversedObject = {}
952
- for (const key of Object.keys(CoCreateConfig.attributes)) {
953
- reversedObject[CoCreateConfig.attributes[key]] = key
954
- }
955
-
956
- for (const attribute of Object.keys(attributes)) {
957
- const variable = attributes[attribute]
958
- if (!reversedObject[variable] || overWrite != false)
959
- reversedObject[variable] = attribute
960
- }
961
-
962
- let revertObject = {}
963
- for (const key of Object.keys(reversedObject)) {
964
- revertObject[reversedObject[key]] = key
965
- }
966
- CoCreateConfig.attributes = revertObject
967
- }
968
-
969
- if (isBrowser)
970
- clickedElement();
971
-
972
- return {
973
- ObjectId,
974
- checkValue,
975
- isValidDate,
976
- dotNotationToObject,
977
- getValueFromObject,
978
- domParser,
979
- parseTextToHtml,
980
- escapeHtml,
981
- cssPath,
982
- queryElements,
983
- checkMediaQueries,
984
- queryData,
985
- searchData,
986
- sortData,
987
- createUpdate,
988
- getAttributes,
989
- setAttributeNames,
990
- getAttributeNames
991
- }
992
-
993
- }));
2
+ if (typeof define === "function" && define.amd) {
3
+ define([], function () {
4
+ return factory(true);
5
+ });
6
+ } else if (typeof module === "object" && module.exports) {
7
+ module.exports = factory(false);
8
+ } else {
9
+ root.returnExports = factory(true);
10
+ }
11
+ })(typeof self !== "undefined" ? self : this, function (isBrowser) {
12
+ /*globals DOMParser*/
13
+ function clickedElement() {
14
+ document.addEventListener("click", (e) => {
15
+ document.clickedElement = e.target;
16
+ });
17
+
18
+ try {
19
+ let frames = document.querySelectorAll("iframe");
20
+ for (let frame of frames) {
21
+ try {
22
+ let frameDocument = frame.contentDocument;
23
+ if (!frameDocument.clickedElementListenerAdded) {
24
+ frameDocument.addEventListener("click", (e) => {
25
+ frameDocument.clickedElement = e.target;
26
+ });
27
+
28
+ // Mark the document to avoid adding duplicate listeners
29
+ frameDocument.clickedElementListenerAdded = true;
30
+ }
31
+ } catch (iframeError) {
32
+ console.log(
33
+ `Cross-origin frame handling failed for: ${frame}`,
34
+ iframeError
35
+ );
36
+ }
37
+ }
38
+ } catch (e) {
39
+ console.log("Top-level frame document handling failed:", e);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Generates an ObjectId
45
+ */
46
+ let counter = 0;
47
+ function ObjectId(inputId) {
48
+ if (inputId && /^[0-9a-fA-F]{24}$/.test(inputId)) {
49
+ // If a valid ObjectId is provided, return it as a custom ObjectId object
50
+ return {
51
+ timestamp: inputId.substring(0, 8),
52
+ processId: inputId.substring(8, 20),
53
+ counter: inputId.substring(20),
54
+ toString: function () {
55
+ return this.timestamp + this.processId + this.counter;
56
+ }
57
+ };
58
+ } else if (inputId) {
59
+ throw new Error("Invalid ObjectId provided.");
60
+ }
61
+
62
+ // Generate a new custom ObjectId
63
+ const timestampHex = Math.floor(
64
+ new Date(new Date().toISOString()).getTime() / 1000
65
+ )
66
+ .toString(16)
67
+ .padStart(8, "0");
68
+ const processIdHex = Math.floor(Math.random() * 0x100000000000)
69
+ .toString(16)
70
+ .padStart(12, "0");
71
+
72
+ counter = (counter + 1) % 10000;
73
+ if (counter < 2) {
74
+ counter = Math.floor(Math.random() * (5000 - 100 + 1)) + 100;
75
+ }
76
+
77
+ const counterHex = counter.toString(16).padStart(4, "0");
78
+
79
+ // Return the custom ObjectId object with a toString() method
80
+ return {
81
+ timestamp: timestampHex,
82
+ processId: processIdHex,
83
+ counter: counterHex,
84
+ toString: function () {
85
+ return this.timestamp + this.processId + this.counter;
86
+ }
87
+ };
88
+ }
89
+
90
+ function checkValue(value) {
91
+ if (/{{\s*([\w\W]+)\s*}}/g.test(value)) return false;
92
+ else return true;
93
+ }
94
+
95
+ function isValidDate(value) {
96
+ if (
97
+ typeof value === "string" &&
98
+ value.length >= 20 &&
99
+ value.length <= 24
100
+ ) {
101
+ // if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z$/i.test(value))
102
+ if (
103
+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?([-+]\d{2}:\d{2}|Z)?$/i.test(
104
+ value
105
+ )
106
+ ) {
107
+ return true;
108
+ }
109
+ }
110
+
111
+ return false;
112
+ }
113
+
114
+ function dotNotationToObject(data, obj = {}) {
115
+ try {
116
+ let arrayGroup = {}; // Track groups by key paths (e.g., 'messages[a]')
117
+
118
+ for (const key of Object.keys(data)) {
119
+ let value = data[key];
120
+ let newObject = obj;
121
+ let oldObject = new Object(obj);
122
+ let keys = key.split(".");
123
+ let length = keys.length - 1;
124
+
125
+ for (let i = 0; i < keys.length; i++) {
126
+ // Check if the key ends with ']', indicating an array or grouping operation
127
+ if (keys[i].endsWith("]")) {
128
+ // Handle array push (e.g., messages[] -> push value)
129
+ if (keys[i].endsWith("[]")) {
130
+ let baseKey = keys[i].slice(0, -2); // Remove '[]'
131
+
132
+ // Initialize newObject[baseKey] as an array if not an array or doesn't exist
133
+ if (!Array.isArray(newObject[baseKey])) {
134
+ newObject[baseKey] = [];
135
+ }
136
+
137
+ if (length == i) {
138
+ // If value is an array, spread the array values into newObject[baseKey]
139
+ if (Array.isArray(value)) {
140
+ newObject[baseKey].push(...value);
141
+ } else {
142
+ // If value is not an array, just push the single value
143
+ newObject[baseKey].push(value);
144
+ }
145
+ }
146
+ }
147
+ // Check for array index (e.g., messages[0])
148
+ else if (/\[([0-9]+)\]/g.test(keys[i])) {
149
+ let [k, index] = keys[i].split("[");
150
+ index = index.slice(0, -1); // Get the index
151
+
152
+ // Initialize newObject[k] as an array if it doesn't exist or is not an array
153
+ if (!Array.isArray(newObject[k])) {
154
+ newObject[k] = [];
155
+ }
156
+
157
+ if (length == i) {
158
+ if (value === undefined) {
159
+ newObject[k].splice(index, 1); // Remove element if value is undefined
160
+ } else {
161
+ newObject[k][index] = value; // Replace value at specified index
162
+ }
163
+ } else {
164
+ newObject[k][index] = oldObject[k][index] || {}; // Initialize inner object
165
+ newObject = newObject[k][index];
166
+ oldObject = oldObject[k][index];
167
+ }
168
+ }
169
+ // Handle letter-based groupings (e.g., messages[a].role)
170
+ else if (/\[\w\]/g.test(keys[i])) {
171
+ let [k, group] = keys[i].split("[");
172
+ group = group.slice(0, -1); // Get the letter inside []
173
+
174
+ // Initialize newObject[k] as an array if not an array or doesn't exist
175
+ if (!Array.isArray(newObject[k])) {
176
+ newObject[k] = [];
177
+ }
178
+
179
+ // If there's no object at this group index yet, push a new object
180
+ let index;
181
+ if (arrayGroup[keys.slice(0, i + 1).join(".")]) {
182
+ // Reuse the existing index for the group
183
+ index =
184
+ arrayGroup[keys.slice(0, i + 1).join(".")];
185
+ } else {
186
+ // Create a new group and track the index
187
+ index = newObject[k].length;
188
+ arrayGroup[keys.slice(0, i + 1).join(".")] =
189
+ index;
190
+ newObject[k][index] = {};
191
+ }
192
+
193
+ // Move into the newly created or existing object for the group
194
+ if (length == i) {
195
+ newObject[k][index] = value; // Set value in the group
196
+ } else {
197
+ newObject = newObject[k][index]; // Continue with the group object
198
+ }
199
+ }
200
+ }
201
+ // Handle regular object keys (non-array keys)
202
+ else {
203
+ if (length == i) {
204
+ if (value === undefined) {
205
+ delete newObject[keys[i]]; // Delete key if value is undefined
206
+ } else {
207
+ newObject[keys[i]] = value; // Set value
208
+ }
209
+ } else {
210
+ newObject[keys[i]] = oldObject[keys[i]] || {}; // Initialize inner object
211
+ newObject = newObject[keys[i]];
212
+ oldObject = oldObject[keys[i]];
213
+ }
214
+ }
215
+ }
216
+ }
217
+ return obj;
218
+ } catch (error) {
219
+ console.log("Error converting dot notation to object", error);
220
+ return false;
221
+ }
222
+ }
223
+
224
+ function getValueFromObject(object = {}, path = "", throwError = false) {
225
+ try {
226
+ if (!Object.keys(object).length || !path) {
227
+ if (throwError)
228
+ throw new Error("Invalid input to getValueFromObject");
229
+ return;
230
+ }
231
+
232
+ path = path.replace(/\[(\d+)\]/g, ".$1");
233
+
234
+ let data = object,
235
+ subpath = path.split(".");
236
+
237
+ for (let i = 0; i < subpath.length; i++) {
238
+ if (throwError && !(subpath[i] in data))
239
+ throw new Error("Key not found in object: " + subpath[i]);
240
+
241
+ data = data[subpath[i]];
242
+ if (!data) break;
243
+ }
244
+
245
+ return data;
246
+ } catch (error) {
247
+ // console.error("Error in getValueFromObject:", error);
248
+ if (throwError) throw error;
249
+ }
250
+ }
251
+
252
+ function createUpdate(update, data, globalOpertors) {
253
+ let operatorKeys = {};
254
+ if (globalOpertors) operatorKeys = { ...globalOpertors };
255
+
256
+ Object.keys(data).forEach((key) => {
257
+ if (key.startsWith("$")) {
258
+ if (!key.includes("."))
259
+ for (let oldkey of Object.keys(data[key]))
260
+ operatorKeys[key + "." + oldkey] = data[key][oldkey];
261
+ else operatorKeys[key] = data[key];
262
+ } else if (
263
+ typeof data[key] === "string" &&
264
+ data[key].startsWith("$")
265
+ ) {
266
+ operatorKeys[data[key] + "." + key] = data[key];
267
+ } else if (key.endsWith("]")) {
268
+ const regex = /^(.*(?:\[\d+\].*?)?)\[(.*?)\](?:\[\])?$/;
269
+ const match = key.match(regex);
270
+ if (match[2] === "")
271
+ operatorKeys["$push." + match[1]] = data[key];
272
+ else {
273
+ let index = parseInt(match[2], 10);
274
+ if (index === NaN)
275
+ operatorKeys[match[2] + "." + match[1]] = data[key];
276
+ else operatorKeys[key] = data[key];
277
+ }
278
+ } else if (key.includes(".")) {
279
+ operatorKeys[key] = data[key];
280
+ } else if (data[key] === undefined) {
281
+ delete update[key];
282
+ } else update[key] = data[key];
283
+ });
284
+
285
+ return dotNotationToObjectUpdate(operatorKeys, update);
286
+ }
287
+
288
+ function dotNotationToObjectUpdate(data, object = {}) {
289
+ try {
290
+ for (const key of Object.keys(data)) {
291
+ let newObject = object;
292
+ let oldObject = new Object(newObject);
293
+ let keys = key.replace(/\[(\d+)\]/g, ".$1").split(".");
294
+ let value = data[key];
295
+ let operator;
296
+ if (keys[0].startsWith("$")) operator = keys.shift();
297
+
298
+ let length = keys.length - 1;
299
+ for (let i = 0; i < keys.length; i++) {
300
+ if (/^\d+$/.test(keys[i])) keys[i] = parseInt(keys[i]);
301
+
302
+ if (length == i) {
303
+ if (operator) {
304
+ let operators = [
305
+ "$rename",
306
+ "$inc",
307
+ "$push",
308
+ "$each",
309
+ "$splice",
310
+ "$unset",
311
+ "$delete",
312
+ "$slice",
313
+ "$pop",
314
+ "$shift",
315
+ "$addToSet",
316
+ "$pull"
317
+ ];
318
+ if (!operators.includes(operator)) continue;
319
+ if (operator === "$rename") {
320
+ newObject[value] = newObject[keys[i]];
321
+ delete newObject[keys[i]];
322
+ } else if (
323
+ operator === "$delete" ||
324
+ operator === "$unset" ||
325
+ operator === "$slice"
326
+ ) {
327
+ if (typeof keys[i] === "number")
328
+ newObject.slice(keys[i], 1);
329
+ else delete newObject[keys[i]];
330
+ } else if (operator === "$shift") {
331
+ newObject[keys[i]].shift();
332
+ } else if (operator === "$pop") {
333
+ newObject[keys[i]].pop();
334
+ } else if (operator === "$addToSet") {
335
+ if (!newObject[keys[i]])
336
+ newObject[keys[i]] = [];
337
+ let exists;
338
+ if (Array.isArray(value)) {
339
+ exists = newObject[keys[i]].some(
340
+ (item) =>
341
+ Array.isArray(item) &&
342
+ isEqualArray(item, value)
343
+ );
344
+ } else if (
345
+ typeof value === "object" &&
346
+ value !== null
347
+ ) {
348
+ exists = newObject[keys[i]].some(
349
+ (item) =>
350
+ typeof item === "object" &&
351
+ isEqualObject(item, value)
352
+ );
353
+ } else {
354
+ exists = newObject[keys[i]].includes(value);
355
+ }
356
+ if (!exists) newObject[keys[i]].push(value);
357
+ } else if (operator === "$pull") {
358
+ if (!newObject[keys[i]]) continue;
359
+ if (Array.isArray(value)) {
360
+ newObject[keys[i]] = newObject[
361
+ keys[i]
362
+ ].filter(
363
+ (item) =>
364
+ !Array.isArray(item) ||
365
+ !isEqualArray(item, value)
366
+ );
367
+ } else if (
368
+ typeof value === "object" &&
369
+ value !== null
370
+ ) {
371
+ newObject[keys[i]] = newObject[
372
+ keys[i]
373
+ ].filter(
374
+ (item) =>
375
+ typeof item !== "object" ||
376
+ !isEqualObject(item, value)
377
+ );
378
+ } else {
379
+ newObject[keys[i]] = newObject[
380
+ keys[i]
381
+ ].filter((item) => item !== value);
382
+ }
383
+ } else if (
384
+ operator === "$push" ||
385
+ operator === "$splice"
386
+ ) {
387
+ if (
388
+ typeof keys[i] === "number" &&
389
+ newObject.length >= keys[i]
390
+ )
391
+ newObject.splice(keys[i], 0, value);
392
+ else if (newObject[keys[i]])
393
+ newObject[keys[i]].push(value);
394
+ else newObject[keys[i]] = [value];
395
+ } else if (operator === "$each") {
396
+ if (!Array.isArray(value)) value = [value];
397
+ if (typeof keys[i] === "number")
398
+ newObject.splice(keys[i], 0, ...value);
399
+ else newObject[keys[i]].push(...value);
400
+ } else if (operator === "$inc") {
401
+ if (
402
+ !newObject[keys[i]] ||
403
+ typeof newObject[keys[i]] !== "number"
404
+ )
405
+ newObject[keys[i]] = value;
406
+ else newObject[keys[i]] += value;
407
+ }
408
+ } else if (value === undefined) {
409
+ if (typeof keys[i] === "number")
410
+ newObject.slice(keys[i], 1);
411
+ else delete newObject[keys[i]];
412
+ } else newObject[keys[i]] = value;
413
+ } else {
414
+ newObject[keys[i]] = oldObject[keys[i]] || {};
415
+ newObject = newObject[keys[i]];
416
+ oldObject = oldObject[keys[i]];
417
+ }
418
+ }
419
+ }
420
+ return object;
421
+ } catch (error) {
422
+ console.log("Error converting dot notation to object", error);
423
+ return false;
424
+ }
425
+ }
426
+
427
+ function domParser(str) {
428
+ try {
429
+ var mainTag = str.match(/\<(?<tag>[a-z0-9]+)(.*?)?\>/).groups.tag;
430
+ } catch (e) {
431
+ // console.log(e, 'find position: can not find the main tag');
432
+ }
433
+ let doc;
434
+ switch (mainTag) {
435
+ case "html":
436
+ doc = new DOMParser().parseFromString(str, "text/html");
437
+ return doc.documentElement;
438
+ case "body":
439
+ doc = new DOMParser().parseFromString(str, "text/html");
440
+ return doc.body;
441
+ case "head":
442
+ doc = new DOMParser().parseFromString(str, "text/html");
443
+ return doc.head;
444
+
445
+ default:
446
+ let con = document.createElement("dom-parser");
447
+ con.innerHTML = str;
448
+ return con;
449
+ }
450
+ }
451
+
452
+ function parseTextToHtml(text) {
453
+ let doc = new DOMParser().parseFromString(text, "text/html");
454
+ if (doc.head.children[0]) return doc.head.children[0];
455
+ else return doc.body.children[0];
456
+ }
457
+
458
+ function escapeHtml(html) {
459
+ return html
460
+ .replaceAll("&", "&amp")
461
+ .replaceAll("<", "&lt")
462
+ .replaceAll(">", "&gt;")
463
+ .replaceAll("'", "&#39;")
464
+ .replaceAll('"', "&quot;");
465
+ }
466
+
467
+ function cssPath(node, container) {
468
+ let pathSplits = [];
469
+ do {
470
+ if (!node || !node.tagName) return false;
471
+ let pathSplit = node.tagName.toLowerCase();
472
+
473
+ if (node.id) {
474
+ pathSplit += "#" + node.id;
475
+ node = "";
476
+ } else {
477
+ let eid = node.getAttribute("eid");
478
+ if (eid && !/{{\s*([\w\W]+)\s*}}/g.test(eid)) {
479
+ pathSplit += `[eid="${eid}"]`;
480
+ node = "";
481
+ }
482
+ // if (node.classList.length) {
483
+ // node.classList.forEach((item) => {
484
+ // if (item.indexOf(":") === -1) pathSplit += "." + item;
485
+ // });
486
+ // }
487
+ else if (
488
+ node.parentNode &&
489
+ node.parentNode.children.length > 1
490
+ ) {
491
+ // TODO: improve array logic so ignores javascript generated html??
492
+ let children = [];
493
+ for (let child of node.parentNode.children) {
494
+ if (child.tagName == node.tagName) children.push(child);
495
+ }
496
+ let index = Array.prototype.indexOf.call(children, node);
497
+
498
+ pathSplit += `:nth-of-type(${index + 1})`;
499
+ }
500
+
501
+ node = node.parentNode;
502
+ if (
503
+ node == null ||
504
+ node.tagName == "HTML" ||
505
+ node.tagName == "BODY" ||
506
+ node.tagName == "DOM-PARSER" ||
507
+ node.nodeName == "#document" ||
508
+ node.hasAttribute("contenteditable")
509
+ )
510
+ node = "";
511
+ }
512
+
513
+ pathSplits.unshift(pathSplit);
514
+ } while (node);
515
+ let path = pathSplits.join(" > ");
516
+ if (path && path.includes("<")) {
517
+ let index = path.lastIndexOf(" >");
518
+ if (index != -1) path = path.slice(0, index);
519
+ else {
520
+ index = path.lastIndexOf("<");
521
+ path = path.slice(0, index);
522
+ }
523
+ }
524
+
525
+ return path;
526
+ }
527
+
528
+ function queryElements({ element, prefix, type, selector }) {
529
+ let elements = new Map();
530
+ if (!element) element = document;
531
+ let hasAttribute = false;
532
+
533
+ if (selector) {
534
+ if (!type) type = ["selector"];
535
+ else if (!Array.isArray(type)) type = [type];
536
+ } else type = ["selector", "closest", "parent", "next", "previous"];
537
+
538
+ for (let i = 0; i < type.length; i++) {
539
+ let Selector = selector;
540
+ if (!Selector && element.nodeType !== 9) {
541
+ let name = prefix + "-" + type[i];
542
+ if (!element.hasAttribute(name)) continue;
543
+ hasAttribute = true;
544
+ Selector = element.getAttribute(name);
545
+ }
546
+
547
+ if (Selector) {
548
+ let selectors = Selector.split(/,(?![^()]*\))/g);
549
+
550
+ for (let j = 0; j < selectors.length; j++) {
551
+ if (selectors[j].includes("@")) {
552
+ selectors[j] = checkMediaQueries(selectors[j]);
553
+ if (selectors[j] === false) continue;
554
+ }
555
+
556
+ let queriedElement = element;
557
+ let specialSelectors = selectors[j].split(";");
558
+ for (let k = 0; k < specialSelectors.length; k++) {
559
+ // TODO: Support an array of queried elements and branch off to return matches for each
560
+ // if (!Array.isArray(queriedElement)) {
561
+ // queriedElement = [queriedElement]
562
+ // }
563
+
564
+ if (!specialSelectors[k]) continue;
565
+ if (k === 0) {
566
+ if (type[i] === "parent")
567
+ queriedElement = queriedElement.parentElement;
568
+ else if (type[i] === "next")
569
+ queriedElement =
570
+ queriedElement.nextElementSibling;
571
+ else if (type[i] === "previous")
572
+ queriedElement =
573
+ queriedElement.previousElementSibling;
574
+ } else if (queriedElement.contentDocument) {
575
+ queriedElement = queriedElement.contentDocument;
576
+ }
577
+
578
+ switch (
579
+ (specialSelectors[k] = specialSelectors[k].trim())
580
+ ) {
581
+ case "top":
582
+ queriedElement = window.top.document;
583
+ break;
584
+ case "frame":
585
+ if (queriedElement.nodeType === 9)
586
+ queriedElement =
587
+ queriedElement.window.frameElement;
588
+ else if (queriedElement.contentDocument)
589
+ queriedElement =
590
+ queriedElement.contentDocument;
591
+ break;
592
+ case "document":
593
+ queriedElement = document;
594
+ break;
595
+ case "parent":
596
+ queriedElement = queriedElement.parentElement;
597
+ break;
598
+ case "next":
599
+ queriedElement =
600
+ queriedElement.nextElementSibling;
601
+ break;
602
+ case "previous":
603
+ queriedElement =
604
+ queriedElement.previousElementSibling;
605
+ break;
606
+ default:
607
+ if (k === 0 && type[i] === "closest")
608
+ if (specialSelectors[k].includes(" ")) {
609
+ let [firstSelector, ...restSelectors] =
610
+ specialSelectors[k].split(/ (.+)/);
611
+ queriedElement =
612
+ queriedElement.closest(
613
+ firstSelector
614
+ );
615
+ if (restSelectors.length > 0) {
616
+ if (restSelectors[0].endsWith("[]"))
617
+ queriedElement =
618
+ queriedElement.querySelectorAll(
619
+ restSelectors[0].slice(
620
+ 0,
621
+ -2
622
+ )
623
+ );
624
+ else
625
+ queriedElement =
626
+ queriedElement.querySelector(
627
+ restSelectors[0]
628
+ );
629
+ }
630
+ } else {
631
+ // If no space, just use the selector with closest
632
+ queriedElement = queriedElement.closest(
633
+ specialSelectors[k]
634
+ );
635
+ }
636
+ else if (
637
+ specialSelectors[k] === "$clickedElement"
638
+ ) {
639
+ queriedElement =
640
+ queriedElement.clickedElement;
641
+ } else if (specialSelectors[k].endsWith("[]"))
642
+ queriedElement =
643
+ queriedElement.querySelectorAll(
644
+ specialSelectors[k].slice(0, -2)
645
+ );
646
+ else
647
+ queriedElement =
648
+ queriedElement.querySelector(
649
+ specialSelectors[k]
650
+ );
651
+ }
652
+ if (!queriedElement) break;
653
+ }
654
+
655
+ if (
656
+ Array.isArray(queriedElement) ||
657
+ queriedElement instanceof HTMLCollection ||
658
+ queriedElement instanceof NodeList
659
+ ) {
660
+ for (let el of queriedElement) elements.set(el, "");
661
+ } else if (queriedElement) {
662
+ elements.set(queriedElement, "");
663
+ }
664
+ }
665
+ } else if (Selector === "") {
666
+ if (type[i] === "parent")
667
+ elements.set(element.parentElement, "");
668
+ else if (type[i] === "next")
669
+ elements.set(element.nextElementSibling, "");
670
+ else if (type[i] === "previous")
671
+ elements.set(element.previousElementSibling, "");
672
+ }
673
+ }
674
+
675
+ if (!hasAttribute && !selector) elements = false;
676
+ else elements = Array.from(elements.keys());
677
+
678
+ return elements;
679
+ }
680
+
681
+ const mediaRanges = {
682
+ xs: [0, 575],
683
+ sm: [576, 768],
684
+ md: [769, 992],
685
+ lg: [993, 1200],
686
+ xl: [1201, 0]
687
+ };
688
+
689
+ function checkMediaQueries(selector) {
690
+ if (selector && selector.includes("@")) {
691
+ let screenSizes = selector.split("@");
692
+ selector = screenSizes.shift();
693
+ for (let screenSize of screenSizes) {
694
+ const viewportWidth = window.innerWidth;
695
+ let mediaViewport = false;
696
+
697
+ // Check if screenSize is a valid range in the 'ranges' object
698
+ if (mediaRanges.hasOwnProperty(screenSize)) {
699
+ const [minWidth, maxWidth] = mediaRanges[screenSize];
700
+ if (
701
+ viewportWidth >= minWidth &&
702
+ viewportWidth <= maxWidth
703
+ ) {
704
+ mediaViewport = true;
705
+ break;
706
+ }
707
+ }
708
+
709
+ if (!mediaViewport) return false;
710
+ }
711
+ }
712
+
713
+ return selector;
714
+ }
715
+
716
+ function queryData(data, query) {
717
+ if (query.$and) {
718
+ for (let i = 0; i < query.$and.length; i++) {
719
+ if (!queryData(data, query.$and[i])) return false;
720
+ }
721
+ }
722
+
723
+ if (query.$nor) {
724
+ for (let i = 0; i < query.$nor.length; i++) {
725
+ if (queryData(data, query.$nor[i])) return false;
726
+ }
727
+ }
728
+
729
+ for (let key of Object.keys(query)) {
730
+ if (key === "$and" || key === "$or") continue;
731
+ if (!queryMatch(data, { [key]: query[key] })) return false;
732
+ }
733
+
734
+ if (query.$or) {
735
+ for (let i = 0; i < query.$or.length; i++) {
736
+ if (queryData(data, query.$or[i])) return true;
737
+ }
738
+ }
739
+
740
+ return true;
741
+ }
742
+
743
+ function queryMatch(data, query) {
744
+ for (let key of Object.keys(query)) {
745
+ // if (!data.hasOwnProperty(key))
746
+ // return false
747
+
748
+ let dataValue;
749
+ try {
750
+ dataValue = getValueFromObject(data, key, true);
751
+ } catch (error) {
752
+ return false;
753
+ }
754
+
755
+ if (
756
+ typeof query[key] === "string" ||
757
+ typeof query[key] === "number" ||
758
+ typeof query[key] === "boolean"
759
+ ) {
760
+ if (Array.isArray(dataValue))
761
+ return dataValue.includes(query[key]);
762
+ else return dataValue === query[key];
763
+ } else if (Array.isArray(query[key])) {
764
+ if (Array.isArray(dataValue)) {
765
+ return isEqualArray(dataValue, query[key]);
766
+ } else {
767
+ return false;
768
+ }
769
+ } else {
770
+ for (let property of Object.keys(query[key])) {
771
+ if (property === "$options") continue;
772
+ if (!property.startsWith("$")) {
773
+ if (typeof dataValue !== "object") {
774
+ return false;
775
+ } else
776
+ return queryMatch(
777
+ {
778
+ [property]: getValueFromObject(
779
+ dataValue,
780
+ property
781
+ )
782
+ },
783
+ { [property]: query[key][property] }
784
+ );
785
+ } else {
786
+ let queryValue = query[key][property];
787
+ if (isValidDate(queryValue) && isValidDate(dataValue)) {
788
+ queryValue = new Date(queryValue);
789
+ dataValue = new Date(dataValue);
790
+ }
791
+ let queryStatus = false;
792
+ switch (property) {
793
+ case "$eq":
794
+ if (
795
+ Array.isArray(dataValue) &&
796
+ Array.isArray(queryValue)
797
+ ) {
798
+ queryStatus = isEqualArray(
799
+ dataValue,
800
+ queryValue
801
+ );
802
+ } else {
803
+ queryStatus = dataValue === queryValue;
804
+ }
805
+ break;
806
+ case "$ne":
807
+ if (
808
+ Array.isArray(dataValue) &&
809
+ Array.isArray(queryValue)
810
+ ) {
811
+ queryStatus = !isEqualArray(
812
+ dataValue,
813
+ queryValue
814
+ );
815
+ } else {
816
+ queryStatus = dataValue !== queryValue;
817
+ }
818
+ break;
819
+ case "$not":
820
+ queryStatus = !queryMatch(data, {
821
+ [key]: query[key]["$not"]
822
+ });
823
+ break;
824
+ case "$lt":
825
+ queryStatus = dataValue < queryValue;
826
+ break;
827
+ case "$lte":
828
+ queryStatus = dataValue <= queryValue;
829
+ break;
830
+ case "$gt":
831
+ queryStatus = dataValue > queryValue;
832
+ break;
833
+ case "$gte":
834
+ queryStatus = dataValue >= queryValue;
835
+ break;
836
+ case "$in":
837
+ if (Array.isArray(dataValue)) {
838
+ queryStatus = dataValue.some((element) =>
839
+ queryValue.includes(element)
840
+ );
841
+ } else {
842
+ queryStatus =
843
+ queryValue.includes(dataValue);
844
+ }
845
+ break;
846
+ case "$nin":
847
+ if (Array.isArray(dataValue)) {
848
+ queryStatus = !dataValue.some((element) =>
849
+ queryValue.includes(element)
850
+ );
851
+ } else {
852
+ queryStatus =
853
+ !queryValue.includes(dataValue);
854
+ }
855
+ break;
856
+ case "$all":
857
+ if (
858
+ Array.isArray(dataValue) &&
859
+ Array.isArray(queryValue)
860
+ ) {
861
+ queryStatus = queryValue.every((element) =>
862
+ dataValue.includes(element)
863
+ );
864
+ }
865
+ break;
866
+ case "$elemMatch":
867
+ if (Array.isArray(data[key])) {
868
+ queryStatus = data[key].some((element) =>
869
+ queryMatch(
870
+ element,
871
+ query[key][property]
872
+ )
873
+ );
874
+ }
875
+ break;
876
+ case "$size":
877
+ if (Array.isArray(dataValue)) {
878
+ queryStatus =
879
+ dataValue.length === queryValue;
880
+ }
881
+ break;
882
+ case "$exists":
883
+ queryStatus = queryValue
884
+ ? data.hasOwnProperty(key)
885
+ : !data.hasOwnProperty(key);
886
+ break;
887
+ case "$regex":
888
+ if (typeof dataValue === "string") {
889
+ let regexFlag =
890
+ query[key]["$options"] || "";
891
+ let regex = new RegExp(
892
+ queryValue,
893
+ regexFlag
894
+ );
895
+ queryStatus = regex.test(dataValue);
896
+ }
897
+ break;
898
+ case "$type":
899
+ let dataType = typeof dataValue;
900
+ if (Array.isArray(dataValue)) {
901
+ dataType = "array";
902
+ }
903
+ queryStatus = dataType === queryValue;
904
+ break;
905
+ case "$mod":
906
+ if (
907
+ typeof dataValue === "number" &&
908
+ Array.isArray(queryValue) &&
909
+ queryValue.length === 2
910
+ ) {
911
+ const [divisor, remainder] = queryValue;
912
+ queryStatus =
913
+ dataValue % divisor === remainder;
914
+ }
915
+ break;
916
+ case "$where":
917
+ if (typeof queryValue === "function") {
918
+ try {
919
+ // queryStatus = queryValue.call(data);
920
+ } catch (error) {
921
+ console.error(
922
+ "Error in queryData $where function:",
923
+ error
924
+ );
925
+ }
926
+ }
927
+ break;
928
+
929
+ default:
930
+ console.log("unknown operator");
931
+ break;
932
+ }
933
+ if (!queryStatus) return false;
934
+ }
935
+ }
936
+ return true;
937
+ }
938
+ }
939
+ }
940
+
941
+ function isEqualArray(arr1, arr2) {
942
+ if (arr1.length !== arr2.length) {
943
+ return false;
944
+ }
945
+ for (let i = 0; i < arr1.length; i++) {
946
+ if (!isEqualObject(arr1[i], arr2[i])) {
947
+ return false;
948
+ }
949
+ }
950
+ return true;
951
+ }
952
+
953
+ function isEqualObject(obj1, obj2) {
954
+ const keys1 = Object.keys(obj1);
955
+ const keys2 = Object.keys(obj2);
956
+
957
+ if (keys1.length !== keys2.length) {
958
+ return false;
959
+ }
960
+
961
+ for (const key of keys1) {
962
+ if (obj1[key] !== obj2[key]) {
963
+ return false;
964
+ }
965
+ }
966
+
967
+ return true;
968
+ }
969
+
970
+ function searchData(data, search) {
971
+ if (!search) return true;
972
+ if (!Array.isArray(search)) search = [search];
973
+ for (let i = 0; i < search.length; i++) {
974
+ let searchValue = search[i].value;
975
+ if (!Array.isArray(searchValue)) searchValue = [searchValue];
976
+ for (let key in data) {
977
+ let value = data[key];
978
+ let status = false;
979
+ switch (typeof value) {
980
+ case "number":
981
+ value = value.toString();
982
+ break;
983
+ case "object":
984
+ value = JSON.stringify(value);
985
+ break;
986
+ case "function":
987
+ value = value.toString();
988
+ break;
989
+ }
990
+ if (
991
+ search[i].caseSensitive != "true" ||
992
+ search[i].caseSensitive != true
993
+ )
994
+ value = value.toLowerCase();
995
+
996
+ for (let i = 0; i < searchValue.length; i++) {
997
+ let searchString = searchValue[i];
998
+ if (
999
+ search[i].caseSensitive != "true" ||
1000
+ search[i].caseSensitive != true
1001
+ )
1002
+ searchString = searchString.toLowerCase();
1003
+
1004
+ if (searchString === "" && search[i].operator === "and") {
1005
+ if (value !== "") return false;
1006
+ }
1007
+
1008
+ if (value.indexOf(searchString) > -1) status = true;
1009
+
1010
+ if (status) return true;
1011
+ else if (search[i].operator == "and") return false;
1012
+ }
1013
+ }
1014
+ if (search[i].value.length && search[i].operator == "or")
1015
+ return false;
1016
+ }
1017
+ return true;
1018
+ }
1019
+
1020
+ function sortData(data, sort) {
1021
+ return data.sort((a, b) => {
1022
+ for (let i = 0; i < sort.length; i++) {
1023
+ let key = sort[i].key;
1024
+ if (a[key] == null && b[key] == null) continue;
1025
+ if (a[key] == null)
1026
+ return sort[i].direction === "desc" ? -1 : 1;
1027
+ if (b[key] == null)
1028
+ return sort[i].direction === "desc" ? 1 : -1;
1029
+
1030
+ if (typeof a[key] !== typeof b[key]) {
1031
+ return typeof a[key] < typeof b[key] ? -1 : 1;
1032
+ }
1033
+
1034
+ if (a[key] !== b[key]) {
1035
+ if (typeof a[key] === "string") {
1036
+ return sort[i].direction === "desc"
1037
+ ? b[key].localeCompare(a[key])
1038
+ : a[key].localeCompare(b[key]);
1039
+ } else {
1040
+ // Assuming numeric or other comparable types
1041
+ return sort[i].direction === "desc"
1042
+ ? b[key] - a[key]
1043
+ : a[key] - b[key];
1044
+ }
1045
+ }
1046
+ }
1047
+ return 0;
1048
+ });
1049
+ }
1050
+
1051
+ function getAttributes(el) {
1052
+ if (!el) return;
1053
+
1054
+ let attributes = window.CoCreateConfig.attributes;
1055
+ let object = {};
1056
+
1057
+ for (let attribute of el.attributes) {
1058
+ let variable = attributes[attribute.name];
1059
+ if (variable) {
1060
+ object[variable] = el.getAttribute(attribute.name);
1061
+ }
1062
+ }
1063
+
1064
+ return object;
1065
+ }
1066
+
1067
+ function getAttributeNames(variables) {
1068
+ let reversedObject = {};
1069
+ for (const key of Object.keys(CoCreateConfig.attributes)) {
1070
+ reversedObject[CoCreateConfig.attributes[key]] = key;
1071
+ }
1072
+
1073
+ let attributes = [];
1074
+ for (const variable of variables) {
1075
+ let attribute = reversedObject[variable];
1076
+ if (attribute) attributes.push(attribute);
1077
+ }
1078
+ return attributes;
1079
+ }
1080
+
1081
+ function setAttributeNames(attributes, overWrite) {
1082
+ let reversedObject = {};
1083
+ for (const key of Object.keys(CoCreateConfig.attributes)) {
1084
+ reversedObject[CoCreateConfig.attributes[key]] = key;
1085
+ }
1086
+
1087
+ for (const attribute of Object.keys(attributes)) {
1088
+ const variable = attributes[attribute];
1089
+ if (!reversedObject[variable] || overWrite != false)
1090
+ reversedObject[variable] = attribute;
1091
+ }
1092
+
1093
+ let revertObject = {};
1094
+ for (const key of Object.keys(reversedObject)) {
1095
+ revertObject[reversedObject[key]] = key;
1096
+ }
1097
+ CoCreateConfig.attributes = revertObject;
1098
+ }
1099
+
1100
+ if (isBrowser) clickedElement();
1101
+
1102
+ return {
1103
+ ObjectId,
1104
+ checkValue,
1105
+ isValidDate,
1106
+ dotNotationToObject,
1107
+ getValueFromObject,
1108
+ domParser,
1109
+ parseTextToHtml,
1110
+ escapeHtml,
1111
+ cssPath,
1112
+ queryElements,
1113
+ checkMediaQueries,
1114
+ queryData,
1115
+ searchData,
1116
+ sortData,
1117
+ createUpdate,
1118
+ getAttributes,
1119
+ setAttributeNames,
1120
+ getAttributeNames
1121
+ };
1122
+ });