@cocreate/utils 1.41.1 → 1.42.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.
- package/CHANGELOG.md +14 -0
- package/README.md +40 -5
- package/package.json +129 -3
- package/src/ObjectId.js +41 -0
- package/src/attributes.js +48 -0
- package/src/checkValue.js +4 -0
- package/src/clickedElement.js +28 -0
- package/src/core.js +6 -0
- package/src/createUpdate.js +202 -0
- package/src/cssPath.js +50 -0
- package/src/dataQuery.js +291 -0
- package/src/dom.js +4 -0
- package/src/domParser.js +21 -0
- package/src/dotNotationToObject.js +90 -0
- package/src/escapeHtml.js +8 -0
- package/src/getRelativePath.js +24 -0
- package/src/getValueFromObject.js +25 -0
- package/src/index.js +70 -1365
- package/src/init-browser.js +5 -0
- package/src/isValidDate.js +17 -0
- package/src/objectToDotNotation.js +35 -0
- package/src/objectToSearchParams.js +28 -0
- package/src/operators.js +580 -0
- package/src/parseTextToHtml.js +5 -0
- package/src/queryElements.js +174 -0
- package/src/safeParse.js +171 -0
- package/src/uid.js +16 -0
package/src/index.js
CHANGED
|
@@ -1,1365 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// const isBrowser = typeof window !== 'undefined';
|
|
72
|
-
|
|
73
|
-
// // If no path provided, use window.location.pathname
|
|
74
|
-
// if (!path && isBrowser) {
|
|
75
|
-
// path = window.location.pathname;
|
|
76
|
-
|
|
77
|
-
// // FIX: Only remove the end segment if it looks like a file (has an extension like .html)
|
|
78
|
-
// // This prevents stripping valid routes like /dashboard
|
|
79
|
-
// if (/\.[^/]+$/.test(path)) {
|
|
80
|
-
// path = path.replace(/\/[^\/]*$/, "");
|
|
81
|
-
// }
|
|
82
|
-
// }
|
|
83
|
-
|
|
84
|
-
// // For localhost/127.0.0.1, remove everything up to and including the first '/src'
|
|
85
|
-
// if (
|
|
86
|
-
// isBrowser &&
|
|
87
|
-
// (window.location.hostname === "localhost" ||
|
|
88
|
-
// window.location.hostname === "127.0.0.1")
|
|
89
|
-
// ) {
|
|
90
|
-
// const srcIndex = path.indexOf("/src");
|
|
91
|
-
// if (srcIndex !== -1) {
|
|
92
|
-
// // If path is "/BeautySalon/src", this returns ""
|
|
93
|
-
// path = path.slice(srcIndex + 4);
|
|
94
|
-
// }
|
|
95
|
-
// }
|
|
96
|
-
|
|
97
|
-
// // Handle the empty string case here:
|
|
98
|
-
// // "" does not end with "/", so it adds one -> "/"
|
|
99
|
-
// if (!path || !path.endsWith("/")) {
|
|
100
|
-
// path = (path || "") + "/";
|
|
101
|
-
// }
|
|
102
|
-
|
|
103
|
-
// // "/" splits to ['', ''], filter removes them -> length is 0
|
|
104
|
-
// let depth = path.split("/").filter(Boolean).length;
|
|
105
|
-
|
|
106
|
-
// // 0 depth returns "./"
|
|
107
|
-
// return depth > 0 ? "../".repeat(depth) : "./";
|
|
108
|
-
// }
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Generates an ObjectId
|
|
112
|
-
*/
|
|
113
|
-
let counter = 0;
|
|
114
|
-
function ObjectId(inputId) {
|
|
115
|
-
if (inputId && /^[0-9a-fA-F]{24}$/.test(inputId)) {
|
|
116
|
-
// If a valid ObjectId is provided, return it as a custom ObjectId object
|
|
117
|
-
return {
|
|
118
|
-
timestamp: inputId.substring(0, 8),
|
|
119
|
-
processId: inputId.substring(8, 20),
|
|
120
|
-
counter: inputId.substring(20),
|
|
121
|
-
toString: function () {
|
|
122
|
-
return this.timestamp + this.processId + this.counter;
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
} else if (inputId) {
|
|
126
|
-
throw new Error("Invalid ObjectId provided.");
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Generate a new custom ObjectId
|
|
130
|
-
const timestampHex = Math.floor(
|
|
131
|
-
new Date(new Date().toISOString()).getTime() / 1000
|
|
132
|
-
)
|
|
133
|
-
.toString(16)
|
|
134
|
-
.padStart(8, "0");
|
|
135
|
-
const processIdHex = Math.floor(Math.random() * 0x100000000000)
|
|
136
|
-
.toString(16)
|
|
137
|
-
.padStart(12, "0");
|
|
138
|
-
|
|
139
|
-
counter = (counter + 1) % 10000;
|
|
140
|
-
if (counter < 2) {
|
|
141
|
-
counter = Math.floor(Math.random() * (5000 - 100 + 1)) + 100;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const counterHex = counter.toString(16).padStart(4, "0");
|
|
145
|
-
|
|
146
|
-
// Return the custom ObjectId object with a toString() method
|
|
147
|
-
return {
|
|
148
|
-
timestamp: timestampHex,
|
|
149
|
-
processId: processIdHex,
|
|
150
|
-
counter: counterHex,
|
|
151
|
-
toString: function () {
|
|
152
|
-
return this.timestamp + this.processId + this.counter;
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function uid(length = 36) {
|
|
158
|
-
let pattern = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
|
|
159
|
-
if (length > 36) {
|
|
160
|
-
length = 36; // If requested length is more than 36, set it to 36.
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
let uuid = pattern.replace(/[xy]/g, function (c) {
|
|
164
|
-
var r = (Math.random() * 16) | 0;
|
|
165
|
-
var v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
166
|
-
return v.toString(16);
|
|
167
|
-
}).substring(0, length); // Truncate to the requested length.
|
|
168
|
-
|
|
169
|
-
return uuid;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function checkValue(value) {
|
|
173
|
-
if (/{{\s*([\w\W]+)\s*}}/g.test(value)) return false;
|
|
174
|
-
else return true;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function isValidDate(value) {
|
|
178
|
-
if (
|
|
179
|
-
typeof value === "string" &&
|
|
180
|
-
value.length >= 20 &&
|
|
181
|
-
value.length <= 24
|
|
182
|
-
) {
|
|
183
|
-
// if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z$/i.test(value))
|
|
184
|
-
if (
|
|
185
|
-
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?([-+]\d{2}:\d{2}|Z)?$/i.test(
|
|
186
|
-
value
|
|
187
|
-
)
|
|
188
|
-
) {
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function dotNotationToObject(data, obj = {}) {
|
|
197
|
-
try {
|
|
198
|
-
let arrayGroup = {}; // Track groups by key paths (e.g., 'messages[a]')
|
|
199
|
-
|
|
200
|
-
for (const key of Object.keys(data)) {
|
|
201
|
-
let value = data[key];
|
|
202
|
-
let newObject = obj;
|
|
203
|
-
let oldObject = new Object(obj);
|
|
204
|
-
let keys = key.split(".");
|
|
205
|
-
let length = keys.length - 1;
|
|
206
|
-
|
|
207
|
-
for (let i = 0; i < keys.length; i++) {
|
|
208
|
-
// Check if the key ends with ']', indicating an array or grouping operation
|
|
209
|
-
if (keys[i].endsWith("]")) {
|
|
210
|
-
// Handle array push (e.g., messages[] -> push value)
|
|
211
|
-
if (keys[i].endsWith("[]")) {
|
|
212
|
-
let baseKey = keys[i].slice(0, -2); // Remove '[]'
|
|
213
|
-
|
|
214
|
-
// Initialize newObject[baseKey] as an array if not an array or doesn't exist
|
|
215
|
-
if (!Array.isArray(newObject[baseKey])) {
|
|
216
|
-
newObject[baseKey] = [];
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (length == i) {
|
|
220
|
-
// If value is an array, spread the array values into newObject[baseKey]
|
|
221
|
-
if (Array.isArray(value)) {
|
|
222
|
-
newObject[baseKey].push(...value);
|
|
223
|
-
} else {
|
|
224
|
-
// If value is not an array, just push the single value
|
|
225
|
-
newObject[baseKey].push(value);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
// Check for array index (e.g., messages[0])
|
|
230
|
-
else if (/\[([0-9]+)\]/g.test(keys[i])) {
|
|
231
|
-
let [k, index] = keys[i].split("[");
|
|
232
|
-
index = index.slice(0, -1); // Get the index
|
|
233
|
-
|
|
234
|
-
// Initialize newObject[k] as an array if it doesn't exist or is not an array
|
|
235
|
-
if (!Array.isArray(newObject[k])) {
|
|
236
|
-
newObject[k] = [];
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (length == i) {
|
|
240
|
-
if (value === undefined) {
|
|
241
|
-
newObject[k].splice(index, 1); // Remove element if value is undefined
|
|
242
|
-
} else {
|
|
243
|
-
newObject[k][index] = value; // Replace value at specified index
|
|
244
|
-
}
|
|
245
|
-
} else {
|
|
246
|
-
newObject[k][index] = oldObject[k][index] || {}; // Initialize inner object
|
|
247
|
-
newObject = newObject[k][index];
|
|
248
|
-
oldObject = oldObject[k][index];
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
// Handle letter-based groupings (e.g., messages[a].role)
|
|
252
|
-
else if (/\[\w\]/g.test(keys[i])) {
|
|
253
|
-
let [k, group] = keys[i].split("[");
|
|
254
|
-
group = group.slice(0, -1); // Get the letter inside []
|
|
255
|
-
|
|
256
|
-
// Initialize newObject[k] as an array if not an array or doesn't exist
|
|
257
|
-
if (!Array.isArray(newObject[k])) {
|
|
258
|
-
newObject[k] = [];
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// If there's no object at this group index yet, push a new object
|
|
262
|
-
let index;
|
|
263
|
-
if (arrayGroup[keys.slice(0, i + 1).join(".")]) {
|
|
264
|
-
// Reuse the existing index for the group
|
|
265
|
-
index =
|
|
266
|
-
arrayGroup[keys.slice(0, i + 1).join(".")];
|
|
267
|
-
} else {
|
|
268
|
-
// Create a new group and track the index
|
|
269
|
-
index = newObject[k].length;
|
|
270
|
-
arrayGroup[keys.slice(0, i + 1).join(".")] =
|
|
271
|
-
index;
|
|
272
|
-
newObject[k][index] = {};
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// Move into the newly created or existing object for the group
|
|
276
|
-
if (length == i) {
|
|
277
|
-
newObject[k][index] = value; // Set value in the group
|
|
278
|
-
} else {
|
|
279
|
-
newObject = newObject[k][index]; // Continue with the group object
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
// Handle regular object keys (non-array keys)
|
|
284
|
-
else {
|
|
285
|
-
if (length == i) {
|
|
286
|
-
if (value === undefined) {
|
|
287
|
-
delete newObject[keys[i]]; // Delete key if value is undefined
|
|
288
|
-
} else {
|
|
289
|
-
newObject[keys[i]] = value; // Set value
|
|
290
|
-
}
|
|
291
|
-
} else {
|
|
292
|
-
newObject[keys[i]] = oldObject[keys[i]] || {}; // Initialize inner object
|
|
293
|
-
newObject = newObject[keys[i]];
|
|
294
|
-
oldObject = oldObject[keys[i]];
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
return obj;
|
|
300
|
-
} catch (error) {
|
|
301
|
-
console.log("Error converting dot notation to object", error);
|
|
302
|
-
return false;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Flattens a deeply nested object or array into a single-level object
|
|
308
|
-
* where keys are dot/bracket notation paths and values are the corresponding
|
|
309
|
-
* primitive values (string, number, boolean, null, undefined) from the
|
|
310
|
-
* original structure.
|
|
311
|
-
*
|
|
312
|
-
* @param {object|array} input The object or array to flatten.
|
|
313
|
-
* @returns {object} A flat object with dot/bracket notation keys mapped to their primitive values.
|
|
314
|
-
*/
|
|
315
|
-
function objectToDotNotation(input) {
|
|
316
|
-
const results = {}; // Initialize an empty OBJECT to store key-value pairs
|
|
317
|
-
|
|
318
|
-
// Helper function for recursion
|
|
319
|
-
function traverse(currentValue, path) {
|
|
320
|
-
// Base Case: Primitive values (or null/undefined)
|
|
321
|
-
// We consider anything that's not an object or is null as a primitive endpoint.
|
|
322
|
-
if (typeof currentValue !== "object" || currentValue === null) {
|
|
323
|
-
// Only add if a path exists (handles the edge case where the initial input itself is primitive)
|
|
324
|
-
if (path !== undefined && path !== null && path !== "") {
|
|
325
|
-
results[path] = currentValue; // Assign the primitive value to the constructed path key
|
|
326
|
-
}
|
|
327
|
-
return; // Stop recursion for this branch
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Recursive Step: Array
|
|
331
|
-
if (Array.isArray(currentValue)) {
|
|
332
|
-
// Only traverse non-empty arrays if we're looking for primitive values
|
|
333
|
-
// If you wanted empty arrays represented (e.g., 'notes': []), you'd add logic here.
|
|
334
|
-
if (currentValue.length > 0) {
|
|
335
|
-
currentValue.forEach((item, index) => {
|
|
336
|
-
// Build the next path segment using bracket notation for arrays
|
|
337
|
-
const nextPath = `${path}[${index}]`;
|
|
338
|
-
traverse(item, nextPath);
|
|
339
|
-
});
|
|
340
|
-
} else if (path) {
|
|
341
|
-
// Optional: represent empty arrays explicitly if needed
|
|
342
|
-
// results[path] = []; // Uncomment this line if you want empty arrays included
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
// Recursive Step: Object (and not null, not an array)
|
|
346
|
-
else {
|
|
347
|
-
const keys = Object.keys(currentValue);
|
|
348
|
-
// Only traverse non-empty objects if we're looking for primitive values
|
|
349
|
-
// If you wanted empty objects represented (e.g., 'metadata': {}), you'd add logic here.
|
|
350
|
-
if (keys.length > 0) {
|
|
351
|
-
keys.forEach((key) => {
|
|
352
|
-
// Build the next path segment:
|
|
353
|
-
// - Use dot notation if the current path is not empty.
|
|
354
|
-
// - Just use the key if it's the first level.
|
|
355
|
-
const nextPath = path ? `${path}.${key}` : key;
|
|
356
|
-
traverse(currentValue[key], nextPath);
|
|
357
|
-
});
|
|
358
|
-
} else if (path) {
|
|
359
|
-
// Optional: represent empty objects explicitly if needed
|
|
360
|
-
// results[path] = {}; // Uncomment this line if you want empty objects included
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// Start the traversal with the initial input and an empty path
|
|
366
|
-
// Using an empty string '' ensures the first level keys don't start with '.'
|
|
367
|
-
traverse(input, "");
|
|
368
|
-
|
|
369
|
-
return results; // Return the populated results object
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function getValueFromObject(object = {}, path = "", throwError = false) {
|
|
373
|
-
try {
|
|
374
|
-
if ((!Array.isArray(object) && !Object.keys(object).length) || !path) {
|
|
375
|
-
if (throwError)
|
|
376
|
-
throw new Error("Invalid input to getValueFromObject");
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// remove leading dot if path is like `[0].src`
|
|
381
|
-
path = path.replace(/\[(\d+)\]/g, ".$1").replace(/^\./, '');
|
|
382
|
-
|
|
383
|
-
let data = object,
|
|
384
|
-
subpath = path.split(".");
|
|
385
|
-
|
|
386
|
-
for (let i = 0; i < subpath.length; i++) {
|
|
387
|
-
if (throwError && !(subpath[i] in data))
|
|
388
|
-
throw new Error("Key not found in object: " + subpath[i]);
|
|
389
|
-
|
|
390
|
-
data = data[subpath[i]];
|
|
391
|
-
if (!data) break;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
return data;
|
|
395
|
-
} catch (error) {
|
|
396
|
-
// console.error("Error in getValueFromObject:", error);
|
|
397
|
-
if (throwError) throw error;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function createUpdate(update, data, globalOpertors) {
|
|
402
|
-
let operatorKeys = {};
|
|
403
|
-
if (globalOpertors) operatorKeys = { ...globalOpertors };
|
|
404
|
-
|
|
405
|
-
Object.keys(data).forEach((key) => {
|
|
406
|
-
if (key.startsWith("$")) {
|
|
407
|
-
if (!key.includes("."))
|
|
408
|
-
for (let oldkey of Object.keys(data[key]))
|
|
409
|
-
operatorKeys[key + "." + oldkey] = data[key][oldkey];
|
|
410
|
-
else operatorKeys[key] = data[key];
|
|
411
|
-
} else if (
|
|
412
|
-
typeof data[key] === "string" &&
|
|
413
|
-
data[key].startsWith("$")
|
|
414
|
-
) {
|
|
415
|
-
operatorKeys[data[key] + "." + key] = data[key];
|
|
416
|
-
} else if (key.endsWith("]")) {
|
|
417
|
-
const regex = /^(.*(?:\[\d+\].*?)?)\[(.*?)\](?:\[\])?$/;
|
|
418
|
-
const match = key.match(regex);
|
|
419
|
-
if (match[2] === "")
|
|
420
|
-
operatorKeys["$push." + match[1]] = data[key];
|
|
421
|
-
else {
|
|
422
|
-
let index = parseInt(match[2], 10);
|
|
423
|
-
if (index === NaN)
|
|
424
|
-
operatorKeys[match[2] + "." + match[1]] = data[key];
|
|
425
|
-
else operatorKeys[key] = data[key];
|
|
426
|
-
}
|
|
427
|
-
} else if (key.includes(".")) {
|
|
428
|
-
operatorKeys[key] = data[key];
|
|
429
|
-
} else if (data[key] === undefined) {
|
|
430
|
-
delete update[key];
|
|
431
|
-
} else update[key] = data[key];
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
return dotNotationToObjectUpdate(operatorKeys, update);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
function dotNotationToObjectUpdate(data, object = {}) {
|
|
438
|
-
try {
|
|
439
|
-
for (const key of Object.keys(data)) {
|
|
440
|
-
let newObject = object;
|
|
441
|
-
let oldObject = new Object(newObject);
|
|
442
|
-
let keys = key
|
|
443
|
-
.replace(/\[(\d+)\]/g, ".$1")
|
|
444
|
-
.split(".")
|
|
445
|
-
.map((k) => (isNaN(k) ? k : Number(k)));
|
|
446
|
-
let value = data[key];
|
|
447
|
-
let operator;
|
|
448
|
-
if (keys[0].startsWith("$")) operator = keys.shift();
|
|
449
|
-
|
|
450
|
-
let length = keys.length - 1;
|
|
451
|
-
for (let i = 0; i < keys.length; i++) {
|
|
452
|
-
// if (/^\d+$/.test(keys[i])) keys[i] = parseInt(keys[i]);
|
|
453
|
-
|
|
454
|
-
if (length == i) {
|
|
455
|
-
if (operator) {
|
|
456
|
-
let operators = [
|
|
457
|
-
"$rename",
|
|
458
|
-
"$inc",
|
|
459
|
-
"$push",
|
|
460
|
-
"$each",
|
|
461
|
-
"$splice",
|
|
462
|
-
"$unset",
|
|
463
|
-
"$delete",
|
|
464
|
-
"$slice",
|
|
465
|
-
"$pop",
|
|
466
|
-
"$shift",
|
|
467
|
-
"$addToSet",
|
|
468
|
-
"$pull"
|
|
469
|
-
];
|
|
470
|
-
if (!operators.includes(operator)) continue;
|
|
471
|
-
if (operator === "$rename") {
|
|
472
|
-
newObject[value] = newObject[keys[i]];
|
|
473
|
-
delete newObject[keys[i]];
|
|
474
|
-
} else if (
|
|
475
|
-
operator === "$delete" ||
|
|
476
|
-
operator === "$unset" ||
|
|
477
|
-
operator === "$slice"
|
|
478
|
-
) {
|
|
479
|
-
if (typeof keys[i] === "number") {
|
|
480
|
-
newObject.splice(keys[i], 1);
|
|
481
|
-
} else {
|
|
482
|
-
delete newObject[keys[i]];
|
|
483
|
-
}
|
|
484
|
-
} else if (operator === "$shift") {
|
|
485
|
-
newObject[keys[i]].shift();
|
|
486
|
-
} else if (operator === "$pop") {
|
|
487
|
-
newObject[keys[i]].pop();
|
|
488
|
-
} else if (operator === "$addToSet") {
|
|
489
|
-
if (!newObject[keys[i]])
|
|
490
|
-
newObject[keys[i]] = [];
|
|
491
|
-
let exists;
|
|
492
|
-
if (Array.isArray(value)) {
|
|
493
|
-
exists = newObject[keys[i]].some(
|
|
494
|
-
(item) =>
|
|
495
|
-
Array.isArray(item) &&
|
|
496
|
-
isEqualArray(item, value)
|
|
497
|
-
);
|
|
498
|
-
} else if (
|
|
499
|
-
typeof value === "object" &&
|
|
500
|
-
value !== null
|
|
501
|
-
) {
|
|
502
|
-
exists = newObject[keys[i]].some(
|
|
503
|
-
(item) =>
|
|
504
|
-
typeof item === "object" &&
|
|
505
|
-
isEqualObject(item, value)
|
|
506
|
-
);
|
|
507
|
-
} else {
|
|
508
|
-
exists = newObject[keys[i]].includes(value);
|
|
509
|
-
}
|
|
510
|
-
if (!exists) newObject[keys[i]].push(value);
|
|
511
|
-
} else if (operator === "$pull") {
|
|
512
|
-
if (!newObject[keys[i]]) continue;
|
|
513
|
-
if (Array.isArray(value)) {
|
|
514
|
-
newObject[keys[i]] = newObject[
|
|
515
|
-
keys[i]
|
|
516
|
-
].filter(
|
|
517
|
-
(item) =>
|
|
518
|
-
!Array.isArray(item) ||
|
|
519
|
-
!isEqualArray(item, value)
|
|
520
|
-
);
|
|
521
|
-
} else if (
|
|
522
|
-
typeof value === "object" &&
|
|
523
|
-
value !== null
|
|
524
|
-
) {
|
|
525
|
-
newObject[keys[i]] = newObject[
|
|
526
|
-
keys[i]
|
|
527
|
-
].filter(
|
|
528
|
-
(item) =>
|
|
529
|
-
typeof item !== "object" ||
|
|
530
|
-
!isEqualObject(item, value)
|
|
531
|
-
);
|
|
532
|
-
} else {
|
|
533
|
-
newObject[keys[i]] = newObject[
|
|
534
|
-
keys[i]
|
|
535
|
-
].filter((item) => item !== value);
|
|
536
|
-
}
|
|
537
|
-
} else if (
|
|
538
|
-
operator === "$push" ||
|
|
539
|
-
operator === "$splice"
|
|
540
|
-
) {
|
|
541
|
-
if (
|
|
542
|
-
typeof keys[i] === "number" &&
|
|
543
|
-
newObject.length >= keys[i]
|
|
544
|
-
)
|
|
545
|
-
newObject.splice(keys[i], 0, value);
|
|
546
|
-
else if (newObject[keys[i]])
|
|
547
|
-
newObject[keys[i]].push(value);
|
|
548
|
-
else newObject[keys[i]] = [value];
|
|
549
|
-
} else if (operator === "$each") {
|
|
550
|
-
if (!Array.isArray(value)) value = [value];
|
|
551
|
-
if (typeof keys[i] === "number")
|
|
552
|
-
newObject.splice(keys[i], 0, ...value);
|
|
553
|
-
else newObject[keys[i]].push(...value);
|
|
554
|
-
} else if (operator === "$inc") {
|
|
555
|
-
if (
|
|
556
|
-
!newObject[keys[i]] ||
|
|
557
|
-
typeof newObject[keys[i]] !== "number"
|
|
558
|
-
)
|
|
559
|
-
newObject[keys[i]] = value;
|
|
560
|
-
else newObject[keys[i]] += value;
|
|
561
|
-
}
|
|
562
|
-
} else if (value === undefined) {
|
|
563
|
-
if (typeof keys[i] === "number")
|
|
564
|
-
newObject.splice(keys[i], 1);
|
|
565
|
-
else delete newObject[keys[i]];
|
|
566
|
-
} else if (typeof keys[i] === "number") {
|
|
567
|
-
newObject.splice(keys[i], 0, value);
|
|
568
|
-
} else {
|
|
569
|
-
newObject[keys[i]] = value;
|
|
570
|
-
}
|
|
571
|
-
} else if (
|
|
572
|
-
typeof keys[i + 1] === "number" &&
|
|
573
|
-
!Array.isArray(newObject[keys[i]])
|
|
574
|
-
) {
|
|
575
|
-
newObject[keys[i]] = [];
|
|
576
|
-
} else {
|
|
577
|
-
newObject[keys[i]] = newObject[keys[i]] || {};
|
|
578
|
-
// newObject[keys[i]] = oldObject[keys[i]] || {};
|
|
579
|
-
// oldObject = oldObject[keys[i]];
|
|
580
|
-
}
|
|
581
|
-
newObject = newObject[keys[i]];
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
return object;
|
|
585
|
-
} catch (error) {
|
|
586
|
-
console.log("Error converting dot notation to object", error);
|
|
587
|
-
return false;
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
/**
|
|
592
|
-
* Converts a JavaScript object into a URL-encoded query string using
|
|
593
|
-
* the standard URLSearchParams API (works in Node.js and modern browsers).
|
|
594
|
-
* - Uses repeated keys for arrays.
|
|
595
|
-
* - Skips null/undefined values.
|
|
596
|
-
* - Converts other values to strings.
|
|
597
|
-
*
|
|
598
|
-
* @param {object | null | undefined} paramsObj The object to convert.
|
|
599
|
-
* @returns {string} A URL-encoded query string starting with '?'
|
|
600
|
-
* if params exist, otherwise an empty string.
|
|
601
|
-
*/
|
|
602
|
-
function objectToSearchParams(paramsObj) {
|
|
603
|
-
if (
|
|
604
|
-
!paramsObj ||
|
|
605
|
-
typeof paramsObj !== "object" ||
|
|
606
|
-
Array.isArray(paramsObj)
|
|
607
|
-
) {
|
|
608
|
-
return "";
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
// Filter out null/undefined values
|
|
612
|
-
const filteredObj = {};
|
|
613
|
-
for (const key in paramsObj) {
|
|
614
|
-
if (Object.hasOwn(paramsObj, key)) {
|
|
615
|
-
const value = paramsObj[key];
|
|
616
|
-
if (value !== null && value !== undefined) {
|
|
617
|
-
filteredObj[key] = value;
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
if (Object.keys(filteredObj).length === 0) {
|
|
623
|
-
return "";
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// --- CORE LOGIC ---
|
|
627
|
-
// Create URLSearchParams directly from the filtered object
|
|
628
|
-
// This works identically in modern Node.js and browsers.
|
|
629
|
-
const searchParams = new URLSearchParams(filteredObj);
|
|
630
|
-
const queryString = searchParams.toString();
|
|
631
|
-
// --- END CORE LOGIC ---
|
|
632
|
-
|
|
633
|
-
return queryString ? `?${queryString}` : "";
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
function domParser(str) {
|
|
637
|
-
try {
|
|
638
|
-
var mainTag = str.match(/\<(?<tag>[a-z0-9]+)(.*?)?\>/).groups.tag;
|
|
639
|
-
} catch (e) {
|
|
640
|
-
// console.log(e, 'find position: can not find the main tag');
|
|
641
|
-
}
|
|
642
|
-
let doc;
|
|
643
|
-
switch (mainTag) {
|
|
644
|
-
case "html":
|
|
645
|
-
doc = new DOMParser().parseFromString(str, "text/html");
|
|
646
|
-
return doc.documentElement;
|
|
647
|
-
case "body":
|
|
648
|
-
doc = new DOMParser().parseFromString(str, "text/html");
|
|
649
|
-
return doc.body;
|
|
650
|
-
case "head":
|
|
651
|
-
doc = new DOMParser().parseFromString(str, "text/html");
|
|
652
|
-
return doc.head;
|
|
653
|
-
|
|
654
|
-
default:
|
|
655
|
-
let con = document.createElement("dom-parser");
|
|
656
|
-
con.innerHTML = str;
|
|
657
|
-
return con;
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
function parseTextToHtml(text) {
|
|
662
|
-
let doc = new DOMParser().parseFromString(text, "text/html");
|
|
663
|
-
if (doc.head.children[0]) return doc.head.children[0];
|
|
664
|
-
else return doc.body.children[0];
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
function escapeHtml(html) {
|
|
668
|
-
return html
|
|
669
|
-
.replaceAll("&", "&")
|
|
670
|
-
.replaceAll("<", "<")
|
|
671
|
-
.replaceAll(">", ">")
|
|
672
|
-
.replaceAll("'", "'")
|
|
673
|
-
.replaceAll('"', """);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
function cssPath(node, container) {
|
|
677
|
-
let pathSplits = [];
|
|
678
|
-
do {
|
|
679
|
-
if (!node || !node.tagName) return false;
|
|
680
|
-
let pathSplit = node.tagName.toLowerCase();
|
|
681
|
-
|
|
682
|
-
if (node.id) {
|
|
683
|
-
pathSplit += "#" + node.id;
|
|
684
|
-
node = "";
|
|
685
|
-
} else {
|
|
686
|
-
let eid = node.getAttribute("eid");
|
|
687
|
-
if (eid && !/{{\s*([\w\W]+)\s*}}/g.test(eid)) {
|
|
688
|
-
pathSplit += `[eid="${eid}"]`;
|
|
689
|
-
node = "";
|
|
690
|
-
}
|
|
691
|
-
// if (node.classList.length) {
|
|
692
|
-
// node.classList.forEach((item) => {
|
|
693
|
-
// if (item.indexOf(":") === -1) pathSplit += "." + item;
|
|
694
|
-
// });
|
|
695
|
-
// }
|
|
696
|
-
else if (
|
|
697
|
-
node.parentNode &&
|
|
698
|
-
node.parentNode.children.length > 1
|
|
699
|
-
) {
|
|
700
|
-
// TODO: improve array logic so ignores javascript generated html??
|
|
701
|
-
let children = [];
|
|
702
|
-
for (let child of node.parentNode.children) {
|
|
703
|
-
if (child.tagName == node.tagName) children.push(child);
|
|
704
|
-
}
|
|
705
|
-
let index = Array.prototype.indexOf.call(children, node);
|
|
706
|
-
|
|
707
|
-
pathSplit += `:nth-of-type(${index + 1})`;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
node = node.parentNode;
|
|
711
|
-
if (
|
|
712
|
-
node == null ||
|
|
713
|
-
node.tagName == "HTML" ||
|
|
714
|
-
node.tagName == "BODY" ||
|
|
715
|
-
node.tagName == "DOM-PARSER" ||
|
|
716
|
-
node.nodeName == "#document" ||
|
|
717
|
-
node.hasAttribute("contenteditable")
|
|
718
|
-
)
|
|
719
|
-
node = "";
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
pathSplits.unshift(pathSplit);
|
|
723
|
-
} while (node);
|
|
724
|
-
let path = pathSplits.join(" > ");
|
|
725
|
-
if (path && path.includes("<")) {
|
|
726
|
-
let index = path.lastIndexOf(" >");
|
|
727
|
-
if (index != -1) path = path.slice(0, index);
|
|
728
|
-
else {
|
|
729
|
-
index = path.lastIndexOf("<");
|
|
730
|
-
path = path.slice(0, index);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
return path;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
// Define a list of query types that describe relationships or contexts in the DOM.
|
|
738
|
-
const queryTypes = [
|
|
739
|
-
"$closest", // Selects the closest ancestor matching the selector
|
|
740
|
-
"$parent", // Selects the direct parent element
|
|
741
|
-
"$next", // Selects the next sibling element
|
|
742
|
-
"$previous", // Selects the previous sibling element
|
|
743
|
-
"$document", // Selects the document containing the element
|
|
744
|
-
"$frame", // Selects the frame or iframe containing the element
|
|
745
|
-
"$top" // Selects the top-level document or window
|
|
746
|
-
];
|
|
747
|
-
|
|
748
|
-
// Construct a regular expression pattern to match any of the query types.
|
|
749
|
-
// Each query type begins with a dollar sign, which is escaped in the regex.
|
|
750
|
-
const regexPatternString = `(?:${queryTypes
|
|
751
|
-
.map((type) => type.replace("$", "\\$")) // Escape $ character for regex
|
|
752
|
-
.join("|")})`;
|
|
753
|
-
|
|
754
|
-
// Compile the regular expression pattern into a RegExp object.
|
|
755
|
-
// This regex will be used to find the first occurrence of any query type within a string.
|
|
756
|
-
const queryTypesRegex = new RegExp(regexPatternString);
|
|
757
|
-
|
|
758
|
-
/**
|
|
759
|
-
* Function to query DOM elements based on specified criteria.
|
|
760
|
-
* @param {Object} params - Object containing parameters for querying elements.
|
|
761
|
-
* @param {Element|Document} params.element - The root element or document to start the query from. Defaults to the entire document.
|
|
762
|
-
* @param {string} params.prefix - Optional prefix used to construct the query.
|
|
763
|
-
* @param {string} params.selector - The CSS selector or query string to use.
|
|
764
|
-
* @returns {Array} - An array of elements that match the query.
|
|
765
|
-
*/
|
|
766
|
-
function queryElements({ element = document, prefix, selector }) {
|
|
767
|
-
try {
|
|
768
|
-
// Initialize a Set to store unique elements.
|
|
769
|
-
let elements = new Set();
|
|
770
|
-
|
|
771
|
-
// If no selector is provided and the element is an element node.
|
|
772
|
-
if (!selector && element.nodeType === 1) {
|
|
773
|
-
// If no prefix is provided, derive one from the element's attributes.
|
|
774
|
-
if (!prefix) {
|
|
775
|
-
for (let attr of element.attributes) {
|
|
776
|
-
// If an attribute with "-query" suffix is found, extract prefix.
|
|
777
|
-
if (attr.name.endsWith("-query")) {
|
|
778
|
-
prefix = attr.name.slice(0, -6);
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
// If no valid prefix is found, exit the function.
|
|
782
|
-
if (!prefix) return [];
|
|
783
|
-
}
|
|
784
|
-
// Get the selector using the derived prefix.
|
|
785
|
-
selector = element.getAttribute(prefix + "-" + "query");
|
|
786
|
-
if (!selector) return []; // Exit if no selector is found.
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
// Split complex selectors into individual ones, handling nested structures.
|
|
790
|
-
let selectors = selector.split(/,(?![^()\[\]]*[)\]])/g);
|
|
791
|
-
for (let i = 0; i < selectors.length; i++) {
|
|
792
|
-
if (!selectors[i]) continue; // Skip empty selectors.
|
|
793
|
-
|
|
794
|
-
let queriedElement = element; // Start query from the current element.
|
|
795
|
-
|
|
796
|
-
// If media queries are included, verify and filter the selector accordingly.
|
|
797
|
-
if (selectors[i].includes("@")) {
|
|
798
|
-
selectors[i] = checkMediaQueries(selectors[i]);
|
|
799
|
-
if (selectors[i] === false) continue; // Skip if media query is not matched.
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
let remainingSelector = selectors[i].trim(); // Trim any whitespace.
|
|
803
|
-
let match;
|
|
804
|
-
|
|
805
|
-
// Process each part of the selector that corresponds to specific query types/operators.
|
|
806
|
-
while (
|
|
807
|
-
(match = queryTypesRegex.exec(remainingSelector)) !== null
|
|
808
|
-
) {
|
|
809
|
-
const matchIndex = match.index;
|
|
810
|
-
const operator = match[0];
|
|
811
|
-
|
|
812
|
-
// Process the part before the operator (if any).
|
|
813
|
-
const part = remainingSelector
|
|
814
|
-
.substring(0, matchIndex)
|
|
815
|
-
.trim()
|
|
816
|
-
.replace(/,$/, "");
|
|
817
|
-
if (part) {
|
|
818
|
-
queriedElement = querySelector(queriedElement, part);
|
|
819
|
-
if (!queriedElement) break; // Exit loop if no element is found.
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
// Remove the processed part and operator from the remaining selector.
|
|
823
|
-
remainingSelector = remainingSelector
|
|
824
|
-
.substring(matchIndex + operator.length)
|
|
825
|
-
.trim();
|
|
826
|
-
|
|
827
|
-
// Handle the $closest operator specifically.
|
|
828
|
-
if (operator === "$closest") {
|
|
829
|
-
let [closest, remaining = ""] =
|
|
830
|
-
remainingSelector.split(/\s+/, 2);
|
|
831
|
-
queriedElement = queriedElement.closest(closest);
|
|
832
|
-
remainingSelector = remaining.trim();
|
|
833
|
-
} else {
|
|
834
|
-
// Process other operators using the queryType function.
|
|
835
|
-
queriedElement = queryType(queriedElement, operator);
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
if (!queriedElement) break; // Exit loop if no element is found.
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
if (!queriedElement) continue; // Skip if no element is found.
|
|
842
|
-
|
|
843
|
-
// Process the remaining part after the last operator (if any).
|
|
844
|
-
if (remainingSelector) {
|
|
845
|
-
queriedElement = querySelector(
|
|
846
|
-
queriedElement,
|
|
847
|
-
remainingSelector
|
|
848
|
-
);
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
// Add elements to the set.
|
|
852
|
-
if (
|
|
853
|
-
Array.isArray(queriedElement) ||
|
|
854
|
-
queriedElement instanceof HTMLCollection ||
|
|
855
|
-
queriedElement instanceof NodeList
|
|
856
|
-
) {
|
|
857
|
-
for (let el of queriedElement) {
|
|
858
|
-
if (el instanceof Element) {
|
|
859
|
-
elements.add(el);
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
} else if (queriedElement instanceof Element) {
|
|
863
|
-
elements.add(queriedElement);
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
return Array.from(elements); // Convert Set to Array and return found elements.
|
|
868
|
-
} catch (e) {
|
|
869
|
-
console.error(
|
|
870
|
-
`CoCreate: Error in queryElements with selector: "${selector}".`,
|
|
871
|
-
e
|
|
872
|
-
);
|
|
873
|
-
return [];
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
function queryType(element, type) {
|
|
878
|
-
if (!element) return null;
|
|
879
|
-
|
|
880
|
-
switch (type) {
|
|
881
|
-
case "$top":
|
|
882
|
-
return window.top.document;
|
|
883
|
-
case "$frame":
|
|
884
|
-
// If element is a document, return the iframe element containing it
|
|
885
|
-
if (element.nodeType === 9) return window.frameElement;
|
|
886
|
-
// If element is an iframe, return it as is
|
|
887
|
-
return element;
|
|
888
|
-
case "$document":
|
|
889
|
-
// If element is a document, return itself, else return `ownerDocument`
|
|
890
|
-
return element.nodeType === 9 ? element : element.ownerDocument;
|
|
891
|
-
case "$closest":
|
|
892
|
-
// If closest find the first selector seperated by space
|
|
893
|
-
|
|
894
|
-
return element.nodeType === 9 ? element : element.ownerDocument;
|
|
895
|
-
case "$parent":
|
|
896
|
-
// If it's a document, return the parent document (if inside an iframe)
|
|
897
|
-
if (element.nodeType === 9) {
|
|
898
|
-
return element.defaultView !== window.top
|
|
899
|
-
? element.defaultView.parent.document
|
|
900
|
-
: null;
|
|
901
|
-
}
|
|
902
|
-
// Otherwise, return parent element
|
|
903
|
-
return element.parentElement;
|
|
904
|
-
case "$next":
|
|
905
|
-
return element.nextElementSibling;
|
|
906
|
-
case "$previous":
|
|
907
|
-
return element.previousElementSibling;
|
|
908
|
-
default:
|
|
909
|
-
return null;
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
function querySelector(element, selector) {
|
|
914
|
-
if (!element) return null;
|
|
915
|
-
return selector.endsWith("[]")
|
|
916
|
-
? element.querySelectorAll(selector.slice(0, -2))
|
|
917
|
-
: element.querySelector(selector);
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
const mediaRanges = {
|
|
921
|
-
xs: [0, 575],
|
|
922
|
-
sm: [576, 768],
|
|
923
|
-
md: [769, 992],
|
|
924
|
-
lg: [993, 1200],
|
|
925
|
-
xl: [1201, 0]
|
|
926
|
-
};
|
|
927
|
-
|
|
928
|
-
function checkMediaQueries(selector) {
|
|
929
|
-
if (selector && selector.includes("@")) {
|
|
930
|
-
const viewportWidth = window.innerWidth;
|
|
931
|
-
let mediaViewport = false;
|
|
932
|
-
|
|
933
|
-
let screenSizes = selector.split("@");
|
|
934
|
-
selector = screenSizes.shift();
|
|
935
|
-
|
|
936
|
-
for (let screenSize of screenSizes) {
|
|
937
|
-
// Check if screenSize is a valid range in the 'ranges' object
|
|
938
|
-
if (mediaRanges.hasOwnProperty(screenSize)) {
|
|
939
|
-
const [minWidth, maxWidth] = mediaRanges[screenSize];
|
|
940
|
-
if (
|
|
941
|
-
viewportWidth >= minWidth &&
|
|
942
|
-
viewportWidth <= maxWidth
|
|
943
|
-
) {
|
|
944
|
-
mediaViewport = true;
|
|
945
|
-
break;
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
if (!mediaViewport) return false;
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
return selector;
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
function queryData(data, query) {
|
|
956
|
-
if (query.$and) {
|
|
957
|
-
for (let i = 0; i < query.$and.length; i++) {
|
|
958
|
-
if (!queryData(data, query.$and[i])) return false;
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
if (query.$nor) {
|
|
963
|
-
for (let i = 0; i < query.$nor.length; i++) {
|
|
964
|
-
if (queryData(data, query.$nor[i])) return false;
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
for (let key of Object.keys(query)) {
|
|
969
|
-
if (key === "$and" || key === "$or") continue;
|
|
970
|
-
if (!queryMatch(data, { [key]: query[key] })) return false;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
if (query.$or) {
|
|
974
|
-
for (let i = 0; i < query.$or.length; i++) {
|
|
975
|
-
if (queryData(data, query.$or[i])) return true;
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
return true;
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
function queryMatch(data, query) {
|
|
983
|
-
for (let key of Object.keys(query)) {
|
|
984
|
-
// if (!data.hasOwnProperty(key))
|
|
985
|
-
// return false
|
|
986
|
-
|
|
987
|
-
let dataValue;
|
|
988
|
-
try {
|
|
989
|
-
dataValue = getValueFromObject(data, key, true);
|
|
990
|
-
} catch (error) {
|
|
991
|
-
return false;
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
if (
|
|
995
|
-
typeof query[key] === "string" ||
|
|
996
|
-
typeof query[key] === "number" ||
|
|
997
|
-
typeof query[key] === "boolean"
|
|
998
|
-
) {
|
|
999
|
-
if (Array.isArray(dataValue))
|
|
1000
|
-
return dataValue.includes(query[key]);
|
|
1001
|
-
else return dataValue === query[key];
|
|
1002
|
-
} else if (Array.isArray(query[key])) {
|
|
1003
|
-
if (Array.isArray(dataValue)) {
|
|
1004
|
-
return isEqualArray(dataValue, query[key]);
|
|
1005
|
-
} else {
|
|
1006
|
-
return false;
|
|
1007
|
-
}
|
|
1008
|
-
} else {
|
|
1009
|
-
for (let property of Object.keys(query[key])) {
|
|
1010
|
-
if (property === "$options") continue;
|
|
1011
|
-
if (!property.startsWith("$")) {
|
|
1012
|
-
if (typeof dataValue !== "object") {
|
|
1013
|
-
return false;
|
|
1014
|
-
} else
|
|
1015
|
-
return queryMatch(
|
|
1016
|
-
{
|
|
1017
|
-
[property]: getValueFromObject(
|
|
1018
|
-
dataValue,
|
|
1019
|
-
property
|
|
1020
|
-
)
|
|
1021
|
-
},
|
|
1022
|
-
{ [property]: query[key][property] }
|
|
1023
|
-
);
|
|
1024
|
-
} else {
|
|
1025
|
-
let queryValue = query[key][property];
|
|
1026
|
-
if (isValidDate(queryValue) && isValidDate(dataValue)) {
|
|
1027
|
-
queryValue = new Date(queryValue);
|
|
1028
|
-
dataValue = new Date(dataValue);
|
|
1029
|
-
}
|
|
1030
|
-
let queryStatus = false;
|
|
1031
|
-
switch (property) {
|
|
1032
|
-
case "$eq":
|
|
1033
|
-
if (
|
|
1034
|
-
Array.isArray(dataValue) &&
|
|
1035
|
-
Array.isArray(queryValue)
|
|
1036
|
-
) {
|
|
1037
|
-
queryStatus = isEqualArray(
|
|
1038
|
-
dataValue,
|
|
1039
|
-
queryValue
|
|
1040
|
-
);
|
|
1041
|
-
} else {
|
|
1042
|
-
queryStatus = dataValue === queryValue;
|
|
1043
|
-
}
|
|
1044
|
-
break;
|
|
1045
|
-
case "$ne":
|
|
1046
|
-
if (
|
|
1047
|
-
Array.isArray(dataValue) &&
|
|
1048
|
-
Array.isArray(queryValue)
|
|
1049
|
-
) {
|
|
1050
|
-
queryStatus = !isEqualArray(
|
|
1051
|
-
dataValue,
|
|
1052
|
-
queryValue
|
|
1053
|
-
);
|
|
1054
|
-
} else {
|
|
1055
|
-
queryStatus = dataValue !== queryValue;
|
|
1056
|
-
}
|
|
1057
|
-
break;
|
|
1058
|
-
case "$not":
|
|
1059
|
-
queryStatus = !queryMatch(data, {
|
|
1060
|
-
[key]: query[key]["$not"]
|
|
1061
|
-
});
|
|
1062
|
-
break;
|
|
1063
|
-
case "$lt":
|
|
1064
|
-
queryStatus = dataValue < queryValue;
|
|
1065
|
-
break;
|
|
1066
|
-
case "$lte":
|
|
1067
|
-
queryStatus = dataValue <= queryValue;
|
|
1068
|
-
break;
|
|
1069
|
-
case "$gt":
|
|
1070
|
-
queryStatus = dataValue > queryValue;
|
|
1071
|
-
break;
|
|
1072
|
-
case "$gte":
|
|
1073
|
-
queryStatus = dataValue >= queryValue;
|
|
1074
|
-
break;
|
|
1075
|
-
case "$in":
|
|
1076
|
-
if (Array.isArray(dataValue)) {
|
|
1077
|
-
queryStatus = dataValue.some((element) =>
|
|
1078
|
-
queryValue.includes(element)
|
|
1079
|
-
);
|
|
1080
|
-
} else {
|
|
1081
|
-
queryStatus =
|
|
1082
|
-
queryValue.includes(dataValue);
|
|
1083
|
-
}
|
|
1084
|
-
break;
|
|
1085
|
-
case "$nin":
|
|
1086
|
-
if (Array.isArray(dataValue)) {
|
|
1087
|
-
queryStatus = !dataValue.some((element) =>
|
|
1088
|
-
queryValue.includes(element)
|
|
1089
|
-
);
|
|
1090
|
-
} else {
|
|
1091
|
-
queryStatus =
|
|
1092
|
-
!queryValue.includes(dataValue);
|
|
1093
|
-
}
|
|
1094
|
-
break;
|
|
1095
|
-
case "$all":
|
|
1096
|
-
if (
|
|
1097
|
-
Array.isArray(dataValue) &&
|
|
1098
|
-
Array.isArray(queryValue)
|
|
1099
|
-
) {
|
|
1100
|
-
queryStatus = queryValue.every((element) =>
|
|
1101
|
-
dataValue.includes(element)
|
|
1102
|
-
);
|
|
1103
|
-
}
|
|
1104
|
-
break;
|
|
1105
|
-
case "$elemMatch":
|
|
1106
|
-
if (Array.isArray(data[key])) {
|
|
1107
|
-
queryStatus = data[key].some((element) =>
|
|
1108
|
-
queryMatch(
|
|
1109
|
-
element,
|
|
1110
|
-
query[key][property]
|
|
1111
|
-
)
|
|
1112
|
-
);
|
|
1113
|
-
}
|
|
1114
|
-
break;
|
|
1115
|
-
case "$size":
|
|
1116
|
-
if (Array.isArray(dataValue)) {
|
|
1117
|
-
queryStatus =
|
|
1118
|
-
dataValue.length === queryValue;
|
|
1119
|
-
}
|
|
1120
|
-
break;
|
|
1121
|
-
case "$exists":
|
|
1122
|
-
queryStatus = queryValue
|
|
1123
|
-
? data.hasOwnProperty(key)
|
|
1124
|
-
: !data.hasOwnProperty(key);
|
|
1125
|
-
break;
|
|
1126
|
-
case "$regex":
|
|
1127
|
-
if (typeof dataValue === "string") {
|
|
1128
|
-
let regexFlag =
|
|
1129
|
-
query[key]["$options"] || "";
|
|
1130
|
-
let regex = new RegExp(
|
|
1131
|
-
queryValue,
|
|
1132
|
-
regexFlag
|
|
1133
|
-
);
|
|
1134
|
-
queryStatus = regex.test(dataValue);
|
|
1135
|
-
}
|
|
1136
|
-
break;
|
|
1137
|
-
case "$type":
|
|
1138
|
-
let dataType = typeof dataValue;
|
|
1139
|
-
if (Array.isArray(dataValue)) {
|
|
1140
|
-
dataType = "array";
|
|
1141
|
-
}
|
|
1142
|
-
queryStatus = dataType === queryValue;
|
|
1143
|
-
break;
|
|
1144
|
-
case "$mod":
|
|
1145
|
-
if (
|
|
1146
|
-
typeof dataValue === "number" &&
|
|
1147
|
-
Array.isArray(queryValue) &&
|
|
1148
|
-
queryValue.length === 2
|
|
1149
|
-
) {
|
|
1150
|
-
const [divisor, remainder] = queryValue;
|
|
1151
|
-
queryStatus =
|
|
1152
|
-
dataValue % divisor === remainder;
|
|
1153
|
-
}
|
|
1154
|
-
break;
|
|
1155
|
-
case "$where":
|
|
1156
|
-
if (typeof queryValue === "function") {
|
|
1157
|
-
try {
|
|
1158
|
-
// queryStatus = queryValue.call(data);
|
|
1159
|
-
} catch (error) {
|
|
1160
|
-
console.error(
|
|
1161
|
-
"Error in queryData $where function:",
|
|
1162
|
-
error
|
|
1163
|
-
);
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
break;
|
|
1167
|
-
|
|
1168
|
-
default:
|
|
1169
|
-
console.log("unknown operator");
|
|
1170
|
-
break;
|
|
1171
|
-
}
|
|
1172
|
-
if (!queryStatus) return false;
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
return true;
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
function isEqualArray(arr1, arr2) {
|
|
1181
|
-
if (arr1.length !== arr2.length) {
|
|
1182
|
-
return false;
|
|
1183
|
-
}
|
|
1184
|
-
for (let i = 0; i < arr1.length; i++) {
|
|
1185
|
-
if (!isEqualObject(arr1[i], arr2[i])) {
|
|
1186
|
-
return false;
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
return true;
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
function isEqualObject(obj1, obj2) {
|
|
1193
|
-
const keys1 = Object.keys(obj1);
|
|
1194
|
-
const keys2 = Object.keys(obj2);
|
|
1195
|
-
|
|
1196
|
-
if (keys1.length !== keys2.length) {
|
|
1197
|
-
return false;
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
for (const key of keys1) {
|
|
1201
|
-
if (obj1[key] !== obj2[key]) {
|
|
1202
|
-
return false;
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
return true;
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
function searchData(data, search) {
|
|
1210
|
-
if (!search) return true;
|
|
1211
|
-
if (!Array.isArray(search)) search = [search];
|
|
1212
|
-
for (let i = 0; i < search.length; i++) {
|
|
1213
|
-
let searchValue = search[i].value;
|
|
1214
|
-
if (!Array.isArray(searchValue)) searchValue = [searchValue];
|
|
1215
|
-
for (let key in data) {
|
|
1216
|
-
let value = data[key];
|
|
1217
|
-
let status = false;
|
|
1218
|
-
switch (typeof value) {
|
|
1219
|
-
case "number":
|
|
1220
|
-
value = value.toString();
|
|
1221
|
-
break;
|
|
1222
|
-
case "object":
|
|
1223
|
-
value = JSON.stringify(value);
|
|
1224
|
-
break;
|
|
1225
|
-
case "function":
|
|
1226
|
-
value = value.toString();
|
|
1227
|
-
break;
|
|
1228
|
-
}
|
|
1229
|
-
if (
|
|
1230
|
-
search[i].caseSensitive != "true" ||
|
|
1231
|
-
search[i].caseSensitive != true
|
|
1232
|
-
)
|
|
1233
|
-
value = value.toLowerCase();
|
|
1234
|
-
|
|
1235
|
-
for (let i = 0; i < searchValue.length; i++) {
|
|
1236
|
-
let searchString = searchValue[i];
|
|
1237
|
-
if (
|
|
1238
|
-
search[i].caseSensitive != "true" ||
|
|
1239
|
-
search[i].caseSensitive != true
|
|
1240
|
-
)
|
|
1241
|
-
searchString = searchString.toLowerCase();
|
|
1242
|
-
|
|
1243
|
-
if (searchString === "" && search[i].operator === "and") {
|
|
1244
|
-
if (value !== "") return false;
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
if (value.indexOf(searchString) > -1) status = true;
|
|
1248
|
-
|
|
1249
|
-
if (status) return true;
|
|
1250
|
-
else if (search[i].operator == "and") return false;
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
if (search[i].value.length && search[i].operator == "or")
|
|
1254
|
-
return false;
|
|
1255
|
-
}
|
|
1256
|
-
return true;
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
function sortData(data, sort) {
|
|
1260
|
-
return data.sort((a, b) => {
|
|
1261
|
-
for (let i = 0; i < sort.length; i++) {
|
|
1262
|
-
let key = sort[i].key;
|
|
1263
|
-
if (a[key] == null && b[key] == null) continue;
|
|
1264
|
-
if (a[key] == null)
|
|
1265
|
-
return sort[i].direction === "desc" ? -1 : 1;
|
|
1266
|
-
if (b[key] == null)
|
|
1267
|
-
return sort[i].direction === "desc" ? 1 : -1;
|
|
1268
|
-
|
|
1269
|
-
if (typeof a[key] !== typeof b[key]) {
|
|
1270
|
-
return typeof a[key] < typeof b[key] ? -1 : 1;
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
if (a[key] !== b[key]) {
|
|
1274
|
-
if (typeof a[key] === "string") {
|
|
1275
|
-
return sort[i].direction === "desc"
|
|
1276
|
-
? b[key].localeCompare(a[key])
|
|
1277
|
-
: a[key].localeCompare(b[key]);
|
|
1278
|
-
} else {
|
|
1279
|
-
// Assuming numeric or other comparable types
|
|
1280
|
-
return sort[i].direction === "desc"
|
|
1281
|
-
? b[key] - a[key]
|
|
1282
|
-
: a[key] - b[key];
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
return 0;
|
|
1287
|
-
});
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
function getAttributes(el) {
|
|
1291
|
-
if (!el) return;
|
|
1292
|
-
|
|
1293
|
-
let attributes = window.CoCreateConfig.attributes;
|
|
1294
|
-
let object = {};
|
|
1295
|
-
|
|
1296
|
-
for (let attribute of el.attributes) {
|
|
1297
|
-
let variable = attributes[attribute.name];
|
|
1298
|
-
if (variable) {
|
|
1299
|
-
object[variable] = el.getAttribute(attribute.name);
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
return object;
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
function getAttributeNames(variables) {
|
|
1307
|
-
let reversedObject = {};
|
|
1308
|
-
for (const key of Object.keys(CoCreateConfig.attributes)) {
|
|
1309
|
-
reversedObject[CoCreateConfig.attributes[key]] = key;
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
let attributes = [];
|
|
1313
|
-
for (const variable of variables) {
|
|
1314
|
-
let attribute = reversedObject[variable];
|
|
1315
|
-
if (attribute) attributes.push(attribute);
|
|
1316
|
-
}
|
|
1317
|
-
return attributes;
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
function setAttributeNames(attributes, overWrite) {
|
|
1321
|
-
let reversedObject = {};
|
|
1322
|
-
for (const key of Object.keys(CoCreateConfig.attributes)) {
|
|
1323
|
-
reversedObject[CoCreateConfig.attributes[key]] = key;
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
for (const attribute of Object.keys(attributes)) {
|
|
1327
|
-
const variable = attributes[attribute];
|
|
1328
|
-
if (!reversedObject[variable] || overWrite != false)
|
|
1329
|
-
reversedObject[variable] = attribute;
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
|
-
let revertObject = {};
|
|
1333
|
-
for (const key of Object.keys(reversedObject)) {
|
|
1334
|
-
revertObject[reversedObject[key]] = key;
|
|
1335
|
-
}
|
|
1336
|
-
CoCreateConfig.attributes = revertObject;
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1339
|
-
if (isBrowser) clickedElement();
|
|
1340
|
-
|
|
1341
|
-
return {
|
|
1342
|
-
getRelativePath,
|
|
1343
|
-
ObjectId,
|
|
1344
|
-
uid,
|
|
1345
|
-
checkValue,
|
|
1346
|
-
isValidDate,
|
|
1347
|
-
dotNotationToObject,
|
|
1348
|
-
objectToDotNotation,
|
|
1349
|
-
getValueFromObject,
|
|
1350
|
-
objectToSearchParams,
|
|
1351
|
-
domParser,
|
|
1352
|
-
parseTextToHtml,
|
|
1353
|
-
escapeHtml,
|
|
1354
|
-
cssPath,
|
|
1355
|
-
queryElements,
|
|
1356
|
-
checkMediaQueries,
|
|
1357
|
-
queryData,
|
|
1358
|
-
searchData,
|
|
1359
|
-
sortData,
|
|
1360
|
-
createUpdate,
|
|
1361
|
-
getAttributes,
|
|
1362
|
-
setAttributeNames,
|
|
1363
|
-
getAttributeNames
|
|
1364
|
-
};
|
|
1365
|
-
});
|
|
1
|
+
export { getRelativePath } from "./getRelativePath.js";
|
|
2
|
+
export { ObjectId } from "./ObjectId.js";
|
|
3
|
+
export { uid } from "./uid.js";
|
|
4
|
+
export { checkValue } from "./checkValue.js";
|
|
5
|
+
export { isValidDate } from "./isValidDate.js";
|
|
6
|
+
export { objectToSearchParams } from "./objectToSearchParams.js";
|
|
7
|
+
export { dotNotationToObject } from "./dotNotationToObject.js";
|
|
8
|
+
export { objectToDotNotation } from "./objectToDotNotation.js";
|
|
9
|
+
export { getValueFromObject } from "./getValueFromObject.js";
|
|
10
|
+
export { createUpdate } from "./createUpdate.js";
|
|
11
|
+
export { domParser } from "./domParser.js";
|
|
12
|
+
export { parseTextToHtml } from "./parseTextToHtml.js";
|
|
13
|
+
export { escapeHtml } from "./escapeHtml.js";
|
|
14
|
+
export { cssPath } from "./cssPath.js";
|
|
15
|
+
export { queryElements, checkMediaQueries } from "./queryElements.js";
|
|
16
|
+
export { queryData, searchData, sortData } from "./dataQuery.js";
|
|
17
|
+
export { getAttributes, getAttributeNames, setAttributeNames } from "./attributes.js";
|
|
18
|
+
export { safeParse } from "./safeParse.js";
|
|
19
|
+
export { clickedElement } from "./clickedElement.js";
|
|
20
|
+
export { processOperators, processOperatorsAsync } from "./operators.js";
|
|
21
|
+
|
|
22
|
+
import { getRelativePath } from "./getRelativePath.js";
|
|
23
|
+
import { ObjectId } from "./ObjectId.js";
|
|
24
|
+
import { uid } from "./uid.js";
|
|
25
|
+
import { checkValue } from "./checkValue.js";
|
|
26
|
+
import { isValidDate } from "./isValidDate.js";
|
|
27
|
+
import { objectToSearchParams } from "./objectToSearchParams.js";
|
|
28
|
+
import { dotNotationToObject } from "./dotNotationToObject.js";
|
|
29
|
+
import { objectToDotNotation } from "./objectToDotNotation.js";
|
|
30
|
+
import { getValueFromObject } from "./getValueFromObject.js";
|
|
31
|
+
import { createUpdate } from "./createUpdate.js";
|
|
32
|
+
import { domParser } from "./domParser.js";
|
|
33
|
+
import { parseTextToHtml } from "./parseTextToHtml.js";
|
|
34
|
+
import { escapeHtml } from "./escapeHtml.js";
|
|
35
|
+
import { cssPath } from "./cssPath.js";
|
|
36
|
+
import { queryElements, checkMediaQueries } from "./queryElements.js";
|
|
37
|
+
import { queryData, searchData, sortData } from "./dataQuery.js";
|
|
38
|
+
import { getAttributes, getAttributeNames, setAttributeNames } from "./attributes.js";
|
|
39
|
+
import { safeParse } from "./safeParse.js";
|
|
40
|
+
import { processOperators, processOperatorsAsync } from "./operators.js";
|
|
41
|
+
|
|
42
|
+
const utils = {
|
|
43
|
+
getRelativePath,
|
|
44
|
+
ObjectId,
|
|
45
|
+
uid,
|
|
46
|
+
checkValue,
|
|
47
|
+
isValidDate,
|
|
48
|
+
dotNotationToObject,
|
|
49
|
+
objectToDotNotation,
|
|
50
|
+
getValueFromObject,
|
|
51
|
+
objectToSearchParams,
|
|
52
|
+
domParser,
|
|
53
|
+
parseTextToHtml,
|
|
54
|
+
escapeHtml,
|
|
55
|
+
cssPath,
|
|
56
|
+
queryElements,
|
|
57
|
+
checkMediaQueries,
|
|
58
|
+
queryData,
|
|
59
|
+
searchData,
|
|
60
|
+
sortData,
|
|
61
|
+
createUpdate,
|
|
62
|
+
getAttributes,
|
|
63
|
+
setAttributeNames,
|
|
64
|
+
getAttributeNames,
|
|
65
|
+
safeParse,
|
|
66
|
+
processOperators,
|
|
67
|
+
processOperatorsAsync
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export default utils;
|