@pacem/pacem 1.0.0-bessel → 1.0.0-dirac
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/dist/browser/pacem-2d.js +149 -2
- package/dist/browser/pacem-2d.js.map +1 -1
- package/dist/browser/pacem-2d.min.js +1 -1
- package/dist/browser/pacem-3d.js +646 -2
- package/dist/browser/pacem-3d.js.map +1 -1
- package/dist/browser/pacem-3d.min.js +1 -1
- package/dist/browser/pacem-charts.js +21 -1
- package/dist/browser/pacem-charts.js.map +1 -1
- package/dist/browser/pacem-charts.min.js +1 -1
- package/dist/browser/pacem-cms.js +118 -3
- package/dist/browser/pacem-cms.js.map +1 -1
- package/dist/browser/pacem-cms.min.js +1 -1
- package/dist/browser/pacem-core.js +870 -9
- package/dist/browser/pacem-core.js.map +1 -1
- package/dist/browser/pacem-core.min.js +2 -2
- package/dist/browser/pacem-foundation.js +296 -1
- package/dist/browser/pacem-foundation.js.map +1 -1
- package/dist/browser/pacem-foundation.min.js +1 -1
- package/dist/browser/pacem-fx.js +18 -1
- package/dist/browser/pacem-fx.js.map +1 -1
- package/dist/browser/pacem-fx.min.js +1 -1
- package/dist/browser/pacem-logging.js +15 -1
- package/dist/browser/pacem-logging.js.map +1 -1
- package/dist/browser/pacem-logging.min.js +1 -1
- package/dist/browser/pacem-maps.js +97 -1
- package/dist/browser/pacem-maps.js.map +1 -1
- package/dist/browser/pacem-maps.min.js +1 -1
- package/dist/browser/pacem-media.js +14 -1
- package/dist/browser/pacem-media.js.map +1 -1
- package/dist/browser/pacem-media.min.js +1 -1
- package/dist/browser/pacem-networking.js +22 -1
- package/dist/browser/pacem-networking.js.map +1 -1
- package/dist/browser/pacem-networking.min.js +1 -1
- package/dist/browser/pacem-numerical.js +360 -1
- package/dist/browser/pacem-numerical.js.map +1 -1
- package/dist/browser/pacem-numerical.min.js +1 -1
- package/dist/browser/pacem-plus.js +195 -4
- package/dist/browser/pacem-plus.js.map +1 -1
- package/dist/browser/pacem-plus.min.js +1 -1
- package/dist/browser/pacem-scaffolding.js +420 -38
- package/dist/browser/pacem-scaffolding.js.map +1 -1
- package/dist/browser/pacem-scaffolding.min.js +2 -2
- package/dist/browser/pacem-ui.js +143 -19
- package/dist/browser/pacem-ui.js.map +1 -1
- package/dist/browser/pacem-ui.min.js +2 -2
- package/dist/bundle/pacem.min.mjs +147 -147
- package/dist/bundle/pacem.mjs +2905 -1417
- package/dist/bundle/pacem.mjs.map +3 -3
- package/dist/docs/pacem-2d.json +11549 -0
- package/dist/docs/pacem-3d.json +29096 -0
- package/dist/docs/pacem-charts.json +4244 -0
- package/dist/docs/pacem-cms.json +9325 -0
- package/dist/docs/pacem-core.json +40109 -0
- package/dist/docs/pacem-foundation.json +8941 -0
- package/dist/docs/pacem-fx.json +3121 -0
- package/dist/docs/pacem-logging.json +941 -0
- package/dist/docs/pacem-maps.json +17387 -0
- package/dist/docs/pacem-media.json +1203 -0
- package/dist/docs/pacem-networking.json +1798 -0
- package/dist/docs/pacem-numerical.json +13706 -0
- package/dist/docs/pacem-plus.json +8468 -0
- package/dist/docs/pacem-scaffolding.json +34788 -0
- package/dist/docs/pacem-ui.json +18628 -0
- package/dist/typings/index.d.ts +4109 -31
- package/dist/vscode.html-custom.json +1303 -741
- package/package.json +4 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @pacem/pacem v1.0.0-
|
|
2
|
+
* @pacem/pacem v1.0.0-dirac (https://js.pacem.it)
|
|
3
3
|
* Pacem (https://pacem.it)
|
|
4
4
|
* Licensed under Apache-2.0
|
|
5
5
|
*/
|
|
@@ -24,22 +24,39 @@
|
|
|
24
24
|
output['css'] = css;
|
|
25
25
|
return output;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Collection of ready-made {@link Easing} functions, each paired with its CSS timing-function equivalent.
|
|
29
|
+
*/
|
|
27
30
|
const Easings = {
|
|
31
|
+
/** No easing: progress is proportional to elapsed time. */
|
|
28
32
|
linear: assembleEasing(EASINGS.linear, "linear"),
|
|
33
|
+
/** Sine ease-in: starts slow, accelerates towards the end. */
|
|
29
34
|
sineIn: assembleEasing(EASINGS.sineIn, 'cubic-bezier(0.12, 0, 0.39, 0)'),
|
|
35
|
+
/** Sine ease-out: starts fast, decelerates towards the end. */
|
|
30
36
|
sineOut: assembleEasing(EASINGS.sineOut, 'cubic-bezier(0.61, 1, 0.88, 1)'),
|
|
37
|
+
/** Sine ease-in-out: accelerates then decelerates, symmetric around the midpoint. */
|
|
31
38
|
sineInOut: assembleEasing(EASINGS.sineInOut, 'cubic-bezier(0.37, 0, 0.63, 1)'),
|
|
32
39
|
// TODO: set correct pairing
|
|
40
|
+
/** Exponential ease-in: starts very slow, accelerates sharply towards the end. */
|
|
33
41
|
expoIn: assembleEasing(EASINGS.expoIn, 'cubic-bezier(0.7, 0, 0.84, 0)'),
|
|
42
|
+
/** Exponential ease-out: starts very fast, decelerates sharply towards the end. */
|
|
34
43
|
expoOut: assembleEasing(EASINGS.expoOut, 'cubic-bezier(0.16, 1, 0.3, 1)'),
|
|
44
|
+
/** Exponential ease-in-out: sharp acceleration then sharp deceleration, symmetric around the midpoint. */
|
|
35
45
|
expoInOut: assembleEasing(EASINGS.expoInOut, 'cubic-bezier(0.87, 0, 0.13, 1)'),
|
|
36
46
|
};
|
|
37
47
|
//}
|
|
38
48
|
|
|
39
49
|
// namespace Pacem {
|
|
50
|
+
/**
|
|
51
|
+
* Recursively clones plain objects, arrays, `Date`s and `RegExp`s, preserving reference cycles/shared
|
|
52
|
+
* references within a single `clone` call (via an internal `WeakMap`). DOM `Element`s, `FileSystemHandle`s
|
|
53
|
+
* and `File`s are returned as-is (not cloned) - they aren't meaningfully deep-cloneable and are typically
|
|
54
|
+
* meant to be referenced, not duplicated.
|
|
55
|
+
*/
|
|
40
56
|
class DeepCloner {
|
|
41
57
|
constructor() {
|
|
42
58
|
}
|
|
59
|
+
/** Deep-clones `obj`; see {@link DeepCloner} for what gets cloned vs. passed through by reference. */
|
|
43
60
|
static clone(obj) {
|
|
44
61
|
return new DeepCloner()._clone(obj);
|
|
45
62
|
}
|
|
@@ -110,13 +127,27 @@
|
|
|
110
127
|
this._jsonFnWeakMap.delete(fn);
|
|
111
128
|
}
|
|
112
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* A `JSON.stringify`/`JSON.parse` superset able to round-trip values plain JSON can't represent: circular/
|
|
132
|
+
* shared object references (`$#ref_N` markers), `RegExp` instances, DOM `Element`s (serialized by `id`
|
|
133
|
+
* and revived via `document.getElementById`, so they must have one), and - depending on
|
|
134
|
+
* {@link JsonSerializationOptions.functions} - functions themselves. The source object is deep-cloned
|
|
135
|
+
* first (via {@link DeepCloner}) so serialization never mutates the input.
|
|
136
|
+
*/
|
|
113
137
|
class Json {
|
|
114
138
|
constructor(_options) {
|
|
115
139
|
this._options = _options;
|
|
116
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Serializes `obj` to a JSON string, extended to support circular/shared references, `RegExp`s,
|
|
143
|
+
* `Element`s (by `id`) and, per `options`, functions.
|
|
144
|
+
* @param obj Value to serialize.
|
|
145
|
+
* @param options Controls how function-valued properties are handled.
|
|
146
|
+
*/
|
|
117
147
|
static serialize(obj, options) {
|
|
118
148
|
return new Json(options)._serialize(obj);
|
|
119
149
|
}
|
|
150
|
+
/** Deserializes a string produced by {@link serialize}, restoring references, `RegExp`s, `Element`s and functions. */
|
|
120
151
|
static deserialize(json) {
|
|
121
152
|
return new Json()._deserialize(json);
|
|
122
153
|
}
|
|
@@ -240,6 +271,12 @@
|
|
|
240
271
|
//}
|
|
241
272
|
|
|
242
273
|
//namespace Pacem {
|
|
274
|
+
/**
|
|
275
|
+
* A `PromiseLike<T>` whose resolution is externalized: unlike a plain `Promise`, the executor isn't
|
|
276
|
+
* passed a callback up front - instead, `resolve`/`reject` are exposed for the caller to invoke later,
|
|
277
|
+
* via the {@link defer} static factory. Useful when the completion of an operation is driven by code
|
|
278
|
+
* that doesn't naturally live inside a `Promise` executor (e.g. event callbacks, decorator plumbing).
|
|
279
|
+
*/
|
|
243
280
|
class DeferPromise {
|
|
244
281
|
constructor() {
|
|
245
282
|
this.deferred = null;
|
|
@@ -248,6 +285,7 @@
|
|
|
248
285
|
me.deferred = { 'resolve': resolve, 'reject': reject, 'promise': me };
|
|
249
286
|
});
|
|
250
287
|
}
|
|
288
|
+
/** Standard `PromiseLike.then`, delegating to the underlying native `Promise`. */
|
|
251
289
|
then(onCompleted, onFailed) {
|
|
252
290
|
return this.promise.then(onCompleted, onFailed);
|
|
253
291
|
}
|
|
@@ -259,14 +297,17 @@
|
|
|
259
297
|
this.promise.then(callback, callback);
|
|
260
298
|
return this;
|
|
261
299
|
}
|
|
300
|
+
/** Registers a fulfillment-only callback (fluent, chainable alternative to `then(callback)`). */
|
|
262
301
|
success(callback) {
|
|
263
302
|
this.promise.then(callback, null);
|
|
264
303
|
return this;
|
|
265
304
|
}
|
|
305
|
+
/** Registers a rejection-only callback (fluent, chainable alternative to `then(null, callback)`). */
|
|
266
306
|
error(callback) {
|
|
267
307
|
this.promise.then(null, callback);
|
|
268
308
|
return this;
|
|
269
309
|
}
|
|
310
|
+
/** Creates a new deferred promise and returns its controller: `{ resolve, reject, promise }`. */
|
|
270
311
|
static defer() {
|
|
271
312
|
var q = new DeferPromise();
|
|
272
313
|
return q.deferred;
|
|
@@ -277,40 +318,56 @@
|
|
|
277
318
|
// namespace Pacem {
|
|
278
319
|
const PACEM_CORE_DEFAULT = 'pacem';
|
|
279
320
|
const DEFAULT_DOWNLOAD_FILENAME = 'download';
|
|
321
|
+
/** Ready-to-use event listener that only calls `evt.stopPropagation()`; handy as an `addEventListener` callback without allocating a closure. */
|
|
280
322
|
const stopPropagationHandler = (evt) => {
|
|
281
323
|
evt.stopPropagation();
|
|
282
324
|
};
|
|
325
|
+
/** Ready-to-use event listener that only calls `evt.preventDefault()`; handy as an `addEventListener` callback without allocating a closure. */
|
|
283
326
|
const preventDefaultHandler = (evt) => {
|
|
284
327
|
evt.preventDefault();
|
|
285
328
|
};
|
|
329
|
+
/** Ready-to-use event listener that calls both `evt.preventDefault()` and `evt.stopPropagation()`. */
|
|
286
330
|
const avoidHandler = (evt) => {
|
|
287
331
|
evt.preventDefault();
|
|
288
332
|
evt.stopPropagation();
|
|
289
333
|
};
|
|
290
334
|
const SEGMENT_PATTERN = /^\/[^\/]+/;
|
|
291
335
|
const ROUTE_SEGMENT_PATTERN = /\/\{([a-z\$_][\w]*)\??\}/;
|
|
336
|
+
/**
|
|
337
|
+
* The framework's static utility grab-bag: general helpers plus namespaced sub-modules (`Json`, `Dates`,
|
|
338
|
+
* `Css`, `Strings`, `Blobs`, `Images`, `Browsers`, `Cookies`, `URIs`) re-exposing (and in some cases
|
|
339
|
+
* extending) functionality from `@pacem/pacem-foundation`. Also the home of `Utils.core`, the global
|
|
340
|
+
* registry object used for cross-cutting framework state (e.g. registered {@link Transformer}s).
|
|
341
|
+
*/
|
|
292
342
|
class Utils {
|
|
343
|
+
/** The framework's global scratch/registry object (`window[id]`, where `id` defaults to `'pacem'` and is configurable via `window.Pacem.Configuration.core`); created on first access. Used e.g. to store {@link Transformer}-registered transform functions. */
|
|
293
344
|
static get core() {
|
|
294
345
|
const root = window['Pacem'];
|
|
295
346
|
var id = (root && root.Configuration && root.Configuration.core) || PACEM_CORE_DEFAULT;
|
|
296
347
|
return window[id] = window[id] || {};
|
|
297
348
|
}
|
|
349
|
+
/** The platform's (native or polyfilled) `customElements` registry. */
|
|
298
350
|
static get customElements() {
|
|
299
351
|
return window['customElements'];
|
|
300
352
|
}
|
|
301
353
|
// #region GENERAL
|
|
354
|
+
/** Generates a unique numeric-ish id string. */
|
|
302
355
|
static uniqueId() {
|
|
303
356
|
return pacemFoundation.Keys.uniqueId();
|
|
304
357
|
}
|
|
358
|
+
/** Generates a unique short code string. */
|
|
305
359
|
static uniqueCode() {
|
|
306
360
|
return pacemFoundation.Keys.uniqueCode();
|
|
307
361
|
}
|
|
362
|
+
/** Generates a random string of the given `length`. */
|
|
308
363
|
static randomString(length) {
|
|
309
364
|
return pacemFoundation.Keys.randomString(length);
|
|
310
365
|
}
|
|
366
|
+
/** Parses a date-like value (ISO string, `Date`, or timestamp) into a `Date`. */
|
|
311
367
|
static parseDate(input) {
|
|
312
368
|
return pacemFoundation.Dates.parse(input);
|
|
313
369
|
}
|
|
370
|
+
/** Writes `input` to the system clipboard, using the async Clipboard API when available and falling back to `document.execCommand('copy')` otherwise. */
|
|
314
371
|
static copyToClipboard(input) {
|
|
315
372
|
if (navigator.clipboard) {
|
|
316
373
|
return navigator.clipboard.writeText(input);
|
|
@@ -378,6 +435,7 @@
|
|
|
378
435
|
return filter;
|
|
379
436
|
}
|
|
380
437
|
}
|
|
438
|
+
/** Escapes `input` for safe use as a CSS identifier/selector fragment. */
|
|
381
439
|
static cssEscape(input) {
|
|
382
440
|
return escape(input).replace('%', '\\');
|
|
383
441
|
}
|
|
@@ -385,9 +443,11 @@
|
|
|
385
443
|
static { this.Css = {
|
|
386
444
|
colorize: Utils.colorize,
|
|
387
445
|
escape: Utils.cssEscape,
|
|
446
|
+
/** Reads a CSS custom property's current value off the document root (`:root`/`html`). */
|
|
388
447
|
getVariableValue(name) {
|
|
389
448
|
return getComputedStyle(document.documentElement).getPropertyValue(name);
|
|
390
449
|
},
|
|
450
|
+
/** Sets a CSS custom property's value on the document root (`:root`/`html`). */
|
|
391
451
|
setVariable(name, value) {
|
|
392
452
|
getComputedStyle(document.documentElement).setProperty(name, value);
|
|
393
453
|
},
|
|
@@ -417,6 +477,7 @@
|
|
|
417
477
|
}
|
|
418
478
|
return false;
|
|
419
479
|
},
|
|
480
|
+
/** Parses an element's (or style declaration's) computed `transform: matrix(...)` CSS value into its 2D affine matrix components; identity if unset. */
|
|
420
481
|
deserializeTransform(element) {
|
|
421
482
|
const style = element instanceof Element ? getComputedStyle(element) : element;
|
|
422
483
|
let a = 1, b = 0, c = 0, d = 1, x = 0, y = 0, matches = /^matrix\((.*)\)$/.exec(style.transform), mij;
|
|
@@ -443,6 +504,7 @@
|
|
|
443
504
|
leftPad: pacemFoundation.Strings.leftPad,
|
|
444
505
|
format: pacemFoundation.Strings.format,
|
|
445
506
|
diff: pacemFoundation.Strings.diff,
|
|
507
|
+
/** Strips HTML markup from `html`, returning its plain-text content. */
|
|
446
508
|
stripHTML: (html) => {
|
|
447
509
|
let doc = new DOMParser().parseFromString(html, 'text/html');
|
|
448
510
|
return doc.body.textContent || '';
|
|
@@ -461,6 +523,7 @@
|
|
|
461
523
|
load: pacemFoundation.Imaging.loadImage,
|
|
462
524
|
resize: pacemFoundation.Imaging.resizeImage
|
|
463
525
|
}; }
|
|
526
|
+
/** Loads an image from `src` and resolves with the `HTMLImageElement` once ready (or rejects on error). */
|
|
464
527
|
static loadImage(src) {
|
|
465
528
|
return new Promise((resolve, reject) => {
|
|
466
529
|
const img = new Image();
|
|
@@ -478,15 +541,19 @@
|
|
|
478
541
|
}
|
|
479
542
|
});
|
|
480
543
|
}
|
|
544
|
+
/** Converts a `Blob` to a `data:` URL string. */
|
|
481
545
|
static blobToDataURL(blob) {
|
|
482
546
|
return Utils.Blobs.toDataURL(blob);
|
|
483
547
|
}
|
|
548
|
+
/** Converts a `data:` URL string back into a `Blob`. */
|
|
484
549
|
static dataURLToBlob(dataURL) {
|
|
485
550
|
return Utils.Blobs.fromDataURL(dataURL);
|
|
486
551
|
}
|
|
552
|
+
/** Reads a `Blob`'s content as text, using the given `encoding` (default UTF-8). */
|
|
487
553
|
static blobToText(blob, encoding) {
|
|
488
554
|
return Utils.Blobs.toText(blob, encoding);
|
|
489
555
|
}
|
|
556
|
+
/** Wraps `content` in a `Blob` of the given MIME `type` (default `'text/plain'`). */
|
|
490
557
|
static textToBlob(content, type = 'text/plain') {
|
|
491
558
|
return Utils.Blobs.fromText(content, type);
|
|
492
559
|
}
|
|
@@ -572,6 +639,7 @@
|
|
|
572
639
|
el.src = url;
|
|
573
640
|
return deferred.promise;
|
|
574
641
|
}
|
|
642
|
+
/** Returns the list of vendor-prefixed `getUserMedia` implementations available on `navigator`, if any. */
|
|
575
643
|
static getUserMediaFunctions() {
|
|
576
644
|
var _getUserMedia = [];
|
|
577
645
|
let methods = [navigator['getUserMedia'], navigator['webkitGetUserMedia'], navigator['msGetUserMedia'], navigator['mozGetUserMedia']];
|
|
@@ -818,10 +886,12 @@
|
|
|
818
886
|
}
|
|
819
887
|
// #endregion
|
|
820
888
|
// #region DOM
|
|
889
|
+
/** Whether the document (including module scripts) has fully finished loading (`document.readyState === 'complete'`). */
|
|
821
890
|
static isDOMReady() {
|
|
822
891
|
// Must exclude 'interactive' state since module script haven't been processed yet.
|
|
823
892
|
return /* document.readyState === 'interactive' ||*/ document.readyState === 'complete';
|
|
824
893
|
}
|
|
894
|
+
/** Registers `listener` to run once the document (and its resources, e.g. images) has fully loaded (the `window` `'load'` event). */
|
|
825
895
|
static onDOMReady(listener) {
|
|
826
896
|
//window.addEventListener('DOMContentLoaded', listener, false);
|
|
827
897
|
// window 'load' event fires after 'DOMCOntentLoaded' since includes images load.
|
|
@@ -850,13 +920,16 @@
|
|
|
850
920
|
}
|
|
851
921
|
return dom;
|
|
852
922
|
}
|
|
923
|
+
/** Cross-browser `Element.matches(selector)`, falling back to vendor-prefixed variants. */
|
|
853
924
|
static is(el, selector) {
|
|
854
925
|
return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector)
|
|
855
926
|
.call(el, selector);
|
|
856
927
|
}
|
|
928
|
+
/** Resolves the effective language for `el`: its own `lang` attribute, else the document's, else the browser's. */
|
|
857
929
|
static lang(el) {
|
|
858
930
|
return el.lang || document.documentElement.lang || navigator.language;
|
|
859
931
|
}
|
|
932
|
+
/** JSON-stringifies `obj` (via {@link Json}), or passes through `null`/`undefined` unchanged. */
|
|
860
933
|
static jsonSortStringify(obj) {
|
|
861
934
|
if (Utils.isNull(obj)) {
|
|
862
935
|
return obj;
|
|
@@ -866,6 +939,7 @@
|
|
|
866
939
|
static { this.Browsers = {
|
|
867
940
|
detect: pacemFoundation.detect
|
|
868
941
|
}; }
|
|
942
|
+
/** Parses a `document.cookie`-style string (or `document.cookie` itself, by default) into a name/value map. */
|
|
869
943
|
static cookies(cookie) {
|
|
870
944
|
const cookies = (cookie ?? document.cookie).split(';'), retval = {};
|
|
871
945
|
for (var pair of cookies) {
|
|
@@ -881,7 +955,9 @@
|
|
|
881
955
|
}
|
|
882
956
|
return retval;
|
|
883
957
|
}
|
|
958
|
+
/** Cookie helpers, preferring the native `cookieStore` API when available and falling back to `document.cookie` parsing otherwise. */
|
|
884
959
|
static { this.Cookies = {
|
|
960
|
+
/** Retrieves all cookies (or just `cookieName`, if given) as {@link CookieData} entries. */
|
|
885
961
|
getAll: async (cookieName) => {
|
|
886
962
|
const store = 'cookieStore' in window ? window.cookieStore : null;
|
|
887
963
|
const retval = [];
|
|
@@ -899,6 +975,7 @@
|
|
|
899
975
|
return await store.getAll(cookieName);
|
|
900
976
|
}
|
|
901
977
|
},
|
|
978
|
+
/** Serializes a {@link CookieData} descriptor into a `document.cookie`-assignable string (including `domain`/`path`/`max-age`/`expires`/`Partitioned`/`SameSite`/`Secure` attributes, as provided). */
|
|
902
979
|
stringify: (data) => {
|
|
903
980
|
let retval = `${data.name}=${encodeURIComponent(data.value ?? '')}`;
|
|
904
981
|
if (!Utils.isNullOrEmpty(data.domain)) {
|
|
@@ -925,6 +1002,7 @@
|
|
|
925
1002
|
return retval;
|
|
926
1003
|
}
|
|
927
1004
|
}; }
|
|
1005
|
+
/** Tests whether `el` is currently visible (via the `checkVisibility` API when available, falling back to a CSS-visibility/size heuristic). */
|
|
928
1006
|
static isVisible(el) {
|
|
929
1007
|
if ('checkVisibility' in el) {
|
|
930
1008
|
return el.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true });
|
|
@@ -932,6 +1010,7 @@
|
|
|
932
1010
|
return getComputedStyle(el).visibility !== 'hidden' && (el.clientWidth > 0 || el.clientHeight > 0);
|
|
933
1011
|
}
|
|
934
1012
|
//#region classList DOMTokenList (css)
|
|
1013
|
+
/** Tests whether `el` has `className` set, using `classList` when available (with a regex-based fallback). */
|
|
935
1014
|
static hasClass(el, className) {
|
|
936
1015
|
if (el.classList) {
|
|
937
1016
|
return el.classList.contains(className);
|
|
@@ -940,6 +1019,7 @@
|
|
|
940
1019
|
return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
|
|
941
1020
|
}
|
|
942
1021
|
}
|
|
1022
|
+
/** Adds one or more (space-separated) classes to `el`, using `classList` when available. */
|
|
943
1023
|
static addClass(el, className) {
|
|
944
1024
|
const css = className.trim();
|
|
945
1025
|
if (el.classList) {
|
|
@@ -949,6 +1029,7 @@
|
|
|
949
1029
|
el.setAttribute('class', el.className + ' ' + css);
|
|
950
1030
|
}
|
|
951
1031
|
}
|
|
1032
|
+
/** Removes one or more (space-separated) classes from `el`, using `classList` when available. */
|
|
952
1033
|
static removeClass(el, className) {
|
|
953
1034
|
const css = className.trim();
|
|
954
1035
|
if (el.classList) {
|
|
@@ -958,6 +1039,7 @@
|
|
|
958
1039
|
el.setAttribute('class', el.className.replace(new RegExp('(^|\\b)' + css.split(' ').join('|') + '(\\b|$)', 'gi'), ' '));
|
|
959
1040
|
}
|
|
960
1041
|
}
|
|
1042
|
+
/** Adds or removes `className` on `el` depending on `on`; see {@link addClass}/{@link removeClass}. */
|
|
961
1043
|
static toggleClass(el, className, on) {
|
|
962
1044
|
if (on) {
|
|
963
1045
|
Utils.addClass(el, className);
|
|
@@ -968,15 +1050,19 @@
|
|
|
968
1050
|
}
|
|
969
1051
|
//#endregion
|
|
970
1052
|
//#region part DOMTokenList (shadow-DOM)
|
|
1053
|
+
/** Tests whether `el`'s `part` attribute (CSS Shadow Parts) contains `partName`. */
|
|
971
1054
|
static hasPart(el, partName) {
|
|
972
1055
|
return el.part.contains(partName);
|
|
973
1056
|
}
|
|
1057
|
+
/** Adds one or more (space-separated) shadow-part names to `el`'s `part` attribute. */
|
|
974
1058
|
static addPart(el, partName) {
|
|
975
1059
|
DOMTokenList.prototype.add.apply(el.part, partName.trim().split(' '));
|
|
976
1060
|
}
|
|
1061
|
+
/** Removes one or more (space-separated) shadow-part names from `el`'s `part` attribute. */
|
|
977
1062
|
static removePart(el, partName) {
|
|
978
1063
|
DOMTokenList.prototype.remove.apply(el.part, partName.trim().split(' '));
|
|
979
1064
|
}
|
|
1065
|
+
/** Adds or removes `partName` on `el`'s `part` attribute depending on `on`; see {@link addPart}/{@link removePart}. */
|
|
980
1066
|
static togglePart(el, partName, on) {
|
|
981
1067
|
if (on) {
|
|
982
1068
|
Utils.addPart(el, partName);
|
|
@@ -1012,9 +1098,11 @@
|
|
|
1012
1098
|
height: rect.height
|
|
1013
1099
|
};
|
|
1014
1100
|
}
|
|
1101
|
+
/** Sums `offsetTop` up the `offsetParent` chain, giving `el`'s vertical position relative to the document rather than just its nearest positioned ancestor. */
|
|
1015
1102
|
static naturalOffsetTop(el) {
|
|
1016
1103
|
return (el?.offsetTop ?? 0) + ((el?.offsetParent && el.offsetParent instanceof HTMLElement) ? this.naturalOffsetTop(el.offsetParent) : 0);
|
|
1017
1104
|
}
|
|
1105
|
+
/** Sums `offsetTop` up the `offsetParent` chain (note: mirrors {@link naturalOffsetTop}'s calculation, not `offsetLeft`), giving `el`'s horizontal position relative to the document. */
|
|
1018
1106
|
static naturalOffsetLeft(el) {
|
|
1019
1107
|
return (el?.offsetTop ?? 0) + ((el?.offsetParent && el.offsetParent instanceof HTMLElement) ? this.naturalOffsetLeft(el.offsetParent) : 0);
|
|
1020
1108
|
}
|
|
@@ -1042,9 +1130,11 @@
|
|
|
1042
1130
|
static deserializeTransform(obj) {
|
|
1043
1131
|
return Utils.Css.deserializeTransform(obj);
|
|
1044
1132
|
}
|
|
1133
|
+
/** Sets the window's vertical scroll position, keeping the current horizontal position. */
|
|
1045
1134
|
static set scrollTop(y) {
|
|
1046
1135
|
window.scrollTo(Utils.scrollLeft, y);
|
|
1047
1136
|
}
|
|
1137
|
+
/** Sets the window's horizontal scroll position, keeping the current vertical position. */
|
|
1048
1138
|
static set scrollLeft(x) {
|
|
1049
1139
|
window.scrollTo(x, Utils.scrollTop);
|
|
1050
1140
|
}
|
|
@@ -1055,12 +1145,15 @@
|
|
|
1055
1145
|
const behavior = (yFirst ? y : smooth) ? 'smooth' : 'instant';
|
|
1056
1146
|
window.scrollTo({ behavior, left, top });
|
|
1057
1147
|
}
|
|
1148
|
+
/** The window's current vertical scroll position, with fallbacks for older browsers. */
|
|
1058
1149
|
static get scrollTop() {
|
|
1059
1150
|
return window.scrollY /*window.pageYOffset*/ || document.documentElement.scrollTop || document.body.scrollTop || 0;
|
|
1060
1151
|
}
|
|
1152
|
+
/** The window's current horizontal scroll position, with fallbacks for older browsers. */
|
|
1061
1153
|
static get scrollLeft() {
|
|
1062
1154
|
return window.scrollX /*window.pageXOffset*/ || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
|
|
1063
1155
|
}
|
|
1156
|
+
/** The window's current viewport size (`{ width, height }`), with fallbacks for older browsers. */
|
|
1064
1157
|
static get windowSize() {
|
|
1065
1158
|
let win = window;
|
|
1066
1159
|
return {
|
|
@@ -1136,16 +1229,20 @@
|
|
|
1136
1229
|
}
|
|
1137
1230
|
// #endregion
|
|
1138
1231
|
// #region other
|
|
1232
|
+
/** Tests whether `obj` is "empty" (per {@link NullChecker.isEmpty}: `null`/`undefined`/`''`/an empty array or object), excluding DOM `Node`s (which are never considered empty here). */
|
|
1139
1233
|
static isEmpty(obj) {
|
|
1140
1234
|
return pacemFoundation.NullChecker.isEmpty(obj) && !(obj instanceof Node);
|
|
1141
1235
|
}
|
|
1236
|
+
/** Type-guarding test for `obj` being `null` or `undefined`. */
|
|
1142
1237
|
static isNull(obj) {
|
|
1143
1238
|
return pacemFoundation.NullChecker.isNull(obj);
|
|
1144
1239
|
}
|
|
1145
1240
|
// legacy
|
|
1241
|
+
/** Type-guarding test for `val` being an array. */
|
|
1146
1242
|
static isArray(val) {
|
|
1147
1243
|
return Array.isArray(val);
|
|
1148
1244
|
}
|
|
1245
|
+
/** Tests whether `val` is `null`/`undefined` or "empty"; see {@link isNull}/{@link isEmpty}. */
|
|
1149
1246
|
static isNullOrEmpty(val) {
|
|
1150
1247
|
return Utils.isNull(val) || Utils.isEmpty(val);
|
|
1151
1248
|
}
|
|
@@ -1164,6 +1261,7 @@
|
|
|
1164
1261
|
}
|
|
1165
1262
|
/** Legacy alias for Object.assign(). */
|
|
1166
1263
|
static { this.extend = Object.assign; }
|
|
1264
|
+
/** Deep-clones `obj`; see {@link DeepCloner}. */
|
|
1167
1265
|
static clone(obj) {
|
|
1168
1266
|
if (obj === undefined)
|
|
1169
1267
|
return undefined;
|
|
@@ -1173,6 +1271,7 @@
|
|
|
1173
1271
|
static fromResult(v) {
|
|
1174
1272
|
return Promise.resolve(v);
|
|
1175
1273
|
}
|
|
1274
|
+
/** Runs `task` on the next animation frame and wraps its result in a `Promise`. */
|
|
1176
1275
|
static fromResultAsync(task) {
|
|
1177
1276
|
return new Promise(resolve => requestAnimationFrame(() => resolve(task())));
|
|
1178
1277
|
}
|
|
@@ -1196,7 +1295,15 @@
|
|
|
1196
1295
|
}
|
|
1197
1296
|
//#endregion
|
|
1198
1297
|
//#region Net
|
|
1298
|
+
/** URL/route parsing and formatting helpers, chiefly backing the router (`{segment}`/`{segment?}` template resolution, query-string parsing, route metadata). */
|
|
1199
1299
|
static { this.URIs = {
|
|
1300
|
+
/**
|
|
1301
|
+
* Substitutes each `{name}`/`{name?}` template segment in `url` with the matching entry of `parameters`
|
|
1302
|
+
* (URL-encoded), then strips out any remaining unmatched *optional* segments.
|
|
1303
|
+
* @param url URL/route template containing `{name}`/`{name?}` segments.
|
|
1304
|
+
* @param parameters Values to substitute, keyed by segment name.
|
|
1305
|
+
* @param removeMatchedParameters When `true`, consumed entries are deleted from `parameters`.
|
|
1306
|
+
*/
|
|
1200
1307
|
format: function (url, parameters, removeMatchedParameters) {
|
|
1201
1308
|
// replace segments
|
|
1202
1309
|
for (let name in parameters || {}) {
|
|
@@ -1219,6 +1326,14 @@
|
|
|
1219
1326
|
}
|
|
1220
1327
|
return url;
|
|
1221
1328
|
},
|
|
1329
|
+
/**
|
|
1330
|
+
* Appends `parameters` to `url`'s query string (or hash fragment, when `hash` is `true`), URL-encoding
|
|
1331
|
+
* names and values, and correctly choosing `?`/`&` (or `#`/`&`) as the joining separator.
|
|
1332
|
+
* @param url Base URL.
|
|
1333
|
+
* @param parameters Values to append, keyed by parameter name.
|
|
1334
|
+
* @param removeNullEntries When `true`, entries whose value is `null`/`undefined` are omitted instead of appended as empty.
|
|
1335
|
+
* @param hash When `true`, appends to the URL's hash fragment instead of its query string.
|
|
1336
|
+
*/
|
|
1222
1337
|
appendQuery: function (url, parameters, removeNullEntries = false, hash = false) {
|
|
1223
1338
|
const char = hash ? '#' : '?', pattern = hash ? /#/ : /\?/;
|
|
1224
1339
|
const query = (pattern.test(url) ? '&' : char) +
|
|
@@ -1227,6 +1342,7 @@
|
|
|
1227
1342
|
.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(parameters[k] ?? '')).join('&');
|
|
1228
1343
|
return url + (query.length > 1 ? query : '');
|
|
1229
1344
|
},
|
|
1345
|
+
/** Parses a query string (or a `Location`'s `.search`, defaulting to `window.location`) into a name/value map. */
|
|
1230
1346
|
parseQuery: (query = window.location) => {
|
|
1231
1347
|
if (typeof query !== 'string') {
|
|
1232
1348
|
query = query.search;
|
|
@@ -1237,9 +1353,11 @@
|
|
|
1237
1353
|
});
|
|
1238
1354
|
return obj;
|
|
1239
1355
|
},
|
|
1356
|
+
/** Tests whether `url` contains at least one non-optional `{name}` template segment (as opposed to only `{name?}` ones). */
|
|
1240
1357
|
hasMandatoryTemplateSegments: function (url) {
|
|
1241
1358
|
return /(^|\/)\{\.*\}(\/|$)/.test(url);
|
|
1242
1359
|
},
|
|
1360
|
+
/** Parses a route template's `{name}`/`{name?}` segments into an ordered list of {@link RouteMetadata} descriptors, consumed by {@link parseState}. */
|
|
1243
1361
|
parseRoute: function (pathTemplate) {
|
|
1244
1362
|
let tmpl = pathTemplate;
|
|
1245
1363
|
const trunks = [];
|
|
@@ -1259,6 +1377,7 @@
|
|
|
1259
1377
|
}
|
|
1260
1378
|
return trunks;
|
|
1261
1379
|
},
|
|
1380
|
+
/** Splits `url` into its `protocol`, `domain`, `path`, `query` (including leading `?`) and `hash` (including leading `#`) parts, or `null` if it can't be parsed. */
|
|
1262
1381
|
split: function (url) {
|
|
1263
1382
|
const URL_PATTERN = /^((https?:)?\/\/[^\/]+)?([^\?#]+)(\?[^#]*)?(#[^#]*)?$/;
|
|
1264
1383
|
const regArr = URL_PATTERN.exec(url);
|
|
@@ -1267,6 +1386,16 @@
|
|
|
1267
1386
|
}
|
|
1268
1387
|
return { domain: regArr[2] ?? '', protocol: regArr[1] ?? '', path: regArr[3] ?? '', query: regArr[4] ?? '', hash: regArr[5] ?? '' };
|
|
1269
1388
|
},
|
|
1389
|
+
/**
|
|
1390
|
+
* Builds a {@link RouterState} for `url`, extracting named route segments per `metadata` (see
|
|
1391
|
+
* {@link parseRoute}) as top-level properties, alongside the standard `$path`/`$pathname`/`$querystring`/
|
|
1392
|
+
* `$query`/`$hash` keys. Throws if a non-optional route segment declared in `metadata` isn't present in `path`.
|
|
1393
|
+
* @param metadata Route segment descriptors, as produced by {@link parseRoute}.
|
|
1394
|
+
* @param url Full URL/path being navigated to.
|
|
1395
|
+
* @param path Path component override; parsed out of `url` via {@link split} when omitted.
|
|
1396
|
+
* @param query Query-string override (including leading `?`); parsed out of `url` when omitted.
|
|
1397
|
+
* @param hash Hash-fragment override (including leading `#`); parsed out of `url` when omitted.
|
|
1398
|
+
*/
|
|
1270
1399
|
parseState: function (metadata, url, path, query, hash) {
|
|
1271
1400
|
let fullPath = url;
|
|
1272
1401
|
if (Utils.isNullOrEmpty(path)) {
|
|
@@ -1351,6 +1480,7 @@
|
|
|
1351
1480
|
}
|
|
1352
1481
|
// }
|
|
1353
1482
|
|
|
1483
|
+
/** String tokens accepted by {@link CustomEventUtils.matchModifiers} to describe a keyboard/mouse modifier. */
|
|
1354
1484
|
var EventKeyModifier;
|
|
1355
1485
|
(function (EventKeyModifier) {
|
|
1356
1486
|
EventKeyModifier["AltKey"] = "Alt";
|
|
@@ -1358,11 +1488,24 @@
|
|
|
1358
1488
|
EventKeyModifier["ShiftKey"] = "Shift";
|
|
1359
1489
|
EventKeyModifier["MetaKey"] = "Cmd";
|
|
1360
1490
|
})(EventKeyModifier || (EventKeyModifier = {}));
|
|
1491
|
+
/** Static helpers for inspecting and normalizing native/custom events (coordinates, keyboard modifiers, type checks). */
|
|
1361
1492
|
class CustomEventUtils {
|
|
1493
|
+
/**
|
|
1494
|
+
* Type-guarding check for whether `evt` is an instance of the given event `type`.
|
|
1495
|
+
* @param evt Event to test.
|
|
1496
|
+
* @param type Event constructor to test against.
|
|
1497
|
+
* @returns `true` (narrowing `evt` to `TEvent`) if `evt instanceof type`.
|
|
1498
|
+
*/
|
|
1362
1499
|
static isInstanceOf(evt, type) {
|
|
1363
1500
|
return evt instanceof type;
|
|
1364
1501
|
// || CustomElementUtils.getAttachedPropertyValue(evt, 'pacem:custom-event') === evt.type;
|
|
1365
1502
|
}
|
|
1503
|
+
/**
|
|
1504
|
+
* Extracts page/client/screen coordinates from a mouse or (single-)touch event, using the first
|
|
1505
|
+
* active touch (`touches[0]`, falling back to `changedTouches[0]`) for `TouchEvent`s.
|
|
1506
|
+
* @param evt Source mouse/touch event, or an already-extracted {@link UIEventLike}.
|
|
1507
|
+
* @returns The event's position in all three coordinate systems.
|
|
1508
|
+
*/
|
|
1366
1509
|
static getEventCoordinates(evt) {
|
|
1367
1510
|
var src;
|
|
1368
1511
|
if ('touches' in evt) {
|
|
@@ -1382,6 +1525,11 @@
|
|
|
1382
1525
|
client: { x: src.clientX, y: src.clientY }
|
|
1383
1526
|
};
|
|
1384
1527
|
}
|
|
1528
|
+
/**
|
|
1529
|
+
* Extracts the keyboard-modifier flags (and, for mouse events, the pressed button as `which`) from a native event.
|
|
1530
|
+
* @param evt Source keyboard/mouse/touch event, or an already-extracted {@link KeyEventLike}.
|
|
1531
|
+
* @returns The captured modifier flags.
|
|
1532
|
+
*/
|
|
1385
1533
|
static getEventKeyModifiers(evt) {
|
|
1386
1534
|
var which = evt.which;
|
|
1387
1535
|
if (evt instanceof MouseEvent) {
|
|
@@ -1402,6 +1550,13 @@
|
|
|
1402
1550
|
}
|
|
1403
1551
|
return true;
|
|
1404
1552
|
}
|
|
1553
|
+
/**
|
|
1554
|
+
* Works around a legacy Edge/ChakraCore bug (see {@link https://github.com/Microsoft/ChakraCore/issues/3952})
|
|
1555
|
+
* where an instance built via `super(...)` from a `CustomEvent` subclass constructor doesn't correctly
|
|
1556
|
+
* pass `instanceof` checks against that subclass; forcibly resets its prototype when so.
|
|
1557
|
+
* @param evt Event instance to fix up.
|
|
1558
|
+
* @param type The subclass constructor `evt` is supposed to be an instance of.
|
|
1559
|
+
*/
|
|
1405
1560
|
static fixEdgeCustomEventSubClassInstance(evt, type) {
|
|
1406
1561
|
// this an optimistic BUGGED workaround due to a damn' Edge bug: https://github.com/Microsoft/ChakraCore/issues/3952
|
|
1407
1562
|
if (!(evt instanceof type)) {
|
|
@@ -1413,7 +1568,17 @@
|
|
|
1413
1568
|
|
|
1414
1569
|
/// <reference path="utils-customevent.ts" />
|
|
1415
1570
|
// namespace Pacem {
|
|
1571
|
+
/**
|
|
1572
|
+
* Base class for framework custom events whose `detail` payload is strongly typed as `TDetail`.
|
|
1573
|
+
* Thin wrapper around the native `CustomEvent<TDetail>` that also works around an old Edge bug
|
|
1574
|
+
* (see {@link CustomEventUtils.fixEdgeCustomEventSubClassInstance}) affecting `CustomEvent` subclasses.
|
|
1575
|
+
*/
|
|
1416
1576
|
class CustomTypedEvent extends CustomEvent /* new in TypeScript v2.7.1 -> */ {
|
|
1577
|
+
/**
|
|
1578
|
+
* @param type Event name.
|
|
1579
|
+
* @param detail Strongly-typed payload, exposed as `event.detail`.
|
|
1580
|
+
* @param eventInit Standard `CustomEvent` initialization options (`bubbles`, `cancelable`, `composed`).
|
|
1581
|
+
*/
|
|
1417
1582
|
constructor(type, detail, eventInit) {
|
|
1418
1583
|
super(type, Utils.extend({ detail: detail }, eventInit || {}));
|
|
1419
1584
|
CustomEventUtils.fixEdgeCustomEventSubClassInstance(this, this.constructor);
|
|
@@ -1432,7 +1597,20 @@
|
|
|
1432
1597
|
return false;
|
|
1433
1598
|
}
|
|
1434
1599
|
// TODO: make inherit from CustomTypedEvent
|
|
1600
|
+
/**
|
|
1601
|
+
* Base class for UI-originated custom events: like {@link CustomTypedEvent}, but additionally captures
|
|
1602
|
+
* the mouse/touch/keyboard modifiers and coordinates of the originating native event (when supplied),
|
|
1603
|
+
* exposing them through the {@link UIEventLike} surface (`which`, `altKey`, `pageX`, `clientY`, ...).
|
|
1604
|
+
* Useful for events that are re-dispatched/synthesized (e.g. drag & drop) from an original pointer or
|
|
1605
|
+
* keyboard event, so that consumers can still inspect that original event's modifiers/position.
|
|
1606
|
+
*/
|
|
1435
1607
|
class CustomUIEvent extends CustomEvent {
|
|
1608
|
+
/**
|
|
1609
|
+
* @param type Event name.
|
|
1610
|
+
* @param detail Either the strongly-typed payload, or (when it satisfies `CustomEventInit`, i.e. has a `detail` key) the full event-init object.
|
|
1611
|
+
* @param eventInit Either standard `CustomEvent` init options, or the original native event this custom event derives from (in which case its coordinates/modifiers get captured).
|
|
1612
|
+
* @param orig The original native mouse/touch/keyboard event this custom event derives from, when `eventInit` is itself the init options.
|
|
1613
|
+
*/
|
|
1436
1614
|
constructor(type, detail, eventInit, orig) {
|
|
1437
1615
|
super(type, Utils.extend((isEventInit(detail || {}) ? detail : { detail: detail }), (!(eventInit instanceof Event) && eventInit) || {}));
|
|
1438
1616
|
const originalEvent = orig || eventInit;
|
|
@@ -1485,27 +1663,44 @@
|
|
|
1485
1663
|
return this.#coords?.screen.y;
|
|
1486
1664
|
}
|
|
1487
1665
|
}
|
|
1666
|
+
/** Event name dispatched whenever an observed attribute changes; see {@link AttributeChangeEvent}. */
|
|
1488
1667
|
const AttributeChangeEventName = 'attributechange';
|
|
1668
|
+
/**
|
|
1669
|
+
* Dispatched by elements registered with the {@link CustomElement} decorator whenever one of their
|
|
1670
|
+
* observed attributes changes, mirroring the native `attributeChangedCallback` as a DOM event.
|
|
1671
|
+
*/
|
|
1489
1672
|
class AttributeChangeEvent extends CustomTypedEvent {
|
|
1490
1673
|
constructor(args) {
|
|
1491
1674
|
super(AttributeChangeEventName, args);
|
|
1492
1675
|
}
|
|
1493
1676
|
}
|
|
1677
|
+
/** Event name dispatched whenever a `@Watch`-decorated property changes value; see {@link PropertyChangeEvent}. */
|
|
1494
1678
|
const PropertyChangeEventName = 'propertychange';
|
|
1679
|
+
/**
|
|
1680
|
+
* Dispatched whenever a property decorated with {@link Watch} changes value (unless that decorator's
|
|
1681
|
+
* `emit` option is set to `false`). This is the mechanism data-bound expressions listen to in order to
|
|
1682
|
+
* re-evaluate themselves when one of their dependencies changes.
|
|
1683
|
+
*/
|
|
1495
1684
|
class PropertyChangeEvent extends CustomTypedEvent {
|
|
1496
1685
|
constructor(args) {
|
|
1497
1686
|
super(PropertyChangeEventName, args);
|
|
1498
1687
|
}
|
|
1499
1688
|
}
|
|
1500
1689
|
// #region NAVIGATING
|
|
1690
|
+
/** Event name dispatched by a router *before* a navigation is committed; see {@link RouterNavigatingEvent}. Cancelable: calling `preventDefault()` aborts the navigation. */
|
|
1501
1691
|
const RouterNavigatingEventName = 'navigating';
|
|
1692
|
+
/** Event name dispatched by a router *after* a navigation has been committed; see {@link RouterNavigateEvent}. */
|
|
1502
1693
|
const RouterNavigateEventName = 'navigate';
|
|
1694
|
+
/** Dispatched by a router once it has navigated to a new `path` (not cancelable — the navigation already happened). */
|
|
1503
1695
|
class RouterNavigateEvent extends CustomTypedEvent {
|
|
1696
|
+
/** @param path Either the destination path alone, or the full navigation args (path, title, referrer). */
|
|
1504
1697
|
constructor(path) {
|
|
1505
1698
|
super(RouterNavigateEventName, typeof path === 'string' ? { path } : path, { cancelable: false, bubbles: false });
|
|
1506
1699
|
}
|
|
1507
1700
|
}
|
|
1701
|
+
/** Dispatched by a router right before navigating to `path`; cancelable, so a listener can call `preventDefault()` to abort the navigation. */
|
|
1508
1702
|
class RouterNavigatingEvent extends CustomTypedEvent {
|
|
1703
|
+
/** @param path Destination path about to be navigated to. */
|
|
1509
1704
|
constructor(path) {
|
|
1510
1705
|
super(RouterNavigatingEventName, path, { cancelable: true, bubbles: false });
|
|
1511
1706
|
}
|
|
@@ -1513,16 +1708,25 @@
|
|
|
1513
1708
|
// #endregion
|
|
1514
1709
|
//}
|
|
1515
1710
|
|
|
1711
|
+
/**
|
|
1712
|
+
* `step` event dispatched on every animation frame of a running tween, carrying the current progress and value.
|
|
1713
|
+
*/
|
|
1516
1714
|
class AnimationEvent extends CustomTypedEvent {
|
|
1517
1715
|
constructor(args) {
|
|
1518
1716
|
super("step", args);
|
|
1519
1717
|
}
|
|
1520
1718
|
}
|
|
1719
|
+
/**
|
|
1720
|
+
* `end` event dispatched once a tween/animation completes.
|
|
1721
|
+
*/
|
|
1521
1722
|
class AnimationEndEvent extends CustomEvent {
|
|
1522
1723
|
constructor() {
|
|
1523
1724
|
super('end');
|
|
1524
1725
|
}
|
|
1525
1726
|
}
|
|
1727
|
+
/**
|
|
1728
|
+
* `start` event dispatched when a tween/animation begins.
|
|
1729
|
+
*/
|
|
1526
1730
|
class AnimationStartEvent extends CustomEvent {
|
|
1527
1731
|
constructor() {
|
|
1528
1732
|
super('start');
|
|
@@ -1531,7 +1735,20 @@
|
|
|
1531
1735
|
//}
|
|
1532
1736
|
|
|
1533
1737
|
//namespace Pacem.Animations {
|
|
1738
|
+
/**
|
|
1739
|
+
* Runs `requestAnimationFrame`-driven numeric tweens between two values, invoking a callback on each frame.
|
|
1740
|
+
*/
|
|
1534
1741
|
class TweenService {
|
|
1742
|
+
/**
|
|
1743
|
+
* Tweens a numeric value from `from` to `to` over `duration` milliseconds, invoking `callback` on every animation frame.
|
|
1744
|
+
* @param from Starting value.
|
|
1745
|
+
* @param to Ending value.
|
|
1746
|
+
* @param duration Tween duration, in milliseconds.
|
|
1747
|
+
* @param delay Delay before the tween starts, in milliseconds (default `0`).
|
|
1748
|
+
* @param easing Easing function applied to the normalized `[0,1]` time (defaults to {@link Easings.linear}).
|
|
1749
|
+
* @param callback Invoked on every frame (and once more with `time === 1.0`) with the normalized time and the current value.
|
|
1750
|
+
* @returns A promise resolved when the tween completes.
|
|
1751
|
+
*/
|
|
1535
1752
|
run(from, to, duration, delay = 0, easing = Easings.linear, callback = null) {
|
|
1536
1753
|
return new Promise((resolve, _) => {
|
|
1537
1754
|
const now = (performance && performance.now()) || Date.now();
|
|
@@ -1564,6 +1781,10 @@
|
|
|
1564
1781
|
//}
|
|
1565
1782
|
|
|
1566
1783
|
// namespace Pacem.Animations {
|
|
1784
|
+
/**
|
|
1785
|
+
* `requestAnimationFrame`-driven timer that invokes a callback at (approximately) a given frame rate.
|
|
1786
|
+
* Instances are created via the static {@link Timer.run} factory rather than `new`.
|
|
1787
|
+
*/
|
|
1567
1788
|
class Timer {
|
|
1568
1789
|
#fps;
|
|
1569
1790
|
#callback;
|
|
@@ -1584,9 +1805,15 @@
|
|
|
1584
1805
|
this.#handle = requestAnimationFrame(this._run);
|
|
1585
1806
|
}
|
|
1586
1807
|
#then;
|
|
1808
|
+
/**
|
|
1809
|
+
* Creates and starts a new {@link Timer}.
|
|
1810
|
+
* @param callback Invoked on every tick with the current frame timestamp.
|
|
1811
|
+
* @param fps Target frame rate, in frames per second (default `60`).
|
|
1812
|
+
*/
|
|
1587
1813
|
static run(callback, fps = 60) {
|
|
1588
1814
|
return new Timer(callback, fps);
|
|
1589
1815
|
}
|
|
1816
|
+
/** Stops the timer, cancelling any pending animation frame. */
|
|
1590
1817
|
stop() {
|
|
1591
1818
|
cancelAnimationFrame(this.#handle);
|
|
1592
1819
|
}
|
|
@@ -1604,6 +1831,7 @@
|
|
|
1604
1831
|
});
|
|
1605
1832
|
|
|
1606
1833
|
//namespace Pacem.Net {
|
|
1834
|
+
/** HTTP verbs accepted by {@link Fetcher.method} / {@link Http}. */
|
|
1607
1835
|
var HttpMethod;
|
|
1608
1836
|
(function (HttpMethod) {
|
|
1609
1837
|
HttpMethod["Get"] = "GET";
|
|
@@ -1616,10 +1844,15 @@
|
|
|
1616
1844
|
HttpMethod["Connect"] = "CONNECT";
|
|
1617
1845
|
HttpMethod["Trace"] = "TRACE";
|
|
1618
1846
|
})(HttpMethod || (HttpMethod = {}));
|
|
1847
|
+
/** Event name dispatched with the raw fetch result payload; see {@link Fetcher.result}. */
|
|
1619
1848
|
const FetchResultEventName = 'fetchresult';
|
|
1849
|
+
/** Event name dispatched when a {@link Fetcher}'s request fails. */
|
|
1620
1850
|
const FetchErrorEventName = 'error';
|
|
1851
|
+
/** Event name dispatched when a {@link Fetcher}'s request completes successfully. */
|
|
1621
1852
|
const FetchSuccessEventName = 'success';
|
|
1853
|
+
/** Static helpers for working with fetch `Response`s. */
|
|
1622
1854
|
class Fetcher {
|
|
1855
|
+
/** Tests whether a response carries no body (HTTP 204, or an explicit `Content-Length: 0`). */
|
|
1623
1856
|
static isEmpty(r) {
|
|
1624
1857
|
return r.status === 204 || r.headers.get("Content-Length") === "0";
|
|
1625
1858
|
}
|
|
@@ -1629,17 +1862,22 @@
|
|
|
1629
1862
|
/// <reference path="../promise.ts" />
|
|
1630
1863
|
// namespace Pacem.Net {
|
|
1631
1864
|
const noop = () => { };
|
|
1865
|
+
/** Error thrown by {@link Http.request} when a request fails outright or completes with a non-2xx status. */
|
|
1632
1866
|
class StatusCodeError extends Error {
|
|
1867
|
+
/** @param statusCode HTTP status code (`500` for network-level failures). @param statusText Status text / error message. */
|
|
1633
1868
|
constructor(statusCode, statusText) {
|
|
1634
1869
|
super(statusText);
|
|
1635
1870
|
this.statusCode = statusCode;
|
|
1636
1871
|
}
|
|
1872
|
+
/** The HTTP status code that caused this error. */
|
|
1637
1873
|
get status() {
|
|
1638
1874
|
return this.statusCode;
|
|
1639
1875
|
}
|
|
1640
1876
|
}
|
|
1641
|
-
/** @
|
|
1877
|
+
/** Wraps a completed `XMLHttpRequest` produced by {@link Http.request}, exposing its status, headers and body in convenient forms.
|
|
1878
|
+
* @deprecated */
|
|
1642
1879
|
class Response {
|
|
1880
|
+
/** @param req The completed `XMLHttpRequest`. @param processTime Elapsed request time, in milliseconds. */
|
|
1643
1881
|
constructor(req, processTime) {
|
|
1644
1882
|
if (!req)
|
|
1645
1883
|
return;
|
|
@@ -1650,20 +1888,25 @@
|
|
|
1650
1888
|
this._allHeadersRaw = req.getAllResponseHeaders();
|
|
1651
1889
|
this._processTime = processTime;
|
|
1652
1890
|
}
|
|
1891
|
+
/** Elapsed request time, in milliseconds. */
|
|
1653
1892
|
get processTime() {
|
|
1654
1893
|
return this._processTime;
|
|
1655
1894
|
}
|
|
1895
|
+
/** Response headers, parsed into a name/value map (lazily, on first access). */
|
|
1656
1896
|
get headers() {
|
|
1657
1897
|
if (this._headers === undefined && this._allHeadersRaw)
|
|
1658
1898
|
this._parseHeaders();
|
|
1659
1899
|
return this._headers;
|
|
1660
1900
|
}
|
|
1901
|
+
/** The `Content-Length` response header, parsed as a number. */
|
|
1661
1902
|
get size() {
|
|
1662
1903
|
return +this.headers['Content-Length'];
|
|
1663
1904
|
}
|
|
1905
|
+
/** The `Content-Type` response header. */
|
|
1664
1906
|
get mime() {
|
|
1665
1907
|
return this.headers['Content-Type'];
|
|
1666
1908
|
}
|
|
1909
|
+
/** The `Date` response header, parsed into a `Date`. */
|
|
1667
1910
|
get date() {
|
|
1668
1911
|
return new Date(Date.parse(this.headers['Date']));
|
|
1669
1912
|
}
|
|
@@ -1679,9 +1922,13 @@
|
|
|
1679
1922
|
});
|
|
1680
1923
|
this._headers = headers;
|
|
1681
1924
|
}
|
|
1925
|
+
/** HTTP status code. */
|
|
1682
1926
|
get status() { return this._status; }
|
|
1927
|
+
/** Raw response body as text. */
|
|
1683
1928
|
get text() { return this._text; }
|
|
1929
|
+
/** Response body, typed per `XMLHttpRequest.responseType` (see {@link type}). */
|
|
1684
1930
|
get content() { return this._body; }
|
|
1931
|
+
/** The `XMLHttpRequest.responseType` used for this request. */
|
|
1685
1932
|
get type() { return this._type; }
|
|
1686
1933
|
/**
|
|
1687
1934
|
* Short-hand utility for getting or parsing json content (if any).
|
|
@@ -1698,7 +1945,11 @@
|
|
|
1698
1945
|
}
|
|
1699
1946
|
}
|
|
1700
1947
|
}
|
|
1701
|
-
/**
|
|
1948
|
+
/**
|
|
1949
|
+
* Legacy `XMLHttpRequest`-based HTTP client, superseded by the standard `fetch` API and {@link Fetcher}.
|
|
1950
|
+
* Kept for backward compatibility.
|
|
1951
|
+
* @deprecated
|
|
1952
|
+
*/
|
|
1702
1953
|
class Http {
|
|
1703
1954
|
constructor() { }
|
|
1704
1955
|
/**
|
|
@@ -1844,6 +2095,9 @@
|
|
|
1844
2095
|
/** Terminating the drag-drop activities. */
|
|
1845
2096
|
DragDropEventType["End"] = "dragend";
|
|
1846
2097
|
})(DragDropEventType || (DragDropEventType = {}));
|
|
2098
|
+
/**
|
|
2099
|
+
* Base class shared by the drag & drop event-args classes; wraps a {@link DragDropEventArgs} builder and exposes its common, read-only facets.
|
|
2100
|
+
*/
|
|
1847
2101
|
class DragDropEventArgsBaseClass {
|
|
1848
2102
|
constructor(_builder) {
|
|
1849
2103
|
this._builder = _builder;
|
|
@@ -1870,32 +2124,46 @@
|
|
|
1870
2124
|
return pacemFoundation.Point.add(args.initialDelta, /* included in `initialDelta` for perf sake => { x: this._builder.scroll.left, y: this._builder.scroll.top },*/ pacemFoundation.Point.subtract(args.origin, args.currentPosition));
|
|
1871
2125
|
}
|
|
1872
2126
|
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Event args dispatched with the {@link DragDropEventType.Init} event, mutable so listeners can override
|
|
2129
|
+
* the `placeholder` and `data` before the drag actually starts.
|
|
2130
|
+
*/
|
|
1873
2131
|
class DragDropInitEventArgsClass extends DragDropEventArgsBaseClass {
|
|
1874
2132
|
constructor(_builder) {
|
|
1875
2133
|
super(_builder);
|
|
1876
2134
|
this.placeholder = _builder.placeholder;
|
|
1877
2135
|
this.data = _builder.data;
|
|
1878
2136
|
}
|
|
2137
|
+
/** Builds a new {@link DragDropInitEventArgsClass} out of a plain {@link DragDropEventArgs} builder. */
|
|
1879
2138
|
static fromArgs(builder) {
|
|
1880
2139
|
return new DragDropInitEventArgsClass(Utils.extend({}, builder));
|
|
1881
2140
|
}
|
|
1882
2141
|
}
|
|
2142
|
+
/**
|
|
2143
|
+
* Read-only event args dispatched with the drag/drop lifecycle events other than `draginit` (start, drag, drop, over, out, end).
|
|
2144
|
+
*/
|
|
1883
2145
|
class DragDropEventArgsClass extends DragDropEventArgsBaseClass {
|
|
1884
2146
|
constructor(_builder, _placeholder = _builder.placeholder, _data = _builder.data) {
|
|
1885
2147
|
super(_builder);
|
|
1886
2148
|
this._placeholder = _placeholder;
|
|
1887
2149
|
this._data = _data;
|
|
1888
2150
|
}
|
|
2151
|
+
/** @readonly Gets the element used as a dragging placeholder. */
|
|
1889
2152
|
get placeholder() {
|
|
1890
2153
|
return this._placeholder;
|
|
1891
2154
|
}
|
|
2155
|
+
/** @readonly Gets the logical payload being dragged. */
|
|
1892
2156
|
get data() {
|
|
1893
2157
|
return this._data;
|
|
1894
2158
|
}
|
|
2159
|
+
/** Builds a new {@link DragDropEventArgsClass} out of a plain {@link DragDropEventArgs} builder. */
|
|
1895
2160
|
static fromArgs(builder) {
|
|
1896
2161
|
return new DragDropEventArgsClass(Utils.extend({}, builder));
|
|
1897
2162
|
}
|
|
1898
2163
|
}
|
|
2164
|
+
/**
|
|
2165
|
+
* Custom UI event dispatched throughout the drag & drop lifecycle (see {@link DragDropEventType}).
|
|
2166
|
+
*/
|
|
1899
2167
|
class DragDropEvent extends CustomUIEvent {
|
|
1900
2168
|
constructor(type, args, eventInit, evt) {
|
|
1901
2169
|
super(type, args, eventInit, evt);
|
|
@@ -1904,40 +2172,65 @@
|
|
|
1904
2172
|
//}
|
|
1905
2173
|
|
|
1906
2174
|
//namespace Pacem.UI {
|
|
2175
|
+
/**
|
|
2176
|
+
* Enumerates the resize handles a {@link Rescaler} can expose around a rescalable element.
|
|
2177
|
+
*/
|
|
1907
2178
|
var RescaleHandle;
|
|
1908
2179
|
(function (RescaleHandle) {
|
|
2180
|
+
/** All four sides/corners are enabled. */
|
|
1909
2181
|
RescaleHandle["All"] = "all";
|
|
2182
|
+
/** The top edge (and its corners) is enabled. */
|
|
1910
2183
|
RescaleHandle["Top"] = "top";
|
|
2184
|
+
/** The left edge (and its corners) is enabled. */
|
|
1911
2185
|
RescaleHandle["Left"] = "left";
|
|
2186
|
+
/** The right edge (and its corners) is enabled. */
|
|
1912
2187
|
RescaleHandle["Right"] = "right";
|
|
2188
|
+
/** The bottom edge (and its corners) is enabled. */
|
|
1913
2189
|
RescaleHandle["Bottom"] = "bottom";
|
|
1914
2190
|
})(RescaleHandle || (RescaleHandle = {}));
|
|
2191
|
+
/**
|
|
2192
|
+
* Enumerates the events dispatched throughout the rescale gesture lifecycle.
|
|
2193
|
+
*/
|
|
1915
2194
|
var RescaleEventType;
|
|
1916
2195
|
(function (RescaleEventType) {
|
|
2196
|
+
/** First rescaling act. */
|
|
1917
2197
|
RescaleEventType["Start"] = "rescalestart";
|
|
2198
|
+
/** Any rescaling act. */
|
|
1918
2199
|
RescaleEventType["Rescale"] = "rescale";
|
|
2200
|
+
/** Terminating the rescaling activities. */
|
|
1919
2201
|
RescaleEventType["End"] = "rescaleend";
|
|
1920
2202
|
})(RescaleEventType || (RescaleEventType = {}));
|
|
2203
|
+
/**
|
|
2204
|
+
* Read-only event args dispatched with the rescale gesture lifecycle events.
|
|
2205
|
+
*/
|
|
1921
2206
|
class RescaleEventArgsClass {
|
|
1922
2207
|
constructor(_builder) {
|
|
1923
2208
|
this._builder = _builder;
|
|
1924
2209
|
}
|
|
2210
|
+
/** @readonly Gets the current pointer position. */
|
|
1925
2211
|
get currentPosition() {
|
|
1926
2212
|
return this._builder.currentPosition;
|
|
1927
2213
|
}
|
|
2214
|
+
/** @readonly Gets the rectangle the element is being resized to. */
|
|
1928
2215
|
get targetRect() {
|
|
1929
2216
|
return this._builder.targetRect;
|
|
1930
2217
|
}
|
|
2218
|
+
/** @readonly Gets the element being resized. */
|
|
1931
2219
|
get element() {
|
|
1932
2220
|
return this._builder.element;
|
|
1933
2221
|
}
|
|
2222
|
+
/** @readonly Gets the handle being dragged (see {@link RescaleHandle}). */
|
|
1934
2223
|
get handle() {
|
|
1935
2224
|
return this._builder.handle;
|
|
1936
2225
|
}
|
|
2226
|
+
/** Builds a new {@link RescaleEventArgsClass} out of a plain {@link RescaleEventArgs} builder. */
|
|
1937
2227
|
static fromArgs(builder) {
|
|
1938
2228
|
return new RescaleEventArgsClass(Utils.extend({}, builder));
|
|
1939
2229
|
}
|
|
1940
2230
|
}
|
|
2231
|
+
/**
|
|
2232
|
+
* Custom UI event dispatched throughout the rescale gesture lifecycle (see {@link RescaleEventType}).
|
|
2233
|
+
*/
|
|
1941
2234
|
class RescaleEvent extends CustomUIEvent {
|
|
1942
2235
|
constructor(type, args, eventInit, evt) {
|
|
1943
2236
|
super(type, args, eventInit, evt);
|
|
@@ -1945,32 +2238,49 @@
|
|
|
1945
2238
|
}
|
|
1946
2239
|
//}
|
|
1947
2240
|
|
|
2241
|
+
/**
|
|
2242
|
+
* Enumerates the events dispatched throughout the rotate gesture lifecycle.
|
|
2243
|
+
*/
|
|
1948
2244
|
var RotateEventType;
|
|
1949
2245
|
(function (RotateEventType) {
|
|
2246
|
+
/** First rotating act. */
|
|
1950
2247
|
RotateEventType["Start"] = "rotatestart";
|
|
2248
|
+
/** Any rotating act. */
|
|
1951
2249
|
RotateEventType["Rotate"] = "rotate";
|
|
2250
|
+
/** Terminating the rotating activities. */
|
|
1952
2251
|
RotateEventType["End"] = "rotateend";
|
|
1953
2252
|
})(RotateEventType || (RotateEventType = {}));
|
|
2253
|
+
/**
|
|
2254
|
+
* Read-only event args dispatched with the rotate gesture lifecycle events.
|
|
2255
|
+
*/
|
|
1954
2256
|
class RotateEventArgsClass {
|
|
1955
2257
|
constructor(_builder) {
|
|
1956
2258
|
this._builder = _builder;
|
|
1957
2259
|
}
|
|
2260
|
+
/** @readonly Gets the current pointer position. */
|
|
1958
2261
|
get currentPosition() {
|
|
1959
2262
|
return this._builder.currentPosition;
|
|
1960
2263
|
}
|
|
2264
|
+
/** @readonly Gets the current rotation, in radians. */
|
|
1961
2265
|
get rotation() {
|
|
1962
2266
|
return this._builder.rotation;
|
|
1963
2267
|
}
|
|
2268
|
+
/** @readonly Gets the element being rotated. */
|
|
1964
2269
|
get element() {
|
|
1965
2270
|
return this._builder.element;
|
|
1966
2271
|
}
|
|
2272
|
+
/** @readonly Gets the pivot point the element is rotating around. */
|
|
1967
2273
|
get center() {
|
|
1968
2274
|
return this._builder.center;
|
|
1969
2275
|
}
|
|
2276
|
+
/** Builds a new {@link RotateEventArgsClass} out of a plain {@link RotateEventArgs} builder. */
|
|
1970
2277
|
static fromArgs(builder) {
|
|
1971
2278
|
return new RotateEventArgsClass(Utils.extend({}, builder));
|
|
1972
2279
|
}
|
|
1973
2280
|
}
|
|
2281
|
+
/**
|
|
2282
|
+
* Custom UI event dispatched throughout the rotate gesture lifecycle (see {@link RotateEventType}).
|
|
2283
|
+
*/
|
|
1974
2284
|
class RotateEvent extends CustomUIEvent {
|
|
1975
2285
|
constructor(type, args, eventInit, evt) {
|
|
1976
2286
|
super(type, args, eventInit, evt);
|
|
@@ -1978,21 +2288,38 @@
|
|
|
1978
2288
|
}
|
|
1979
2289
|
//}
|
|
1980
2290
|
|
|
2291
|
+
/**
|
|
2292
|
+
* Enumerates the events dispatched throughout the swipe gesture lifecycle.
|
|
2293
|
+
*/
|
|
1981
2294
|
var SwipeEventType;
|
|
1982
2295
|
(function (SwipeEventType) {
|
|
2296
|
+
/** Dispatched when the swipe gesture ends (release). */
|
|
1983
2297
|
SwipeEventType["Swipe"] = "swipe";
|
|
2298
|
+
/** Dispatched while the pointer is dragging the element around. */
|
|
1984
2299
|
SwipeEventType["Pan"] = "pan";
|
|
2300
|
+
/** Dispatched when the swipe ends and its resolved direction is leftward. */
|
|
1985
2301
|
SwipeEventType["SwipeLeft"] = "swipeleft";
|
|
2302
|
+
/** Dispatched when the swipe ends and its resolved direction is rightward. */
|
|
1986
2303
|
SwipeEventType["SwipeRight"] = "swiperight";
|
|
2304
|
+
/** Dispatched when the swipe ends and its resolved direction is upward. */
|
|
1987
2305
|
SwipeEventType["SwipeUp"] = "swipeup";
|
|
2306
|
+
/** Dispatched when the swipe ends and its resolved direction is downward. */
|
|
1988
2307
|
SwipeEventType["SwipeDown"] = "swipedown";
|
|
1989
2308
|
// end of swipe animation
|
|
2309
|
+
/** Dispatched when the snap/bounce-back animation following a swipe completes. */
|
|
1990
2310
|
SwipeEventType["SwipeAnimationEnd"] = "swipeanimationend";
|
|
2311
|
+
/** Dispatched when the snap/bounce-back animation following a leftward swipe completes. */
|
|
1991
2312
|
SwipeEventType["SwipeLeftAnimationEnd"] = "swipeleftanimationend";
|
|
2313
|
+
/** Dispatched when the snap/bounce-back animation following a rightward swipe completes. */
|
|
1992
2314
|
SwipeEventType["SwipeRightAnimationEnd"] = "swiperightanimationend";
|
|
2315
|
+
/** Dispatched when the snap/bounce-back animation following an upward swipe completes. */
|
|
1993
2316
|
SwipeEventType["SwipeUpAnimationEnd"] = "swipeupanimationend";
|
|
2317
|
+
/** Dispatched when the snap/bounce-back animation following a downward swipe completes. */
|
|
1994
2318
|
SwipeEventType["SwipeDownAnimationEnd"] = "swipedownanimationend";
|
|
1995
2319
|
})(SwipeEventType || (SwipeEventType = {}));
|
|
2320
|
+
/**
|
|
2321
|
+
* Read-only event args dispatched with the swipe gesture lifecycle events.
|
|
2322
|
+
*/
|
|
1996
2323
|
class SwipeEventArgsClass {
|
|
1997
2324
|
constructor(_builder) {
|
|
1998
2325
|
this._builder = _builder;
|
|
@@ -2002,6 +2329,7 @@
|
|
|
2002
2329
|
const isVertical = vertical ?? (Math.abs(horizontalspeed) < Math.abs(verticalspeed));
|
|
2003
2330
|
return isVertical;
|
|
2004
2331
|
}
|
|
2332
|
+
/** @readonly Gets the resolved swipe direction (`'up'`, `'down'`, `'left'` or `'right'`). */
|
|
2005
2333
|
get direction() {
|
|
2006
2334
|
return this.#isVertical
|
|
2007
2335
|
? (this._builder.verticalspeed > 0 ? 'down' : 'up')
|
|
@@ -2033,13 +2361,18 @@
|
|
|
2033
2361
|
const inertia = this._builder.inertia ?? 8;
|
|
2034
2362
|
return -Math.log(.01 /* v/v0 where v ~ 0 <=> 1% of v0 */) / inertia;
|
|
2035
2363
|
}
|
|
2364
|
+
/** @readonly Gets the element being swiped. */
|
|
2036
2365
|
get element() {
|
|
2037
2366
|
return this._builder.element;
|
|
2038
2367
|
}
|
|
2368
|
+
/** Builds a new {@link SwipeEventArgsClass} out of a plain {@link SwipeEventArgs} builder. */
|
|
2039
2369
|
static fromArgs(builder) {
|
|
2040
2370
|
return new SwipeEventArgsClass(Utils.extend({}, builder));
|
|
2041
2371
|
}
|
|
2042
2372
|
}
|
|
2373
|
+
/**
|
|
2374
|
+
* Custom typed event dispatched throughout the swipe gesture lifecycle (see {@link SwipeEventType}).
|
|
2375
|
+
*/
|
|
2043
2376
|
class SwipeEvent extends CustomTypedEvent {
|
|
2044
2377
|
constructor(type, args, eventInit) {
|
|
2045
2378
|
super(type, args, eventInit);
|
|
@@ -2068,6 +2401,7 @@
|
|
|
2068
2401
|
get SwipeEventType () { return SwipeEventType; }
|
|
2069
2402
|
});
|
|
2070
2403
|
|
|
2404
|
+
/** Dispatched by an {@link Iterative} container whenever its `index` changes. */
|
|
2071
2405
|
class CurrentIndexChangeEvent extends CustomTypedEvent {
|
|
2072
2406
|
constructor(args) {
|
|
2073
2407
|
super('currentindexchange', args);
|
|
@@ -2076,11 +2410,16 @@
|
|
|
2076
2410
|
//}
|
|
2077
2411
|
|
|
2078
2412
|
/// <reference path="events.ts" />
|
|
2413
|
+
/** Runtime value (aliasing the built-in `Function`) usable where a constructor reference is needed as a value, paired with the {@link Type} interface for typing it. */
|
|
2079
2414
|
const Type = Function;
|
|
2080
2415
|
// #region CONSTS
|
|
2416
|
+
/** Key used to attach, on an element's constructor, the list of its `@Watch`-decorated (watched) property descriptors. */
|
|
2081
2417
|
const WATCH_PROPS_VAR = 'pacem:properties';
|
|
2418
|
+
/** Key used to attach, on an element instance, the list of attribute names currently holding a pending (not-yet-evaluable) binding expression. */
|
|
2082
2419
|
const INSTANCE_BINDINGS_VAR = 'pacem:custom-element:bindings';
|
|
2420
|
+
/** Key used to attach, on a templated node, a reference to the custom element instance ("host") whose template produced it — used to resolve binding expression scope. */
|
|
2083
2421
|
const INSTANCE_HOST_VAR = 'pacem:custom-element:host';
|
|
2422
|
+
/** Key used to attach, on an element instance, its binding-expression evaluation scope object. */
|
|
2084
2423
|
const INSTANCE_SCOPE_VAR = 'pacem:custom-element:scope';
|
|
2085
2424
|
// #endregion
|
|
2086
2425
|
//}
|
|
@@ -2089,37 +2428,66 @@
|
|
|
2089
2428
|
var root;
|
|
2090
2429
|
/** the overall customelement prefix */
|
|
2091
2430
|
const P = (root = window['Pacem'])?.Configuration?.prefix ?? 'pacem';
|
|
2431
|
+
/** The prefix used for CSS custom properties and classes (e.g. `--{PCSS}-font-main`); configurable independently of the element tag prefix {@link P} via `window.Pacem.Configuration.css`, defaults to {@link P}. */
|
|
2092
2432
|
const PCSS = root?.Configuration?.css ?? P;
|
|
2093
2433
|
//}
|
|
2094
2434
|
|
|
2095
2435
|
//namespace Pacem {
|
|
2436
|
+
/** Marker base class for elements that behave like `<template>` (e.g. a custom template-proxy element), so template-detection logic can treat them the same as a native `HTMLTemplateElement`. */
|
|
2096
2437
|
class TemplateElement extends HTMLElement {
|
|
2097
2438
|
}
|
|
2098
2439
|
//}
|
|
2099
2440
|
|
|
2100
|
-
/// <reference path="expression.ts" />
|
|
2101
|
-
/// <reference path="promise.ts" />
|
|
2102
|
-
/// <reference path="prefix.ts" />
|
|
2103
|
-
/// <reference path="trees/json.ts" />
|
|
2104
|
-
/// <reference path="utils.ts" />
|
|
2105
2441
|
// namespace Pacem {
|
|
2106
2442
|
const PACEM_BAG = '__pacem__';
|
|
2107
2443
|
// {{ binding.expression }}
|
|
2108
2444
|
const bindingPattern = /^\{\{(.|\n)+\}\}$/;
|
|
2109
2445
|
// TODO: CSP-proof binding (no unsafe-eval)
|
|
2110
2446
|
// binding syntax example: `{ binding: { source: ^item.property.path, binder: $pacem.func, parameters: [ ^index, 'foo', : host._baz], mode: 'twoway' } }`
|
|
2447
|
+
/**
|
|
2448
|
+
* Static grab-bag of low-level helpers underpinning the {@link CustomElement}/{@link Watch} decorators
|
|
2449
|
+
* and the binding-expression engine: attached-property storage (a per-instance, non-enumerable "bag"
|
|
2450
|
+
* used instead of expando properties), attribute/property name conversion, DOM tree traversal, host/
|
|
2451
|
+
* scope resolution for templated content, and binding-attribute parsing.
|
|
2452
|
+
*/
|
|
2111
2453
|
class CustomElementUtils {
|
|
2454
|
+
/** `true` when the platform's `customElements` registry is the Custom Elements polyfill rather than a native implementation. */
|
|
2112
2455
|
static get polyfilling() {
|
|
2113
2456
|
return customElements instanceof window['CustomElementRegistry'];
|
|
2114
2457
|
}
|
|
2458
|
+
/** Converts a camelCase property name to its kebab-case attribute-name equivalent (e.g. `myProp` → `my-prop`). */
|
|
2115
2459
|
static camelToKebab(camelCased) {
|
|
2116
2460
|
return camelCased && camelCased.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
2117
2461
|
}
|
|
2462
|
+
/** Converts a kebab-case attribute name to its camelCase property-name equivalent (e.g. `my-prop` → `myProp`). */
|
|
2118
2463
|
static kebabToCamel(kebabCased) {
|
|
2119
2464
|
return kebabCased && kebabCased.replace(/(-[a-z])/g, (m) => {
|
|
2120
2465
|
return m[1].toUpperCase();
|
|
2121
2466
|
});
|
|
2122
2467
|
}
|
|
2468
|
+
/** Waits for the specified alement to be ready. */
|
|
2469
|
+
static waitForReady(element) {
|
|
2470
|
+
return new Promise((resolve, reject) => {
|
|
2471
|
+
if (Utils.isNull(element)) {
|
|
2472
|
+
reject('Not found.');
|
|
2473
|
+
}
|
|
2474
|
+
// if (element.isConnected && !(element instanceof PacemEventTarget)){
|
|
2475
|
+
// reject('Invalid element.');
|
|
2476
|
+
// }
|
|
2477
|
+
if (element.isReady) {
|
|
2478
|
+
resolve();
|
|
2479
|
+
}
|
|
2480
|
+
const callback = () => {
|
|
2481
|
+
element.removeEventListener('load', callback);
|
|
2482
|
+
resolve();
|
|
2483
|
+
};
|
|
2484
|
+
element.addEventListener('load', callback);
|
|
2485
|
+
});
|
|
2486
|
+
}
|
|
2487
|
+
/** Waits for the specified element to be ready, then executes the provided callback. */
|
|
2488
|
+
static whenReady(element, callback) {
|
|
2489
|
+
CustomElementUtils.waitForReady(element).then(callback);
|
|
2490
|
+
}
|
|
2123
2491
|
static getWatchedProperties(target, includeInherited = true) {
|
|
2124
2492
|
var properties = [];
|
|
2125
2493
|
var chain = target instanceof HTMLElement ? target.constructor : target;
|
|
@@ -2130,9 +2498,16 @@
|
|
|
2130
2498
|
} while (includeInherited && (chain = Object.getPrototypeOf(chain)));
|
|
2131
2499
|
return properties;
|
|
2132
2500
|
}
|
|
2501
|
+
/** Retrieves a single `@Watch`-decorated property descriptor by name; see {@link getWatchedProperties}. */
|
|
2133
2502
|
static getWatchedProperty(target, name) {
|
|
2134
2503
|
return this.getWatchedProperties(target, true).find(p => p.name === name);
|
|
2135
2504
|
}
|
|
2505
|
+
/**
|
|
2506
|
+
* Loads a `<script>` tag once (deduplicated by `src`, cached via {@link import}), resolving when it fires `load`.
|
|
2507
|
+
* @param src Script URL.
|
|
2508
|
+
* @param integrity Optional Subresource Integrity hash.
|
|
2509
|
+
* @param crossorigin Whether to set `crossorigin` on the tag.
|
|
2510
|
+
*/
|
|
2136
2511
|
static importjs(src, integrity = null, crossorigin = false) {
|
|
2137
2512
|
var attrs = { 'type': 'text\/javascript', 'src': src };
|
|
2138
2513
|
if (!Utils.isNullOrEmpty(integrity))
|
|
@@ -2141,6 +2516,12 @@
|
|
|
2141
2516
|
Utils.extend(attrs, { 'crossorigin': '' });
|
|
2142
2517
|
return CustomElementUtils.import(src, 'script', attrs, (document.head || document.getElementsByTagName("head")[0]));
|
|
2143
2518
|
}
|
|
2519
|
+
/**
|
|
2520
|
+
* Loads a `<link rel="stylesheet">` tag once (deduplicated by `src`, cached via {@link import}), resolving when it fires `load`.
|
|
2521
|
+
* @param src Stylesheet URL.
|
|
2522
|
+
* @param integrity Optional Subresource Integrity hash.
|
|
2523
|
+
* @param crossorigin Whether to set `crossorigin="anonymous"` on the tag.
|
|
2524
|
+
*/
|
|
2144
2525
|
static importcss(src, integrity = null, crossorigin = false) {
|
|
2145
2526
|
var attrs = { 'rel': 'stylesheet', 'href': src };
|
|
2146
2527
|
if (!Utils.isNullOrEmpty(integrity))
|
|
@@ -2149,6 +2530,15 @@
|
|
|
2149
2530
|
Utils.extend(attrs, { 'crossorigin': 'anonymous' });
|
|
2150
2531
|
return CustomElementUtils.import(src, 'link', attrs, (document.head || document.getElementsByTagName("head")[0]));
|
|
2151
2532
|
}
|
|
2533
|
+
/**
|
|
2534
|
+
* Creates (or reuses an already-present, matching) element of `tagName` with the given attributes and
|
|
2535
|
+
* appends it to the DOM, returning a promise that resolves once it loads (or rejects on error). Results
|
|
2536
|
+
* are cached per `key` (under `Utils.core.imports`) so repeated calls with the same key are a no-op.
|
|
2537
|
+
* @param key Cache/dedupe key (typically the resource URL).
|
|
2538
|
+
* @param tagName Tag name of the element to create (e.g. `'script'`, `'link'`).
|
|
2539
|
+
* @param attrs Attributes to set on the element, also used to build a matching CSS selector to detect a pre-existing element.
|
|
2540
|
+
* @param appendTo Node to append the newly created element to, if none was found. Defaults to `document.body`.
|
|
2541
|
+
*/
|
|
2152
2542
|
static import(key, tagName, attrs, appendTo = document.body) {
|
|
2153
2543
|
const _p = Utils.core;
|
|
2154
2544
|
var _imports = _p['imports'] = _p['imports'] || {};
|
|
@@ -2178,7 +2568,9 @@
|
|
|
2178
2568
|
}
|
|
2179
2569
|
});
|
|
2180
2570
|
}
|
|
2571
|
+
/** Theming-related helpers. */
|
|
2181
2572
|
static { this.Theme = {
|
|
2573
|
+
/** Downloads the web fonts referenced by the current theme's `--{@link PCSS}-font-*` CSS custom properties, resolving once at least one font face is ready (or after a short timeout). */
|
|
2182
2574
|
importWebFonts() {
|
|
2183
2575
|
function cleanupQuotes(input) {
|
|
2184
2576
|
// check if the string is wrapped around quotes to escape ';' chars
|
|
@@ -2216,6 +2608,14 @@
|
|
|
2216
2608
|
return Promise.all(promises);
|
|
2217
2609
|
}
|
|
2218
2610
|
}; }
|
|
2611
|
+
/**
|
|
2612
|
+
* Stores an arbitrary value "attached" to `target` under `name`, in a private, non-enumerable bag
|
|
2613
|
+
* (rather than as a plain expando property) so it doesn't show up in `for...in`/`Object.keys`/JSON
|
|
2614
|
+
* serialization. Setting `value` to `null`/`undefined` removes the entry. See {@link getAttachedPropertyValue}.
|
|
2615
|
+
* @param target Object to attach the value to.
|
|
2616
|
+
* @param name Key under which the value is stored.
|
|
2617
|
+
* @param value Value to store, or `null`/`undefined` to remove the entry.
|
|
2618
|
+
*/
|
|
2219
2619
|
static setAttachedPropertyValue(target, name, value) {
|
|
2220
2620
|
/*(target[PACEM_BAG] = target[PACEM_BAG] || {})[name] = value;*/
|
|
2221
2621
|
if (Utils.isNull(target))
|
|
@@ -2230,9 +2630,16 @@
|
|
|
2230
2630
|
else
|
|
2231
2631
|
bag[name] = value;
|
|
2232
2632
|
}
|
|
2633
|
+
/** Removes a value previously stored via {@link setAttachedPropertyValue}. */
|
|
2233
2634
|
static deleteAttachedPropertyValue(target, name) {
|
|
2234
2635
|
CustomElementUtils.setAttachedPropertyValue(target, name, undefined);
|
|
2235
2636
|
}
|
|
2637
|
+
/**
|
|
2638
|
+
* Reads a value previously stored via {@link setAttachedPropertyValue}.
|
|
2639
|
+
* @param target Object the value is attached to.
|
|
2640
|
+
* @param name Key the value is stored under.
|
|
2641
|
+
* @param ensureValue If provided and no value is currently stored, this value is stored and returned (lazy-initialization).
|
|
2642
|
+
*/
|
|
2236
2643
|
static getAttachedPropertyValue(target, name, ensureValue) {
|
|
2237
2644
|
const propKey = Object.getOwnPropertyDescriptor(target, PACEM_BAG), bag = propKey && propKey.value;
|
|
2238
2645
|
if (Utils.isNull(bag && bag[name]) && !Utils.isNull(ensureValue)) {
|
|
@@ -2278,6 +2685,17 @@
|
|
|
2278
2685
|
}
|
|
2279
2686
|
return { target: { value: ref, name: name }, parent: { value: parent || scope, path: path.substring(0, ndx) }, root: { value: root, property: core } };
|
|
2280
2687
|
}
|
|
2688
|
+
/**
|
|
2689
|
+
* Writes `value` at the given dotted `path`, rooted at `element` (see {@link resolvePath}), triggering
|
|
2690
|
+
* the appropriate `propertychange` notification. For paths nested more than one level deep (and not
|
|
2691
|
+
* targeting an `HTMLElement`, which fires change notifications autonomously), the whole root property
|
|
2692
|
+
* is cloned, mutated and reassigned so that a `propertychange` fires with meaningful old/new values -
|
|
2693
|
+
* a plain nested assignment wouldn't otherwise be observed. Repeater-bound `item` paths are special-cased
|
|
2694
|
+
* to update the owning {@link Repeater}'s `datasource` array in place.
|
|
2695
|
+
* @param element Root element the path is resolved against.
|
|
2696
|
+
* @param path Dotted path (e.g. `'foo.bar[0].baz'`) to the target property.
|
|
2697
|
+
* @param value New value to assign.
|
|
2698
|
+
*/
|
|
2281
2699
|
static set(element, path, value) {
|
|
2282
2700
|
var obj = CustomElementUtils.resolvePath(path, element);
|
|
2283
2701
|
var current = obj.target.value;
|
|
@@ -2308,6 +2726,7 @@
|
|
|
2308
2726
|
}
|
|
2309
2727
|
}
|
|
2310
2728
|
}
|
|
2729
|
+
/** Reads the value at the given dotted `path`, rooted at `element`; see {@link resolvePath}. */
|
|
2311
2730
|
static get(element, path) {
|
|
2312
2731
|
var obj = CustomElementUtils.resolvePath(path, element);
|
|
2313
2732
|
return obj && obj.target && obj.target.value;
|
|
@@ -2328,12 +2747,27 @@
|
|
|
2328
2747
|
// logFn(`Element "${element.constructor.name}" isn't attached to any context yet.`);
|
|
2329
2748
|
return retval;
|
|
2330
2749
|
}
|
|
2750
|
+
/**
|
|
2751
|
+
* Finds the `Document` or `ShadowRoot` that `element` belongs to - used as the root for resolving
|
|
2752
|
+
* scoped binding expressions (e.g. `$document`/`$host` lookups). Falls back to the previously-attached
|
|
2753
|
+
* scope value (see `INSTANCE_SCOPE_VAR`, set on `connectedCallback`) when `element` is currently
|
|
2754
|
+
* disconnected, and to a legacy manual-walk implementation as a last resort (needed under Jasmine tests,
|
|
2755
|
+
* where `element.isConnected` never reports `true`).
|
|
2756
|
+
* @param element Element to resolve the containing document/shadow-root scope for.
|
|
2757
|
+
*/
|
|
2331
2758
|
static findScopeContext(element) {
|
|
2332
2759
|
let retval = (element.isConnected) ?
|
|
2333
2760
|
element.getRootNode()
|
|
2334
2761
|
: CustomElementUtils.getAttachedPropertyValue(element, INSTANCE_SCOPE_VAR);
|
|
2335
2762
|
return retval ?? /* in Jasmine TESTS `element.isConnected` always returns false (attached to #document-fragment) */ CustomElementUtils._findScopeContextLegacy(element);
|
|
2336
2763
|
}
|
|
2764
|
+
/**
|
|
2765
|
+
* Walks up from `element` (crossing shadow-root boundaries via the host element) looking for the
|
|
2766
|
+
* first ancestor matching `predicate`.
|
|
2767
|
+
* @param element Element to start the upward search from.
|
|
2768
|
+
* @param predicate Test invoked (as `this`-bound and argument-passed) against each ancestor.
|
|
2769
|
+
* @returns The first matching ancestor, or `undefined` if none matches.
|
|
2770
|
+
*/
|
|
2337
2771
|
static findAncestor(element, predicate) {
|
|
2338
2772
|
let el = element;
|
|
2339
2773
|
let retval;
|
|
@@ -2347,12 +2781,20 @@
|
|
|
2347
2781
|
}
|
|
2348
2782
|
return retval;
|
|
2349
2783
|
}
|
|
2784
|
+
/** Finds the nearest ancestor "shell" element - matching `.{@link PCSS}-body` - or falls back to `document.body`; see {@link findAncestor}. */
|
|
2350
2785
|
static findAncestorShell(element) {
|
|
2351
2786
|
return CustomElementUtils.findAncestor(element, el => Utils.is(el, `.${PCSS}-body`) || el === document.body);
|
|
2352
2787
|
}
|
|
2788
|
+
/** Finds the nearest ancestor that is an instance of `ctor`; see {@link findAncestor}. */
|
|
2353
2789
|
static findAncestorOfType(element, ctor) {
|
|
2354
2790
|
return CustomElementUtils.findAncestor(element, el => el instanceof ctor);
|
|
2355
2791
|
}
|
|
2792
|
+
/**
|
|
2793
|
+
* Collects the descendants of `element` matching `predicate`, via a `TreeWalker` over element nodes.
|
|
2794
|
+
* @param element Root element to search from (exclusive - the walker starts on its descendants).
|
|
2795
|
+
* @param predicate Test invoked against each descendant element.
|
|
2796
|
+
* @param firstOnly When `true`, stops and returns as soon as one match is found.
|
|
2797
|
+
*/
|
|
2356
2798
|
static findDescendants(element, predicate, firstOnly = false) {
|
|
2357
2799
|
const walker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT);
|
|
2358
2800
|
var retval = [];
|
|
@@ -2367,10 +2809,16 @@
|
|
|
2367
2809
|
}
|
|
2368
2810
|
return retval;
|
|
2369
2811
|
}
|
|
2812
|
+
/** Finds the first descendant of `element` matching `predicate`, or `undefined` if none matches; see {@link findDescendants}. */
|
|
2370
2813
|
static findFirstDescendant(element, predicate) {
|
|
2371
2814
|
const any = CustomElementUtils.findDescendants(element, predicate, true);
|
|
2372
2815
|
return Utils.isNullOrEmpty(any) ? void 0 : any[0];
|
|
2373
2816
|
}
|
|
2817
|
+
/**
|
|
2818
|
+
* Queries the whole document for elements matching `selector`, additionally filtered by `filter`.
|
|
2819
|
+
* @param selector CSS selector to query for. Defaults to `'[pacem]'` (every Pacem custom element, which all carry that attribute once connected).
|
|
2820
|
+
* @param filter Extra predicate applied to each matched element. Defaults to accepting everything.
|
|
2821
|
+
*/
|
|
2374
2822
|
static findAll(selector = '[pacem]', filter = (e) => true) {
|
|
2375
2823
|
const retval = [];
|
|
2376
2824
|
document.querySelectorAll(selector).forEach((e, i, arr) => {
|
|
@@ -2432,6 +2880,14 @@
|
|
|
2432
2880
|
} while (el != null);
|
|
2433
2881
|
return retval;
|
|
2434
2882
|
}
|
|
2883
|
+
/**
|
|
2884
|
+
* Tags every element/document-fragment node inside `template`'s content (that isn't already tagged)
|
|
2885
|
+
* with `host` under `INSTANCE_HOST_VAR`, so that once cloned and inserted into the DOM, binding
|
|
2886
|
+
* expressions in that fragment can resolve back to the custom element instance ("host") that owns
|
|
2887
|
+
* this template. See {@link findHostContext}.
|
|
2888
|
+
* @param host The custom element instance whose template this is.
|
|
2889
|
+
* @param template Template whose content's descendants should be tagged.
|
|
2890
|
+
*/
|
|
2435
2891
|
static assignHostContext(host, template) {
|
|
2436
2892
|
// navigate through the DOM hierarchy
|
|
2437
2893
|
const walker = document.createTreeWalker(template.content, NodeFilter.SHOW_ELEMENT + /* traverse templates' content */ NodeFilter.SHOW_DOCUMENT_FRAGMENT);
|
|
@@ -2444,6 +2900,13 @@
|
|
|
2444
2900
|
}
|
|
2445
2901
|
}
|
|
2446
2902
|
}
|
|
2903
|
+
/**
|
|
2904
|
+
* Walks up from `element` looking for the nearest ancestor (inclusive) tagged with a host reference
|
|
2905
|
+
* via {@link assignHostContext}; this is the custom element instance whose template produced `element`,
|
|
2906
|
+
* used to resolve `$host`/scope references in binding expressions. Returns `undefined` (with a console
|
|
2907
|
+
* warning) if `element` is disconnected or isn't part of any templated component.
|
|
2908
|
+
* @param element Element to resolve the owning host for.
|
|
2909
|
+
*/
|
|
2447
2910
|
static findHostContext(element) {
|
|
2448
2911
|
let el = element;
|
|
2449
2912
|
let retval;
|
|
@@ -2466,6 +2929,7 @@
|
|
|
2466
2929
|
logFn(`Element "${element.constructor.name}" isn't a descendant of a templated component.`);
|
|
2467
2930
|
return retval;
|
|
2468
2931
|
}
|
|
2932
|
+
/** Tests whether an attribute's raw string value has binding-expression syntax (`{{ ... }}`). */
|
|
2469
2933
|
static isBindingAttribute(attr) {
|
|
2470
2934
|
/*if (/^\s*\{\s*binding\s+.*\}\s*$/.test(attr)) {
|
|
2471
2935
|
|
|
@@ -2485,6 +2949,7 @@
|
|
|
2485
2949
|
else*/
|
|
2486
2950
|
return bindingPattern.test(attr);
|
|
2487
2951
|
}
|
|
2952
|
+
/** Strips the `{{ }}` delimiters off a binding attribute's raw value, returning the bare expression text. Throws if `attr` isn't a valid binding attribute; see {@link isBindingAttribute}. */
|
|
2488
2953
|
static extractBindingAttributeExpression(attr) {
|
|
2489
2954
|
if (CustomElementUtils.isBindingAttribute(attr)) {
|
|
2490
2955
|
return attr.substr(2, attr.length - 4);
|
|
@@ -2493,6 +2958,13 @@
|
|
|
2493
2958
|
throw `Invalid attribute: incorrect binding syntax.`;
|
|
2494
2959
|
}
|
|
2495
2960
|
}
|
|
2961
|
+
/**
|
|
2962
|
+
* Parses a `{{ ... }}` binding attribute value into an {@link Expression}, recognizing the optional
|
|
2963
|
+
* trailing `, twoway` / `, once` modifier and stamping it onto the expression's dependencies (`twoway`
|
|
2964
|
+
* only applies when the expression has exactly one dependency that itself allows two-way binding).
|
|
2965
|
+
* @param attr Raw binding attribute value, including the `{{ }}` delimiters.
|
|
2966
|
+
* @param element Element the expression is evaluated/bound against (used to resolve scope references).
|
|
2967
|
+
*/
|
|
2496
2968
|
static parseBindingAttribute(attr, element) {
|
|
2497
2969
|
// loose syntax {{ ... }}
|
|
2498
2970
|
let expression = CustomElementUtils.extractBindingAttributeExpression(attr);
|
|
@@ -2513,6 +2985,14 @@
|
|
|
2513
2985
|
});
|
|
2514
2986
|
return expr;
|
|
2515
2987
|
}
|
|
2988
|
+
/**
|
|
2989
|
+
* Defines an own property `name` on `o` with `attributes`, unless `o` already has an own property
|
|
2990
|
+
* descriptor for that name (in which case the existing descriptor is returned untouched).
|
|
2991
|
+
* @param o Object to define the property on.
|
|
2992
|
+
* @param name Property name.
|
|
2993
|
+
* @param attributes Property descriptor to apply if the property isn't already defined.
|
|
2994
|
+
* @returns The (possibly pre-existing) property descriptor.
|
|
2995
|
+
*/
|
|
2516
2996
|
static ensureMember(o, name, attributes) {
|
|
2517
2997
|
let original = Object.getOwnPropertyDescriptor(o, name);
|
|
2518
2998
|
if (original != undefined)
|
|
@@ -2573,6 +3053,7 @@
|
|
|
2573
3053
|
const GET_VAL$6 = CustomElementUtils.getAttachedPropertyValue;
|
|
2574
3054
|
const SET_VAL$5 = CustomElementUtils.setAttachedPropertyValue;
|
|
2575
3055
|
const REPEATERITEM_PLACEHOLDER = 'pacem:repeater-item';
|
|
3056
|
+
/** Static lookup helpers for locating the {@link RepeaterItem} context a given element belongs to. */
|
|
2576
3057
|
class Repeater {
|
|
2577
3058
|
/**
|
|
2578
3059
|
* Seeks for a PacemRepeaterItem element upwards through the DOM tree, given a starting element and the number of nesting levels.
|
|
@@ -2587,7 +3068,22 @@
|
|
|
2587
3068
|
return retval;
|
|
2588
3069
|
}
|
|
2589
3070
|
}
|
|
3071
|
+
/**
|
|
3072
|
+
* Base class tracking a single rendered repetition of a {@link Repeater}'s template: it associates a
|
|
3073
|
+
* DOM placeholder node with the `item`/`index` scope values that template's binding expressions
|
|
3074
|
+
* evaluate against, and is itself attached to that placeholder (see {@link getRepeaterItem}) so
|
|
3075
|
+
* descendant elements can find their way back to it via {@link findUpwards}.
|
|
3076
|
+
*/
|
|
2590
3077
|
let RepeaterItem$1 = class RepeaterItem {
|
|
3078
|
+
/**
|
|
3079
|
+
* Seeks upwards from `element` (previous siblings, then parent, repeated) for the nearest ancestor
|
|
3080
|
+
* placeholder tagged as a {@link RepeaterItem}, skipping `upLevels` matches before returning one -
|
|
3081
|
+
* this is how deeply-nested repeaters resolve which repetition (of which ancestor repeater) an
|
|
3082
|
+
* expression's `^item`/`^^item`/... token refers to.
|
|
3083
|
+
* @param element Element to start the upward search from.
|
|
3084
|
+
* @param upLevels 0-based number of matching ancestors to skip before returning one (`0` = nearest).
|
|
3085
|
+
* @param logFn Called with a warning message if no match is found and `element` is connected to the DOM.
|
|
3086
|
+
*/
|
|
2591
3087
|
static findUpwards(element, upLevels = 0, logFn = console.warn) {
|
|
2592
3088
|
if (Utils.isNull(element) || element.localName === 'template' || element instanceof /* template-like element? */ TemplateElement) {
|
|
2593
3089
|
return null;
|
|
@@ -2600,16 +3096,20 @@
|
|
|
2600
3096
|
}
|
|
2601
3097
|
return item;
|
|
2602
3098
|
}
|
|
3099
|
+
/** Tests whether `node` is the placeholder of some {@link RepeaterItem}. */
|
|
2603
3100
|
static isRepeaterItem(node) {
|
|
2604
3101
|
return !Utils.isNull(GET_VAL$6(node, REPEATERITEM_PLACEHOLDER));
|
|
2605
3102
|
}
|
|
3103
|
+
/** Retrieves the {@link RepeaterItem} attached to `node`, if `node` is a repeater-item placeholder; see {@link isRepeaterItem}. */
|
|
2606
3104
|
static getRepeaterItem(node) {
|
|
2607
3105
|
return GET_VAL$6(node, REPEATERITEM_PLACEHOLDER);
|
|
2608
3106
|
}
|
|
3107
|
+
/** @param _placeholder DOM node (typically a comment) that stands in for this repetition and gets tagged so {@link getRepeaterItem} can retrieve this instance back from it. */
|
|
2609
3108
|
constructor(_placeholder) {
|
|
2610
3109
|
this._placeholder = _placeholder;
|
|
2611
3110
|
SET_VAL$5(_placeholder, REPEATERITEM_PLACEHOLDER, this);
|
|
2612
3111
|
}
|
|
3112
|
+
/** The DOM placeholder node standing in for this repetition. */
|
|
2613
3113
|
get placeholder() {
|
|
2614
3114
|
return this._placeholder;
|
|
2615
3115
|
}
|
|
@@ -2655,32 +3155,53 @@
|
|
|
2655
3155
|
// * ...
|
|
2656
3156
|
// */
|
|
2657
3157
|
//const purePropertyPathPattern = /^[\w\.\$]+/;
|
|
3158
|
+
/**
|
|
3159
|
+
* A parsed, compiled binding expression (the content of a `{{ ... }}` attribute value). Parsing
|
|
3160
|
+
* (see {@link parse}) rewrites special tokens found in the source text - `:host.`, `^item`/`^^item`/...,
|
|
3161
|
+
* `^index`/`^^index`/..., `#id`, `::hostProp` - into references resolvable at evaluation time, and
|
|
3162
|
+
* records each of them as a {@link PropertyDependency} so the owning element can be notified (via
|
|
3163
|
+
* {@link PropertyChangeEvent}) and re-evaluate the expression whenever a dependency changes - this is
|
|
3164
|
+
* what powers the two-way/live data binding wired up by the {@link CustomElement} decorator.
|
|
3165
|
+
* Expressions with no dependencies are flagged `independent` (effectively a constant) and can be
|
|
3166
|
+
* evaluated immediately without waiting for the DOM/scope to be ready.
|
|
3167
|
+
*/
|
|
2658
3168
|
class Expression {
|
|
2659
3169
|
constructor() {
|
|
2660
3170
|
this._pending = false;
|
|
2661
3171
|
this._independent = false;
|
|
2662
3172
|
}
|
|
3173
|
+
/** The resolved property dependencies (element + property + path) this expression re-evaluates on change. Empty for {@link independent} expressions. */
|
|
2663
3174
|
get dependencies() {
|
|
2664
3175
|
return this._dependencies;
|
|
2665
3176
|
}
|
|
3177
|
+
/** The compiled function body used by {@link evaluate}/{@link evaluateAsync} (a `return <expr>;` statement, guarded by a try/catch). */
|
|
2666
3178
|
get functionBody() {
|
|
2667
3179
|
return this._fnBody;
|
|
2668
3180
|
}
|
|
3181
|
+
/** The compiled function body used by {@link evaluatePlus} (a bare, non-`return`ing statement, guarded by a try/catch) - suited for expressions run for their side effects, e.g. `on-*` event handlers. */
|
|
2669
3182
|
get voidBody() {
|
|
2670
3183
|
return this._voidBody;
|
|
2671
3184
|
}
|
|
3185
|
+
/**
|
|
3186
|
+
* `true` when this expression couldn't be resolved against a scope yet (the element wasn't connected
|
|
3187
|
+
* to a document/shadow-root at parse time) - a shared, inert placeholder singleton returned by
|
|
3188
|
+
* {@link parse} in that case; evaluating it is a no-op. Callers should re-parse once the element is ready.
|
|
3189
|
+
*/
|
|
2672
3190
|
get pending() {
|
|
2673
3191
|
return this._pending;
|
|
2674
3192
|
}
|
|
3193
|
+
/** `true` when the expression has no dependencies (a constant) and can be evaluated immediately, without a resolved scope. */
|
|
2675
3194
|
get independent() {
|
|
2676
3195
|
return this._independent;
|
|
2677
3196
|
}
|
|
3197
|
+
/** Evaluates the expression and returns its result, swallowing any runtime error (returning `undefined`). */
|
|
2678
3198
|
evaluate() {
|
|
2679
3199
|
if (!this._fn) {
|
|
2680
3200
|
this._fn = new Function('$pacem', CONTEXT_PREFIX, this._fnBody);
|
|
2681
3201
|
}
|
|
2682
3202
|
return this._fn.apply(null, [Utils.core, this._args]);
|
|
2683
3203
|
}
|
|
3204
|
+
/** Promise-wrapped variant of {@link evaluate} (resolves synchronously with the same result - kept for call-site uniformity with genuinely async evaluation paths). */
|
|
2684
3205
|
evaluateAsync() {
|
|
2685
3206
|
const deferred = DeferPromise.defer();
|
|
2686
3207
|
if (!this._fn) {
|
|
@@ -2689,6 +3210,12 @@
|
|
|
2689
3210
|
deferred.resolve(this._fn.apply(null, [Utils.core, this._args]));
|
|
2690
3211
|
return deferred.promise;
|
|
2691
3212
|
}
|
|
3213
|
+
/**
|
|
3214
|
+
* Executes the expression for its side effects (using {@link voidBody}, so no value is returned),
|
|
3215
|
+
* with extra named variables merged into scope alongside the expression's own dependencies -
|
|
3216
|
+
* used to expose e.g. `$event` to `on-*` event handler expressions.
|
|
3217
|
+
* @param args Extra name/value pairs made available to the expression, in addition to its resolved dependencies.
|
|
3218
|
+
*/
|
|
2692
3219
|
evaluatePlus(args = {}) {
|
|
2693
3220
|
if (!this._fn) {
|
|
2694
3221
|
let argNames = [CONTEXT_PREFIX];
|
|
@@ -2713,6 +3240,15 @@
|
|
|
2713
3240
|
}
|
|
2714
3241
|
return Expression._pendingExpression;
|
|
2715
3242
|
}
|
|
3243
|
+
/**
|
|
3244
|
+
* Parses a binding expression's source text (the bare content of a `{{ ... }}` attribute, without the
|
|
3245
|
+
* delimiters - see {@link CustomElementUtils.extractBindingAttributeExpression}) into an {@link Expression},
|
|
3246
|
+
* resolving its special tokens against `element`'s scope (see {@link CustomElementUtils.findScopeContext}).
|
|
3247
|
+
* Throws if the expression matches the unsafe-code guard (`new`, `window.`, `document.`, `eval(`).
|
|
3248
|
+
* @param expression Bare expression source text.
|
|
3249
|
+
* @param element Element the expression is bound to; provides the scope special tokens (`:host.`, `#id`, `^item`, ...) resolve against.
|
|
3250
|
+
* @returns A constant expression if it has no dependencies; a shared pending placeholder if `element` isn't attached to a scope yet; otherwise a fully resolved expression.
|
|
3251
|
+
*/
|
|
2716
3252
|
static parse(expression, element) {
|
|
2717
3253
|
var context = CustomElementUtils.findScopeContext(element);
|
|
2718
3254
|
var args = { '$this': element };
|
|
@@ -2843,13 +3379,20 @@
|
|
|
2843
3379
|
// }
|
|
2844
3380
|
|
|
2845
3381
|
//namespace Pacem.Logging {
|
|
3382
|
+
/** Severity levels accepted by {@link Logger.log}, and used by {@link PacemEventTarget.log}. */
|
|
2846
3383
|
var LogLevel;
|
|
2847
3384
|
(function (LogLevel) {
|
|
3385
|
+
/** Fine-grained diagnostic detail. */
|
|
2848
3386
|
LogLevel["Trace"] = "trace";
|
|
3387
|
+
/** Development-time diagnostic detail. */
|
|
2849
3388
|
LogLevel["Debug"] = "debug";
|
|
3389
|
+
/** Recoverable but noteworthy condition. */
|
|
2850
3390
|
LogLevel["Warn"] = "warn";
|
|
3391
|
+
/** Unrecoverable or unexpected failure. */
|
|
2851
3392
|
LogLevel["Error"] = "error";
|
|
3393
|
+
/** General informational message. */
|
|
2852
3394
|
LogLevel["Info"] = "info";
|
|
3395
|
+
/** Generic/default-severity message. */
|
|
2853
3396
|
LogLevel["Log"] = "log";
|
|
2854
3397
|
})(LogLevel || (LogLevel = {}));
|
|
2855
3398
|
//}
|
|
@@ -2903,6 +3446,11 @@
|
|
|
2903
3446
|
convert: (attr) => pacemFoundation.Rect.parse(attr),
|
|
2904
3447
|
convertBack: (prop) => `${prop.x || 0} ${prop.y || 0} ${prop.width || 0} ${prop.height || 0}`
|
|
2905
3448
|
};
|
|
3449
|
+
/**
|
|
3450
|
+
* Built-in {@link PropertyConverter} implementations, keyed by the type they convert to/from. Passed as
|
|
3451
|
+
* the `converter` option of a {@link Watch}-decorated property (e.g. `@Watch({ converter: PropertyConverters.Number })`)
|
|
3452
|
+
* to control how that property's attribute string is parsed and, on change, reflected back.
|
|
3453
|
+
*/
|
|
2906
3454
|
const PropertyConverters /*: { [name: string]: PropertyConverter }*/ = {
|
|
2907
3455
|
None: NonePropertyConverter,
|
|
2908
3456
|
String: StringPropertyConverter,
|
|
@@ -3050,6 +3598,31 @@
|
|
|
3050
3598
|
}
|
|
3051
3599
|
return promises;
|
|
3052
3600
|
}
|
|
3601
|
+
/**
|
|
3602
|
+
* Class decorator that turns a class extending `HTMLElement` (typically {@link PacemEventTarget}) into a
|
|
3603
|
+
* fully-fledged Pacem custom element: it registers the tag with the custom elements registry and wraps
|
|
3604
|
+
* the standard `connectedCallback`/`disconnectedCallback`/`attributeChangedCallback`/`propertyChangedCallback`
|
|
3605
|
+
* lifecycle hooks (calling through to any hooks already defined on the class) so that:
|
|
3606
|
+
*
|
|
3607
|
+
* - `observedAttributes` is computed automatically from the class's {@link Watch}-decorated properties
|
|
3608
|
+
* (in kebab-case), merged with any statically-declared `observedAttributes`.
|
|
3609
|
+
* - On first connection, `config.template`/`config.templateUrl` (if provided) is fetched, parsed and
|
|
3610
|
+
* injected — into a Shadow Root when `config.shadow` is `true`, otherwise as light-DOM children,
|
|
3611
|
+
* splicing any pre-existing light-DOM content into a `<pacem-content>` placeholder if present.
|
|
3612
|
+
* - Attribute changes are converted to property values via each watched property's {@link PropertyConverter},
|
|
3613
|
+
* and dispatched as an {@link AttributeChangeEvent}.
|
|
3614
|
+
* - Property changes are dispatched as a {@link PropertyChangeEvent} (unless the property's `@Watch`
|
|
3615
|
+
* config sets `emit: false`) and, when `reflectBack` is enabled, written back onto the corresponding
|
|
3616
|
+
* attribute via the converter's `convertBack`.
|
|
3617
|
+
* - Binding expression attributes (`{{ ... }}`) are parsed and kept live: dependent properties are
|
|
3618
|
+
* re-evaluated whenever one of the expression's upstream properties fires a {@link PropertyChangeEvent}.
|
|
3619
|
+
* - Once the template (and all descendant templated custom elements) have finished rendering, the
|
|
3620
|
+
* `cloak` attribute is removed and `viewActivatedCallback` fires — this is the right place for logic
|
|
3621
|
+
* that depends on the element's full DOM (light or shadow) being in place.
|
|
3622
|
+
*
|
|
3623
|
+
* @param config Tag name, optional native `customElements.define` options, and optional template/templateUrl/shadow settings.
|
|
3624
|
+
* @returns A class decorator to apply to the custom element's class declaration.
|
|
3625
|
+
*/
|
|
3053
3626
|
const CustomElement = (config) => {
|
|
3054
3627
|
return (target) => {
|
|
3055
3628
|
// might be already registered
|
|
@@ -3384,6 +3957,27 @@
|
|
|
3384
3957
|
// #endregion
|
|
3385
3958
|
// #region WATCH PROPERTIES
|
|
3386
3959
|
const DefaultPropertyConverter = PropertyConverters.None;
|
|
3960
|
+
/**
|
|
3961
|
+
* Property decorator that turns a plain class field (or accessor) into a Pacem "watched" property:
|
|
3962
|
+
* a property whose changes are detected (via reference/value comparison, see {@link DefaultComparer}),
|
|
3963
|
+
* optionally converted from/to its corresponding attribute string via a {@link PropertyConverter}
|
|
3964
|
+
* (see {@link PropertyConverters}), and notified through `propertyChangedCallback` plus a
|
|
3965
|
+
* {@link PropertyChangeEvent} (unless `config.emit` is `false`).
|
|
3966
|
+
*
|
|
3967
|
+
* Must be paired with the {@link CustomElement} class decorator, which is what actually reads the list
|
|
3968
|
+
* of watched properties (via `WATCH_PROPS_VAR`) to compute `observedAttributes` and wire up attribute/
|
|
3969
|
+
* property change plumbing — `@Watch` alone, on a class not decorated with `@CustomElement`, only sets
|
|
3970
|
+
* up the getter/setter and change notification, with no attribute involvement.
|
|
3971
|
+
*
|
|
3972
|
+
* Array-valued properties are additionally instrumented: their mutating methods (`push`, `pop`, `splice`,
|
|
3973
|
+
* `shift`, `unshift`, `copyWithin`) are patched so in-place mutations also trigger a change notification.
|
|
3974
|
+
*
|
|
3975
|
+
* @param config Optional behavior: `converter` (attribute↔property conversion, default `PropertyConverters.None`),
|
|
3976
|
+
* `emit` (whether to dispatch a {@link PropertyChangeEvent}, default `true`), `debounce` (delay the
|
|
3977
|
+
* change notification, either by a fixed number of milliseconds or `true` for one animation frame),
|
|
3978
|
+
* and `reflectBack` (write the property value back onto the attribute on change, default `false`).
|
|
3979
|
+
* @returns A property decorator to apply to the watched field/accessor.
|
|
3980
|
+
*/
|
|
3387
3981
|
function Watch(config) {
|
|
3388
3982
|
return (target, prop, descriptor) => {
|
|
3389
3983
|
var watchableProperties = GET_VAL$5(target.constructor, WATCH_PROPS_VAR, []);
|
|
@@ -3502,6 +4096,17 @@
|
|
|
3502
4096
|
}
|
|
3503
4097
|
};
|
|
3504
4098
|
}
|
|
4099
|
+
/**
|
|
4100
|
+
* Property decorator that turns a class field into a lazily-resolved, cached reference to a descendant
|
|
4101
|
+
* element matching `selector`. Resolution happens on first read (via `shadowRoot.querySelectorAll` when
|
|
4102
|
+
* available, falling back to the element itself), and only nodes whose `INSTANCE_HOST_VAR` points back
|
|
4103
|
+
* at `this` are considered — this keeps the lookup scoped to the current element's own template output,
|
|
4104
|
+
* skipping over descendants that belong to a nested custom element's own template. The cache is reset
|
|
4105
|
+
* whenever the host element reconnects to the DOM (`connectedCallback`, see the {@link CustomElement} decorator).
|
|
4106
|
+
*
|
|
4107
|
+
* @param selector CSS selector identifying the child element to bind to.
|
|
4108
|
+
* @returns A property decorator to apply to the view-child field (read-only; no setter is defined).
|
|
4109
|
+
*/
|
|
3505
4110
|
function ViewChild(selector) {
|
|
3506
4111
|
return (target, prop, descriptor) => {
|
|
3507
4112
|
const key = `${prop}_${Utils.uniqueCode()}`;
|
|
@@ -3534,6 +4139,15 @@
|
|
|
3534
4139
|
}
|
|
3535
4140
|
// #endregion
|
|
3536
4141
|
// #region CONCURRENT/DEBOUNCE EXECUTION
|
|
4142
|
+
/**
|
|
4143
|
+
* Method decorator that serializes calls to an async (promise-returning) method on a per-instance basis:
|
|
4144
|
+
* while an invocation is in flight, further calls are queued (their arguments buffered) instead of running
|
|
4145
|
+
* concurrently, and each queued call gets its own promise that resolves/rejects once it eventually runs.
|
|
4146
|
+
* Once the in-flight call settles, the oldest buffered call (if any) is dequeued and executed next.
|
|
4147
|
+
* Methods that don't return a promise-like value are simply invoked synchronously with no queuing.
|
|
4148
|
+
*
|
|
4149
|
+
* @returns A method decorator to apply to an async instance method.
|
|
4150
|
+
*/
|
|
3537
4151
|
function Concurrent() {
|
|
3538
4152
|
function isPromiseLike(obj) {
|
|
3539
4153
|
return obj && typeof obj.then === 'function';
|
|
@@ -3584,6 +4198,15 @@
|
|
|
3584
4198
|
};
|
|
3585
4199
|
};
|
|
3586
4200
|
}
|
|
4201
|
+
/**
|
|
4202
|
+
* Method decorator that debounces calls to an instance method: repeated calls within the debounce window
|
|
4203
|
+
* cancel the previously scheduled invocation and reschedule it, so only the last call in a rapid burst
|
|
4204
|
+
* actually runs (with its own arguments), after the window elapses.
|
|
4205
|
+
*
|
|
4206
|
+
* @param msecs Debounce delay in milliseconds, or `true` to debounce to the next animation frame (`requestAnimationFrame`) instead of a fixed delay. Defaults to `50`.
|
|
4207
|
+
* @param keyFactory Computes the per-instance timer key from the method name and call arguments; override to scope debouncing per argument (e.g. debounce separately per id) instead of per method. Defaults to a single shared key per method.
|
|
4208
|
+
* @returns A method decorator to apply to the instance method to debounce.
|
|
4209
|
+
*/
|
|
3587
4210
|
function Debounce(msecs = 50, keyFactory = (key, ...args) => `pacem:debouncer:${key}`) {
|
|
3588
4211
|
return function (target /* type, actually */, key, descriptor) {
|
|
3589
4212
|
const originalMethod = descriptor.value;
|
|
@@ -3609,6 +4232,16 @@
|
|
|
3609
4232
|
}
|
|
3610
4233
|
};
|
|
3611
4234
|
}
|
|
4235
|
+
/**
|
|
4236
|
+
* Method decorator that throttles calls to an instance method: the first call in a window runs immediately;
|
|
4237
|
+
* further calls arriving before the window elapses are not dropped but coalesced — only the most recent
|
|
4238
|
+
* set of arguments is remembered and, once the window elapses, one trailing call runs with those arguments
|
|
4239
|
+
* (mirroring a classic "leading + trailing" throttle).
|
|
4240
|
+
*
|
|
4241
|
+
* @param msecs Throttle window in milliseconds, or `true` to use a single animation frame (`requestAnimationFrame`) as the window. Defaults to `50`.
|
|
4242
|
+
* @param keyFactory Computes the per-instance timer key from the method name and call arguments; override to scope throttling per argument instead of per method. Defaults to a single shared key per method.
|
|
4243
|
+
* @returns A method decorator to apply to the instance method to throttle.
|
|
4244
|
+
*/
|
|
3612
4245
|
function Throttle(msecs = 50, keyFactory = (key, ...args) => `pacem:throttler:${key}`) {
|
|
3613
4246
|
return function (target /* type, actually */, key, descriptor) {
|
|
3614
4247
|
const originalMethod = descriptor.value;
|
|
@@ -3658,6 +4291,14 @@
|
|
|
3658
4291
|
}
|
|
3659
4292
|
}
|
|
3660
4293
|
};
|
|
4294
|
+
/**
|
|
4295
|
+
* Method decorator that registers a static/instance method as a globally-named {@link TransformFunction},
|
|
4296
|
+
* making it callable by name from template binding expressions (e.g. `{{ ^value | myTransform }}`).
|
|
4297
|
+
* The registration is global (attached under `Utils.core`, dot-segmented by `name`), not per-instance.
|
|
4298
|
+
*
|
|
4299
|
+
* @param name Dot-separated registration path (e.g. `'strings.upper'`); segments before the last create/reuse nested namespaces under `Utils.core`. Defaults to the decorated method's own name when omitted.
|
|
4300
|
+
* @returns A method decorator to apply to the transform function.
|
|
4301
|
+
*/
|
|
3661
4302
|
function Transformer(name) {
|
|
3662
4303
|
return function (target, key, descriptor) {
|
|
3663
4304
|
const method = descriptor.value;
|
|
@@ -3675,6 +4316,16 @@
|
|
|
3675
4316
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3676
4317
|
};
|
|
3677
4318
|
//namespace Pacem.Components {
|
|
4319
|
+
/**
|
|
4320
|
+
* Base class for (almost) every Pacem custom element. Extends `HTMLElement` with the framework's
|
|
4321
|
+
* common lifecycle/event plumbing: `on-{event-type}` attribute handlers (see {@link emit}), a
|
|
4322
|
+
* {@link disabled} property that suppresses both outgoing (`dispatchEvent`) and incoming
|
|
4323
|
+
* (`emitHandler`) events, an optional {@link logger} sink, and an {@link isReady} flag toggled once
|
|
4324
|
+
* `viewActivatedCallback` has fired (see the {@link CustomElement} decorator for when that happens).
|
|
4325
|
+
* Concrete elements are expected to be decorated with `@CustomElement` and typically override
|
|
4326
|
+
* `propertyChangedCallback`/`viewActivatedCallback`/`connectedCallback`/`disconnectedCallback`,
|
|
4327
|
+
* calling `super.xxxCallback()` first/last as documented on each.
|
|
4328
|
+
*/
|
|
3678
4329
|
class PacemEventTarget extends HTMLElement {
|
|
3679
4330
|
constructor() {
|
|
3680
4331
|
super();
|
|
@@ -3857,12 +4508,14 @@
|
|
|
3857
4508
|
return this._aria.attrs;
|
|
3858
4509
|
}
|
|
3859
4510
|
}
|
|
4511
|
+
/** Common base class for Pacem custom elements: adds ARIA support, CSS class/part/style bags, visibility, tab order and behaviors. */
|
|
3860
4512
|
class PacemElement extends PacemEventTarget {
|
|
3861
4513
|
constructor(role, aria) {
|
|
3862
4514
|
super();
|
|
3863
4515
|
this.#cssBag = [];
|
|
3864
4516
|
this.#parts = [];
|
|
3865
4517
|
this._tabIndex = -1;
|
|
4518
|
+
/** Gets or sets the list of behaviors to attach to this element. */
|
|
3866
4519
|
this.behaviors = [];
|
|
3867
4520
|
this._aria = new ElementAria(this, role, aria);
|
|
3868
4521
|
}
|
|
@@ -4047,6 +4700,7 @@
|
|
|
4047
4700
|
__decorate$H([
|
|
4048
4701
|
Watch({ emit: false })
|
|
4049
4702
|
], PacemElement.prototype, "behaviors", void 0);
|
|
4703
|
+
/** Base class for elements whose (sanitized) inner content is driven by a `content` property, restoring the original markup on disconnect. */
|
|
4050
4704
|
class PacemContentElement extends PacemElement {
|
|
4051
4705
|
propertyChangedCallback(name, old, val, first) {
|
|
4052
4706
|
super.propertyChangedCallback(name, old, val, first);
|
|
@@ -4090,11 +4744,13 @@
|
|
|
4090
4744
|
__decorate$H([
|
|
4091
4745
|
Watch({ emit: false, converter: PropertyConverters.String })
|
|
4092
4746
|
], PacemContentElement.prototype, "content", void 0);
|
|
4747
|
+
/** {@link PacemContentElement} variant that renders `content` verbatim, without any sanitization. */
|
|
4093
4748
|
class PacemUnsafeContentElement extends PacemContentElement {
|
|
4094
4749
|
sanitize(html) {
|
|
4095
4750
|
return html;
|
|
4096
4751
|
}
|
|
4097
4752
|
}
|
|
4753
|
+
/** {@link PacemContentElement} variant that strips out `<script>` blocks (and, for `Node` content, `<script>` elements) before rendering `content`. */
|
|
4098
4754
|
class PacemSafeContentElement extends PacemContentElement {
|
|
4099
4755
|
_sanitizeLegacy(html) {
|
|
4100
4756
|
if (Utils.isNullOrEmpty(html)) {
|
|
@@ -4126,6 +4782,7 @@
|
|
|
4126
4782
|
}
|
|
4127
4783
|
//}
|
|
4128
4784
|
|
|
4785
|
+
/** Base class for pluggable adapters that drive the focus/navigation behavior of a {@link PacemIterativeElement}. */
|
|
4129
4786
|
class PacemAdapter extends PacemElement {
|
|
4130
4787
|
constructor() {
|
|
4131
4788
|
super(...arguments);
|
|
@@ -4254,6 +4911,10 @@
|
|
|
4254
4911
|
const current = this._getAvailable();
|
|
4255
4912
|
return ndx === this._getNextAvailable(current);
|
|
4256
4913
|
}
|
|
4914
|
+
/**
|
|
4915
|
+
* Sets the master's index to the closest available item to the provided one.
|
|
4916
|
+
* @param ndx Desired index
|
|
4917
|
+
*/
|
|
4257
4918
|
select(ndx) {
|
|
4258
4919
|
this._element.index = this._getAvailable(ndx);
|
|
4259
4920
|
}
|
|
@@ -4277,6 +4938,7 @@
|
|
|
4277
4938
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4278
4939
|
};
|
|
4279
4940
|
//namespace Pacem.Components {
|
|
4941
|
+
/** Removes itself from the DOM as soon as it gets connected; handy to strip out placeholder markup at runtime. */
|
|
4280
4942
|
let PacemAnnihilatorElement = class PacemAnnihilatorElement extends HTMLElement {
|
|
4281
4943
|
constructor() {
|
|
4282
4944
|
super();
|
|
@@ -4297,6 +4959,7 @@
|
|
|
4297
4959
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4298
4960
|
};
|
|
4299
4961
|
//namespace Pacem.Components {
|
|
4962
|
+
/** Warns the user (native `beforeunload` prompt or router-driven confirm dialog) before leaving the page. */
|
|
4300
4963
|
let PacemBeforeunloadElement = class PacemBeforeunloadElement extends PacemEventTarget {
|
|
4301
4964
|
constructor() {
|
|
4302
4965
|
super(...arguments);
|
|
@@ -4343,9 +5006,11 @@
|
|
|
4343
5006
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4344
5007
|
};
|
|
4345
5008
|
//namespace Pacem.Components {
|
|
5009
|
+
/** Wraps a {@link BroadcastChannel}, sending/receiving messages to/from other same-origin browsing contexts. */
|
|
4346
5010
|
let PacemBroadcastChannelProxyElement = class PacemBroadcastChannelProxyElement extends PacemEventTarget {
|
|
4347
5011
|
constructor() {
|
|
4348
5012
|
super(...arguments);
|
|
5013
|
+
/** Gets or sets whether to automatically send `message` as soon as it changes (default `true`). */
|
|
4349
5014
|
this.autosend = true;
|
|
4350
5015
|
this._messageHandler = (evt) => {
|
|
4351
5016
|
this.result = evt.data;
|
|
@@ -4381,6 +5046,10 @@
|
|
|
4381
5046
|
this._disposeChannel();
|
|
4382
5047
|
super.disconnectedCallback();
|
|
4383
5048
|
}
|
|
5049
|
+
/**
|
|
5050
|
+
* Posts a message through the channel.
|
|
5051
|
+
* @param message Message to send; defaults to the current `message` property
|
|
5052
|
+
*/
|
|
4384
5053
|
send(message = this.message) {
|
|
4385
5054
|
if (this.disabled) {
|
|
4386
5055
|
return;
|
|
@@ -4433,6 +5102,7 @@
|
|
|
4433
5102
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4434
5103
|
};
|
|
4435
5104
|
//namespace Pacem.Components {
|
|
5105
|
+
/** Detects the name and version of the current (or a provided) browser user agent. */
|
|
4436
5106
|
let PacemBrowserDetectElement = class PacemBrowserDetectElement extends PacemEventTarget {
|
|
4437
5107
|
viewActivatedCallback() {
|
|
4438
5108
|
super.viewActivatedCallback();
|
|
@@ -4446,9 +5116,11 @@
|
|
|
4446
5116
|
}
|
|
4447
5117
|
#browser;
|
|
4448
5118
|
#version;
|
|
5119
|
+
/** @readonly Gets the detected browser name. */
|
|
4449
5120
|
get browser() {
|
|
4450
5121
|
return this.#browser;
|
|
4451
5122
|
}
|
|
5123
|
+
/** @readonly Gets the detected browser version. */
|
|
4452
5124
|
get version() {
|
|
4453
5125
|
return this.#version;
|
|
4454
5126
|
}
|
|
@@ -4475,6 +5147,12 @@
|
|
|
4475
5147
|
|
|
4476
5148
|
//namespace Pacem {
|
|
4477
5149
|
const EXPIRATION_FIELD = '_exp';
|
|
5150
|
+
/**
|
|
5151
|
+
* JSON-serializing wrapper around `sessionStorage`/`localStorage` that transparently supports per-key
|
|
5152
|
+
* expiration: values stored with a `duration` are stamped with an expiry timestamp and evicted lazily
|
|
5153
|
+
* (checked on the next {@link getPropertyValue} call for that key, not via a timer). Session storage and
|
|
5154
|
+
* local storage are treated as a single logical namespace - storing a key in one clears any same-named entry in the other.
|
|
5155
|
+
*/
|
|
4478
5156
|
class Storage {
|
|
4479
5157
|
_getStorage(persistent) {
|
|
4480
5158
|
return !!persistent ? window.localStorage : window.sessionStorage;
|
|
@@ -4509,10 +5187,16 @@
|
|
|
4509
5187
|
storage = this._getStorage(!persistent);
|
|
4510
5188
|
storage.removeItem(name);
|
|
4511
5189
|
}
|
|
5190
|
+
/**
|
|
5191
|
+
* Retrieves a previously stored value by `name`, checking session storage first, then local storage.
|
|
5192
|
+
* Returns `null` if not found, or if found but past its expiration.
|
|
5193
|
+
* @param name The unique key.
|
|
5194
|
+
*/
|
|
4512
5195
|
getPropertyValue(name) {
|
|
4513
5196
|
return this._parseValue(this._getStorage(false), name)
|
|
4514
5197
|
|| this._parseValue(this._getStorage(true), name);
|
|
4515
5198
|
}
|
|
5199
|
+
/** Clears both session and local storage entirely. */
|
|
4516
5200
|
clear() {
|
|
4517
5201
|
var storage = this._getStorage(true);
|
|
4518
5202
|
storage.clear();
|
|
@@ -4520,6 +5204,7 @@
|
|
|
4520
5204
|
storage.clear();
|
|
4521
5205
|
}
|
|
4522
5206
|
;
|
|
5207
|
+
/** Removes a single entry by `name` from both session and local storage. */
|
|
4523
5208
|
removeProperty(name) {
|
|
4524
5209
|
var storage = this._getStorage(true);
|
|
4525
5210
|
storage.removeItem(name);
|
|
@@ -4536,6 +5221,7 @@
|
|
|
4536
5221
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4537
5222
|
};
|
|
4538
5223
|
//namespace Pacem.Components {
|
|
5224
|
+
/** Holds an arbitrary data model, optionally persisting it to local storage and debouncing/throttling change notifications. */
|
|
4539
5225
|
let PacemDataElement = class PacemDataElement extends PacemEventTarget {
|
|
4540
5226
|
constructor(storage = new Storage()) {
|
|
4541
5227
|
super();
|
|
@@ -4731,6 +5417,7 @@
|
|
|
4731
5417
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4732
5418
|
};
|
|
4733
5419
|
//namespace Pacem.Components {
|
|
5420
|
+
/** Base class for elements that move their own content to another DOM location, restoring nothing on disconnect. */
|
|
4734
5421
|
class PacemTransferProxyElement extends PacemEventTarget {
|
|
4735
5422
|
constructor() {
|
|
4736
5423
|
super(...arguments);
|
|
@@ -4836,6 +5523,7 @@
|
|
|
4836
5523
|
return PropertyConverters.Element.convertBack(prop, element);
|
|
4837
5524
|
}
|
|
4838
5525
|
};
|
|
5526
|
+
/** Listens for an arbitrary DOM event on a `target` element (or `window`) and re-dispatches it as its own `emit` event. */
|
|
4839
5527
|
let PacemEventProxyElement = class PacemEventProxyElement extends PacemEventTarget {
|
|
4840
5528
|
constructor() {
|
|
4841
5529
|
super(...arguments);
|
|
@@ -4908,11 +5596,13 @@
|
|
|
4908
5596
|
};
|
|
4909
5597
|
//namespace Pacem.Components {
|
|
4910
5598
|
const ABORT_MESSAGE = "New incoming request overrides the ongoing one. Aborting.";
|
|
5599
|
+
/** Declarative wrapper around the `fetch()` API, debouncing/aborting requests as its properties change and exposing the parsed `result`. */
|
|
4911
5600
|
let PacemFetchElement = class PacemFetchElement extends PacemEventTarget {
|
|
4912
5601
|
constructor() {
|
|
4913
5602
|
super(...arguments);
|
|
4914
5603
|
/** Gets or sets whether to trigger a fetch whenever a significant property has changed (default: true). */
|
|
4915
5604
|
this.autofetch = true;
|
|
5605
|
+
/** Gets or sets the debounce delay (in milliseconds) applied before auto-triggered fetches (default `100`). */
|
|
4916
5606
|
this.debounce = 100;
|
|
4917
5607
|
}
|
|
4918
5608
|
viewActivatedCallback() {
|
|
@@ -5171,6 +5861,7 @@
|
|
|
5171
5861
|
super(type, { detail });
|
|
5172
5862
|
}
|
|
5173
5863
|
}
|
|
5864
|
+
/** Keeps track of an undo/redo-capable history of an arbitrary state. */
|
|
5174
5865
|
let PacemHistoryElement = class PacemHistoryElement extends PacemEventTarget {
|
|
5175
5866
|
#history;
|
|
5176
5867
|
propertyChangedCallback(name, old, val, first) {
|
|
@@ -5204,6 +5895,7 @@
|
|
|
5204
5895
|
this.#history = new pacemFoundation.HistoryService(val, this.maxlength);
|
|
5205
5896
|
}
|
|
5206
5897
|
}
|
|
5898
|
+
/** Moves the state forward one step, if `canRedo` is `true`. */
|
|
5207
5899
|
redo() {
|
|
5208
5900
|
const h = this.#history;
|
|
5209
5901
|
if (!Utils.isNull(h)) {
|
|
@@ -5212,6 +5904,7 @@
|
|
|
5212
5904
|
this._synchronize('redo');
|
|
5213
5905
|
}
|
|
5214
5906
|
}
|
|
5907
|
+
/** Clears the history stack, keeping only the current state. */
|
|
5215
5908
|
reset() {
|
|
5216
5909
|
const h = this.#history;
|
|
5217
5910
|
if (!Utils.isNull(h)) {
|
|
@@ -5220,6 +5913,7 @@
|
|
|
5220
5913
|
this._synchronize('reset');
|
|
5221
5914
|
}
|
|
5222
5915
|
}
|
|
5916
|
+
/** Moves the state back one step, if `canUndo` is `true`. */
|
|
5223
5917
|
undo() {
|
|
5224
5918
|
const h = this.#history;
|
|
5225
5919
|
if (!Utils.isNull(h)) {
|
|
@@ -5261,6 +5955,7 @@
|
|
|
5261
5955
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5262
5956
|
};
|
|
5263
5957
|
//namespace Pacem.Components {
|
|
5958
|
+
/** Sets (or removes) an attribute on the document's root `<html>` element. */
|
|
5264
5959
|
let PacemHtmlProxyElement = class PacemHtmlProxyElement extends PacemEventTarget {
|
|
5265
5960
|
constructor() {
|
|
5266
5961
|
super(...arguments);
|
|
@@ -5309,6 +6004,7 @@
|
|
|
5309
6004
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5310
6005
|
};
|
|
5311
6006
|
//namespace Pacem.Components {
|
|
6007
|
+
/** Conditionally shows or clears its own inner content, restoring the original markup whenever `match` becomes truthy again. */
|
|
5312
6008
|
let PacemIfElement = class PacemIfElement extends HTMLElement {
|
|
5313
6009
|
#innerHTML;
|
|
5314
6010
|
propertyChangedCallback(name, old, val, first) {
|
|
@@ -5339,6 +6035,7 @@
|
|
|
5339
6035
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5340
6036
|
};
|
|
5341
6037
|
//namespace Pacem.Components {
|
|
6038
|
+
/** Base class for elements that register themselves against an ancestor {@link PacemItemsContainerElement}. */
|
|
5342
6039
|
class PacemItemElement extends PacemElement {
|
|
5343
6040
|
get container() {
|
|
5344
6041
|
return this._container;
|
|
@@ -5444,6 +6141,7 @@
|
|
|
5444
6141
|
__decorate$u([
|
|
5445
6142
|
Watch( /* can only be databound or assigned at runtime */)
|
|
5446
6143
|
], PacemCrossItemsContainerElement.prototype, "items", void 0);
|
|
6144
|
+
/** Base class for container elements holding a registry of {@link PacemItemElement} children. */
|
|
5447
6145
|
class PacemItemsContainerElement extends PacemElement {
|
|
5448
6146
|
constructor(role, aria) {
|
|
5449
6147
|
super(role, aria);
|
|
@@ -5476,6 +6174,7 @@
|
|
|
5476
6174
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5477
6175
|
};
|
|
5478
6176
|
//namespace Pacem.Components {
|
|
6177
|
+
/** Base class for items belonging to a {@link PacemIterativeElement}, forwarding their property changes to the master's `adapter`. */
|
|
5479
6178
|
class PacemIterableElement extends PacemItemElement {
|
|
5480
6179
|
/** @overrides */
|
|
5481
6180
|
findContainer() {
|
|
@@ -5491,6 +6190,7 @@
|
|
|
5491
6190
|
&& iter.adapter.itemPropertyChangedCallback(index, name, old, val, first);
|
|
5492
6191
|
}
|
|
5493
6192
|
}
|
|
6193
|
+
/** Base class for container elements whose items are driven by a pluggable {@link PacemAdapter}, tracking a `current` `index`. */
|
|
5494
6194
|
class PacemIterativeElement extends PacemItemsContainerElement {
|
|
5495
6195
|
propertyChangedCallback(name, old, val, first) {
|
|
5496
6196
|
super.propertyChangedCallback(name, old, val, first);
|
|
@@ -5548,6 +6248,7 @@
|
|
|
5548
6248
|
//namespace Pacem.Components {
|
|
5549
6249
|
const REMOVE_VALUE = 'false';
|
|
5550
6250
|
const EMPTY_VALUE = 'true';
|
|
6251
|
+
/** Sets (or removes) an attribute on the closest ancestor shell element, e.g. to drive layout-wide CSS state. */
|
|
5551
6252
|
let PacemLayoutProxyElement = class PacemLayoutProxyElement extends PacemEventTarget {
|
|
5552
6253
|
#shell;
|
|
5553
6254
|
connectedCallback() {
|
|
@@ -5601,6 +6302,7 @@
|
|
|
5601
6302
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5602
6303
|
};
|
|
5603
6304
|
//namespace Pacem.Components {
|
|
6305
|
+
/** Creates, updates or removes a `<meta>` element in the document `<head>`, keyed by either `name` or `itemprop`. */
|
|
5604
6306
|
let PacemMetaProxyElement = class PacemMetaProxyElement extends PacemEventTarget {
|
|
5605
6307
|
propertyChangedCallback(name, old, val, first) {
|
|
5606
6308
|
super.propertyChangedCallback(name, old, val, first);
|
|
@@ -5662,6 +6364,7 @@
|
|
|
5662
6364
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5663
6365
|
};
|
|
5664
6366
|
//namespace Pacem.Components {
|
|
6367
|
+
/** Tracks the browser's network connectivity (`navigator.onLine`), updating `online` on `online`/`offline` events. */
|
|
5665
6368
|
let PacemOnlineStatusElement = class PacemOnlineStatusElement extends PacemEventTarget {
|
|
5666
6369
|
constructor() {
|
|
5667
6370
|
super(...arguments);
|
|
@@ -5704,6 +6407,7 @@
|
|
|
5704
6407
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5705
6408
|
};
|
|
5706
6409
|
//namespace Pacem.Components {
|
|
6410
|
+
/** Plain generic-purpose container element, useful as a databinding/behaviors host wherever a `<div>` would do. */
|
|
5707
6411
|
let PacemPanelElement = class PacemPanelElement extends PacemSafeContentElement {
|
|
5708
6412
|
};
|
|
5709
6413
|
PacemPanelElement = __decorate$p([
|
|
@@ -5713,7 +6417,12 @@
|
|
|
5713
6417
|
|
|
5714
6418
|
/// <reference path="events.ts" />
|
|
5715
6419
|
//namespace Pacem {
|
|
6420
|
+
/** Event name dispatched to signal a generic, named command invocation; see {@link CommandEvent}. */
|
|
5716
6421
|
const CommandEventName = 'command';
|
|
6422
|
+
/**
|
|
6423
|
+
* Bubbling, cancelable event representing a generic UI command (e.g. a button's `command`/`command-argument`
|
|
6424
|
+
* attributes), letting ancestor elements handle named actions without wiring a dedicated listener per command.
|
|
6425
|
+
*/
|
|
5717
6426
|
class CommandEvent extends CustomTypedEvent {
|
|
5718
6427
|
constructor(args) {
|
|
5719
6428
|
super(CommandEventName, args, { bubbles: true, cancelable: true });
|
|
@@ -5728,6 +6437,7 @@
|
|
|
5728
6437
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5729
6438
|
};
|
|
5730
6439
|
//namespace Pacem.Components {
|
|
6440
|
+
/** Redirects consumers (e.g. {@link PacemRepeaterElement}) to an external `<template>` element, firing a `templatechange` event when it changes. */
|
|
5731
6441
|
let PacemTemplateProxyElement = class PacemTemplateProxyElement extends /*PacemEventTarget*/ /*PacemEventTarget*/ TemplateElement {
|
|
5732
6442
|
propertyChangedCallback(name, old, val, first) {
|
|
5733
6443
|
// super.propertyChangedCallback(name, old, val, first);
|
|
@@ -5782,6 +6492,8 @@
|
|
|
5782
6492
|
}
|
|
5783
6493
|
//
|
|
5784
6494
|
/**
|
|
6495
|
+
* Repeats its `<template>` content once per `datasource` item, keeping the rendered items in sync as the datasource changes.
|
|
6496
|
+
* @example
|
|
5785
6497
|
* <pacem-repeater datasource="[{id:'first', items:['a','b','c']}, ...]">
|
|
5786
6498
|
* <ol>
|
|
5787
6499
|
* <li>
|
|
@@ -5813,6 +6525,7 @@
|
|
|
5813
6525
|
this._databind();
|
|
5814
6526
|
};
|
|
5815
6527
|
}
|
|
6528
|
+
/** Removes the rendered item at the given index. */
|
|
5816
6529
|
removeItem(index) {
|
|
5817
6530
|
this._removeItems(index, index);
|
|
5818
6531
|
}
|
|
@@ -5841,6 +6554,7 @@
|
|
|
5841
6554
|
item.remove();
|
|
5842
6555
|
}
|
|
5843
6556
|
}
|
|
6557
|
+
/** Forces a full re-render of the items against the current `datasource`. */
|
|
5844
6558
|
databind() {
|
|
5845
6559
|
this._databind();
|
|
5846
6560
|
}
|
|
@@ -6038,6 +6752,7 @@
|
|
|
6038
6752
|
}
|
|
6039
6753
|
}
|
|
6040
6754
|
const BORDER_BOX = { box: 'border-box' };
|
|
6755
|
+
/** Observes size (and, optionally, position) changes of itself or a `target` element, firing a `resize` event accordingly. */
|
|
6041
6756
|
let PacemResizeElement = class PacemResizeElement extends PacemEventTarget {
|
|
6042
6757
|
constructor() {
|
|
6043
6758
|
super(...arguments);
|
|
@@ -6136,6 +6851,7 @@
|
|
|
6136
6851
|
this._dispatchResize();
|
|
6137
6852
|
}
|
|
6138
6853
|
}
|
|
6854
|
+
/** @readonly Gets the last measured size (and position, if `watchPosition` is set) of the observed target. */
|
|
6139
6855
|
get currentSize() {
|
|
6140
6856
|
var args = { height: this._previousHeight, width: this._previousWidth };
|
|
6141
6857
|
if (this.watchPosition) {
|
|
@@ -6175,6 +6891,7 @@
|
|
|
6175
6891
|
};
|
|
6176
6892
|
//namespace Pacem.Components {
|
|
6177
6893
|
const CHECK_PATTERN = /^([\w\.]:)?\/\/[^\/]+/;
|
|
6894
|
+
/** Client-side router: parses/generates paths against a template and drives the browser History API. */
|
|
6178
6895
|
let PacemRouterElement = class PacemRouterElement extends PacemEventTarget {
|
|
6179
6896
|
constructor() {
|
|
6180
6897
|
super(...arguments);
|
|
@@ -6196,6 +6913,10 @@
|
|
|
6196
6913
|
}
|
|
6197
6914
|
#cancelingNavigation;
|
|
6198
6915
|
#template;
|
|
6916
|
+
/**
|
|
6917
|
+
* Merges the provided partial state into the current one and returns the resulting parsed {@link RouterState}, without navigating.
|
|
6918
|
+
* @param state Piece of new state to be merged
|
|
6919
|
+
*/
|
|
6199
6920
|
parseState(state = {}) {
|
|
6200
6921
|
const path = this._stringifyMergedState(state);
|
|
6201
6922
|
const segments = this._segmentateUrl(path);
|
|
@@ -6455,6 +7176,7 @@
|
|
|
6455
7176
|
}
|
|
6456
7177
|
return output;
|
|
6457
7178
|
}
|
|
7179
|
+
/** Registers a service worker and manages its (optional) Push API subscription. */
|
|
6458
7180
|
let PacemServiceWorkerProxyElement = class PacemServiceWorkerProxyElement extends PacemEventTarget {
|
|
6459
7181
|
viewActivatedCallback() {
|
|
6460
7182
|
super.viewActivatedCallback();
|
|
@@ -6507,6 +7229,10 @@
|
|
|
6507
7229
|
}
|
|
6508
7230
|
});
|
|
6509
7231
|
}
|
|
7232
|
+
/**
|
|
7233
|
+
* Unsubscribes from push notifications.
|
|
7234
|
+
* @param subscription Subscription to cancel; defaults to the current `pushSubscription`
|
|
7235
|
+
*/
|
|
6510
7236
|
unsubscribe(subscription = this.pushSubscription) {
|
|
6511
7237
|
return new Promise((resolve, reject) => {
|
|
6512
7238
|
if (!Utils.isNull(subscription)) {
|
|
@@ -6524,6 +7250,10 @@
|
|
|
6524
7250
|
}
|
|
6525
7251
|
});
|
|
6526
7252
|
}
|
|
7253
|
+
/**
|
|
7254
|
+
* Subscribes to push notifications through the registered service worker.
|
|
7255
|
+
* @param publicKey VAPID public key (base64url or raw bytes); defaults to `publicKey`
|
|
7256
|
+
*/
|
|
6527
7257
|
subscribe(publicKey = this.publicKey) {
|
|
6528
7258
|
return new Promise((resolve, reject) => {
|
|
6529
7259
|
if (typeof publicKey === 'string') {
|
|
@@ -6611,6 +7341,7 @@
|
|
|
6611
7341
|
|| (/^arrow/.test(key) && (piece === key.substr(5)));
|
|
6612
7342
|
}
|
|
6613
7343
|
const KeyboardShortcutExecuteEventName = "execute";
|
|
7344
|
+
/** Listens for a keyboard shortcut (optionally chorded, e.g. `"ctrl+k, s"`) on a target and fires an `execute` event when matched. */
|
|
6614
7345
|
let PacemShortcutElement = class PacemShortcutElement extends PacemEventTarget {
|
|
6615
7346
|
constructor() {
|
|
6616
7347
|
super(...arguments);
|
|
@@ -6668,6 +7399,7 @@
|
|
|
6668
7399
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6669
7400
|
};
|
|
6670
7401
|
//namespace Pacem.Components {
|
|
7402
|
+
/** Sets its own `textContent` to the `text` property, escaping any markup. */
|
|
6671
7403
|
let PacemSpanElement = class PacemSpanElement extends PacemSafeContentElement {
|
|
6672
7404
|
propertyChangedCallback(name, old, val, first) {
|
|
6673
7405
|
super.propertyChangedCallback(name, old, val, first);
|
|
@@ -6697,6 +7429,7 @@
|
|
|
6697
7429
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6698
7430
|
};
|
|
6699
7431
|
//namespace Pacem.Components {
|
|
7432
|
+
/** Injects a `<style>` element into the document `<head>`, populated either inline (`cssText`) or by fetching `src`. */
|
|
6700
7433
|
let PacemStyleProxyElement = class PacemStyleProxyElement extends PacemEventTarget {
|
|
6701
7434
|
propertyChangedCallback(name, old, val, first) {
|
|
6702
7435
|
super.propertyChangedCallback(name, old, val, first);
|
|
@@ -6797,6 +7530,7 @@
|
|
|
6797
7530
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6798
7531
|
};
|
|
6799
7532
|
//namespace Pacem.Components {
|
|
7533
|
+
/** Renders the `text` property as its own plain-text content, replacing any existing child markup. */
|
|
6800
7534
|
let PacemTextElement = class PacemTextElement extends HTMLElement {
|
|
6801
7535
|
constructor() {
|
|
6802
7536
|
super();
|
|
@@ -6828,6 +7562,7 @@
|
|
|
6828
7562
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6829
7563
|
};
|
|
6830
7564
|
//namespace Pacem.Components {
|
|
7565
|
+
/** Fires a `tick` event on a regular interval, as long as it's enabled and `interval` is greater than zero. */
|
|
6831
7566
|
let PacemTimerElement = class PacemTimerElement extends PacemEventTarget {
|
|
6832
7567
|
constructor() {
|
|
6833
7568
|
super();
|
|
@@ -6874,6 +7609,7 @@
|
|
|
6874
7609
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6875
7610
|
};
|
|
6876
7611
|
//namespace Pacem.Components {
|
|
7612
|
+
/** Sets `document.title` to `value` whenever it changes. */
|
|
6877
7613
|
let PacemTitleProxyElement = class PacemTitleProxyElement extends PacemEventTarget {
|
|
6878
7614
|
propertyChangedCallback(name, old, val, first) {
|
|
6879
7615
|
super.propertyChangedCallback(name, old, val, first);
|
|
@@ -6909,10 +7645,12 @@
|
|
|
6909
7645
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6910
7646
|
};
|
|
6911
7647
|
//namespace Pacem.Components {
|
|
7648
|
+
/** Animates a numeric `value` from `from` to `to` over `duration`, dispatching animation lifecycle events along the way. */
|
|
6912
7649
|
let PacemTweenElement = class PacemTweenElement extends PacemEventTarget {
|
|
6913
7650
|
constructor(_tweener = new TweenService()) {
|
|
6914
7651
|
super();
|
|
6915
7652
|
this._tweener = _tweener;
|
|
7653
|
+
/** Gets or sets the animation duration, in milliseconds (default `1000`). */
|
|
6916
7654
|
this.duration = 1000;
|
|
6917
7655
|
}
|
|
6918
7656
|
propertyChangedCallback(name, old, val, first) {
|
|
@@ -6922,6 +7660,7 @@
|
|
|
6922
7660
|
this._animate();
|
|
6923
7661
|
}
|
|
6924
7662
|
}
|
|
7663
|
+
/** Starts the animation programmatically and returns a promise resolved once it completes. */
|
|
6925
7664
|
run() {
|
|
6926
7665
|
return this._animate();
|
|
6927
7666
|
}
|
|
@@ -7071,9 +7810,11 @@
|
|
|
7071
7810
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7072
7811
|
};
|
|
7073
7812
|
//namespace Pacem.Components {
|
|
7813
|
+
/** Wraps a {@link Worker}, sending/receiving messages to/from a web worker script. */
|
|
7074
7814
|
let PacemWebWorkerProxyElement = class PacemWebWorkerProxyElement extends PacemEventTarget {
|
|
7075
7815
|
constructor() {
|
|
7076
7816
|
super(...arguments);
|
|
7817
|
+
/** Gets or sets whether to automatically send `message` as soon as it changes (default `true`). */
|
|
7077
7818
|
this.autosend = true;
|
|
7078
7819
|
this._messageHandler = (evt) => {
|
|
7079
7820
|
this.result = evt.data;
|
|
@@ -7109,6 +7850,10 @@
|
|
|
7109
7850
|
this._disposeWorker();
|
|
7110
7851
|
super.disconnectedCallback();
|
|
7111
7852
|
}
|
|
7853
|
+
/**
|
|
7854
|
+
* Posts a message to the worker.
|
|
7855
|
+
* @param message Message to send; defaults to the current `message` property
|
|
7856
|
+
*/
|
|
7112
7857
|
send(message = this.message) {
|
|
7113
7858
|
if (this.disabled) {
|
|
7114
7859
|
return;
|
|
@@ -7154,8 +7899,16 @@
|
|
|
7154
7899
|
//}
|
|
7155
7900
|
|
|
7156
7901
|
//namespace Pacem.Behaviors{
|
|
7902
|
+
/**
|
|
7903
|
+
* Base class for the "behavior" custom elements (drag & drop, swipe, rotate, rescale, ...) that attach
|
|
7904
|
+
* gesture-driven functionality to a set of registered elements without rendering anything of their own.
|
|
7905
|
+
*/
|
|
7157
7906
|
class PacemBehavior extends PacemEventTarget {
|
|
7158
7907
|
#items = new WeakSet();
|
|
7908
|
+
/**
|
|
7909
|
+
* Registers an element with this behavior, decorating it if it wasn't already registered.
|
|
7910
|
+
* @param element Element to register.
|
|
7911
|
+
*/
|
|
7159
7912
|
register(element) {
|
|
7160
7913
|
var container = this.#items;
|
|
7161
7914
|
if (!container.has(element)) {
|
|
@@ -7163,6 +7916,10 @@
|
|
|
7163
7916
|
this.decorate(element);
|
|
7164
7917
|
}
|
|
7165
7918
|
}
|
|
7919
|
+
/**
|
|
7920
|
+
* Unregisters a previously registered element, undecorating it.
|
|
7921
|
+
* @param element Element to unregister.
|
|
7922
|
+
*/
|
|
7166
7923
|
unregister(element) {
|
|
7167
7924
|
var container = this.#items;
|
|
7168
7925
|
if (container.has(element)) {
|
|
@@ -7170,6 +7927,7 @@
|
|
|
7170
7927
|
container.delete(element);
|
|
7171
7928
|
}
|
|
7172
7929
|
}
|
|
7930
|
+
/** @readonly Determines whether the given element is currently registered with this behavior. */
|
|
7173
7931
|
has(element) {
|
|
7174
7932
|
return this.#items.has(element);
|
|
7175
7933
|
}
|
|
@@ -7591,7 +8349,8 @@
|
|
|
7591
8349
|
}
|
|
7592
8350
|
}
|
|
7593
8351
|
/**
|
|
7594
|
-
* Pacem Drag & Drop element adapter
|
|
8352
|
+
* Pacem Drag & Drop element adapter: implements {@link DragDropper} on top of {@link PacemBehavior} to make
|
|
8353
|
+
* registered elements draggable and, optionally, sortable/droppable onto {@link dropTargets}.
|
|
7595
8354
|
*/
|
|
7596
8355
|
let PacemDragDropElement = class PacemDragDropElement extends PacemBehavior {
|
|
7597
8356
|
constructor() {
|
|
@@ -7655,23 +8414,28 @@
|
|
|
7655
8414
|
/** Gets or sets the drag mode ("self", "alias", "copy"). */
|
|
7656
8415
|
this.mode = DragDataMode.Self;
|
|
7657
8416
|
}
|
|
8417
|
+
/** Wires up the `mousedown`/`touchstart` listeners that arm the drag gesture on the given element. */
|
|
7658
8418
|
decorate(element) {
|
|
7659
8419
|
const options = { capture: false, passive: false };
|
|
7660
8420
|
// TODO: add special effects starting the drag process after a while (timeout) the element is pressed.
|
|
7661
8421
|
element.addEventListener('mousedown', this._startHandler, false);
|
|
7662
8422
|
element.addEventListener('touchstart', this._startHandler, options);
|
|
7663
8423
|
}
|
|
8424
|
+
/** Removes the listeners set up by {@link decorate}. */
|
|
7664
8425
|
undecorate(element) {
|
|
7665
8426
|
const options = { capture: false, passive: false };
|
|
7666
8427
|
element.removeEventListener('mousedown', this._startHandler, false);
|
|
7667
8428
|
element.removeEventListener('touchstart', this._startHandler, options);
|
|
7668
8429
|
}
|
|
8430
|
+
/** Registers a listener for a {@link DragDropEventType} lifecycle event. */
|
|
7669
8431
|
addEventListener(type, listener, useCapture) {
|
|
7670
8432
|
super.addEventListener(type, listener, useCapture);
|
|
7671
8433
|
}
|
|
8434
|
+
/** Unregisters a listener previously added for a {@link DragDropEventType} lifecycle event. */
|
|
7672
8435
|
removeEventListener(type, listener, useCapture) {
|
|
7673
8436
|
super.removeEventListener(type, listener, useCapture);
|
|
7674
8437
|
}
|
|
8438
|
+
/** Dispatches a {@link DragDropEvent}, clearing internal per-element bookkeeping once the drag ends. */
|
|
7675
8439
|
dispatchEvent(evt) {
|
|
7676
8440
|
if (evt.type === DragDropEventType.End) {
|
|
7677
8441
|
DEL_VAL$3(evt.detail.element, MOUSE_DOWN$2);
|
|
@@ -7854,6 +8618,10 @@
|
|
|
7854
8618
|
const RESCALE_FRAME = 'pacem:rescale:frame';
|
|
7855
8619
|
const MOUSE_DOWN$1 = 'pacem:rescale:origin';
|
|
7856
8620
|
const DELEGATE$1 = 'pacem:rescale:delegate';
|
|
8621
|
+
/**
|
|
8622
|
+
* Pacem Rescale element adapter: implements {@link Rescaler} on top of {@link PacemBehavior}, decorating
|
|
8623
|
+
* registered elements with draggable resize handles (see {@link RescaleHandle}).
|
|
8624
|
+
*/
|
|
7857
8625
|
let PacemRescaleElement = class PacemRescaleElement extends PacemBehavior {
|
|
7858
8626
|
constructor() {
|
|
7859
8627
|
super(...arguments);
|
|
@@ -7881,11 +8649,13 @@
|
|
|
7881
8649
|
/* logging */ (level, message, category) => this.log.apply(this, [level, message, category])));
|
|
7882
8650
|
};
|
|
7883
8651
|
}
|
|
8652
|
+
/** Adds the resize-handle frame (see {@link RescaleHandle}) around the given element. */
|
|
7884
8653
|
decorate(element) {
|
|
7885
8654
|
const el = element; getComputedStyle(el);
|
|
7886
8655
|
Utils.addClass(el, PCSS + '-rescalable');
|
|
7887
8656
|
this._setFrame(el);
|
|
7888
8657
|
}
|
|
8658
|
+
/** Removes the resize-handle frame set up by {@link decorate}. */
|
|
7889
8659
|
undecorate(element) {
|
|
7890
8660
|
const el = element;
|
|
7891
8661
|
Utils.removeClass(el, PCSS + '-rescalable');
|
|
@@ -8069,6 +8839,10 @@
|
|
|
8069
8839
|
return x;
|
|
8070
8840
|
}
|
|
8071
8841
|
}
|
|
8842
|
+
/**
|
|
8843
|
+
* Pacem Rotate element adapter: implements {@link Rotator} on top of {@link PacemBehavior} to make
|
|
8844
|
+
* registered elements rotatable around a pivot point via mouse/touch drag.
|
|
8845
|
+
*/
|
|
8072
8846
|
let PacemRotateElement = class PacemRotateElement extends PacemBehavior {
|
|
8073
8847
|
constructor() {
|
|
8074
8848
|
super(...arguments);
|
|
@@ -8106,6 +8880,7 @@
|
|
|
8106
8880
|
/* logging */ (level, message, category) => this.log.apply(this, [level, message, category])));
|
|
8107
8881
|
};
|
|
8108
8882
|
}
|
|
8883
|
+
/** Wires up the `mousedown`/`touchstart` listeners that arm the rotate gesture on the given element. */
|
|
8109
8884
|
decorate(element) {
|
|
8110
8885
|
const el = element;
|
|
8111
8886
|
Utils.addClass(el, PCSS + '-rotatable');
|
|
@@ -8113,6 +8888,7 @@
|
|
|
8113
8888
|
element.addEventListener('mousedown', this._startHandler, false);
|
|
8114
8889
|
element.addEventListener('touchstart', this._startHandler, options);
|
|
8115
8890
|
}
|
|
8891
|
+
/** Removes the listeners set up by {@link decorate}. */
|
|
8116
8892
|
undecorate(element) {
|
|
8117
8893
|
const el = element;
|
|
8118
8894
|
Utils.removeClass(el, PCSS + '-rotatable');
|
|
@@ -8344,6 +9120,10 @@
|
|
|
8344
9120
|
window.removeEventListener('pointerup', this._endHandler);
|
|
8345
9121
|
}
|
|
8346
9122
|
}
|
|
9123
|
+
/**
|
|
9124
|
+
* Pacem Swipe element adapter: implements {@link Swiper} on top of {@link PacemBehavior} to make
|
|
9125
|
+
* registered elements draggable along one axis, with snap points and fling/bounce-back detection.
|
|
9126
|
+
*/
|
|
8347
9127
|
let PacemSwipeElement = class PacemSwipeElement extends PacemBehavior {
|
|
8348
9128
|
constructor() {
|
|
8349
9129
|
super(...arguments);
|
|
@@ -8396,6 +9176,7 @@
|
|
|
8396
9176
|
this._undo(el);
|
|
8397
9177
|
};
|
|
8398
9178
|
}
|
|
9179
|
+
/** Wires up the `pointerdown` listener that arms the swipe gesture on the given element. */
|
|
8399
9180
|
decorate(element) {
|
|
8400
9181
|
// https://docs.microsoft.com/en-us/microsoft-edge/dev-guide/dom/pointer-events
|
|
8401
9182
|
if (element instanceof HTMLElement || element instanceof SVGElement) {
|
|
@@ -8403,6 +9184,7 @@
|
|
|
8403
9184
|
}
|
|
8404
9185
|
element.addEventListener('pointerdown', this._prepareHandler, false);
|
|
8405
9186
|
}
|
|
9187
|
+
/** Removes the listener set up by {@link decorate}. */
|
|
8406
9188
|
undecorate(element) {
|
|
8407
9189
|
if (element instanceof HTMLElement || element instanceof SVGElement) {
|
|
8408
9190
|
Utils.removeClass(element, PCSS + '-swipe');
|
|
@@ -8467,6 +9249,10 @@
|
|
|
8467
9249
|
const EasingConverter = {
|
|
8468
9250
|
convert: (attr) => Easings[attr] ?? Easings.linear
|
|
8469
9251
|
};
|
|
9252
|
+
/**
|
|
9253
|
+
* Abstract base class for the `@CustomElement` animation items (color/number/point animations) that can be
|
|
9254
|
+
* hosted within a {@link PacemStoryboardElement}. Implements {@link Timeline}.
|
|
9255
|
+
*/
|
|
8470
9256
|
class AnimationElement extends PacemItemElement {
|
|
8471
9257
|
}
|
|
8472
9258
|
__decorate$5([
|
|
@@ -8490,15 +9276,21 @@
|
|
|
8490
9276
|
__decorate$5([
|
|
8491
9277
|
Watch({ emit: false, converter: PropertyConverters.String })
|
|
8492
9278
|
], AnimationElement.prototype, "direction", void 0);
|
|
9279
|
+
/**
|
|
9280
|
+
* Base class for animation elements that interpolate their `from`/`to` value via {@link TweenService}.
|
|
9281
|
+
* Concrete subclasses only need to supply {@link tweenInterpolationCallback} to map normalized progress to a value of type `T`.
|
|
9282
|
+
*/
|
|
8493
9283
|
class TweenAnimationElement extends AnimationElement {
|
|
8494
9284
|
constructor(_tweener = new TweenService()) {
|
|
8495
9285
|
super();
|
|
8496
9286
|
this._tweener = _tweener;
|
|
8497
9287
|
}
|
|
9288
|
+
/** @readonly Gets the {@link TweenService} instance driving this animation. */
|
|
8498
9289
|
get tweener() {
|
|
8499
9290
|
return this._tweener;
|
|
8500
9291
|
}
|
|
8501
9292
|
#cancelToken = false;
|
|
9293
|
+
/** Starts (or restarts) the tween and returns a promise resolved once it completes. */
|
|
8502
9294
|
startAnimation() {
|
|
8503
9295
|
this.#cancelToken = false;
|
|
8504
9296
|
return new Promise((resolve, _) => {
|
|
@@ -8511,6 +9303,7 @@
|
|
|
8511
9303
|
.then(resolve);
|
|
8512
9304
|
});
|
|
8513
9305
|
}
|
|
9306
|
+
/** Cancels the running tween. */
|
|
8514
9307
|
cancelAnimation() {
|
|
8515
9308
|
this.#cancelToken = true;
|
|
8516
9309
|
}
|
|
@@ -8525,6 +9318,7 @@
|
|
|
8525
9318
|
//namespace Pacem.Components {
|
|
8526
9319
|
const DEFAULT_FROM$2 = { h: 0, l: 0, s: 0.5, a: 1 };
|
|
8527
9320
|
const DEFAULT_TO$2 = { h: 0, l: 1, s: 0.5, a: 1 };
|
|
9321
|
+
/** Animates a CSS color `target[property]` from `from` to `to` (interpolated in HSLA space) over `duration`. */
|
|
8528
9322
|
let PacemColorAnimationElement = class PacemColorAnimationElement extends TweenAnimationElement {
|
|
8529
9323
|
propertyChangedCallback(name, old, val, first) {
|
|
8530
9324
|
super.propertyChangedCallback(name, old, val, first);
|
|
@@ -8568,6 +9362,7 @@
|
|
|
8568
9362
|
_parseColor(clr) {
|
|
8569
9363
|
return pacemFoundation.Colors.hsl(pacemFoundation.Colors.parse(clr));
|
|
8570
9364
|
}
|
|
9365
|
+
/** @inheritdoc */
|
|
8571
9366
|
tweenInterpolationCallback(time, progress) {
|
|
8572
9367
|
const from = this.#from, to = this.#to;
|
|
8573
9368
|
const hsla = {
|
|
@@ -8598,7 +9393,9 @@
|
|
|
8598
9393
|
//namespace Pacem.Components {
|
|
8599
9394
|
const DEFAULT_FROM$1 = 0;
|
|
8600
9395
|
const DEFAULT_TO$1 = 1;
|
|
9396
|
+
/** Animates a numeric `target[property]` from `from` to `to` over `duration`. */
|
|
8601
9397
|
let PacemNumberAnimationElement = class PacemNumberAnimationElement extends TweenAnimationElement {
|
|
9398
|
+
/** @inheritdoc */
|
|
8602
9399
|
tweenInterpolationCallback(time, progress) {
|
|
8603
9400
|
const to = this.to ?? DEFAULT_TO$1, from = this.from ?? DEFAULT_FROM$1;
|
|
8604
9401
|
return (to - from) * progress + from;
|
|
@@ -8623,7 +9420,9 @@
|
|
|
8623
9420
|
//namespace Pacem.Components {
|
|
8624
9421
|
const DEFAULT_FROM = { x: 0, y: 0 };
|
|
8625
9422
|
const DEFAULT_TO = { x: 1, y: 1 };
|
|
9423
|
+
/** Animates a {@link Point} `target[property]` from `from` to `to` over `duration`. */
|
|
8626
9424
|
let PacemPointAnimationElement = class PacemPointAnimationElement extends TweenAnimationElement {
|
|
9425
|
+
/** @inheritdoc */
|
|
8627
9426
|
tweenInterpolationCallback(time, progress) {
|
|
8628
9427
|
const to = this.to ?? DEFAULT_TO, from = this.from ?? DEFAULT_FROM;
|
|
8629
9428
|
return {
|
|
@@ -8650,7 +9449,12 @@
|
|
|
8650
9449
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
8651
9450
|
};
|
|
8652
9451
|
//namespace Pacem.Components {
|
|
9452
|
+
/**
|
|
9453
|
+
* Groups one or more {@link Timeline}s (either {@link AnimationElement} child items or an explicit
|
|
9454
|
+
* `datasource`) and starts/cancels them together, optionally on view activation via `autostart`.
|
|
9455
|
+
*/
|
|
8653
9456
|
let PacemStoryboardElement = class PacemStoryboardElement extends PacemItemsContainerElement {
|
|
9457
|
+
/** @inheritdoc */
|
|
8654
9458
|
validate(item) {
|
|
8655
9459
|
return item instanceof AnimationElement;
|
|
8656
9460
|
}
|
|
@@ -8691,12 +9495,14 @@
|
|
|
8691
9495
|
}
|
|
8692
9496
|
return Promise.all(promises);
|
|
8693
9497
|
}
|
|
9498
|
+
/** Cancels every running {@link Timeline} in this storyboard. */
|
|
8694
9499
|
cancelAnimation() {
|
|
8695
9500
|
const ds = this._adaptedDatasource || [];
|
|
8696
9501
|
for (let timeline of ds) {
|
|
8697
9502
|
timeline.cancelAnimation();
|
|
8698
9503
|
}
|
|
8699
9504
|
}
|
|
9505
|
+
/** Starts (or restarts) every {@link Timeline} in this storyboard. */
|
|
8700
9506
|
startAnimation() {
|
|
8701
9507
|
return this._animate(true);
|
|
8702
9508
|
}
|
|
@@ -8806,13 +9612,16 @@
|
|
|
8806
9612
|
});
|
|
8807
9613
|
|
|
8808
9614
|
//namespace Pacem {
|
|
9615
|
+
/** Framework-wide default settings. */
|
|
8809
9616
|
const Defaults = {
|
|
8810
9617
|
USE_SHADOW_ROOT: /*'attachShadow' in Element.prototype &&*/ false /* <- wait until html-imports */
|
|
8811
9618
|
};
|
|
8812
9619
|
//}
|
|
8813
9620
|
|
|
8814
9621
|
//namespace Pacem.RegularExpressions {
|
|
9622
|
+
/** A pattern that can never match any string (`/a^/`); useful as a safe no-op default for optional matcher parameters. */
|
|
8815
9623
|
const EMPTY_MATCHER = /a^/;
|
|
9624
|
+
/** Static regular-expression helpers. */
|
|
8816
9625
|
class Regex {
|
|
8817
9626
|
/**
|
|
8818
9627
|
* Splits an input string into segments based on a matching pattern.
|
|
@@ -8868,7 +9677,21 @@
|
|
|
8868
9677
|
cssRemove: cssRemove ?? 'fill-red-container',
|
|
8869
9678
|
};
|
|
8870
9679
|
}
|
|
9680
|
+
/**
|
|
9681
|
+
* The framework's built-in library of template-expression transform functions. Each static method here
|
|
9682
|
+
* is registered, via the {@link Transformer} decorator, under `Utils.core` (mostly by its own method
|
|
9683
|
+
* name - see each method's `@Transformer(...)` name override where present) so it becomes callable by
|
|
9684
|
+
* name from binding expressions (e.g. `{{ ^value | size }}`). Not part of the module's exported surface -
|
|
9685
|
+
* consumers use these by their registered transform name, not by importing this class.
|
|
9686
|
+
*/
|
|
8871
9687
|
class Transforms {
|
|
9688
|
+
/**
|
|
9689
|
+
* Wraps every case-insensitive occurrence of each whitespace-separated token of `query` found in `src`
|
|
9690
|
+
* (skipping matches inside HTML tags) with a `<span class="{css}">` highlight wrapper.
|
|
9691
|
+
* @param src Source HTML/text to search within.
|
|
9692
|
+
* @param query Whitespace-separated search terms.
|
|
9693
|
+
* @param css CSS class applied to the highlight `<span>`. Defaults to `{PCSS}-highlight`.
|
|
9694
|
+
*/
|
|
8872
9695
|
static highlight(src, query, css = PCSS + '-highlight') {
|
|
8873
9696
|
if (!query || !src)
|
|
8874
9697
|
return src;
|
|
@@ -8911,9 +9734,11 @@
|
|
|
8911
9734
|
return acc;
|
|
8912
9735
|
}, '');
|
|
8913
9736
|
}
|
|
9737
|
+
/** Left-pads `src` (stringified) to `length` characters using `pad`; see {@link Utils.leftPad}. */
|
|
8914
9738
|
static padleft(src, length, pad) {
|
|
8915
9739
|
return Utils.leftPad('' + src, length, pad);
|
|
8916
9740
|
}
|
|
9741
|
+
/** Formats a byte count `src` as a human-readable size string (`B`/`kB`/`MB`/`GB`), or `'-'` if not a positive number. */
|
|
8917
9742
|
static size(src) {
|
|
8918
9743
|
// TODO: use logarithms
|
|
8919
9744
|
if (!(src > 0))
|
|
@@ -8926,12 +9751,25 @@
|
|
|
8926
9751
|
return (src / 1_048_576).toFixed(2) + ' MB';
|
|
8927
9752
|
return (src / 1_073_741_824).toFixed(2) + ' GB';
|
|
8928
9753
|
}
|
|
9754
|
+
/**
|
|
9755
|
+
* Formats a decimal-degrees number `src` as degrees/minutes/seconds (e.g. `41° 53' 24"`).
|
|
9756
|
+
* @param src Decimal degrees value (sign indicates direction).
|
|
9757
|
+
* @param degSeparator Text following the degrees component.
|
|
9758
|
+
* @param minSeparator Text following the minutes component.
|
|
9759
|
+
* @param secSeparator Text following the seconds component.
|
|
9760
|
+
*/
|
|
8929
9761
|
static decToDeg(src, degSeparator = '° ', minSeparator = '\' ', secSeparator = '"') {
|
|
8930
9762
|
const sign = Math.sign(src);
|
|
8931
9763
|
src = Math.abs(src);
|
|
8932
9764
|
const deg = Math.floor(src), min0 = (src - deg) * 60, min = Math.floor(min0), sec0 = (min0 - min) * 60, sec = Math.floor(sec0);
|
|
8933
9765
|
return (sign < 0 ? '-' : '') + deg + degSeparator + min + minSeparator + sec + secSeparator;
|
|
8934
9766
|
}
|
|
9767
|
+
/**
|
|
9768
|
+
* Formats a date-like value `src` (parsed via {@link Utils.parseDate}) as text.
|
|
9769
|
+
* @param src Date, timestamp, or parseable date string.
|
|
9770
|
+
* @param format Either a named shorthand (`'iso'`, `'isodate'`, `'localdate'`, `'time'`/`'localtime'`, `'full'`, or the default locale date format) or an `Intl.DateTimeFormatOptions` object.
|
|
9771
|
+
* @param culture BCP 47 locale to format with. Defaults to the browser's language.
|
|
9772
|
+
*/
|
|
8935
9773
|
static date(src, format, culture) {
|
|
8936
9774
|
var date = Utils.parseDate(src), lang = culture || navigator.language;
|
|
8937
9775
|
if (Utils.isNull(format) || typeof format === 'string') {
|
|
@@ -8959,6 +9797,13 @@
|
|
|
8959
9797
|
return date.toLocaleString(culture, format);
|
|
8960
9798
|
}
|
|
8961
9799
|
}
|
|
9800
|
+
/**
|
|
9801
|
+
* Formats the elapsed time between `start` and `end`.
|
|
9802
|
+
* @param start Start date-like value.
|
|
9803
|
+
* @param end End date-like value.
|
|
9804
|
+
* @param format Either an `Intl.DateTimeFormatOptions` (formatted as a UTC duration, optionally sign-prefixed via `sign: true`), or omitted for the legacy `"{d}d {h}h {m}m {s}s {ms}ms"` textual format.
|
|
9805
|
+
* @param culture BCP 47 locale to format with (only used with `Intl.DateTimeFormatOptions`). Defaults to the browser's language.
|
|
9806
|
+
*/
|
|
8962
9807
|
static timespan(start, end, format, culture) {
|
|
8963
9808
|
const startDate = Utils.parseDate(start), endDate = Utils.parseDate(end), span = endDate.valueOf() - startDate.valueOf(), sign = span < 0 ? '-' : '', elapsed = Math.abs(span);
|
|
8964
9809
|
if (typeof format === 'object') {
|
|
@@ -8969,18 +9814,26 @@
|
|
|
8969
9814
|
const msecsPerDay = 86400000, msecsPerHr = 3600000, msecsPerMin = 60000, days = Math.floor(elapsed / msecsPerDay), hrs = Math.floor((elapsed % msecsPerDay) / msecsPerHr), mins = Math.floor((elapsed % msecsPerHr) / msecsPerMin), secs = Math.floor((elapsed % msecsPerMin) / 1000), msecs = Math.floor(elapsed % 1000);
|
|
8970
9815
|
return `${sign}${days}d ${hrs}h ${mins}m ${secs}s ${msecs}ms`;
|
|
8971
9816
|
}
|
|
9817
|
+
/** Formats `src` as a currency amount using `Intl.NumberFormat`. @param currency ISO 4217 currency code. @param culture BCP 47 locale. Defaults to the browser's language. */
|
|
8972
9818
|
static currency(src, currency, culture) {
|
|
8973
9819
|
return new Intl.NumberFormat(culture ?? navigator.language, { style: 'currency', currency: currency }).format(src);
|
|
8974
9820
|
}
|
|
9821
|
+
/**
|
|
9822
|
+
* Formats `src` as a number using `Intl.NumberFormat`.
|
|
9823
|
+
* @param formatOrCulture Either a BCP 47 locale string, or `Intl.NumberFormatOptions` (in which case `culture` supplies the locale).
|
|
9824
|
+
* @param culture BCP 47 locale, used only when `formatOrCulture` is a format-options object. Defaults to the browser's language.
|
|
9825
|
+
*/
|
|
8975
9826
|
static number(src, formatOrCulture, culture) {
|
|
8976
9827
|
if (typeof formatOrCulture === 'string') {
|
|
8977
9828
|
return new Intl.NumberFormat(formatOrCulture || navigator.language).format(src);
|
|
8978
9829
|
}
|
|
8979
9830
|
return new Intl.NumberFormat(culture ?? navigator.language, formatOrCulture).format(src);
|
|
8980
9831
|
}
|
|
9832
|
+
/** Filters `src` with `filter`; a thin wrapper over `Array.prototype.filter` usable from template expressions. */
|
|
8981
9833
|
static filter(src, filter) {
|
|
8982
9834
|
return src.filter(filter);
|
|
8983
9835
|
}
|
|
9836
|
+
/** Sorts `src` in place (ascending, via `>`/`<` comparison), optionally by a property path when items are objects. @param prop Property name to sort by; omit to compare items directly. */
|
|
8984
9837
|
static orderby(src, prop) {
|
|
8985
9838
|
return src.sort((a, b) => {
|
|
8986
9839
|
if (!Utils.isNullOrEmpty(prop)) {
|
|
@@ -8991,31 +9844,39 @@
|
|
|
8991
9844
|
});
|
|
8992
9845
|
}
|
|
8993
9846
|
// #region RegExp
|
|
9847
|
+
/** Tests `input` against a `RegExp` built from `pattern`/`flags`. Registered as `regex.isMatch`. */
|
|
8994
9848
|
static isMatch(input, pattern, flags) {
|
|
8995
9849
|
return new RegExp(pattern, flags).test(input);
|
|
8996
9850
|
}
|
|
8997
9851
|
// #endregion
|
|
8998
9852
|
// #region shortcuts from 'Utils'
|
|
9853
|
+
/** Template-expression shortcut for {@link Utils.isEmpty}. */
|
|
8999
9854
|
static isEmpty(obj) {
|
|
9000
9855
|
return Utils.isEmpty(obj);
|
|
9001
9856
|
}
|
|
9857
|
+
/** Template-expression shortcut for {@link Utils.isNull}. */
|
|
9002
9858
|
static isNull(obj) {
|
|
9003
9859
|
return Utils.isNull(obj);
|
|
9004
9860
|
}
|
|
9861
|
+
/** Template-expression shortcut for {@link Utils.isNullOrEmpty}. */
|
|
9005
9862
|
static isNullOrEmpty(obj) {
|
|
9006
9863
|
return Utils.isNullOrEmpty(obj);
|
|
9007
9864
|
}
|
|
9865
|
+
/** Reads a CSS custom property's value off the document; see {@link Utils.Css.getVariableValue}. Registered as `cssvar`. */
|
|
9008
9866
|
static getCssVariable(name) {
|
|
9009
9867
|
return Utils.Css.getVariableValue(name);
|
|
9010
9868
|
}
|
|
9869
|
+
/** Reads a query-string parameter's value off the current URL; see {@link Utils.URIs.parseQuery}. Registered as `querystring`. */
|
|
9011
9870
|
static getQuerystring(name) {
|
|
9012
9871
|
return Utils.URIs.parseQuery()[name];
|
|
9013
9872
|
}
|
|
9014
9873
|
// #endregion
|
|
9015
9874
|
// #region shortcuts from 'CustomElementUtils'
|
|
9875
|
+
/** Template-expression shortcut for {@link CustomElementUtils.Theme}'s `importWebFonts`. */
|
|
9016
9876
|
static importThemeWebFonts() {
|
|
9017
9877
|
return CustomElementUtils.Theme.importWebFonts();
|
|
9018
9878
|
}
|
|
9879
|
+
/** Template-expression shortcut for {@link CustomElementUtils.findHostContext}. Registered as `host`. */
|
|
9019
9880
|
static findHostContext(element) {
|
|
9020
9881
|
return CustomElementUtils.findHostContext(element);
|
|
9021
9882
|
}
|