@schukai/monster 3.95.2 → 3.96.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 (31) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/package.json +1 -1
  3. package/source/components/datatable/dataset.mjs +23 -19
  4. package/source/components/datatable/datasource/dom.mjs +4 -6
  5. package/source/components/datatable/datasource/rest.mjs +469 -471
  6. package/source/components/datatable/datasource.mjs +0 -8
  7. package/source/components/datatable/pagination.mjs +433 -439
  8. package/source/components/datatable/status.mjs +1 -3
  9. package/source/components/datatable/stylesheet/pagination.mjs +13 -6
  10. package/source/components/datatable/util.mjs +1 -1
  11. package/source/components/form/select.mjs +1 -1
  12. package/source/components/form/toggle-switch.mjs +2 -6
  13. package/source/components/layout/tabs.mjs +897 -895
  14. package/source/components/notify/message.mjs +10 -14
  15. package/source/components/notify/notify.mjs +9 -13
  16. package/source/components/notify/stylesheet/notify.mjs +13 -6
  17. package/source/components/state/log.mjs +184 -184
  18. package/source/components/state/stylesheet/log.mjs +13 -6
  19. package/source/data/datasource/server/restapi.mjs +2 -3
  20. package/source/data/transformer.mjs +803 -806
  21. package/source/dom/customelement.mjs +0 -34
  22. package/source/dom/updater.mjs +767 -767
  23. package/source/i18n/time-ago.mjs +1352 -636
  24. package/source/monster.mjs +2 -0
  25. package/source/types/has.mjs +3 -6
  26. package/source/types/version.mjs +1 -1
  27. package/test/cases/components/form/form.mjs +166 -125
  28. package/test/cases/monster.mjs +1 -1
  29. package/test/web/import.js +1 -0
  30. package/test/web/test.html +2 -2
  31. package/test/web/tests.js +2080 -1433
@@ -12,28 +12,28 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import {getLocaleOfDocument} from "../dom/locale.mjs";
16
- import {Base} from "../types/base.mjs";
17
- import {getGlobal, getGlobalObject} from "../types/global.mjs";
18
- import {ID} from "../types/id.mjs";
19
- import {isArray, isObject, isString, isPrimitive} from "../types/is.mjs";
15
+ import { getLocaleOfDocument } from "../dom/locale.mjs";
16
+ import { Base } from "../types/base.mjs";
17
+ import { getGlobal, getGlobalObject } from "../types/global.mjs";
18
+ import { ID } from "../types/id.mjs";
19
+ import { isArray, isObject, isString, isPrimitive } from "../types/is.mjs";
20
20
  import {
21
- getDocumentTranslations,
22
- Translations,
21
+ getDocumentTranslations,
22
+ Translations,
23
23
  } from "../i18n/translations.mjs";
24
24
  import {
25
- validateFunction,
26
- validateInteger,
27
- validateObject,
28
- validatePrimitive,
29
- validateString,
30
- validateBoolean,
25
+ validateFunction,
26
+ validateInteger,
27
+ validateObject,
28
+ validatePrimitive,
29
+ validateString,
30
+ validateBoolean,
31
31
  } from "../types/validate.mjs";
32
- import {clone} from "../util/clone.mjs";
33
- import {Pathfinder} from "./pathfinder.mjs";
34
- import {formatTimeAgo} from "../i18n/time-ago.mjs";
32
+ import { clone } from "../util/clone.mjs";
33
+ import { Pathfinder } from "./pathfinder.mjs";
34
+ import { formatTimeAgo } from "../i18n/time-ago.mjs";
35
35
 
36
- export {Transformer};
36
+ export { Transformer };
37
37
 
38
38
  /**
39
39
  * The transformer class is a swiss army knife for manipulating values.
@@ -53,53 +53,53 @@ export {Transformer};
53
53
  * @summary The transformer class is a swiss army knife for manipulating values. especially in combination with the pipe, processing chains can be built up.
54
54
  */
55
55
  class Transformer extends Base {
56
- /**
57
- *
58
- * @param {string} definition
59
- */
60
- constructor(definition) {
61
- super();
62
- this.args = disassemble(definition);
63
- this.command = this.args.shift();
64
- this.callbacks = new Map();
65
- }
66
-
67
- /**
68
- *
69
- * @param {string} name
70
- * @param {function} callback
71
- * @param {object} context
72
- * @return {Transformer}
73
- * @throws {TypeError} value is not a string
74
- * @throws {TypeError} value is not a function
75
- */
76
- setCallback(name, callback, context) {
77
- validateString(name);
78
- validateFunction(callback);
79
-
80
- if (context !== undefined) {
81
- validateObject(context);
82
- }
83
-
84
- this.callbacks.set(name, {
85
- callback: callback,
86
- context: context,
87
- });
88
-
89
- return this;
90
- }
91
-
92
- /**
93
- *
94
- * @param {*} value
95
- * @return {*}
96
- * @throws {Error} unknown command
97
- * @throws {TypeError} unsupported type
98
- * @throws {Error} type not supported
99
- */
100
- run(value) {
101
- return transform.apply(this, [value]);
102
- }
56
+ /**
57
+ *
58
+ * @param {string} definition
59
+ */
60
+ constructor(definition) {
61
+ super();
62
+ this.args = disassemble(definition);
63
+ this.command = this.args.shift();
64
+ this.callbacks = new Map();
65
+ }
66
+
67
+ /**
68
+ *
69
+ * @param {string} name
70
+ * @param {function} callback
71
+ * @param {object} context
72
+ * @return {Transformer}
73
+ * @throws {TypeError} value is not a string
74
+ * @throws {TypeError} value is not a function
75
+ */
76
+ setCallback(name, callback, context) {
77
+ validateString(name);
78
+ validateFunction(callback);
79
+
80
+ if (context !== undefined) {
81
+ validateObject(context);
82
+ }
83
+
84
+ this.callbacks.set(name, {
85
+ callback: callback,
86
+ context: context,
87
+ });
88
+
89
+ return this;
90
+ }
91
+
92
+ /**
93
+ *
94
+ * @param {*} value
95
+ * @return {*}
96
+ * @throws {Error} unknown command
97
+ * @throws {TypeError} unsupported type
98
+ * @throws {Error} type not supported
99
+ */
100
+ run(value) {
101
+ return transform.apply(this, [value]);
102
+ }
103
103
  }
