@pacem/pacem-core 1.0.0-abel

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 (41) hide show
  1. package/LICENSE +191 -0
  2. package/NOTICE +4 -0
  3. package/dist/browser/pacem-core.js +9099 -0
  4. package/dist/browser/pacem-core.js.map +1 -0
  5. package/dist/browser/pacem-core.min.js +2 -0
  6. package/dist/browser/pacem-core.min.js.map +1 -0
  7. package/dist/bundle/pacem-core.min.mjs +3 -0
  8. package/dist/bundle/pacem-core.mjs +8479 -0
  9. package/dist/bundle/pacem-core.mjs.map +7 -0
  10. package/dist/esm/adapter.js +7 -0
  11. package/dist/esm/command.js +10 -0
  12. package/dist/esm/comparers.js +8 -0
  13. package/dist/esm/converters.js +70 -0
  14. package/dist/esm/decorators-next.js +783 -0
  15. package/dist/esm/decorators.js +736 -0
  16. package/dist/esm/defaults.js +5 -0
  17. package/dist/esm/events.js +89 -0
  18. package/dist/esm/eventtarget.js +131 -0
  19. package/dist/esm/expression.js +228 -0
  20. package/dist/esm/index-animations.js +1 -0
  21. package/dist/esm/index-behaviors.js +1 -0
  22. package/dist/esm/index-components.js +1 -0
  23. package/dist/esm/index-iife.js +3 -0
  24. package/dist/esm/index-logging.js +1 -0
  25. package/dist/esm/index-net.js +1 -0
  26. package/dist/esm/index-root.js +20 -0
  27. package/dist/esm/index-ui.js +1 -0
  28. package/dist/esm/index.js +7 -0
  29. package/dist/esm/logger.js +11 -0
  30. package/dist/esm/prefix.js +6 -0
  31. package/dist/esm/promise.js +34 -0
  32. package/dist/esm/regex.js +22 -0
  33. package/dist/esm/storage.js +56 -0
  34. package/dist/esm/template.js +4 -0
  35. package/dist/esm/transforms.js +248 -0
  36. package/dist/esm/types.js +10 -0
  37. package/dist/esm/utils-customelement.js +524 -0
  38. package/dist/esm/utils-customevent.js +60 -0
  39. package/dist/esm/utils.js +1073 -0
  40. package/package.json +37 -0
  41. package/typings/index.d.ts +2521 -0
