@cocreate/element-prototype 1.30.0 → 1.31.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 +7 -0
- package/package.json +1 -1
- package/src/getValue.js +54 -0
- package/src/operators.js +68 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [1.31.0](https://github.com/CoCreate-app/CoCreate-element-prototype/compare/v1.30.0...v1.31.0) (2025-11-16)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* enhance date handling in getValue and add custom operators for number formatting and UID generation ([280a469](https://github.com/CoCreate-app/CoCreate-element-prototype/commit/280a469d7c8b007c4cb2ed35ac7f4645327ac25e))
|
|
7
|
+
|
|
1
8
|
# [1.30.0](https://github.com/CoCreate-app/CoCreate-element-prototype/compare/v1.29.3...v1.30.0) (2025-10-11)
|
|
2
9
|
|
|
3
10
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocreate/element-prototype",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.31.0",
|
|
4
4
|
"description": "A simple element-prototype component in vanilla javascript. Easily configured using HTML5 data-attributes and/or JavaScript API.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"element-prototype",
|
package/src/getValue.js
CHANGED
|
@@ -203,6 +203,8 @@ const handleDateTime = (element, value, valueType) => {
|
|
|
203
203
|
} else if (value) {
|
|
204
204
|
// Initialize a new Date from the string or object
|
|
205
205
|
value = new Date(value);
|
|
206
|
+
} else {
|
|
207
|
+
value = new Date();
|
|
206
208
|
}
|
|
207
209
|
|
|
208
210
|
// Check if value is a valid date
|
|
@@ -255,6 +257,58 @@ const handleDateTime = (element, value, valueType) => {
|
|
|
255
257
|
let locale = element.getAttribute("locale") || "en-US";
|
|
256
258
|
value = value.toLocaleString(locale);
|
|
257
259
|
break;
|
|
260
|
+
case "addDays":
|
|
261
|
+
// Add days to the current date
|
|
262
|
+
const addDays = parseInt(element.getAttribute("add-days") || 0, 10);
|
|
263
|
+
value.setDate(value.getDate() + addDays);
|
|
264
|
+
value = value.toISOString();
|
|
265
|
+
break;
|
|
266
|
+
case "subtractDays":
|
|
267
|
+
// Subtract days from the current date
|
|
268
|
+
const subtractDays = parseInt(element.getAttribute("subtract-days") || 0, 10);
|
|
269
|
+
value.setDate(value.getDate() - subtractDays);
|
|
270
|
+
value = value.toISOString();
|
|
271
|
+
break;
|
|
272
|
+
case "startOfDay":
|
|
273
|
+
// Get the start of the current day (12:00 midnight)
|
|
274
|
+
const startOfDay = new Date(value);
|
|
275
|
+
startOfDay.setHours(0, 0, 0, 0); // Set time to midnight
|
|
276
|
+
value = startOfDay.toISOString();
|
|
277
|
+
break;
|
|
278
|
+
case "startOfWeek":
|
|
279
|
+
// Get the start of the current week (Sunday by default)
|
|
280
|
+
const startOfWeekOffset = parseInt(element.getAttribute("week-start-day") || 0, 10); // Default to Sunday (0)
|
|
281
|
+
const startOfWeek = new Date(value);
|
|
282
|
+
startOfWeek.setDate(value.getDate() - value.getDay() + startOfWeekOffset);
|
|
283
|
+
startOfWeek.setHours(0, 0, 0, 0); // Set to midnight
|
|
284
|
+
value = startOfWeek.toISOString();
|
|
285
|
+
break;
|
|
286
|
+
case "endOfWeek":
|
|
287
|
+
// Get the end of the current week (Saturday by default)
|
|
288
|
+
const endOfWeekOffset = parseInt(element.getAttribute("week-start-day") || 0, 10); // Default to Sunday (0)
|
|
289
|
+
const endOfWeek = new Date(value);
|
|
290
|
+
endOfWeek.setDate(value.getDate() - value.getDay() + 6 + endOfWeekOffset);
|
|
291
|
+
endOfWeek.setHours(23, 59, 59, 999); // Set to the end of the day
|
|
292
|
+
value = endOfWeek.toISOString();
|
|
293
|
+
break;
|
|
294
|
+
case "startOfMonth":
|
|
295
|
+
// Get the start of the month
|
|
296
|
+
value = new Date(value.getFullYear(), value.getMonth(), 1).toISOString();
|
|
297
|
+
break;
|
|
298
|
+
case "endOfMonth":
|
|
299
|
+
// Get the end of the month
|
|
300
|
+
value = new Date(value.getFullYear(), value.getMonth() + 1, 0).toISOString();
|
|
301
|
+
break;
|
|
302
|
+
case "startOfYear":
|
|
303
|
+
// Get the start of the year
|
|
304
|
+
value = new Date(value.getFullYear(), 0, 1).toISOString();
|
|
305
|
+
break;
|
|
306
|
+
case "endOfYear":
|
|
307
|
+
// Get the end of the year
|
|
308
|
+
value = new Date(value.getFullYear(), 11, 31).toISOString();
|
|
309
|
+
break;
|
|
310
|
+
|
|
311
|
+
|
|
258
312
|
default:
|
|
259
313
|
if (typeof value[valueType] === "function") {
|
|
260
314
|
value = value[valueType]();
|
package/src/operators.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ObjectId, queryElements, getValueFromObject } from "@cocreate/utils";
|
|
1
|
+
import { ObjectId, queryElements, getValueFromObject, uid } from "@cocreate/utils";
|
|
2
2
|
|
|
3
3
|
// Operators handled directly for simple, synchronous value retrieval
|
|
4
4
|
const customOperators = new Map(
|
|
@@ -54,7 +54,28 @@ const customOperators = new Map(
|
|
|
54
54
|
} catch (e) {
|
|
55
55
|
return value;
|
|
56
56
|
}
|
|
57
|
-
}
|
|
57
|
+
},
|
|
58
|
+
// TODO: Implement number formatting
|
|
59
|
+
$numberFormat: (element, args) => {
|
|
60
|
+
let number = parseFloat(args[0]);
|
|
61
|
+
// Simple, fixed arg mapping:
|
|
62
|
+
// args[0] = locale (internationalization)
|
|
63
|
+
// args[1] = options (object)
|
|
64
|
+
// args[2] = number (if provided). If not provided, fall back to legacy behavior where args[0] might be the number.
|
|
65
|
+
if (!Array.isArray(args)) args = [args];
|
|
66
|
+
|
|
67
|
+
const locale = args[0] || undefined;
|
|
68
|
+
const options = args[1] || {};
|
|
69
|
+
const numCandidate = args[2] !== undefined ? args[2] : args[0];
|
|
70
|
+
|
|
71
|
+
number = parseFloat(numCandidate);
|
|
72
|
+
|
|
73
|
+
if (isNaN(number)) return String(numCandidate ?? "");
|
|
74
|
+
|
|
75
|
+
return new Intl.NumberFormat(locale, options).format(number);
|
|
76
|
+
},
|
|
77
|
+
$uid: (element, args) => uid(args[0]) || "",
|
|
78
|
+
|
|
58
79
|
})
|
|
59
80
|
);
|
|
60
81
|
|
|
@@ -206,19 +227,32 @@ const findInnermostFunctionCall = (expression) => {
|
|
|
206
227
|
* @returns {{operator: string, args: string, rawContent: string, fullMatch?: string} | {operator: null, args: string, rawContent: string}}
|
|
207
228
|
*/
|
|
208
229
|
const findInnermostOperator = (expression) => {
|
|
209
|
-
|
|
230
|
+
// Helper function to strip leading and trailing parentheses from a string
|
|
231
|
+
function stripParentheses(str) {
|
|
232
|
+
let result = str;
|
|
233
|
+
if (result.startsWith("(")) {
|
|
234
|
+
result = result.substring(1);
|
|
235
|
+
}
|
|
236
|
+
if (result.endsWith(")")) {
|
|
237
|
+
result = result.substring(0, result.length - 1);
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
let args;
|
|
242
|
+
|
|
210
243
|
// --- 1. PRIORITY: Find Innermost FUNCTION CALL (Operator with Parentheses) ---
|
|
211
244
|
const functionCall = findInnermostFunctionCall(expression);
|
|
212
245
|
|
|
213
246
|
if (functionCall) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
247
|
+
// Return the full function expression details, including the full string section
|
|
248
|
+
args = stripParentheses(functionCall.args);
|
|
249
|
+
return {
|
|
250
|
+
operator: functionCall.operator,
|
|
251
|
+
args, // Arguments without parentheses
|
|
252
|
+
rawContent: functionCall.args, // The content inside the parentheses (arguments)
|
|
253
|
+
fullMatch: functionCall.fullMatch // The operator(args) string (the complete section to replace)
|
|
254
|
+
};
|
|
255
|
+
}
|
|
222
256
|
|
|
223
257
|
// --- 2. FALLBACK: Find BARE OPERATOR (e.g., $value path) ---
|
|
224
258
|
|
|
@@ -229,18 +263,22 @@ const findInnermostOperator = (expression) => {
|
|
|
229
263
|
const innermostOperator = findBareOperatorInPath(rawContent, knownOperatorKeys);
|
|
230
264
|
|
|
231
265
|
if (innermostOperator) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
266
|
+
const operatorArgs = rawContent.substring(innermostOperator.length).trim();
|
|
267
|
+
args = stripParentheses(operatorArgs);
|
|
268
|
+
return {
|
|
269
|
+
operator: innermostOperator,
|
|
270
|
+
args, // Arguments without parentheses
|
|
271
|
+
rawContent: rawContent,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
239
275
|
|
|
276
|
+
args = stripParentheses(rawContent);
|
|
277
|
+
|
|
240
278
|
// Fallback if no known operator is found
|
|
241
279
|
return {
|
|
242
280
|
operator: null,
|
|
243
|
-
args
|
|
281
|
+
args,
|
|
244
282
|
rawContent: rawContent
|
|
245
283
|
};
|
|
246
284
|
};
|
|
@@ -276,6 +314,7 @@ function processOperators(
|
|
|
276
314
|
|
|
277
315
|
let processedValue = value;
|
|
278
316
|
let hasPromise = false;
|
|
317
|
+
let parsedValue = null
|
|
279
318
|
|
|
280
319
|
while (processedValue.includes("$")) {
|
|
281
320
|
|
|
@@ -336,9 +375,18 @@ function processOperators(
|
|
|
336
375
|
replacement = resolvedValue ?? "";
|
|
337
376
|
}
|
|
338
377
|
|
|
339
|
-
|
|
378
|
+
if (processedValue === textToReplace) {
|
|
379
|
+
processedValue = replacement;
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
|
|
340
383
|
processedValue = processedValue.replace(textToReplace, replacement);
|
|
341
384
|
|
|
385
|
+
if (!processedValue.includes("$")) {
|
|
386
|
+
// If there are still unresolved operators, we need to continue processing
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
|
|
342
390
|
} else {
|
|
343
391
|
// If operator is excluded, we need to advance past it to avoid infinite loop
|
|
344
392
|
break;
|