104
104
 
105
105
  /**
@@ -109,41 +109,41 @@ class Transformer extends Base {
109
109
  * @private
110
110
  */
111
111
  function disassemble(command) {
112
- validateString(command);
113
-
114
- const placeholder = new Map();
115
- const regex = /((?<pattern>\\(?<char>.)){1})/gim;
116
-
117
- // The separator for args must be escaped
118
- // undefined string which should not occur normally and is also not a regex
119
- const result = command.matchAll(regex);
120
-
121
- for (const m of result) {
122
- const g = m?.["groups"];
123
- if (!isObject(g)) {
124
- continue;
125
- }
126
-
127
- const p = g?.["pattern"];
128
- const c = g?.["char"];
129
-
130
- if (p && c) {
131
- const r = `__${new ID().toString()}__`;
132
- placeholder.set(r, c);
133
- command = command.replace(p, r);
134
- }
135
- }
136
- let parts = command.split(":");
137
-
138
- parts = parts.map(function (value) {
139
- let v = value.trim();
140
- for (const k of placeholder) {
141
- v = v.replace(k[0], k[1]);
142
- }
143
- return v;
144
- });
145
-
146
- return parts;
112
+ validateString(command);
113
+
114
+ const placeholder = new Map();
115
+ const regex = /((?<pattern>\\(?<char>.)){1})/gim;
116
+
117
+ // The separator for args must be escaped
118
+ // undefined string which should not occur normally and is also not a regex
119
+ const result = command.matchAll(regex);
120
+
121
+ for (const m of result) {
122
+ const g = m?.["groups"];
123
+ if (!isObject(g)) {
124
+ continue;
125
+ }
126
+
127
+ const p = g?.["pattern"];
128
+ const c = g?.["char"];
129
+
130
+ if (p && c) {
131
+ const r = `__${new ID().toString()}__`;
132
+ placeholder.set(r, c);
133
+ command = command.replace(p, r);
134
+ }
135
+ }
136
+ let parts = command.split(":");
137
+
138
+ parts = parts.map(function (value) {
139
+ let v = value.trim();
140
+ for (const k of placeholder) {
141
+ v = v.replace(k[0], k[1]);
142
+ }
143
+ return v;
144
+ });
145
+
146
+ return parts;
147
147
  }
148
148
 
149
149
  /**
@@ -154,12 +154,12 @@ function disassemble(command) {
154
154
  * @private
155
155
  */
156
156
  function convertToString(value) {
157
- if (isObject(value) && value.hasOwnProperty("toString")) {
158
- value = value.toString();
159
- }
157
+ if (isObject(value) && value.hasOwnProperty("toString")) {
158
+ value = value.toString();
159
+ }
160
160
 
161
- validateString(value);
162
- return value;
161
+ validateString(value);
162
+ return value;
163
163
  }
164
164
 
165
165
  /**
@@ -173,680 +173,680 @@ function convertToString(value) {
173
173
  * @throws {Error} missing key parameter
174
174
  */