@@ -0,0 +1,1073 @@
1
+ import { Keys, Dates, Colors, Strings, Blobs, Imaging, NullChecker, detect } from '@pacem/pacem-foundation';
2
+ import { Json } from './trees/json';
3
+ import { DeepCloner } from './trees/deepcloner';
4
+ import { DeferPromise } from './promise';
5
+ // namespace Pacem {
6
+ const PACEM_CORE_DEFAULT = 'pacem';
7
+ const DEFAULT_DOWNLOAD_FILENAME = 'download';
8
+ export const stopPropagationHandler = (evt) => {
9
+ evt.stopPropagation();
10
+ };
11
+ export const preventDefaultHandler = (evt) => {
12
+ evt.preventDefault();
13
+ };
14
+ export const avoidHandler = (evt) => {
15
+ evt.preventDefault();
16
+ evt.stopPropagation();
17
+ };
18
+ const SEGMENT_PATTERN = /^\/[^\/]+/;
19
+ const ROUTE_SEGMENT_PATTERN = /\/\{([a-z\$_][\w]*)\??\}/;
20
+ export class Utils {
21
+ static get core() {
22
+ const root = window['Pacem'];
23
+ var id = (root && root.Configuration && root.Configuration.core) || PACEM_CORE_DEFAULT;
24
+ return window[id] = window[id] || {};
25
+ }
26
+ static get customElements() {
27
+ return window['customElements'];
28
+ }
29
+ // #region GENERAL
30
+ static uniqueId() {
31
+ return Keys.uniqueId();
32
+ }
33
+ static uniqueCode() {
34
+ return Keys.uniqueCode();
35
+ }
36
+ static randomString(length) {
37
+ return Keys.randomString(length);
38
+ }
39
+ static parseDate(input) {
40
+ return Dates.parse(input);
41
+ }
42
+ static copyToClipboard(input) {
43
+ if (navigator.clipboard) {
44
+ return navigator.clipboard.writeText(input);
45
+ }
46
+ // deprecated code branch
47
+ return new Promise((resolve, reject) => {
48
+ const el = document.createElement('textarea');
49
+ el.value = input;
50
+ el.style.opacity = "0";
51
+ document.body.appendChild(el);
52
+ try {
53
+ el.select();
54
+ document.execCommand('copy');
55
+ el.remove();
56
+ resolve();
57
+ }
58
+ catch (e) {
59
+ reject(e);
60
+ }
61
+ });
62
+ }
63
+ // json-dedicated
64
+ static { this.Json = {
65
+ stringify: Json.serialize,
66
+ parse: Json.deserialize
67
+ }; }
68
+ // dates-dedicated (moved to foundations, kept for backwards compat)
69
+ static { this.Dates = {
70
+ now: () => Utils.parseDate(Date.now()),
71
+ parse: Utils.parseDate,
72
+ isLeapYear: Dates.isLeapYear,
73
+ daysInMonth: Dates.daysInMonth,
74
+ /**
75
+ * Gets whether a date is an `Invalid Date` or not.
76
+ * @param date
77
+ */
78
+ isDate: Dates.isDate,
79
+ dateOnly: Dates.dateOnly,
80
+ addMonths: Dates.addMonths,
81
+ addDays: Dates.addDays,
82
+ daysBetween: Dates.daysBetween,
83
+ }; }
84
+ static colorize(elementOrRgb, rgb) {
85
+ const hsl0 = /*Colors.hsl(Colors.parse('#000'))*/ { h: 38, s: .245, l: .6 };
86
+ var realRgb, rgba, filter, element;
87
+ if (elementOrRgb instanceof HTMLElement) {
88
+ realRgb = rgb;
89
+ }
90
+ else {
91
+ realRgb = elementOrRgb;
92
+ }
93
+ // rgba
94
+ if (typeof realRgb === 'string') {
95
+ rgba = Colors.parse(realRgb);
96
+ }
97
+ else {
98
+ rgba = { r: realRgb[0], g: realRgb[1], b: realRgb[2] };
99
+ }
100
+ const hsl = Colors.hsl(rgba);
101
+ filter = `brightness(50%) sepia(1) hue-rotate(${(hsl.h - hsl0.h)}deg) saturate(${(1.0 + (hsl.s - hsl0.s))}) brightness(${(1.0 + (hsl.l - hsl0.l))})`;
102
+ if (realRgb === rgb) {
103
+ element.style.filter = filter;
104
+ }
105
+ else {
106
+ return filter;
107
+ }
108
+ }
109
+ static cssEscape(input) {
110
+ return escape(input).replace('%', '\\');
111
+ }
112
+ // css-dedicated
113
+ static { this.Css = {
114
+ colorize: Utils.colorize,
115
+ escape: Utils.cssEscape,
116
+ getVariableValue(name) {
117
+ return getComputedStyle(document.documentElement).getPropertyValue(name);
118
+ },
119
+ setVariable(name, value) {
120
+ getComputedStyle(document.documentElement).setProperty(name, value);
121
+ },
122
+ /**
123
+ * Naive O(n^2) implementation for an actual css class presence (definition) in the current DOM.
124
+ * @param name CSS class name
125
+ */
126
+ isClassDefined(name) {
127
+ const pattern = new RegExp('\.' + name + '($|[\s\.,])');
128
+ for (let j = 0; j < document.styleSheets.length; j++) {
129
+ const sheet = document.styleSheets.item(j);
130
+ try {
131
+ const rules = sheet.cssRules;
132
+ for (let i = 0; i < rules.length; i++) {
133
+ const rule = sheet.cssRules.item(i);
134
+ if (pattern.test(rule.selectorText)) {
135
+ return true;
136
+ }
137
+ }
138
+ }
139
+ catch (e) {
140
+ if (e instanceof DOMException) {
141
+ console.warn('Couldn\'t access cssRules of stylesheet "' + sheet.href + '".');
142
+ // console.error(e);
143
+ }
144
+ }
145
+ }
146
+ return false;
147
+ },
148
+ deserializeTransform(element) {
149
+ const style = element instanceof Element ? getComputedStyle(element) : element;
150
+ let a = 1, b = 0, c = 0, d = 1, x = 0, y = 0, matches = /^matrix\((.*)\)$/.exec(style.transform), mij;
151
+ //matrix(1, 0, 0, 1, 2, 4)
152
+ if (matches && matches.length > 1 && (mij = matches[1].split(',')).length == 6) {
153
+ // scale + rot
154
+ a = parseFloat(mij[0]);
155
+ b = parseFloat(mij[1]);
156
+ c = parseFloat(mij[2]);
157
+ d = parseFloat(mij[3]);
158
+ // transl
159
+ x += parseFloat(mij[4]);
160
+ y += parseFloat(mij[5]);
161
+ }
162
+ return { a: a, b: b, c: c, d: d, e: x, f: y };
163
+ }
164
+ }; }
165
+ // #region strings
166
+ // legacy
167
+ static { this.leftPad = Strings.leftPad; }
168
+ static { this.formatString = Strings.format; }
169
+ static { this.diff = Strings.diff; }
170
+ static { this.Strings = {
171
+ leftPad: Strings.leftPad,
172
+ format: Strings.format,
173
+ diff: Strings.diff,
174
+ stripHTML: (html) => {
175
+ let doc = new DOMParser().parseFromString(html, 'text/html');
176
+ return doc.body.textContent || '';
177
+ }
178
+ }; }
179
+ // #endregion
180
+ // #endregion
181
+ // #region blob/files...
182
+ static { this.Blobs = {
183
+ toDataURL: Blobs.blobToDataURL,
184
+ fromDataURL: Blobs.dataURLToBlob,
185
+ toText: Blobs.blobToText,
186
+ fromText: Blobs.textToBlob
187
+ }; }
188
+ static { this.Images = {
189
+ load: Imaging.loadImage,
190
+ resize: Imaging.resizeImage
191
+ }; }
192
+ static loadImage(src) {
193
+ return new Promise((resolve, reject) => {
194
+ const img = new Image();
195
+ img.src = src;
196
+ if (img.complete) {
197
+ resolve(img);
198
+ }
199
+ else {
200
+ img.onload = (evt) => {
201
+ resolve(img);
202
+ };
203
+ img.onerror = (evt) => {
204
+ reject();
205
+ };
206
+ }
207
+ });
208
+ }
209
+ static blobToDataURL(blob) {
210
+ return Utils.Blobs.toDataURL(blob);
211
+ }
212
+ static dataURLToBlob(dataURL) {
213
+ return Utils.Blobs.fromDataURL(dataURL);
214
+ }
215
+ static blobToText(blob, encoding) {
216
+ return Utils.Blobs.toText(blob, encoding);
217
+ }
218
+ static textToBlob(content, type = 'text/plain') {
219
+ return Utils.Blobs.fromText(content, type);
220
+ }
221
+ /** @deprecated Use {Utils.Images.resize}, instead.
222
+ * Resizes an image when exceeding the provided size constraints.
223
+ * @param img {Blob} Input image
224
+ * @param maxWidth {number} Width constraint
225
+ * @param maxHeight {number} Height constraint
226
+ */
227
+ static resizeImage(img, maxWidth, maxHeight, quality) {
228
+ var deferred = DeferPromise.defer();
229
+ Utils.blobToDataURL(img)
230
+ .then(Utils.loadImage)
231
+ .then(el => {
232
+ const origWidth = el.width, origHeight = el.height;
233
+ let cnv = document.createElement('canvas');
234
+ cnv.width = origWidth;
235
+ cnv.height = origHeight;
236
+ let ctx = cnv.getContext('2d');
237
+ //ctx.drawImage(el, 0, 0);
238
+ if (origWidth > maxWidth
239
+ || origHeight > maxHeight) {
240
+ const origRatio = origWidth / origHeight, targetRatio = maxWidth / maxHeight;
241
+ let targetHeight, targetWidth;
242
+ if (targetRatio < origRatio) {
243
+ targetWidth = maxWidth;
244
+ targetHeight = maxWidth / origRatio;
245
+ }
246
+ else {
247
+ targetHeight = maxHeight;
248
+ targetWidth = maxHeight * origRatio;
249
+ }
250
+ cnv.width = targetWidth;
251
+ cnv.height = targetHeight;
252
+ const jpeg = quality > 0 && quality <= 1;
253
+ if (jpeg) {
254
+ ctx.fillStyle = '#000';
255
+ ctx.fillRect(0, 0, cnv.width, cnv.height);
256
+ }
257
+ Utils.cropImageOntoCanvas(el, ctx);
258
+ let newUrl;
259
+ if (jpeg)
260
+ newUrl = ctx.canvas.toDataURL("image/jpeg", quality);
261
+ else
262
+ newUrl = ctx.canvas.toDataURL();
263
+ deferred.resolve(Utils.dataURLToBlob(newUrl));
264
+ }
265
+ else {
266
+ deferred.resolve(img);
267
+ }
268
+ }, _ => {
269
+ // image loading error caught...
270
+ });
271
+ return deferred.promise;
272
+ }
273
+ /** @deprecated Use {Utils.Images.resize}, instead.
274
+ * Crops an image having the provided url (might be a dataURL) into another having the provided size
275
+ * @param url
276
+ * @param width
277
+ * @param height
278
+ * @param ctx
279
+ */
280
+ static cropImage(url, width, height, quality) {
281
+ var deferred = DeferPromise.defer();
282
+ let el = new Image();
283
+ el.crossOrigin = 'anonymous';
284
+ el.onload = function (ev) {
285
+ let cnv = document.createElement('canvas');
286
+ let ctx = cnv.getContext('2d');
287
+ if (width)
288
+ cnv.width = width;
289
+ if (height)
290
+ cnv.height = height;
291
+ //
292
+ const jpeg = quality > 0 && quality <= 1;
293
+ if (jpeg) {
294
+ ctx.fillStyle = '#000';
295
+ ctx.fillRect(0, 0, cnv.width, cnv.height);
296
+ }
297
+ Utils.cropImageOntoCanvas(el, ctx);
298
+ deferred.resolve(jpeg ? cnv.toDataURL('image/jpeg', quality) : cnv.toDataURL());
299
+ };
300
+ el.src = url;
301
+ return deferred.promise;
302
+ }
303
+ static getUserMediaFunctions() {
304
+ var _getUserMedia = [];
305
+ let methods = [navigator['getUserMedia'], navigator['webkitGetUserMedia'], navigator['msGetUserMedia'], navigator['mozGetUserMedia']];
306
+ let fns = methods.filter(function (fn, j) { return typeof fn == 'function'; });
307
+ if (fns.length)
308
+ _getUserMedia = fns;
309
+ return _getUserMedia;
310
+ }
311
+ /**
312
+ * Crops the snapshot of a drawable element onto a provided canvas context. It gets centered in the area and cropped (`cover`-like behavior).
313
+ * @param el drawable element
314
+ * @param ctx canvas context
315
+ * @param sourceWidth forced source width
316
+ * @param sourceHeight forced source height
317
+ */
318
+ static cropImageOntoCanvas(el, ctx, sourceWidth, sourceHeight) {
319
+ ctx.imageSmoothingEnabled =
320
+ ctx['mozImageSmoothingEnabled'] =
321
+ ctx['oImageSmoothingEnabled'] =
322
+ ctx['webkitImageSmoothingEnabled'] =
323
+ true;
324
+ //
325
+ let tgetW = ctx.canvas.width /*= parseFloat(scope.thumbWidth)*/;
326
+ let tgetH = ctx.canvas.height /*= parseFloat(scope.thumbHeight)*/;
327
+ let cnvW = tgetW, cnvH = tgetH;
328
+ let w = sourceWidth || 1.0 * el.width, h = sourceHeight || 1.0 * el.height;
329
+ //console.log('img original size: ' + w + 'x' + h);
330
+ var ratio = w / h;
331
+ var tgetRatio = tgetW / tgetH;
332
+ if (tgetRatio > ratio) {
333
+ // crop vertically
334
+ var f = tgetW / w;
335
+ tgetH = f * h;
336
+ ctx.drawImage(el, 0, .5 * (-tgetH + cnvH), cnvW, tgetH);
337
+ }
338
+ else {
339
+ // crop horizontally
340
+ var f = tgetH / h;
341
+ tgetW = f * w;
342
+ ctx.drawImage(el, -Math.abs(.5 * (-tgetW + cnvW)), 0, tgetW, cnvH);
343
+ }
344
+ }
345
+ static get _domURL() {
346
+ return window.URL || window['webkitURL'] || window;
347
+ }
348
+ /**
349
+ * Snapshots a DOM element and returns its blob image representation.
350
+ * @param el Element to snapshot
351
+ * @param background Background color to replace the original
352
+ * @param type Output mimetype (image/png, image/jpeg, images/webp, ...)
353
+ * @param quality Quality ratio between 0..1
354
+ */
355
+ static snapshotElement(el, background, type = 'image/png', quality) {
356
+ function drawCanvas(img) {
357
+ return new Promise((resolve, reject) => {
358
+ const canvas = document.createElement('canvas'), width = img.width, height = img.height;
359
+ if (!(width > 0)) {
360
+ reject('Image has width zero.');
361
+ }
362
+ else if (!(height > 0)) {
363
+ reject('Image has height zero.');
364
+ }
365
+ else {
366
+ canvas.width = width;
367
+ canvas.height = height;
368
+ const ctx = canvas.getContext('2d');
369
+ if (!Utils.isNullOrEmpty(background)) {
370
+ ctx.fillStyle = background;
371
+ ctx.fillRect(0, 0, width, height);
372
+ }
373
+ ctx.drawImage(img, 0, 0);
374
+ canvas.toBlob(b => {
375
+ resolve(b);
376
+ }, type, quality);
377
+ }
378
+ });
379
+ }
380
+ if (el instanceof HTMLCanvasElement) {
381
+ return drawCanvas(el);
382
+ }
383
+ return new Promise((resolve, _) => {
384
+ const loadPromises = [];
385
+ //#region utils functions
386
+ function addLoadPromise(img) {
387
+ const p = new Promise((resolve0, _) => {
388
+ const getSrc = () => {
389
+ return img instanceof HTMLImageElement ? img.src : img.href.baseVal;
390
+ };
391
+ const setSrc = (src) => {
392
+ if (img instanceof HTMLImageElement)
393
+ img.src = src;
394
+ else {
395
+ img.setAttribute('href', src);
396
+ }
397
+ };
398
+ fetch(getSrc())
399
+ .then(r => r.blob())
400
+ .then(blob => Utils.blobToDataURL(blob))
401
+ .then(url => {
402
+ setSrc(url);
403
+ resolve0();
404
+ });
405
+ });
406
+ loadPromises.push(p);
407
+ }
408
+ function copyCanvas(copy, srcCanvas) {
409
+ const p = new Promise((resolve0, _) => {
410
+ const img = new Image();
411
+ img.crossOrigin = 'anonymous';
412
+ img.width = srcCanvas.width;
413
+ img.height = srcCanvas.height;
414
+ img.style.cssText = copy.style.cssText;
415
+ img.onload = () => {
416
+ copy.replaceWith(img);
417
+ resolve0();
418
+ };
419
+ img.src = srcCanvas.toDataURL();
420
+ });
421
+ loadPromises.push(p);
422
+ }
423
+ function applyCss(copy, src) {
424
+ const css = getComputedStyle(src);
425
+ for (let j = 0; j < css.length; j++) {
426
+ const item = css.item(j);
427
+ copy.style[item] = css[item];
428
+ }
429
+ }
430
+ function recSetupCopy(copy, src) {
431
+ // assign css text
432
+ applyCss(copy, src);
433
+ // bitmaps
434
+ if (copy instanceof HTMLImageElement || copy instanceof SVGImageElement) {
435
+ addLoadPromise(copy);
436
+ }
437
+ else if (copy instanceof HTMLCanvasElement) {
438
+ copyCanvas(copy, src);
439
+ }
440
+ // recursion
441
+ const childLength = copy.children.length;
442
+ for (let i = 0; i < childLength; i++) {
443
+ const copy1 = copy.children.item(i), src1 = src.children.item(i);
444
+ if (copy1.tagName === src1.tagName) {
445
+ recSetupCopy(copy1, src1);
446
+ }
447
+ }
448
+ }
449
+ //#endregion
450
+ const isSvg = el instanceof SVGElement;
451
+ if (!isSvg) {
452
+ var doc = document.implementation.createHTMLDocument('');
453
+ doc.write(el.outerHTML);
454
+ doc.documentElement.setAttribute('xmlns', doc.documentElement.namespaceURI);
455
+ const xpath = document.evaluate(".//" + el.localName, doc.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
456
+ const node = xpath;
457
+ node.setAttribute('xmlns', doc.documentElement.namespaceURI);
458
+ recSetupCopy(node, el);
459
+ Promise.all(loadPromises).then(_ => {
460
+ // Get well-formed markup
461
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", 'svg');
462
+ const size = Utils.offset(el);
463
+ svg.setAttribute('viewBox', `0 0 ${size.width} ${size.height}`);
464
+ svg.setAttribute('width', size.width.toString());
465
+ svg.setAttribute('height', size.height.toString());
466
+ svg.innerHTML = `<foreignObject width="${size.width}" height="${size.height}">${node.outerHTML}</foreignObject>`;
467
+ el = svg;
468
+ execute();
469
+ });
470
+ }
471
+ else {
472
+ const svg = el.cloneNode(true);
473
+ recSetupCopy(svg, el);
474
+ Promise.all(loadPromises).then(_ => {
475
+ el = svg;
476
+ execute();
477
+ });
478
+ }
479
+ function execute() {
480
+ const data = new XMLSerializer().serializeToString(el);
481
+ const img = new Image();
482
+ img.crossOrigin = 'anonymous';
483
+ // switching from blob to data url (see: https://bugs.chromium.org/p/chromium/issues/detail?id=294129)
484
+ //const domURL = this._domURL;
485
+ //var svg = new Blob([data], { type: 'image/svg+xml' });
486
+ //var url = domURL.createObjectURL(svg);
487
+ const url = 'data:image/svg+xml;charset=utf8,' + encodeURIComponent(data);
488
+ img.onload = () => {
489
+ drawCanvas(img).then(resolve);
490
+ //domURL.revokeObjectURL(url);
491
+ };
492
+ img.src = url;
493
+ }
494
+ });
495
+ }
496
+ static async download(arg0, arg1, mime = "application/download") {
497
+ if (typeof arg0 === 'string') {
498
+ const url = arg0;
499
+ let options = {}, filename;
500
+ if (!Utils.isNullOrEmpty(arg1)) {
501
+ if (typeof arg1 === 'object') {
502
+ options = { credentials: arg1.credentials, headers: arg1.headers };
503
+ filename = arg1.filename || filename;
504
+ mime = arg1.mime || mime;
505
+ }
506
+ else {
507
+ filename = arg1;
508
+ }
509
+ }
510
+ var response = await fetch(url, options);
511
+ if (response.ok) {
512
+ if (Utils.isNullOrEmpty(filename)) {
513
+ const headerName = 'Content-Disposition';
514
+ if (response.headers.has(headerName)) {
515
+ const header = response.headers.get(headerName), results = /^attachment; filename=\"?([^;\"]+)\"?(;|$)/.exec(header);
516
+ if (results.length > 1) {
517
+ filename = results[1];
518
+ }
519
+ }
520
+ else {
521
+ filename = DEFAULT_DOWNLOAD_FILENAME;
522
+ }
523
+ }
524
+ var blob = await response.blob();
525
+ const fn = filename.split(/[\\\/]/g).join('_');
526
+ return Utils.download(blob, fn);
527
+ }
528
+ {
529
+ const reason = await response.text();
530
+ throw new Error(reason);
531
+ }
532
+ }
533
+ else {
534
+ const content = arg0, filename = (typeof arg1 === 'string' && arg1) || DEFAULT_DOWNLOAD_FILENAME, fanchor = document.createElement('a');
535
+ fanchor.setAttribute('href', Utils._domURL.createObjectURL(content));
536
+ fanchor.setAttribute('download', filename);
537
+ if (document.createEvent) {
538
+ var event = document.createEvent('MouseEvents');
539
+ event.initEvent('click', true, true);
540
+ fanchor.dispatchEvent(event);
541
+ }
542
+ else {
543
+ fanchor.click();
544
+ }
545
+ }
546
+ }
547
+ // #endregion
548
+ // #region DOM
549
+ static isDOMReady() {
550
+ // Must exclude 'interactive' state since module script haven't been processed yet.
551
+ return /* document.readyState === 'interactive' ||*/ document.readyState === 'complete';
552
+ }
553
+ static onDOMReady(listener) {
554
+ //window.addEventListener('DOMContentLoaded', listener, false);
555
+ // window 'load' event fires after 'DOMCOntentLoaded' since includes images load.
556
+ window.addEventListener('load', listener, false);
557
+ }
558
+ /**
559
+ * Moves all the source element children to the target element and returns them as an array of nodes.
560
+ * @param source Source element.
561
+ * @param target Target element.
562
+ */
563
+ static moveChildren(source, target) {
564
+ return Utils.moveItems(source.childNodes, target);
565
+ }
566
+ /**
567
+ * Moves specific nodes to the target element and returns them as an array of nodes.
568
+ * @param nodes Nodes to move.
569
+ * @param target Target element.
570
+ */
571
+ static moveItems(nodes, target) {
572
+ let dom = [], ref;
573
+ for (let j = nodes.length - 1; j >= 0; j--) {
574
+ let item = nodes instanceof NodeList ? nodes.item(j) : nodes[j];
575
+ target.insertBefore(item, ref);
576
+ dom.unshift(item);
577
+ ref = item;
578
+ }
579
+ return dom;
580
+ }
581
+ static is(el, selector) {
582
+ return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector)
583
+ .call(el, selector);
584
+ }
585
+ static lang(el) {
586
+ return el.lang || document.documentElement.lang || navigator.language;
587
+ }
588
+ static jsonSortStringify(obj) {
589
+ if (Utils.isNull(obj)) {
590
+ return obj;
591
+ }
592
+ return Utils.Json.stringify(obj);
593
+ }
594
+ static { this.Browsers = {
595
+ detect
596
+ }; }
597
+ static cookies(cookie) {
598
+ const cookies = (cookie ?? document.cookie).split(';'), retval = {};
599
+ for (var pair of cookies) {
600
+ const keyval = pair.split('=');
601
+ if (keyval.length < 2) {
602
+ continue;
603
+ }
604
+ const key = (keyval[0] || '').trim(), value = (keyval[1] || '').trim();
605
+ Object.defineProperty(retval, key, {
606
+ configurable: false, enumerable: true, writable: false,
607
+ value: decodeURIComponent(value.split('+').join(' '))
608
+ });
609
+ }
610
+ return retval;
611
+ }
612
+ static { this.Cookies = {
613
+ getAll: async (cookieName) => {
614
+ const store = 'cookieStore' in window ? window.cookieStore : null;
615
+ const retval = [];
616
+ if (Utils.isNull(store)) {
617
+ const nameValues = Utils.cookies();
618
+ for (let name in nameValues) {
619
+ if (!Utils.isNullOrEmpty(cookieName) && cookieName !== name) {
620
+ continue;
621
+ }
622
+ retval.push({ name, value: nameValues[name] });
623
+ }
624
+ return retval;
625
+ }
626
+ else {
627
+ return await store.getAll(cookieName);
628
+ }
629
+ },
630
+ stringify: (data) => {
631
+ let retval = `${data.name}=${encodeURIComponent(data.value ?? '')}`;
632
+ if (!Utils.isNullOrEmpty(data.domain)) {
633
+ retval += `; domain=${encodeURIComponent(data.domain)}`;
634
+ }
635
+ if (!Utils.isNullOrEmpty(data.path)) {
636
+ retval += `; path=${encodeURIComponent(data.path)}`;
637
+ }
638
+ if (data.maxAge > 0) {
639
+ retval += `; max-age=${data.maxAge.toFixed(0)}`;
640
+ }
641
+ if (!Utils.isNullOrEmpty(data.expires)) {
642
+ retval += `; expires=${data.expires}`;
643
+ }
644
+ if (data.partitioned) {
645
+ retval += '; Partitioned';
646
+ }
647
+ if (!Utils.isNullOrEmpty(data.sameSite)) {
648
+ retval += `; SameSite=${encodeURIComponent(data.sameSite)}`;
649
+ }
650
+ if (data.secure) {
651
+ retval += '; Secure';
652
+ }
653
+ return retval;
654
+ }
655
+ }; }
656
+ static isVisible(el) {
657
+ if ('checkVisibility' in el) {
658
+ return el.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true });
659
+ }
660
+ return getComputedStyle(el).visibility !== 'hidden' && (el.clientWidth > 0 || el.clientHeight > 0);
661
+ }
662
+ //#region classList DOMTokenList (css)
663
+ static hasClass(el, className) {
664
+ if (el.classList) {
665
+ return el.classList.contains(className);
666
+ }
667
+ else {
668
+ return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
669
+ }
670
+ }
671
+ static addClass(el, className) {
672
+ const css = className.trim();
673
+ if (el.classList) {
674
+ DOMTokenList.prototype.add.apply(el.classList, css.split(' '));
675
+ }
676
+ else {
677
+ el.setAttribute('class', el.className + ' ' + css);
678
+ }
679
+ }
680
+ static removeClass(el, className) {
681
+ const css = className.trim();
682
+ if (el.classList) {
683
+ DOMTokenList.prototype.remove.apply(el.classList, css.split(' '));
684
+ }
685
+ else {
686
+ el.setAttribute('class', el.className.replace(new RegExp('(^|\\b)' + css.split(' ').join('|') + '(\\b|$)', 'gi'), ' '));
687
+ }
688
+ }
689
+ static toggleClass(el, className, on) {
690
+ if (on) {
691
+ Utils.addClass(el, className);
692
+ }
693
+ else {
694
+ Utils.removeClass(el, className);
695
+ }
696
+ }
697
+ //#endregion
698
+ //#region part DOMTokenList (shadow-DOM)
699
+ static hasPart(el, partName) {
700
+ return el.part.contains(partName);
701
+ }
702
+ static addPart(el, partName) {
703
+ DOMTokenList.prototype.add.apply(el.part, partName.trim().split(' '));
704
+ }
705
+ static removePart(el, partName) {
706
+ DOMTokenList.prototype.remove.apply(el.part, partName.trim().split(' '));
707
+ }
708
+ static togglePart(el, partName, on) {
709
+ if (on) {
710
+ Utils.addPart(el, partName);
711
+ }
712
+ else {
713
+ Utils.removePart(el, partName);
714
+ }
715
+ }
716
+ //#endregion
717
+ /**
718
+ * Retrieve the bounding box of the provided element as of its rendered appearance on the stage (takes transformations into account).
719
+ * @param el The element.
720
+ */
721
+ static offset(el) {
722
+ var rect = el.getBoundingClientRect();
723
+ return {
724
+ top: Math.round(rect.top) + Utils.scrollTop,
725
+ left: Math.round(rect.left) + Utils.scrollLeft,
726
+ width: Math.round(rect.width),
727
+ height: Math.round(rect.height)
728
+ };
729
+ }
730
+ /**
731
+ * Retrieve the bounding box of the provided element as of its rendered appearance on the stage (takes transformations into account).
732
+ * @param el The element.
733
+ */
734
+ static offsetRect(el) {
735
+ var rect = this.offset(el);
736
+ return {
737
+ y: rect.top,
738
+ x: rect.left,
739
+ width: rect.width,
740
+ height: rect.height
741
+ };
742
+ }
743
+ static naturalOffsetTop(el) {
744
+ return (el?.offsetTop ?? 0) + ((el?.offsetParent && el.offsetParent instanceof HTMLElement) ? this.naturalOffsetTop(el.offsetParent) : 0);
745
+ }
746
+ static naturalOffsetLeft(el) {
747
+ return (el?.offsetTop ?? 0) + ((el?.offsetParent && el.offsetParent instanceof HTMLElement) ? this.naturalOffsetLeft(el.offsetParent) : 0);
748
+ }
749
+ /**
750
+ * Retrieve the natural bounding box of the provided element (does not takes transformations into account).
751
+ * @param el {HTMLElement} The element.
752
+ */
753
+ static naturalOffset(el) {
754
+ return { left: this.naturalOffsetLeft(el), top: this.naturalOffsetTop(el), width: el?.offsetWidth ?? 0, height: el?.offsetHeight ?? 0 };
755
+ }
756
+ /**
757
+ * Retrieve the natural bounding box of the provided element (does not takes transformations into account).
758
+ * @param el {HTMLElement} The element.
759
+ */
760
+ static naturalOffsetRect(el) {
761
+ var rect = this.naturalOffset(el);
762
+ return {
763
+ y: rect.top,
764
+ x: rect.left,
765
+ width: rect.width,
766
+ height: rect.height
767
+ };
768
+ }
769
+ /** @deprecated */
770
+ static deserializeTransform(obj) {
771
+ return Utils.Css.deserializeTransform(obj);
772
+ }
773
+ static set scrollTop(y) {
774
+ window.scrollTo(Utils.scrollLeft, y);
775
+ }
776
+ static set scrollLeft(x) {
777
+ window.scrollTo(x, Utils.scrollTop);
778
+ }
779
+ static get scrollTop() {
780
+ return window.scrollY /*window.pageYOffset*/ || document.documentElement.scrollTop || document.body.scrollTop || 0;
781
+ }
782
+ static get scrollLeft() {
783
+ return window.scrollX /*window.pageXOffset*/ || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
784
+ }
785
+ static get windowSize() {
786
+ let win = window;
787
+ return {
788
+ width: win.innerWidth || win.document.documentElement.clientWidth || win.document.body.clientWidth || 0,
789
+ height: win.innerHeight || win.document.documentElement.clientHeight || win.document.body.clientHeight || 0
790
+ };
791
+ }
792
+ /**
793
+ * Adds a callback at the end of a CSS animation/transition for a given element (execute once).
794
+ * @param element The very element that has to trigger the animation/transitionend event.
795
+ * @param callback Then callback.
796
+ * @param timeout Fallback timeout (ms) in case the animation/transitionend event won't fire.
797
+ */
798
+ static addAnimationEndCallback(element, callback, timeout = 500) {
799
+ const fn = (e) => {
800
+ if (!e || e.target == element) {
801
+ clearTimeout(handle);
802
+ element.removeEventListener('animationend', fn, false);
803
+ element.removeEventListener('transitionend', fn, false);
804
+ callback.apply(this, [element]);
805
+ }
806
+ };
807
+ element.addEventListener('animationend', fn, false);
808
+ element.addEventListener('transitionend', fn, false);
809
+ // fallback in case animation is missing
810
+ const handle = setTimeout(fn, timeout);
811
+ }
812
+ /**
813
+ * Promisifies the addAnimationEndCallback function.
814
+ * @param element The very element that has to trigger the animation/transitionend event.
815
+ * @param timeout Fallback timeout (ms) in case the animation/transitionend event won't fire.
816
+ */
817
+ static waitForAnimationEnd(element, timeout = 500) {
818
+ return new Promise((resolve, _) => {
819
+ Utils.addAnimationEndCallback(element, () => {
820
+ resolve();
821
+ }, timeout);
822
+ });
823
+ }
824
+ /**
825
+ * Waits until the provided timespan elapses.
826
+ * @param msecs timespan in milliseconds
827
+ */
828
+ static idle(msecs) {
829
+ return new Promise((resolve, _) => {
830
+ setTimeout(() => resolve(), msecs);
831
+ });
832
+ }
833
+ /**
834
+ * Increases a callback loop call until cancelation is called.
835
+ * @param callback Callback looped.
836
+ * @param interval First callback call delay in ms (default 500).
837
+ * @param pace Acceleration in ms per loop (default 5).
838
+ * @param min Minimum loop rate in ms (default 20).
839
+ *
840
+ * Use case/example: while keeping a button pressed, the related callback execution increases in frequency.
841
+ */
842
+ static accelerateCallback(callback, interval = 500, pace = 5, min = 20) {
843
+ let token = { cancel: false }, int = interval, last = pace + min;
844
+ let fn = () => {
845
+ callback(token);
846
+ if (!token.cancel) {
847
+ setTimeout(fn, int);
848
+ if (int < last) {
849
+ int = min;
850
+ }
851
+ else {
852
+ int -= pace;
853
+ }
854
+ }
855
+ };
856
+ fn();
857
+ }
858
+ // #endregion
859
+ // #region other
860
+ static isEmpty(obj) {
861
+ return NullChecker.isEmpty(obj) && !(obj instanceof Node);
862
+ }
863
+ static isNull(obj) {
864
+ return NullChecker.isNull(obj);
865
+ }
866
+ // legacy
867
+ static isArray(val) {
868
+ return Array.isArray(val);
869
+ }
870
+ static isNullOrEmpty(val) {
871
+ return Utils.isNull(val) || Utils.isEmpty(val);
872
+ }
873
+ /**
874
+ * It is a `valueOf()` based comparison.
875
+ * @param v1 term 1
876
+ * @param v2 term 2
877
+ */
878
+ static areSemanticallyEqual(v1, v2) {
879
+ // undefined and null are semantically equal
880
+ v1 ??= null;
881
+ v2 ??= null;
882
+ const sv1 = v1 && v1.valueOf && v1.valueOf();
883
+ const sv2 = v2 && v2.valueOf && v2.valueOf();
884
+ return sv1 === sv2;
885
+ }
886
+ /** Legacy alias for Object.assign(). */
887
+ static { this.extend = Object.assign; }
888
+ static clone(obj) {
889
+ if (obj === undefined)
890
+ return undefined;
891
+ return DeepCloner.clone(obj);
892
+ }
893
+ /** Legacy alias for Promise.resolve(). */
894
+ static fromResult(v) {
895
+ return Promise.resolve(v);
896
+ }
897
+ static fromResultAsync(task) {
898
+ return new Promise(resolve => requestAnimationFrame(() => resolve(task())));
899
+ }
900
+ static readonlyCopy(obj) {
901
+ if (Utils.isNull(obj)) {
902
+ return null;
903
+ }
904
+ if (Utils.isArray(obj)) {
905
+ const output = obj.slice(0);
906
+ Object.freeze(output);
907
+ return output;
908
+ }
909
+ else {
910
+ const output = {};
911
+ for (let name in obj) {
912
+ output[name] = obj[name];
913
+ }
914
+ Object.freeze(output);
915
+ return output;
916
+ }
917
+ }
918
+ //#endregion
919
+ //#region Net
920
+ static { this.URIs = {
921
+ format: function (url, parameters, removeMatchedParameters) {
922
+ // replace segments
923
+ for (let name in parameters || {}) {
924
+ let tmpl = new RegExp("(^|\\/)\\{" + name + "\\??\\}(\\/|$)");
925
+ let arr = tmpl.exec(url);
926
+ if (arr && arr.length) {
927
+ let rpl = new RegExp("\\{" + name + "\\??\\}"), ndx = arr.index;
928
+ url = url.substring(0, ndx) + url.substring(ndx).replace(rpl, encodeURIComponent(parameters[name]));
929
+ if (removeMatchedParameters) {
930
+ delete parameters[name];
931
+ }
932
+ }
933
+ }
934
+ // clean-up optional
935
+ const optPattern = /(^|\/)\{[\w]+\?\}(\/|$)/;
936
+ var optArr;
937
+ while ((optArr = optPattern.exec(url)) && optArr.length > 0) {
938
+ let wholeMatch = optArr[0];
939
+ url = url.replace(wholeMatch, wholeMatch.endsWith('/') ? "/" : "");
940
+ }
941
+ return url;
942
+ },
943
+ appendQuery: function (url, parameters, removeNullEntries = false, hash = false) {
944
+ const char = hash ? '#' : '?', pattern = hash ? /#/ : /\?/;
945
+ const query = (pattern.test(url) ? '&' : char) +
946
+ Object.keys(parameters)
947
+ .filter(k => !Utils.isNull(parameters[k]) || !removeNullEntries)
948
+ .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(parameters[k] ?? '')).join('&');
949
+ return url + (query.length > 1 ? query : '');
950
+ },
951
+ parseQuery: (query = window.location) => {
952
+ if (typeof query !== 'string') {
953
+ query = query.search;
954
+ }
955
+ const obj = {};
956
+ new URLSearchParams(query).forEach((value, name) => {
957
+ Object.defineProperty(obj, name, { enumerable: true, value });
958
+ });
959
+ return obj;
960
+ },
961
+ hasMandatoryTemplateSegments: function (url) {
962
+ return /(^|\/)\{\.*\}(\/|$)/.test(url);
963
+ },
964
+ parseRoute: function (pathTemplate) {
965
+ let tmpl = pathTemplate;
966
+ const trunks = [];
967
+ if (!Utils.isNullOrEmpty(tmpl)) {
968
+ let res;
969
+ let j = 0;
970
+ while ((res = SEGMENT_PATTERN.exec(tmpl)) != null) {
971
+ const item = res[0];
972
+ const res1 = ROUTE_SEGMENT_PATTERN.exec(item);
973
+ if (!Utils.isNullOrEmpty(res1)) {
974
+ const prop = res1[1];
975
+ trunks.push({ name: prop, optional: item.charAt(item.length - 2) === '?', index: j });
976
+ }
977
+ tmpl = tmpl.substring(res.index + item.length);
978
+ j++;
979
+ }
980
+ }
981
+ return trunks;
982
+ },
983
+ split: function (url) {
984
+ const URL_PATTERN = /^((https?:)?\/\/[^\/]+)?([^\?#]+)(\?[^#]*)?(#[^#]*)?$/;
985
+ const regArr = URL_PATTERN.exec(url);
986
+ if (!regArr /*|| regArr.length <= 3*/) {
987
+ return null;
988
+ }
989
+ return { domain: regArr[2] ?? '', protocol: regArr[1] ?? '', path: regArr[3] ?? '', query: regArr[4] ?? '', hash: regArr[5] ?? '' };
990
+ },
991
+ parseState: function (metadata, url, path, query, hash) {
992
+ let fullPath = url;
993
+ if (Utils.isNullOrEmpty(path)) {
994
+ const split = Utils.URIs.split(url);
995
+ path = split.path;
996
+ if (Utils.isNullOrEmpty(query)) {
997
+ query = split.query ?? '';
998
+ }
999
+ if (Utils.isNullOrEmpty(hash)) {
1000
+ hash = split.hash ?? '';
1001
+ }
1002
+ fullPath = path + query + hash;
1003
+ }
1004
+ const parseHash = (hash) => {
1005
+ const ndx = hash.indexOf('#');
1006
+ if (ndx !== 0) {
1007
+ return null;
1008
+ }
1009
+ return hash.substring(ndx + 1);
1010
+ };
1011
+ const parseQuery = (search) => {
1012
+ const ndx = search.indexOf('?');
1013
+ if (ndx === 0) {
1014
+ return Utils.URIs.parseQuery(search.substring(ndx + 1));
1015
+ }
1016
+ return {};
1017
+ };
1018
+ let obj = {
1019
+ $path: fullPath,
1020
+ $pathname: path,
1021
+ $querystring: query.length > 0 ? query.substring(1) : query,
1022
+ $query: parseQuery(query),
1023
+ $hash: parseHash(hash)
1024
+ }, i = 0;
1025
+ const tmpl = metadata.slice();
1026
+ if (!Utils.isNullOrEmpty(tmpl)) {
1027
+ let res;
1028
+ while ((res = SEGMENT_PATTERN.exec(path)) != null) {
1029
+ const v = res[0];
1030
+ const tmplIndex = tmpl.findIndex(t => t.index === i);
1031
+ if (tmplIndex >= 0) {
1032
+ const tmplItem = tmpl[tmplIndex];
1033
+ const { name: prop } = tmplItem;
1034
+ Object.defineProperty(obj, prop, { enumerable: true, value: v.substring(1) });
1035
+ // remove used value
1036
+ tmpl.splice(tmplIndex, 1);
1037
+ }
1038
+ i++;
1039
+ path = path.substring(res.index + v.length);
1040
+ }
1041
+ }
1042
+ for (let k = 0; k < tmpl.length; k++) {
1043
+ if (!tmpl[k].optional) {
1044
+ throw `Must provide "${tmpl[k].name}" route value.`;
1045
+ }
1046
+ }
1047
+ return obj;
1048
+ }
1049
+ }; }
1050
+ /**
1051
+ * Ensures the proper parsing of Web API results, including deprecated/legacy Pacem wrapped results.
1052
+ */
1053
+ static getApiResult(json) {
1054
+ if (typeof json === 'object'
1055
+ && !Utils.isNull(json)
1056
+ && json.hasOwnProperty('success')) {
1057
+ switch (json.success) {
1058
+ case true:
1059
+ if (json.hasOwnProperty('result')) {
1060
+ return json.result;
1061
+ }
1062
+ break;
1063
+ case false:
1064
+ if (json.hasOwnProperty('error')) {
1065
+ return null;
1066
+ }
1067
+ break;
1068
+ }
1069
+ }
1070
+ return json;
1071
+ }
1072
+ }
1073
+ // }