175
175
  function transform(value) {
176
- const console = getGlobalObject("console");
177
-
178
- const args = clone(this.args);
179
- let key;
180
- let defaultValue;
181
-
182
- let translations;
183
- let date;
184
- let locale;
185
- let timestamp;
186
- let map;
187
- let keyValue;
188
-
189
- switch (this.command) {
190
- case "static":
191
- return this.args.join(":");
192
-
193
- case "tolower":
194
- case "strtolower":
195
- case "tolowercase":
196
- validateString(value);
197
- return value.toLowerCase();
198
-
199
- case "contains":
200
- if (isString(value)) {
201
- return value.includes(args[0]);
202
- }
203
-
204
- if (isArray(value)) {
205
- return value.includes(args[0]);
206
- }
207
-
208
- if (isObject(value)) {
209
- return value.hasOwnProperty(args[0]);
210
- }
211
-
212
- return false;
213
-
214
- case "has-entries":
215
- case "hasentries":
216
- if (isObject(value)) {
217
- return Object.keys(value).length > 0;
218
- }
219
-
220
- if (isArray(value)) {
221
- return value.length > 0;
222
- }
223
-
224
- return false;
225
-
226
- case "isundefined":
227
- case "is-undefined":
228
- return value === undefined;
229
-
230
- case "isnull":
231
- case "is-null":
232
- return value === null;
233
-
234
- case "isset":
235
- case "is-set":
236
- return value !== undefined && value !== null;
237
-
238
- case "isnumber":
239
- case "is-number":
240
- return isPrimitive(value) && !isNaN(value);
241
-
242
- case "isinteger":
243
- case "is-integer":
244
- return isPrimitive(value) && !isNaN(value) && value % 1 === 0;
245
-
246
- case "isfloat":
247
- case "is-float":
248
- return isPrimitive(value) && !isNaN(value) && value % 1 !== 0;
249
-
250
- case "isobject":
251
- case "is-object":
252
- return isObject(value);
253
-
254
- case "isarray":
255
- case "is-array":
256
- return Array.isArray(value);
257
-
258
- case "not":
259
- validateBoolean(value);
260
- return !value;
261
-
262
- case "toupper":
263
- case "strtoupper":
264
- case "touppercase":
265
- validateString(value);
266
- return value.toUpperCase();
267
-
268
- case "tostring":
269
- return `${value}`;
270
-
271
- case "tointeger":
272
- const n = parseInt(value);
273
- validateInteger(n);
274
- return n;
275
-
276
- case "to-json":
277
- case "tojson":
278
- return JSON.stringify(value);
279
-
280
- case "from-json":
281
- case "fromjson":
282
- return JSON.parse(value);
283
-
284
- case "trim":
285
- validateString(value);
286
- return value.trim();
287
-
288
- case "rawurlencode":
289
- validateString(value);
290
- return encodeURIComponent(value)
291
- .replace(/!/g, "%21")
292
- .replace(/'/g, "%27")
293
- .replace(/\(/g, "%28")
294
- .replace(/\)/g, "%29")
295
- .replace(/\*/g, "%2A");
296
-
297
- case "call":
298
- /**
299
- * callback-definition
300
- * function callback(value, ...args) {
301
- * return value;
302
- * }
303
- */
304
-
305
- let callback;
306
- const callbackName = args.shift();
307
- let context = getGlobal();
308
-
309
- if (isObject(value) && value.hasOwnProperty(callbackName)) {
310
- callback = value[callbackName];
311
- } else if (this.callbacks.has(callbackName)) {
312
- const s = this.callbacks.get(callbackName);
313
- callback = s?.["callback"];
314
- context = s?.["context"];
315
- } else if (
316
- typeof window === "object" &&
317
- window.hasOwnProperty(callbackName)
318
- ) {
319
- callback = window[callbackName];
320
- }
321
- validateFunction(callback);
322
-
323
- args.unshift(value);
324
- return callback.call(context, ...args);
325
-
326
- case "plain":
327
- case "plaintext":
328
- validateString(value);
329
- const doc = new DOMParser().parseFromString(value, "text/html");
330
- return doc.body.textContent || "";
331
-
332
- case "if":
333
- case "?":
334
- validatePrimitive(value);
335
-
336
- let trueStatement = args.shift() || undefined;
337
- let falseStatement = args.shift() || undefined;
338
-
339
- trueStatement = convertSpecialStrings(trueStatement, value);
340
- falseStatement = convertSpecialStrings(falseStatement, value);
341
-
342
- const condition = evaluateCondition(value);
343
- return condition ? trueStatement : falseStatement;
344
-
345
- case "ucfirst":
346
- validateString(value);
347
-
348
- const firstchar = value.charAt(0).toUpperCase();
349
- return firstchar + value.substr(1);
350
- case "ucwords":
351
- validateString(value);
352
-
353
- return value.replace(
354
- /^([a-z\u00E0-\u00FC])|\s+([a-z\u00E0-\u00FC])/g,
355
- function (v) {
356
- return v.toUpperCase();
357
- },
358
- );
359
-
360
- case "count":
361
- case "length":
362
- if (
363
- (isString(value) || isObject(value) || isArray(value)) &&
364
- value.hasOwnProperty("length")
365
- ) {
366
- return value.length;
367
- }
368
-
369
- throw new TypeError(`unsupported type ${typeof value}`);
370
-
371
- case "to-base64":
372
- case "btoa":
373
- case "base64":
374
- return btoa(convertToString(value));
375
-
376
- case "atob":
377
- case "from-base64":
378
- return atob(convertToString(value));
379
-
380
- case "empty":
381
- return "";
382
-
383
- case "undefined":
384
- return undefined;
385
-
386
- case "debug":
387
- if (isObject(console)) {
388
- console.log(value);
389
- }
390
-
391
- return value;
392
-
393
- case "prefix":
394
- validateString(value);
395
- const prefix = args?.[0];
396
- return prefix + value;
397
-
398
- case "suffix":
399
- validateString(value);
400
- const suffix = args?.[0];
401
- return value + suffix;
402
-
403
- case "uniqid":
404
- return new ID().toString();
405
-
406
- case "first-key":
407
- case "last-key":
408
- case "nth-last-key":
409
- case "nth-key":
410
- if (!isObject(value)) {
411
- throw new Error("type not supported");
412
- }
413
-
414
- const keys = Object.keys(value).sort();
415
-
416
- if (this.command === "first-key") {
417
- key = 0;
418
- } else if (this.command === "last-key") {
419
- key = keys.length - 1;
420
- } else {
421
- key = validateInteger(parseInt(args.shift()));
422
-
423
- if (this.command === "nth-last-key") {
424
- key = keys.length - key - 1;
425
- }
426
- }
427
-
428
- defaultValue = args.shift() || "";
429
-
430
- const useKey = keys?.[key];
431
-
432
- if (value?.[useKey]) {
433
- return value?.[useKey];
434
- }
435
-
436
- return defaultValue;
437
-
438
- case "key":
439
- case "property":
440
- case "index":
441
- key = args.shift() || undefined;
442
-
443
- if (key === undefined) {
444
- throw new Error("missing key parameter");
445
- }
446
-
447
- defaultValue = args.shift() || undefined;
448
-
449
- if (value instanceof Map) {
450
- if (!value.has(key)) {
451
- return defaultValue;
452
- }
453
- return value.get(key);
454
- }
455
-
456
- if (isObject(value) || isArray(value)) {
457
- if (value?.[key]) {
458
- return value?.[key];
459
- }
460
-
461
- return defaultValue;
462
- }
463
-
464
- throw new Error("type not supported");
465
-
466
- case "path-exists":
467
- key = args.shift();
468
- if (key === undefined) {
469
- throw new Error("missing key parameter");
470
- }
471
-
472
- return new Pathfinder(value).exists(key);
473
-
474
- case "concat":
475
- const pf2 = new Pathfinder(value);
476
- let concat = "";
477
- while (args.length > 0) {
478
- key = args.shift();
479
- if (key === undefined) {
480
- throw new Error("missing key parameter");
481
- }
482
-
483
- // add empty strings
484
- if (isString(key) && key.trim() === "") {
485
- concat += key;
486
- continue;
487
- }
488
-
489
- if (!pf2.exists(key)) {
490
- concat += key;
491
- continue;
492
- }
493
- const v = pf2.getVia(key);
494
- if (!isPrimitive(v)) {
495
- throw new Error("value is not primitive");
496
- }
497
-
498
- concat += v;
499
- }
500
-
501
- return concat;
502
- case "path":
503
- key = args.shift();
504
- if (key === undefined) {
505
- throw new Error("missing key parameter");
506
- }
507
-
508
- const pf = new Pathfinder(value);
509
-
510
- if (!pf.exists(key)) {
511
- return undefined;
512
- }
513
-
514
- return pf.getVia(key);
515
-
516
- case "substring":
517
- validateString(value);
518
-
519
- const start = parseInt(args[0]) || 0;
520
- const end = (parseInt(args[1]) || 0) + start;
521
-
522
- return value.substring(start, end);
523
-
524
- case "nop":
525
- return value;
526
-
527
- case "??":
528
- case "default":
529
- if (value !== undefined && value !== null) {
530
- return value;
531
- }
532
-
533
- defaultValue = args.shift();
534
- let defaultType = args.shift();
535
- if (defaultType === undefined) {
536
- defaultType = "string";
537
- }
538
-
539
- switch (defaultType) {
540
- case "int":
541
- case "integer":
542
- return parseInt(defaultValue);
543
- case "float":
544
- return parseFloat(defaultValue);
545
- case "undefined":
546
- return undefined;
547
- case "bool":
548
- case "boolean":
549
- defaultValue = defaultValue.toLowerCase();
550
- return (
551
- (defaultValue !== "undefined" &&
552
- defaultValue !== "" &&
553
- defaultValue !== "off" &&
554
- defaultValue !== "false" &&
555
- defaultValue !== "false") ||
556
- defaultValue === "on" ||
557
- defaultValue === "true" ||
558
- defaultValue === "true"
559
- );
560
- case "string":
561
- return `${defaultValue}`;
562
- case "object":
563
- return JSON.parse(atob(defaultValue));
564
- }
565
-
566
- throw new Error("type not supported");
567
-
568
- case "map":
569
- map = new Map();
570
- while (args.length > 0) {
571
- keyValue = args.shift();
572
- if (keyValue === undefined) {
573
- throw new Error("missing key parameter");
574
- }
575
-
576
- keyValue = keyValue.split("=");
577
- map.set(keyValue[0], keyValue[1]);
578
- }
579
-
580
- return map.get(value);
581
-
582
- case "equals":
583
- if (args.length === 0) {
584
- throw new Error("missing value parameter");
585
- }
586
-
587
- validatePrimitive(value);
588
-
589
- const equalsValue = args.shift();
590
-
591
- /**
592
- * The history of “typeof null”
593
- * https://2ality.com/2013/10/typeof-null.html
594
- * In JavaScript, typeof null is 'object', which incorrectly suggests
595
- * that null is an object.
596
- */
597
- if (value === null) {
598
- return equalsValue === "null";
599
- }
600
-
601
- const typeOfValue = typeof value;
602
-
603
- switch (typeOfValue) {
604
- case "string":
605
- return value === equalsValue;
606
- case "number":
607
- return value === parseFloat(equalsValue);
608
- case "boolean":
609
- return value === (equalsValue === "true" || equalsValue === "on");
610
- case "undefined":
611
- return equalsValue === "undefined";
612
- default:
613
- throw new Error("type not supported");
614
- }
615
-
616
- case "money":
617
- case "currency":
618
- try {
619
- locale = getLocaleOfDocument();
620
- } catch (e) {
621
- throw new Error(`unsupported locale or missing format (${e.message})`);
622
- }
623
-
624
- // Verwenden von RegExp, um Währung und Betrag zu extrahieren
625
- const match = value.match(/^([A-Z]{3})[\s-]*(\d+(\.\d+)?)$/);
626
- if (!match) {
627
- throw new Error("invalid currency format");
628
- }
629
-
630
- const currency = match[1];
631
- const amount = match[2];
632
-
633
- const maximumFractionDigits = args?.[0] || 2;
634
- const roundingIncrement = args?.[1] || 5;
635
-
636
- const nf = new Intl.NumberFormat(locale.toString(), {
637
- style: "currency",
638
- currency: currency,
639
- maximumFractionDigits: maximumFractionDigits,
640
- roundingIncrement: roundingIncrement,
641
- });
642
-
643
- return nf.format(amount);
644
-
645
- case "timestamp":
646
- date = new Date(value);
647
- timestamp = date.getTime();
648
- if (isNaN(timestamp)) {
649
- throw new Error("invalid date");
650
- }
651
- return timestamp;
652
-
653
- case "time":
654
- date = new Date(value);
655
- if (isNaN(date.getTime())) {
656
- throw new Error("invalid date");
657
- }
658
-
659
- try {
660
- locale = getLocaleOfDocument();
661
- return date.toLocaleTimeString(locale.toString(), {
662
- hour12: false,
663
- });
664
- } catch (e) {
665
- throw new Error(`unsupported locale or missing format (${e.message})`);
666
- }
667
-
668
- case "datetimeformat":
669
- date = new Date(value);
670
- if (isNaN(date.getTime())) {
671
- throw new Error("invalid date");
672
- }
673
-
674
- const options = {
675
- dateStyle: "medium",
676
- timeStyle: "medium",
677
- hour12: false,
678
- };
679
-
680
- if (args.length > 0) {
681
- options.dateStyle = args.shift();
682
- }
683
-
684
- if (args.length > 0) {
685
- options.timeStyle = args.shift();
686
- }
687
-
688
- try {
689
- locale = getLocaleOfDocument().toString();
690
- return new Intl.DateTimeFormat(locale, options).format(date);
691
- } catch (e) {
692
- throw new Error(`unsupported locale or missing format (${e.message})`);
693
- }
694
-
695
- case "datetime":
696
- date = new Date(value);
697
- if (isNaN(date.getTime())) {
698
- throw new Error("invalid date");
699
- }
700
-
701
- try {
702
- locale = getLocaleOfDocument();
703
- return date.toLocaleString(locale.toString(), {
704
- hour12: false,
705
- });
706
- } catch (e) {
707
- throw new Error(`unsupported locale or missing format (${e.message})`);
708
- }
709
-
710
- case "date":
711
- date = new Date(value);
712
- if (isNaN(date.getTime())) {
713
- throw new Error("invalid date");
714
- }
715
-
716
- try {
717
- locale = getLocaleOfDocument();
718
- return date.toLocaleDateString(locale.toString(), {
719
- year: "numeric",
720
- month: "2-digit",
721
- day: "2-digit",
722
- });
723
- } catch (e) {
724
- throw new Error(`unsupported locale or missing format (${e.message})`);
725
- }
726
-
727
- case "time-ago":
728
- date = new Date(value);
729
- if (isNaN(date.getTime())) {
730
- throw new Error("invalid date");
731
- }
732
-
733
- try {
734
- locale = getLocaleOfDocument();
735
- return formatTimeAgo(date, locale.toString());
736
- } catch (e) {
737
- throw new Error(`unsupported locale or missing format (${e.message})`);
738
- }
739
-
740
- case "year":
741
- date = new Date(value);
742
- if (isNaN(date.getTime())) {
743
- throw new Error("invalid date");
744
- }
745
-
746
- return date.getFullYear();
747
-
748
- case "month":
749
- date = new Date(value);
750
- if (isNaN(date.getTime())) {
751
- throw new Error("invalid date");
752
- }
753
-
754
- return date.getMonth() + 1;
755
-
756
- case "day":
757
- date = new Date(value);
758
- if (isNaN(date.getTime())) {
759
- throw new Error("invalid date");
760
- }
761
-
762
- return date.getDate();
763
-
764
- case "weekday":
765
- date = new Date(value);
766
- if (isNaN(date.getTime())) {
767
- throw new Error("invalid date");
768
- }
769
-
770
- return date.getDay();
771
-
772
- case "hour":
773
- case "hours":
774
- date = new Date(value);
775
- if (isNaN(date.getTime())) {
776
- throw new Error("invalid date");
777
- }
778
-
779
- return date.getHours();
780
-
781
- case "minute":
782
- case "minutes":
783
- date = new Date(value);
784
- if (isNaN(date.getTime())) {
785
- throw new Error("invalid date");
786
- }
787
-
788
- return date.getMinutes();
789
-
790
- case "second":
791
- case "seconds":
792
- date = new Date(value);
793
- if (isNaN(date.getTime())) {
794
- throw new Error("invalid date");
795
- }
796
-
797
- return date.getSeconds();
798
-
799
- case "i18n":
800
- case "translation":
801
- translations = getDocumentTranslations();
802
- if (!(translations instanceof Translations)) {
803
- throw new Error("missing translations");
804
- }
805
-
806
- key = args.shift() || undefined;
807
- if (key === undefined) {
808
- key = value;
809
- }
810
-
811
- defaultValue = args.shift() || undefined;
812
-
813
- defaultValue = convertSpecialStrings(defaultValue, value);
814
-
815
- return translations.getText(key, defaultValue);
816
-
817
- case "set-toggle":
818
- case "set-set":
819
- case "set-remove":
820
- const modifier = args.shift();
821
- let delimiter = args.shift();
822
- if (delimiter === undefined) {
823
- delimiter = " ";
824
- }
825
-
826
- const set = new Set(value.split(delimiter));
827
- const toggle = new Set(modifier.split(delimiter));
828
- if (this.command === "set-toggle") {
829
- for (const t of toggle) {
830
- if (set.has(t)) {
831
- set.delete(t);
832
- } else {
833
- set.add(t);
834
- }
835
- }
836
- } else if (this.command === "set-set") {
837
- for (const t of toggle) {
838
- set.add(t);
839
- }
840
- } else if (this.command === "set-remove") {
841
- for (const t of toggle) {
842
- set.delete(t);
843
- }
844
- }
845
- return Array.from(set).join(delimiter);
846
-
847
- default:
848
- throw new Error(`unknown command ${this.command}`);
849
- }
176
+ const console = getGlobalObject("console");
177
+
178
+ const args = clone(this.args);
179
+ let key;
180
+ let defaultValue;
181
+
182
+ let translations;
183
+ let date;
184
+ let locale;
185
+ let timestamp;
186
+ let map;
187
+ let keyValue;
188
+
189
+ switch (this.command) {
190
+ case "static":
191
+ return this.args.join(":");
192
+
193
+ case "tolower":
194
+ case "strtolower":
195
+ case "tolowercase":
196
+ validateString(value);
197
+ return value.toLowerCase();
198
+
199
+ case "contains":
200
+ if (isString(value)) {
201
+ return value.includes(args[0]);
202
+ }
203
+
204
+ if (isArray(value)) {
205
+ return value.includes(args[0]);
206
+ }
207
+
208
+ if (isObject(value)) {
209
+ return value.hasOwnProperty(args[0]);
210
+ }
211
+
212
+ return false;
213
+
214
+ case "has-entries":
215
+ case "hasentries":
216
+ if (isObject(value)) {
217
+ return Object.keys(value).length > 0;
218
+ }
219
+
220
+ if (isArray(value)) {
221
+ return value.length > 0;
222
+ }
223
+
224
+ return false;
225
+
226
+ case "isundefined":
227
+ case "is-undefined":
228
+ return value === undefined;
229
+
230
+ case "isnull":
231
+ case "is-null":
232
+ return value === null;
233
+
234
+ case "isset":
235
+ case "is-set":
236
+ return value !== undefined && value !== null;
237
+
238
+ case "isnumber":
239
+ case "is-number":
240
+ return isPrimitive(value) && !isNaN(value);
241
+
242
+ case "isinteger":
243
+ case "is-integer":
244
+ return isPrimitive(value) && !isNaN(value) && value % 1 === 0;
245
+
246
+ case "isfloat":
247
+ case "is-float":
248
+ return isPrimitive(value) && !isNaN(value) && value % 1 !== 0;
249
+
250
+ case "isobject":
251
+ case "is-object":
252
+ return isObject(value);
253
+
254
+ case "isarray":
255
+ case "is-array":
256
+ return Array.isArray(value);
257
+
258
+ case "not":
259
+ validateBoolean(value);
260
+ return !value;
261
+
262
+ case "toupper":
263
+ case "strtoupper":
264
+ case "touppercase":
265
+ validateString(value);
266
+ return value.toUpperCase();
267
+
268
+ case "tostring":
269
+ return `${value}`;
270
+
271
+ case "tointeger":
272
+ const n = parseInt(value);
273
+ validateInteger(n);
274
+ return n;
275
+
276
+ case "to-json":
277
+ case "tojson":
278
+ return JSON.stringify(value);
279
+
280
+ case "from-json":
281
+ case "fromjson":
282
+ return JSON.parse(value);
283
+
284
+ case "trim":
285
+ validateString(value);
286
+ return value.trim();
287
+
288
+ case "rawurlencode":
289
+ validateString(value);
290
+ return encodeURIComponent(value)
291
+ .replace(/!/g, "%21")
292
+ .replace(/'/g, "%27")
293
+ .replace(/\(/g, "%28")
294
+ .replace(/\)/g, "%29")
295
+ .replace(/\*/g, "%2A");
296
+
297
+ case "call":
298
+ /**
299
+ * callback-definition
300
+ * function callback(value, ...args) {
301
+ * return value;
302
+ * }
303
+ */
304
+
305
+ let callback;
306
+ const callbackName = args.shift();
307
+ let context = getGlobal();
308
+
309
+ if (isObject(value) && value.hasOwnProperty(callbackName)) {
310
+ callback = value[callbackName];
311
+ } else if (this.callbacks.has(callbackName)) {
312
+ const s = this.callbacks.get(callbackName);
313
+ callback = s?.["callback"];
314
+ context = s?.["context"];
315
+ } else if (
316
+ typeof window === "object" &&
317
+ window.hasOwnProperty(callbackName)
318
+ ) {
319
+ callback = window[callbackName];
320
+ }
321
+ validateFunction(callback);
322
+
323
+ args.unshift(value);
324
+ return callback.call(context, ...args);
325
+
326
+ case "plain":
327
+ case "plaintext":
328
+ validateString(value);
329
+ const doc = new DOMParser().parseFromString(value, "text/html");
330
+ return doc.body.textContent || "";
331
+
332
+ case "if":
333
+ case "?":
334
+ validatePrimitive(value);
335
+
336
+ let trueStatement = args.shift() || undefined;
337
+ let falseStatement = args.shift() || undefined;
338
+
339
+ trueStatement = convertSpecialStrings(trueStatement, value);
340
+ falseStatement = convertSpecialStrings(falseStatement, value);
341
+
342
+ const condition = evaluateCondition(value);
343
+ return condition ? trueStatement : falseStatement;
344
+
345
+ case "ucfirst":
346
+ validateString(value);
347
+
348
+ const firstchar = value.charAt(0).toUpperCase();
349
+ return firstchar + value.substr(1);
350
+ case "ucwords":
351
+ validateString(value);
352
+
353
+ return value.replace(
354
+ /^([a-z\u00E0-\u00FC])|\s+([a-z\u00E0-\u00FC])/g,
355
+ function (v) {
356
+ return v.toUpperCase();
357
+ },
358
+ );
359
+
360
+ case "count":
361
+ case "length":
362
+ if (
363
+ (isString(value) || isObject(value) || isArray(value)) &&
364
+ value.hasOwnProperty("length")
365
+ ) {
366
+ return value.length;
367
+ }
368
+
369
+ throw new TypeError(`unsupported type ${typeof value}`);
370
+
371
+ case "to-base64":
372
+ case "btoa":
373
+ case "base64":
374
+ return btoa(convertToString(value));
375
+
376
+ case "atob":
377
+ case "from-base64":
378
+ return atob(convertToString(value));
379
+
380
+ case "empty":
381
+ return "";
382
+
383
+ case "undefined":
384
+ return undefined;
385
+
386
+ case "debug":
387
+ if (isObject(console)) {
388
+ console.log(value);
389
+ }
390
+
391
+ return value;
392
+
393
+ case "prefix":
394
+ validateString(value);
395
+ const prefix = args?.[0];
396
+ return prefix + value;
397
+
398
+ case "suffix":
399
+ validateString(value);
400
+ const suffix = args?.[0];
401
+ return value + suffix;
402
+
403
+ case "uniqid":
404
+ return new ID().toString();
405
+
406
+ case "first-key":
407
+ case "last-key":
408
+ case "nth-last-key":
409
+ case "nth-key":
410
+ if (!isObject(value)) {
411
+ throw new Error("type not supported");
412
+ }
413
+
414
+ const keys = Object.keys(value).sort();
415
+
416
+ if (this.command === "first-key") {
417
+ key = 0;
418
+ } else if (this.command === "last-key") {
419
+ key = keys.length - 1;
420
+ } else {
421
+ key = validateInteger(parseInt(args.shift()));
422
+
423
+ if (this.command === "nth-last-key") {
424
+ key = keys.length - key - 1;
425
+ }
426
+ }
427
+
428
+ defaultValue = args.shift() || "";
429
+
430
+ const useKey = keys?.[key];
431
+
432
+ if (value?.[useKey]) {
433
+ return value?.[useKey];
434
+ }
435
+
436
+ return defaultValue;
437
+
438
+ case "key":
439
+ case "property":
440
+ case "index":
441
+ key = args.shift() || undefined;
442
+
443
+ if (key === undefined) {
444
+ throw new Error("missing key parameter");
445
+ }
446
+
447
+ defaultValue = args.shift() || undefined;
448
+
449
+ if (value instanceof Map) {
450
+ if (!value.has(key)) {
451
+ return defaultValue;
452
+ }
453
+ return value.get(key);
454
+ }
455
+
456
+ if (isObject(value) || isArray(value)) {
457
+ if (value?.[key]) {
458
+ return value?.[key];
459
+ }
460
+
461
+ return defaultValue;
462
+ }
463
+
464
+ throw new Error("type not supported");
465
+
466
+ case "path-exists":
467
+ key = args.shift();
468
+ if (key === undefined) {
469
+ throw new Error("missing key parameter");
470
+ }
471
+
472
+ return new Pathfinder(value).exists(key);
473
+
474
+ case "concat":
475
+ const pf2 = new Pathfinder(value);
476
+ let concat = "";
477
+ while (args.length > 0) {
478
+ key = args.shift();
479
+ if (key === undefined) {
480
+ throw new Error("missing key parameter");
481
+ }
482
+
483
+ // add empty strings
484
+ if (isString(key) && key.trim() === "") {
485
+ concat += key;
486
+ continue;
487
+ }
488
+
489
+ if (!pf2.exists(key)) {
490
+ concat += key;
491
+ continue;
492
+ }
493
+ const v = pf2.getVia(key);
494
+ if (!isPrimitive(v)) {
495
+ throw new Error("value is not primitive");
496
+ }
497
+
498
+ concat += v;
499
+ }
500
+
501
+ return concat;
502
+ case "path":
503
+ key = args.shift();
504
+ if (key === undefined) {
505
+ throw new Error("missing key parameter");
506
+ }
507
+
508
+ const pf = new Pathfinder(value);
509
+
510
+ if (!pf.exists(key)) {
511
+ return undefined;
512
+ }
513
+
514
+ return pf.getVia(key);
515
+
516
+ case "substring":
517
+ validateString(value);
518
+
519
+ const start = parseInt(args[0]) || 0;
520
+ const end = (parseInt(args[1]) || 0) + start;
521
+
522
+ return value.substring(start, end);
523
+
524
+ case "nop":
525
+ return value;
526
+
527
+ case "??":
528
+ case "default":
529
+ if (value !== undefined && value !== null) {
530
+ return value;
531
+ }
532
+
533
+ defaultValue = args.shift();
534
+ let defaultType = args.shift();
535
+ if (defaultType === undefined) {
536
+ defaultType = "string";
537
+ }
538
+
539
+ switch (defaultType) {
540
+ case "int":
541
+ case "integer":
542
+ return parseInt(defaultValue);
543
+ case "float":
544
+ return parseFloat(defaultValue);
545
+ case "undefined":
546
+ return undefined;
547
+ case "bool":
548
+ case "boolean":
549
+ defaultValue = defaultValue.toLowerCase();
550
+ return (
551
+ (defaultValue !== "undefined" &&
552
+ defaultValue !== "" &&
553
+ defaultValue !== "off" &&
554
+ defaultValue !== "false" &&
555
+ defaultValue !== "false") ||
556
+ defaultValue === "on" ||
557
+ defaultValue === "true" ||
558
+ defaultValue === "true"
559
+ );
560
+ case "string":
561
+ return `${defaultValue}`;
562
+ case "object":
563
+ return JSON.parse(atob(defaultValue));
564
+ }
565
+
566
+ throw new Error("type not supported");
567
+
568
+ case "map":
569
+ map = new Map();
570
+ while (args.length > 0) {
571
+ keyValue = args.shift();
572
+ if (keyValue === undefined) {
573
+ throw new Error("missing key parameter");
574
+ }
575
+
576
+ keyValue = keyValue.split("=");
577
+ map.set(keyValue[0], keyValue[1]);
578
+ }
579
+
580
+ return map.get(value);
581
+
582
+ case "equals":
583
+ if (args.length === 0) {
584
+ throw new Error("missing value parameter");
585
+ }
586
+
587
+ validatePrimitive(value);
588
+
589
+ const equalsValue = args.shift();
590
+
591
+ /**
592
+ * The history of “typeof null”
593
+ * https://2ality.com/2013/10/typeof-null.html
594
+ * In JavaScript, typeof null is 'object', which incorrectly suggests
595
+ * that null is an object.
596
+ */
597
+ if (value === null) {
598
+ return equalsValue === "null";
599
+ }
600
+
601
+ const typeOfValue = typeof value;
602
+
603
+ switch (typeOfValue) {
604
+ case "string":
605
+ return value === equalsValue;
606
+ case "number":
607
+ return value === parseFloat(equalsValue);
608
+ case "boolean":
609
+ return value === (equalsValue === "true" || equalsValue === "on");
610
+ case "undefined":
611
+ return equalsValue === "undefined";
612
+ default:
613
+ throw new Error("type not supported");
614
+ }
615
+
616
+ case "money":
617
+ case "currency":
618
+ try {
619
+ locale = getLocaleOfDocument();
620
+ } catch (e) {
621
+ throw new Error(`unsupported locale or missing format (${e.message})`);
622
+ }
623
+
624
+ // Verwenden von RegExp, um Währung und Betrag zu extrahieren
625
+ const match = value.match(/^([A-Z]{3})[\s-]*(\d+(\.\d+)?)$/);
626
+ if (!match) {
627
+ throw new Error("invalid currency format");
628
+ }
629
+
630
+ const currency = match[1];
631
+ const amount = match[2];
632
+
633
+ const maximumFractionDigits = args?.[0] || 2;
634
+ const roundingIncrement = args?.[1] || 5;
635
+
636
+ const nf = new Intl.NumberFormat(locale.toString(), {
637
+ style: "currency",
638
+ currency: currency,
639
+ maximumFractionDigits: maximumFractionDigits,
640
+ roundingIncrement: roundingIncrement,
641
+ });
642
+
643
+ return nf.format(amount);
644
+
645
+ case "timestamp":
646
+ date = new Date(value);
647
+ timestamp = date.getTime();
648
+ if (isNaN(timestamp)) {
649
+ throw new Error("invalid date");
650
+ }
651
+ return timestamp;
652
+
653
+ case "time":
654
+ date = new Date(value);
655
+ if (isNaN(date.getTime())) {
656
+ throw new Error("invalid date");
657
+ }
658
+
659
+ try {
660
+ locale = getLocaleOfDocument();
661
+ return date.toLocaleTimeString(locale.toString(), {
662
+ hour12: false,
663
+ });
664
+ } catch (e) {
665
+ throw new Error(`unsupported locale or missing format (${e.message})`);
666
+ }
667
+
668
+ case "datetimeformat":
669
+ date = new Date(value);
670
+ if (isNaN(date.getTime())) {
671
+ throw new Error("invalid date");
672
+ }
673
+
674
+ const options = {
675
+ dateStyle: "medium",
676
+ timeStyle: "medium",
677
+ hour12: false,
678
+ };
679
+
680
+ if (args.length > 0) {
681
+ options.dateStyle = args.shift();
682
+ }
683
+
684
+ if (args.length > 0) {
685
+ options.timeStyle = args.shift();
686
+ }
687
+
688
+ try {
689
+ locale = getLocaleOfDocument().toString();
690
+ return new Intl.DateTimeFormat(locale, options).format(date);
691
+ } catch (e) {
692
+ throw new Error(`unsupported locale or missing format (${e.message})`);
693
+ }
694
+
695
+ case "datetime":
696
+ date = new Date(value);
697
+ if (isNaN(date.getTime())) {
698
+ throw new Error("invalid date");
699
+ }
700
+
701
+ try {
702
+ locale = getLocaleOfDocument();
703
+ return date.toLocaleString(locale.toString(), {
704
+ hour12: false,
705
+ });
706
+ } catch (e) {
707
+ throw new Error(`unsupported locale or missing format (${e.message})`);
708
+ }
709
+
710
+ case "date":
711
+ date = new Date(value);
712
+ if (isNaN(date.getTime())) {
713
+ throw new Error("invalid date");
714
+ }
715
+
716
+ try {
717
+ locale = getLocaleOfDocument();
718
+ return date.toLocaleDateString(locale.toString(), {
719
+ year: "numeric",
720
+ month: "2-digit",
721
+ day: "2-digit",
722
+ });
723
+ } catch (e) {
724
+ throw new Error(`unsupported locale or missing format (${e.message})`);
725
+ }
726
+
727
+ case "time-ago":
728
+ date = new Date(value);
729
+ if (isNaN(date.getTime())) {
730
+ throw new Error("invalid date");
731
+ }
732
+
733
+ try {
734
+ locale = getLocaleOfDocument();
735
+ return formatTimeAgo(date, locale.toString());
736
+ } catch (e) {
737
+ throw new Error(`unsupported locale or missing format (${e.message})`);
738
+ }
739
+
740
+ case "year":
741
+ date = new Date(value);
742
+ if (isNaN(date.getTime())) {
743
+ throw new Error("invalid date");
744
+ }
745
+
746
+ return date.getFullYear();
747
+
748
+ case "month":
749
+ date = new Date(value);
750
+ if (isNaN(date.getTime())) {
751
+ throw new Error("invalid date");
752
+ }
753
+
754
+ return date.getMonth() + 1;
755
+
756
+ case "day":
757
+ date = new Date(value);
758
+ if (isNaN(date.getTime())) {
759
+ throw new Error("invalid date");
760
+ }
761
+
762
+ return date.getDate();
763
+
764
+ case "weekday":
765
+ date = new Date(value);
766
+ if (isNaN(date.getTime())) {
767
+ throw new Error("invalid date");
768
+ }
769
+
770
+ return date.getDay();
771
+
772
+ case "hour":
773
+ case "hours":
774
+ date = new Date(value);
775
+ if (isNaN(date.getTime())) {
776
+ throw new Error("invalid date");
777
+ }
778
+
779
+ return date.getHours();
780
+
781
+ case "minute":
782
+ case "minutes":
783
+ date = new Date(value);
784
+ if (isNaN(date.getTime())) {
785
+ throw new Error("invalid date");
786
+ }
787
+
788
+ return date.getMinutes();
789
+
790
+ case "second":
791
+ case "seconds":
792
+ date = new Date(value);
793
+ if (isNaN(date.getTime())) {
794
+ throw new Error("invalid date");
795
+ }
796
+
797
+ return date.getSeconds();
798
+
799
+ case "i18n":
800
+ case "translation":
801
+ translations = getDocumentTranslations();
802
+ if (!(translations instanceof Translations)) {
803
+ throw new Error("missing translations");
804
+ }
805
+
806
+ key = args.shift() || undefined;
807
+ if (key === undefined) {
808
+ key = value;
809
+ }
810
+
811
+ defaultValue = args.shift() || undefined;
812
+
813
+ defaultValue = convertSpecialStrings(defaultValue, value);
814
+
815
+ return translations.getText(key, defaultValue);
816
+
817
+ case "set-toggle":
818
+ case "set-set":
819
+ case "set-remove":
820
+ const modifier = args.shift();
821
+ let delimiter = args.shift();
822
+ if (delimiter === undefined) {
823
+ delimiter = " ";
824
+ }
825
+
826
+ const set = new Set(value.split(delimiter));
827
+ const toggle = new Set(modifier.split(delimiter));
828
+ if (this.command === "set-toggle") {
829
+ for (const t of toggle) {
830
+ if (set.has(t)) {
831
+ set.delete(t);
832
+ } else {
833
+ set.add(t);
834
+ }
835
+ }
836
+ } else if (this.command === "set-set") {
837
+ for (const t of toggle) {
838
+ set.add(t);
839
+ }
840
+ } else if (this.command === "set-remove") {
841
+ for (const t of toggle) {
842
+ set.delete(t);
843
+ }
844
+ }
845
+ return Array.from(set).join(delimiter);
846
+
847
+ default:
848
+ throw new Error(`unknown command ${this.command}`);
849
+ }
850
850
  }
851
851
 
852
852
  /**
@@ -857,18 +857,18 @@ function transform(value) {
857
857
  * @return {undefined|*|null|string}
858
858
  */
859
859
  function convertSpecialStrings(input, value) {
860
- switch (input) {
861
- case "value":
862
- return value;
863
- case "\\value":
864
- return "value";
865
- case "\\undefined":
866
- return undefined;
867
- case "\\null":
868
- return null;
869
- default:
870
- return input;
871
- }
860
+ switch (input) {
861
+ case "value":
862
+ return value;
863
+ case "\\value":
864
+ return "value";
865
+ case "\\undefined":
866
+ return undefined;
867
+ case "\\null":
868
+ return null;
869
+ default:
870
+ return input;
871
+ }
872
872
  }
873
873
 
874
874
  /**
@@ -877,20 +877,17 @@ function convertSpecialStrings(input, value) {
877
877
  * @return {boolean}
878
878
  */
879
879
  function evaluateCondition(value) {
880
- const lowerValue = typeof value === "string" ? value.toLowerCase() : value;
881
-
882
- return (
883
- (value !== undefined &&
884
- value !== null &&
885
- value !== "" &&
886
- lowerValue !== "off" &&
887
- lowerValue !== "false" &&
888
- value !== false) ||
889
- lowerValue === "on" ||
890
- lowerValue === "true" ||
891
- value === true
892
- );
880
+ const lowerValue = typeof value === "string" ? value.toLowerCase() : value;
881
+
882
+ return (
883
+ (value !== undefined &&
884
+ value !== null &&
885
+ value !== "" &&
886
+ lowerValue !== "off" &&
887
+ lowerValue !== "false" &&
888
+ value !== false) ||
889
+ lowerValue === "on" ||
890
+ lowerValue === "true" ||
891
+ value === true
892
+ );
893
893
  }
894
-
895
-
896
-