@pacem/pacem-core 2.0.0-goldbach → 2.0.0-hadamard
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-core.js +308 -89
- package/dist/browser/pacem-core.js.map +1 -1
- package/dist/browser/pacem-core.min.js +2 -2
- package/dist/bundle/pacem-core.min.mjs +5 -5
- package/dist/bundle/pacem-core.mjs +193 -67
- package/dist/bundle/pacem-core.mjs.map +3 -3
- package/dist/docs/pacem-core.json +54 -24
- package/dist/esm/adapter.js +1 -1
- package/dist/esm/binding-parser.js +3 -3
- package/dist/esm/command.js +1 -1
- package/dist/esm/comparers.js +1 -1
- package/dist/esm/converters.js +1 -1
- package/dist/esm/decorators-next.js +1 -1
- package/dist/esm/decorators.js +1 -1
- package/dist/esm/defaults.js +1 -1
- package/dist/esm/events.js +1 -1
- package/dist/esm/eventtarget.js +1 -1
- package/dist/esm/expression.js +1 -1
- package/dist/esm/index-animations.js +1 -1
- package/dist/esm/index-behaviors.js +1 -1
- package/dist/esm/index-components.js +1 -1
- package/dist/esm/index-iife.js +1 -1
- package/dist/esm/index-logging.js +1 -1
- package/dist/esm/index-net.js +1 -1
- package/dist/esm/index-root.js +1 -1
- package/dist/esm/index-ui.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/logger.js +1 -1
- package/dist/esm/prefix.js +1 -1
- package/dist/esm/promise.js +1 -1
- package/dist/esm/regex.js +1 -1
- package/dist/esm/storage.js +1 -1
- package/dist/esm/template.js +1 -1
- package/dist/esm/transforms.js +1 -1
- package/dist/esm/types.js +1 -1
- package/dist/esm/utils-customelement.js +1 -1
- package/dist/esm/utils-customevent.js +1 -1
- package/dist/esm/utils.js +2 -2
- package/package.json +1 -1
- package/typings/index.d.ts +114 -20
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @pacem/pacem-core v2.0.0-
|
|
2
|
+
* @pacem/pacem-core v2.0.0-hadamard (https://js.pacem.it)
|
|
3
3
|
* Pacem (https://pacem.it)
|
|
4
4
|
* Licensed under Apache-2.0
|
|
5
5
|
*/
|
|
@@ -409,7 +409,7 @@
|
|
|
409
409
|
},
|
|
410
410
|
/** Sets a CSS custom property's value on the document root (`:root`/`html`). */
|
|
411
411
|
setVariable(name, value) {
|
|
412
|
-
|
|
412
|
+
document.documentElement.style.setProperty(name, value);
|
|
413
413
|
},
|
|
414
414
|
/**
|
|
415
415
|
* Naive O(n^2) implementation for an actual css class presence (definition) in the current DOM.
|
|
@@ -1555,12 +1555,12 @@
|
|
|
1555
1555
|
* Parses a binding expression against a scope.
|
|
1556
1556
|
* @param expression The bare expression text (no `{{ }}` delimiters, no `, twoway`/`, once` modifier).
|
|
1557
1557
|
* @param scope What the references resolve to.
|
|
1558
|
-
* @throws
|
|
1558
|
+
* @throws An `Error` when the expression is unsafe (see {@link analyze}).
|
|
1559
1559
|
*/
|
|
1560
1560
|
static parse(expression, scope) {
|
|
1561
1561
|
const analysis = BindingParser.analyze(expression);
|
|
1562
1562
|
if (analysis.unsafe != null) {
|
|
1563
|
-
throw `Unsafe expression detected: "${analysis.unsafe}" in "${expression}"
|
|
1563
|
+
throw new Error(`Unsafe expression detected: "${analysis.unsafe}" in "${expression}".`);
|
|
1564
1564
|
}
|
|
1565
1565
|
if (!analysis.hasReferences) {
|
|
1566
1566
|
return { kind: 'constant', functionBody: `return ${expression};`, voidBody: expression, dependencies: [] };
|
|
@@ -5009,6 +5009,14 @@
|
|
|
5009
5009
|
get element() {
|
|
5010
5010
|
return this._builder.element;
|
|
5011
5011
|
}
|
|
5012
|
+
/**
|
|
5013
|
+
* @readonly Gets the snap the element is going to rest at, relative to where the gesture started: `0` means it
|
|
5014
|
+
* bounces back home (the release didn't make it). Known on release (`swipe`, `swipe<direction>` and the
|
|
5015
|
+
* animation-end events); `undefined` while panning.
|
|
5016
|
+
*/
|
|
5017
|
+
get snap() {
|
|
5018
|
+
return this._builder.snap;
|
|
5019
|
+
}
|
|
5012
5020
|
/** Builds a new {@link SwipeEventArgsClass} out of a plain {@link SwipeEventArgs} builder. */
|
|
5013
5021
|
static fromArgs(builder) {
|
|
5014
5022
|
return new SwipeEventArgsClass(Utils.extend({}, builder));
|
|
@@ -5402,34 +5410,58 @@
|
|
|
5402
5410
|
return html;
|
|
5403
5411
|
}
|
|
5404
5412
|
}
|
|
5405
|
-
/**
|
|
5413
|
+
/** Attributes holding a URL, checked for `javascript:` ones by {@link sanitizeNode}. */
|
|
5414
|
+
const URL_ATTRIBUTES = ['href', 'src', 'action', 'formaction', 'xlink:href'];
|
|
5415
|
+
/** Whether an attribute value is a `javascript:` URL (whitespace and control characters ignored, as browsers do). */
|
|
5416
|
+
function isScriptUrl(value) {
|
|
5417
|
+
const normalized = (value ?? '').replace(/[\u0000- ]/g, '').toLowerCase();
|
|
5418
|
+
return normalized.startsWith('javascript:');
|
|
5419
|
+
}
|
|
5420
|
+
/**
|
|
5421
|
+
* Strips the script-capable parts of a DOM subtree, in place: `<script>` elements, `on*` event-handler attributes,
|
|
5422
|
+
* `javascript:` URLs.
|
|
5423
|
+
* @param node The subtree's root.
|
|
5424
|
+
*/
|
|
5425
|
+
function sanitizeNode(node) {
|
|
5426
|
+
for (let i = node.childNodes.length - 1; i >= 0; i--) {
|
|
5427
|
+
const child = node.childNodes.item(i);
|
|
5428
|
+
if (child instanceof Element && child.localName === 'script') {
|
|
5429
|
+
child.remove();
|
|
5430
|
+
continue;
|
|
5431
|
+
}
|
|
5432
|
+
sanitizeNode(child);
|
|
5433
|
+
}
|
|
5434
|
+
if (!(node instanceof Element)) {
|
|
5435
|
+
return;
|
|
5436
|
+
}
|
|
5437
|
+
for (const attribute of Array.from(node.attributes)) {
|
|
5438
|
+
const name = attribute.name.toLowerCase();
|
|
5439
|
+
const isHandler = name.startsWith('on');
|
|
5440
|
+
const isScriptLink = URL_ATTRIBUTES.indexOf(name) >= 0 && isScriptUrl(attribute.value);
|
|
5441
|
+
if (isHandler || isScriptLink) {
|
|
5442
|
+
node.removeAttribute(attribute.name);
|
|
5443
|
+
}
|
|
5444
|
+
}
|
|
5445
|
+
}
|
|
5446
|
+
/**
|
|
5447
|
+
* {@link PacemContentElement} variant that renders `content` without what could run script: `<script>` elements,
|
|
5448
|
+
* `on*` event-handler attributes and `javascript:` URLs get removed (HTML strings are parsed, never executed, first).
|
|
5449
|
+
*/
|
|
5406
5450
|
class PacemSafeContentElement extends PacemContentElement {
|
|
5407
|
-
|
|
5451
|
+
sanitize(html) {
|
|
5408
5452
|
if (Utils.isNullOrEmpty(html)) {
|
|
5409
5453
|
return html;
|
|
5410
5454
|
}
|
|
5411
5455
|
if (html instanceof Node) {
|
|
5412
|
-
|
|
5413
|
-
const node = html.childNodes.item(i);
|
|
5414
|
-
if (node instanceof HTMLScriptElement) {
|
|
5415
|
-
node.remove();
|
|
5416
|
-
}
|
|
5417
|
-
else {
|
|
5418
|
-
this.sanitize(node);
|
|
5419
|
-
}
|
|
5420
|
-
}
|
|
5456
|
+
sanitizeNode(html);
|
|
5421
5457
|
return html;
|
|
5422
5458
|
}
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
sanitize(html) {
|
|
5430
|
-
// TODO: implement by using (when available in dom library)
|
|
5431
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/Sanitizer/Sanitizer
|
|
5432
|
-
return this._sanitizeLegacy(html);
|
|
5459
|
+
// a template parses without running anything (scripts, image loads with their handlers…)
|
|
5460
|
+
const template = document.createElement('template');
|
|
5461
|
+
template.innerHTML = html.toString();
|
|
5462
|
+
const fragment = template.content;
|
|
5463
|
+
sanitizeNode(fragment);
|
|
5464
|
+
return fragment;
|
|
5433
5465
|
}
|
|
5434
5466
|
}
|
|
5435
5467
|
//}
|
|
@@ -5658,7 +5690,11 @@
|
|
|
5658
5690
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5659
5691
|
};
|
|
5660
5692
|
//namespace Pacem.Components {
|
|
5661
|
-
/**
|
|
5693
|
+
/**
|
|
5694
|
+
* Wraps a {@link BroadcastChannel}, sending/receiving messages to/from other same-origin browsing contexts.
|
|
5695
|
+
* @fires receive {@link CustomEvent} - when a message arrives from another channel of the same name: `detail` is the message (also in `result`).
|
|
5696
|
+
* @fires error {@link CustomEvent} - when an arrived message couldn't be deserialized.
|
|
5697
|
+
*/
|
|
5662
5698
|
let PacemBroadcastChannelProxyElement = class PacemBroadcastChannelProxyElement extends PacemEventTarget {
|
|
5663
5699
|
constructor() {
|
|
5664
5700
|
super(...arguments);
|
|
@@ -5680,7 +5716,7 @@
|
|
|
5680
5716
|
super.propertyChangedCallback(name, old, val, first);
|
|
5681
5717
|
if (!first) {
|
|
5682
5718
|
switch (name) {
|
|
5683
|
-
case '
|
|
5719
|
+
case 'channelName':
|
|
5684
5720
|
this._disposeChannel();
|
|
5685
5721
|
this._initializeChannel(val);
|
|
5686
5722
|
break;
|
|
@@ -5728,6 +5764,10 @@
|
|
|
5728
5764
|
channel.removeEventListener('message', this._messageHandler, false);
|
|
5729
5765
|
channel.close();
|
|
5730
5766
|
}
|
|
5767
|
+
// (a closed channel can't post anymore)
|
|
5768
|
+
if (channel === this.#channel) {
|
|
5769
|
+
this.#channel = null;
|
|
5770
|
+
}
|
|
5731
5771
|
}
|
|
5732
5772
|
};
|
|
5733
5773
|
__decorate$D([
|
|
@@ -5804,13 +5844,32 @@
|
|
|
5804
5844
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5805
5845
|
};
|
|
5806
5846
|
//namespace Pacem.Components {
|
|
5807
|
-
/**
|
|
5847
|
+
/** Converts the `debounce` attribute: `true`/`false`, or else a number of milliseconds. */
|
|
5848
|
+
const DebouncePropertyConverter = {
|
|
5849
|
+
convert: (attr) => {
|
|
5850
|
+
switch (attr) {
|
|
5851
|
+
case 'true':
|
|
5852
|
+
return true;
|
|
5853
|
+
case 'false':
|
|
5854
|
+
return false;
|
|
5855
|
+
default:
|
|
5856
|
+
return parseFloat(attr);
|
|
5857
|
+
}
|
|
5858
|
+
},
|
|
5859
|
+
convertBack: (prop) => `${prop}`
|
|
5860
|
+
};
|
|
5861
|
+
/**
|
|
5862
|
+
* Holds an arbitrary data model, optionally persisting it to local storage and debouncing/throttling change notifications.
|
|
5863
|
+
* @fires propertychange {@link PropertyChangeEvent} - when `model` changes (debounced or throttled as set by `debounce` and `throttle`).
|
|
5864
|
+
*/
|
|
5808
5865
|
let PacemDataElement = class PacemDataElement extends PacemEventTarget {
|
|
5809
5866
|
constructor(storage = new Storage()) {
|
|
5810
5867
|
super();
|
|
5811
5868
|
this.storage = storage;
|
|
5812
|
-
|
|
5813
|
-
this.
|
|
5869
|
+
/** Cancels the pending (debounced) notification, if any. */
|
|
5870
|
+
this._cancelPending = null;
|
|
5871
|
+
/** Whether a throttling window is open (changes are dropped meanwhile). */
|
|
5872
|
+
this._throttling = false;
|
|
5814
5873
|
}
|
|
5815
5874
|
propertyChangedCallback(name, old, val, first) {
|
|
5816
5875
|
super.propertyChangedCallback(name, old, val, first);
|
|
@@ -5824,35 +5883,63 @@
|
|
|
5824
5883
|
}
|
|
5825
5884
|
break;
|
|
5826
5885
|
case 'model':
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
};
|
|
5830
|
-
if (debounce > 0 && !first) {
|
|
5831
|
-
if (throttle) {
|
|
5832
|
-
if (this._flag)
|
|
5833
|
-
return;
|
|
5834
|
-
this._flag = true;
|
|
5835
|
-
emit();
|
|
5836
|
-
this._handle = window.setTimeout(() => { this._flag = false; }, debounce);
|
|
5837
|
-
}
|
|
5838
|
-
else {
|
|
5839
|
-
clearTimeout(this._handle);
|
|
5840
|
-
this._handle = window.setTimeout(emit, debounce);
|
|
5841
|
-
}
|
|
5842
|
-
}
|
|
5843
|
-
else {
|
|
5844
|
-
emit();
|
|
5845
|
-
}
|
|
5846
|
-
// persist
|
|
5847
|
-
if (!first && !Utils.isNullOrEmpty(this.persistAs)) {
|
|
5848
|
-
if (Utils.isNull(val))
|
|
5849
|
-
this.storage.removeProperty(this.persistAs);
|
|
5850
|
-
else
|
|
5851
|
-
this.storage.setPropertyValue(this.persistAs, val, true);
|
|
5852
|
-
}
|
|
5886
|
+
this._notifyModelChange(old, val, first);
|
|
5887
|
+
this._persist(val, first);
|
|
5853
5888
|
break;
|
|
5854
5889
|
}
|
|
5855
5890
|
}
|
|
5891
|
+
/** Notifies a model change: right away, debounced or throttled (see {@link debounce} and {@link throttle}). */
|
|
5892
|
+
_notifyModelChange(old, val, first) {
|
|
5893
|
+
const emit = () => {
|
|
5894
|
+
this.dispatchEvent(new PropertyChangeEvent({ propertyName: 'model', oldValue: old, currentValue: val, firstChange: first }));
|
|
5895
|
+
};
|
|
5896
|
+
const debounce = this.debounce;
|
|
5897
|
+
const perFrame = debounce === true;
|
|
5898
|
+
const delay = typeof debounce === 'number' && debounce > 0 ? debounce : 0;
|
|
5899
|
+
if (first || (!perFrame && delay === 0)) {
|
|
5900
|
+
emit();
|
|
5901
|
+
return;
|
|
5902
|
+
}
|
|
5903
|
+
if (this.throttle) {
|
|
5904
|
+
this._throttle(emit, perFrame, delay);
|
|
5905
|
+
return;
|
|
5906
|
+
}
|
|
5907
|
+
this._cancelPending?.();
|
|
5908
|
+
this._cancelPending = this._schedule(emit, perFrame, delay);
|
|
5909
|
+
}
|
|
5910
|
+
/** Notifies the first change of a window, and drops the others until the window closes. */
|
|
5911
|
+
_throttle(emit, perFrame, delay) {
|
|
5912
|
+
if (this._throttling) {
|
|
5913
|
+
return;
|
|
5914
|
+
}
|
|
5915
|
+
this._throttling = true;
|
|
5916
|
+
emit();
|
|
5917
|
+
this._schedule(() => { this._throttling = false; }, perFrame, delay);
|
|
5918
|
+
}
|
|
5919
|
+
/**
|
|
5920
|
+
* Runs a callback on the next animation frame, or after a delay.
|
|
5921
|
+
* @returns A function cancelling it.
|
|
5922
|
+
*/
|
|
5923
|
+
_schedule(callback, perFrame, delay) {
|
|
5924
|
+
if (perFrame) {
|
|
5925
|
+
const frame = requestAnimationFrame(callback);
|
|
5926
|
+
return () => cancelAnimationFrame(frame);
|
|
5927
|
+
}
|
|
5928
|
+
const timeout = window.setTimeout(callback, delay);
|
|
5929
|
+
return () => clearTimeout(timeout);
|
|
5930
|
+
}
|
|
5931
|
+
/** Persists the model under {@link persistAs}, if set (a `null` model removes it). */
|
|
5932
|
+
_persist(val, first) {
|
|
5933
|
+
const key = this.persistAs;
|
|
5934
|
+
if (first || Utils.isNullOrEmpty(key)) {
|
|
5935
|
+
return;
|
|
5936
|
+
}
|
|
5937
|
+
if (Utils.isNull(val)) {
|
|
5938
|
+
this.storage.removeProperty(key);
|
|
5939
|
+
return;
|
|
5940
|
+
}
|
|
5941
|
+
this.storage.setPropertyValue(key, val, true);
|
|
5942
|
+
}
|
|
5856
5943
|
};
|
|
5857
5944
|
__decorate$B([
|
|
5858
5945
|
Watch({ emit: false /* in order to debounce the propertychange emit */, converter: PropertyConverters.Eval })
|
|
@@ -5861,7 +5948,7 @@
|
|
|
5861
5948
|
Watch({ emit: false, converter: PropertyConverters.String })
|
|
5862
5949
|
], PacemDataElement.prototype, "persistAs", void 0);
|
|
5863
5950
|
__decorate$B([
|
|
5864
|
-
Watch({ emit: false, converter:
|
|
5951
|
+
Watch({ emit: false, converter: DebouncePropertyConverter })
|
|
5865
5952
|
], PacemDataElement.prototype, "debounce", void 0);
|
|
5866
5953
|
__decorate$B([
|
|
5867
5954
|
Watch({ emit: false, converter: PropertyConverters.BooleanStrict })
|
|
@@ -6106,7 +6193,10 @@
|
|
|
6106
6193
|
return PropertyConverters.Element.convertBack(prop, element);
|
|
6107
6194
|
}
|
|
6108
6195
|
};
|
|
6109
|
-
/**
|
|
6196
|
+
/**
|
|
6197
|
+
* Listens for an arbitrary DOM event on a `target` element (or `window`) and re-dispatches it as its own `emit` event.
|
|
6198
|
+
* @fires emit {@link Event} - for every `event` caught on `target`: the caught one is `originalEvent`.
|
|
6199
|
+
*/
|
|
6110
6200
|
let PacemEventProxyElement = class PacemEventProxyElement extends PacemEventTarget {
|
|
6111
6201
|
constructor() {
|
|
6112
6202
|
super(...arguments);
|
|
@@ -6179,7 +6269,12 @@
|
|
|
6179
6269
|
};
|
|
6180
6270
|
//namespace Pacem.Components {
|
|
6181
6271
|
const ABORT_MESSAGE = "New incoming request overrides the ongoing one. Aborting.";
|
|
6182
|
-
/**
|
|
6272
|
+
/**
|
|
6273
|
+
* Declarative wrapper around the `fetch()` API, debouncing/aborting requests as its properties change and exposing the parsed `result`.
|
|
6274
|
+
* @fires success {@link CustomEvent} - when a response is OK (2xx), before its body gets parsed: `detail` is the `Response`.
|
|
6275
|
+
* @fires fetchresult {@link CustomEvent} - when the body got parsed (as set by `as`): `detail` is the new `result`.
|
|
6276
|
+
* @fires error {@link CustomEvent} - when a response is not OK: `detail` is the `Response` (network failures reject `fetch()` instead).
|
|
6277
|
+
*/
|
|
6183
6278
|
let PacemFetchElement = class PacemFetchElement extends PacemEventTarget {
|
|
6184
6279
|
constructor() {
|
|
6185
6280
|
super(...arguments);
|
|
@@ -6447,7 +6542,7 @@
|
|
|
6447
6542
|
Watch({ reflectBack: true, converter: PropertyConverters.Number })
|
|
6448
6543
|
], PacemFetchElement.prototype, "debounce", void 0);
|
|
6449
6544
|
__decorate$x([
|
|
6450
|
-
Watch({ emit: false, reflectBack: true, converter: PropertyConverters.
|
|
6545
|
+
Watch({ emit: false, reflectBack: true, converter: PropertyConverters.Boolean })
|
|
6451
6546
|
], PacemFetchElement.prototype, "throttle", void 0);
|
|
6452
6547
|
__decorate$x([
|
|
6453
6548
|
Watch({ emit: false, reflectBack: true, converter: PropertyConverters.Boolean })
|
|
@@ -6471,7 +6566,13 @@
|
|
|
6471
6566
|
super(type, { detail });
|
|
6472
6567
|
}
|
|
6473
6568
|
}
|
|
6474
|
-
/**
|
|
6569
|
+
/**
|
|
6570
|
+
* Keeps track of an undo/redo-capable history of an arbitrary state.
|
|
6571
|
+
* @fires push {@link StateEvent} - when a new state got recorded: `detail` has `state`, `canUndo` and `canRedo`.
|
|
6572
|
+
* @fires undo {@link StateEvent} - after a step back.
|
|
6573
|
+
* @fires redo {@link StateEvent} - after a step forward.
|
|
6574
|
+
* @fires reset {@link StateEvent} - when the history got cleared (the current state stays).
|
|
6575
|
+
*/
|
|
6475
6576
|
let PacemHistoryElement = class PacemHistoryElement extends PacemEventTarget {
|
|
6476
6577
|
#history;
|
|
6477
6578
|
propertyChangedCallback(name, old, val, first) {
|
|
@@ -6974,7 +7075,10 @@
|
|
|
6974
7075
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6975
7076
|
};
|
|
6976
7077
|
//namespace Pacem.Components {
|
|
6977
|
-
/**
|
|
7078
|
+
/**
|
|
7079
|
+
* Tracks the browser's network connectivity (`navigator.onLine`), updating `online` on `online`/`offline` events.
|
|
7080
|
+
* @fires propertychange {@link PropertyChangeEvent} - when `online` changes (the connection dropped or came back).
|
|
7081
|
+
*/
|
|
6978
7082
|
let PacemOnlineStatusElement = class PacemOnlineStatusElement extends PacemEventTarget {
|
|
6979
7083
|
constructor() {
|
|
6980
7084
|
super(...arguments);
|
|
@@ -7088,6 +7192,10 @@
|
|
|
7088
7192
|
//
|
|
7089
7193
|
/**
|
|
7090
7194
|
* Repeats its `<template>` content once per `datasource` item, keeping the rendered items in sync as the datasource changes.
|
|
7195
|
+
* @fires repeateritemcreate {@link RepeaterItemCreateEvent} - when an item got rendered (and is in the DOM): `detail` has its `index`, `item` and `dom`.
|
|
7196
|
+
* @fires repeateritemremove {@link RepeaterItemRemoveEvent} - when an item got removed (the datasource shrank).
|
|
7197
|
+
* @fires itemcommand {@link CustomEvent} - when an element of an item dispatches a command (e.g. a `<pacem-button command-name>`): `detail` has `commandName` and `commandArgument`.
|
|
7198
|
+
* @fires item{command} {@link CustomEvent} - right after `itemcommand`, named after the command (e.g. `itemdelete` for `command-name="delete"`): `detail` is the `commandArgument`.
|
|
7091
7199
|
* @example
|
|
7092
7200
|
* <pacem-repeater datasource="[{id:'first', items:['a','b','c']}, ...]">
|
|
7093
7201
|
* <ol>
|
|
@@ -7492,7 +7600,12 @@
|
|
|
7492
7600
|
};
|
|
7493
7601
|
//namespace Pacem.Components {
|
|
7494
7602
|
const CHECK_PATTERN = /^([\w\.]:)?\/\/[^\/]+/;
|
|
7495
|
-
/**
|
|
7603
|
+
/**
|
|
7604
|
+
* Client-side router: parses/generates paths against a template and drives the browser History API.
|
|
7605
|
+
* @fires propertychange {@link PropertyChangeEvent} - when `state` changes (every committed navigation).
|
|
7606
|
+
* @fires navigating {@link RouterNavigatingEvent} - on `window`, right before a navigation: cancelable (`preventDefault()` aborts it), `detail` is the target path.
|
|
7607
|
+
* @fires navigate {@link RouterNavigateEvent} - on `window`, once a navigation is committed: `detail` has `path`, `referrer` and `title`.
|
|
7608
|
+
*/
|
|
7496
7609
|
let PacemRouterElement = class PacemRouterElement extends PacemEventTarget {
|
|
7497
7610
|
constructor() {
|
|
7498
7611
|
super(...arguments);
|
|
@@ -7777,7 +7890,13 @@
|
|
|
7777
7890
|
}
|
|
7778
7891
|
return output;
|
|
7779
7892
|
}
|
|
7780
|
-
/**
|
|
7893
|
+
/**
|
|
7894
|
+
* Registers a service worker and manages its (optional) Push API subscription.
|
|
7895
|
+
* @fires register {@link CustomEvent} - once the service worker got registered: `detail` is the `ServiceWorkerRegistration`.
|
|
7896
|
+
* @fires unregister {@link CustomEvent} - when a previous registration got replaced: `detail` is the old one.
|
|
7897
|
+
* @fires subscribe {@link CustomEvent} - when a push subscription is in place (found at start, or just made): `detail` is the `PushSubscription`.
|
|
7898
|
+
* @fires unsubscribe {@link CustomEvent} - when the push subscription went away: `detail` is the old `PushSubscription`.
|
|
7899
|
+
*/
|
|
7781
7900
|
let PacemServiceWorkerProxyElement = class PacemServiceWorkerProxyElement extends PacemEventTarget {
|
|
7782
7901
|
viewActivatedCallback() {
|
|
7783
7902
|
super.viewActivatedCallback();
|
|
@@ -7844,6 +7963,8 @@
|
|
|
7844
7963
|
this.pushSubscription = null;
|
|
7845
7964
|
}
|
|
7846
7965
|
resolve(result);
|
|
7966
|
+
}, reason => {
|
|
7967
|
+
reject(reason);
|
|
7847
7968
|
});
|
|
7848
7969
|
}
|
|
7849
7970
|
else {
|
|
@@ -7854,6 +7975,8 @@
|
|
|
7854
7975
|
/**
|
|
7855
7976
|
* Subscribes to push notifications through the registered service worker.
|
|
7856
7977
|
* @param publicKey VAPID public key (base64url or raw bytes); defaults to `publicKey`
|
|
7978
|
+
* @returns The subscription (`null` without a push manager, or when notifications are denied); rejects when the
|
|
7979
|
+
* browser refuses to subscribe (no push service, an invalid key…).
|
|
7857
7980
|
*/
|
|
7858
7981
|
subscribe(publicKey = this.publicKey) {
|
|
7859
7982
|
return new Promise((resolve, reject) => {
|
|
@@ -7872,6 +7995,9 @@
|
|
|
7872
7995
|
else {
|
|
7873
7996
|
resolve(/* triggers 'subscribe' event */ this.pushSubscription = subscription);
|
|
7874
7997
|
}
|
|
7998
|
+
}, reason => {
|
|
7999
|
+
// refused (permission denied, no push service, a bad key…): the caller gets to know
|
|
8000
|
+
reject(reason);
|
|
7875
8001
|
});
|
|
7876
8002
|
}
|
|
7877
8003
|
else {
|
|
@@ -7942,12 +8068,20 @@
|
|
|
7942
8068
|
|| (/^arrow/.test(key) && (piece === key.substr(5)));
|
|
7943
8069
|
}
|
|
7944
8070
|
const KeyboardShortcutExecuteEventName = "execute";
|
|
7945
|
-
/**
|
|
8071
|
+
/**
|
|
8072
|
+
* Listens for a keyboard shortcut (optionally chorded, e.g. `"ctrl+k, s"`) on a target and fires an `execute` event when matched.
|
|
8073
|
+
* @fires execute {@link Event} - when the whole combination got typed (the matching key's default action is prevented).
|
|
8074
|
+
*/
|
|
7946
8075
|
let PacemShortcutElement = class PacemShortcutElement extends PacemEventTarget {
|
|
7947
8076
|
constructor() {
|
|
7948
8077
|
super(...arguments);
|
|
7949
8078
|
this._accumulator = [];
|
|
7950
8079
|
this._shortcutHandler = (evt) => {
|
|
8080
|
+
// a disabled shortcut leaves the keys alone (no execute, and no prevented default either)
|
|
8081
|
+
if (this.disabled) {
|
|
8082
|
+
this._accumulator.splice(0);
|
|
8083
|
+
return;
|
|
8084
|
+
}
|
|
7951
8085
|
const result = (matchesKeyCombination(evt, this.combination, this._accumulator));
|
|
7952
8086
|
switch (result) {
|
|
7953
8087
|
case true:
|
|
@@ -8411,7 +8545,11 @@
|
|
|
8411
8545
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
8412
8546
|
};
|
|
8413
8547
|
//namespace Pacem.Components {
|
|
8414
|
-
/**
|
|
8548
|
+
/**
|
|
8549
|
+
* Wraps a {@link Worker}, sending/receiving messages to/from a web worker script.
|
|
8550
|
+
* @fires receive {@link CustomEvent} - when the worker posts a message back: `detail` is the message (also in `result`).
|
|
8551
|
+
* @fires error {@link CustomEvent} - when the worker script fails: `detail` is the error, when the browser can pass it over.
|
|
8552
|
+
*/
|
|
8415
8553
|
let PacemWebWorkerProxyElement = class PacemWebWorkerProxyElement extends PacemEventTarget {
|
|
8416
8554
|
constructor() {
|
|
8417
8555
|
super(...arguments);
|
|
@@ -8480,6 +8618,10 @@
|
|
|
8480
8618
|
worker.removeEventListener('message', this._messageHandler, false);
|
|
8481
8619
|
worker.terminate();
|
|
8482
8620
|
}
|
|
8621
|
+
// (a terminated worker takes no more messages)
|
|
8622
|
+
if (worker === this._worker) {
|
|
8623
|
+
this._worker = null;
|
|
8624
|
+
}
|
|
8483
8625
|
}
|
|
8484
8626
|
};
|
|
8485
8627
|
__decorate$9([
|
|
@@ -8916,6 +9058,13 @@
|
|
|
8916
9058
|
/**
|
|
8917
9059
|
* Pacem Drag & Drop element adapter: implements {@link DragDropper} on top of {@link PacemBehavior} to make
|
|
8918
9060
|
* registered elements draggable and, optionally, sortable/droppable onto {@link dropTargets}.
|
|
9061
|
+
* @fires draginit {@link DragDropEvent} - on press, before anything moves: cancelable (`preventDefault()` refuses the drag).
|
|
9062
|
+
* @fires dragstart {@link DragDropEvent} - when the drag actually starts (the press lasted `lockTimeout`).
|
|
9063
|
+
* @fires drag {@link DragDropEvent} - on every move: cancelable.
|
|
9064
|
+
* @fires dragover {@link DragDropEvent} - when hovering one of the `dropTargets`: cancelable (`preventDefault()` refuses that target).
|
|
9065
|
+
* @fires dragout {@link DragDropEvent} - when leaving a drop target.
|
|
9066
|
+
* @fires drop {@link DragDropEvent} - on release over a drop target: `detail.target` is the target, `detail.element` the dragged element.
|
|
9067
|
+
* @fires dragend {@link DragDropEvent} - when it's all over (dropped or not).
|
|
8919
9068
|
*/
|
|
8920
9069
|
let PacemDragDropElement = class PacemDragDropElement extends PacemBehavior {
|
|
8921
9070
|
constructor() {
|
|
@@ -9041,7 +9190,42 @@
|
|
|
9041
9190
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
9042
9191
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
9043
9192
|
};
|
|
9044
|
-
|
|
9193
|
+
/** Clamps `value` into `[min, max]`. */
|
|
9194
|
+
function clamp(value, min, max) {
|
|
9195
|
+
if (value < min) {
|
|
9196
|
+
return min;
|
|
9197
|
+
}
|
|
9198
|
+
return Math.min(value, max);
|
|
9199
|
+
}
|
|
9200
|
+
/**
|
|
9201
|
+
* Clamps a desired rect to the size constraints, keeping the edges opposite to the dragged handle in place
|
|
9202
|
+
* (a top/left handle moves the rect's origin, a bottom/right one doesn't).
|
|
9203
|
+
* @param rect The desired rect.
|
|
9204
|
+
* @param handle The dragged handle (`top`, `bottomleft`…).
|
|
9205
|
+
* @param constraints Minimum and maximum width and height.
|
|
9206
|
+
* @returns The clamped rect.
|
|
9207
|
+
*/
|
|
9208
|
+
function clampToConstraints(rect, handle, constraints) {
|
|
9209
|
+
const width = clamp(rect.width, constraints.minWidth, constraints.maxWidth);
|
|
9210
|
+
const height = clamp(rect.height, constraints.minHeight, constraints.maxHeight);
|
|
9211
|
+
const x = handle.endsWith('left') ? rect.x + rect.width - width : rect.x;
|
|
9212
|
+
const y = handle.startsWith('top') ? rect.y + rect.height - height : rect.y;
|
|
9213
|
+
return { x, y, width, height };
|
|
9214
|
+
}
|
|
9215
|
+
/**
|
|
9216
|
+
* What an element's `width`/`height` leave out of its border box: nothing for `border-box`, padding and border for
|
|
9217
|
+
* `content-box` (so that a border-box size can be written as `width`/`height` whatever the box sizing).
|
|
9218
|
+
* @param computed The element's computed style.
|
|
9219
|
+
*/
|
|
9220
|
+
function boxChrome(computed) {
|
|
9221
|
+
if (computed.boxSizing === 'border-box') {
|
|
9222
|
+
return { width: 0, height: 0 };
|
|
9223
|
+
}
|
|
9224
|
+
const px = (value) => parseFloat(value) || 0;
|
|
9225
|
+
const width = px(computed.paddingLeft) + px(computed.paddingRight) + px(computed.borderLeftWidth) + px(computed.borderRightWidth);
|
|
9226
|
+
const height = px(computed.paddingTop) + px(computed.paddingBottom) + px(computed.borderTopWidth) + px(computed.borderBottomWidth);
|
|
9227
|
+
return { width, height };
|
|
9228
|
+
}
|
|
9045
9229
|
class RescaleElementDelegate {
|
|
9046
9230
|
constructor(_element, _type, _rescaler, _logFn) {
|
|
9047
9231
|
this._element = _element;
|
|
@@ -9109,9 +9293,13 @@
|
|
|
9109
9293
|
this._logFn(LogLevel.Log, `handle: ${handle}, origin: ${JSON.stringify(origin)}, currentPosition: ${JSON.stringify(currentPosition)}`, `Rescaling`);
|
|
9110
9294
|
this._logFn(LogLevel.Log, `delta: ${JSON.stringify(delta)}, position: ${JSON.stringify(position)}`, `Rescaling`);
|
|
9111
9295
|
this._logFn(LogLevel.Log, `from: ${JSON.stringify(this._rect)}, to: ${JSON.stringify(desiredRect)}`, `Rescaling`);
|
|
9296
|
+
// free rescaling: a move beyond the constraints is clamped to them (a fast drag still reaches the limit)
|
|
9297
|
+
if (!keepProportions) {
|
|
9298
|
+
desiredRect = clampToConstraints(desiredRect, handle, { minWidth, maxWidth, minHeight, maxHeight });
|
|
9299
|
+
}
|
|
9112
9300
|
// check constraints
|
|
9113
9301
|
let horizontally = desiredRect.width >= minWidth && desiredRect.width <= maxWidth, vertically = desiredRect.height >= minHeight && desiredRect.height <= maxHeight;
|
|
9114
|
-
// if proportions are constrained and one fails, then both fail
|
|
9302
|
+
// if proportions are constrained and one fails, then both fail (clamping one side would break the ratio)
|
|
9115
9303
|
if (keepProportions && (!horizontally || !vertically)) {
|
|
9116
9304
|
horizontally = vertically = false;
|
|
9117
9305
|
}
|
|
@@ -9137,8 +9325,10 @@
|
|
|
9137
9325
|
// render resize
|
|
9138
9326
|
const m = this._originalTransform;
|
|
9139
9327
|
el.style.transform = `matrix(${m.a},${m.b},${m.c},${m.d},${(m.e + desiredRect.x - this._rect.x)},${(m.f + desiredRect.y - this._rect.y)})`;
|
|
9140
|
-
|
|
9141
|
-
|
|
9328
|
+
// (the rect is a border box: a content-box element gets it minus its padding and border)
|
|
9329
|
+
const chrome = this._chrome;
|
|
9330
|
+
el.style.width = Math.max(desiredRect.width - chrome.width, 0) + 'px';
|
|
9331
|
+
el.style.height = Math.max(desiredRect.height - chrome.height, 0) + 'px';
|
|
9142
9332
|
}
|
|
9143
9333
|
// store targetRect
|
|
9144
9334
|
this._targetRect = desiredRect;
|
|
@@ -9171,7 +9361,9 @@
|
|
|
9171
9361
|
this._targetRect =
|
|
9172
9362
|
Utils.offsetRect(_element);
|
|
9173
9363
|
//
|
|
9174
|
-
|
|
9364
|
+
const computed = getComputedStyle(_element);
|
|
9365
|
+
this._originalTransform = Utils.deserializeTransform(computed);
|
|
9366
|
+
this._chrome = boxChrome(computed);
|
|
9175
9367
|
// body
|
|
9176
9368
|
Utils.addClass(document.body, PCSS + '-rescaling rescale-' + _type);
|
|
9177
9369
|
}
|
|
@@ -9186,6 +9378,11 @@
|
|
|
9186
9378
|
/**
|
|
9187
9379
|
* Pacem Rescale element adapter: implements {@link Rescaler} on top of {@link PacemBehavior}, decorating
|
|
9188
9380
|
* registered elements with draggable resize handles (see {@link RescaleHandle}).
|
|
9381
|
+
* A move beyond the size constraints (`minWidth`, `maxWidth`, `minHeight`, `maxHeight`) is clamped to them; with
|
|
9382
|
+
* `keepProportions`, such a move is ignored instead (clamping one side would break the ratio).
|
|
9383
|
+
* @fires rescalestart {@link RescaleEvent} - when a handle gets grabbed: `detail.handle` tells which.
|
|
9384
|
+
* @fires rescale {@link RescaleEvent} - on every move: `detail.targetRect` is the size about to be applied; cancelable (`preventDefault()` applies nothing, e.g. to apply it your way).
|
|
9385
|
+
* @fires rescaleend {@link RescaleEvent} - when the handle gets released: `detail.targetRect` is the final size.
|
|
9189
9386
|
*/
|
|
9190
9387
|
let PacemRescaleElement = class PacemRescaleElement extends PacemBehavior {
|
|
9191
9388
|
constructor() {
|
|
@@ -9407,6 +9604,9 @@
|
|
|
9407
9604
|
/**
|
|
9408
9605
|
* Pacem Rotate element adapter: implements {@link Rotator} on top of {@link PacemBehavior} to make
|
|
9409
9606
|
* registered elements rotatable around a pivot point via mouse/touch drag.
|
|
9607
|
+
* @fires rotatestart {@link RotateEvent} - on press: cancelable (`preventDefault()` refuses the gesture).
|
|
9608
|
+
* @fires rotate {@link RotateEvent} - whenever the (stepped) angle changes: `detail.rotation`, in radians; cancelable (nothing gets rendered).
|
|
9609
|
+
* @fires rotateend {@link RotateEvent} - on release: `detail.rotation` is the final angle.
|
|
9410
9610
|
*/
|
|
9411
9611
|
let PacemRotateElement = class PacemRotateElement extends PacemBehavior {
|
|
9412
9612
|
constructor() {
|
|
@@ -9512,9 +9712,10 @@
|
|
|
9512
9712
|
swiper.dispatchEvent(swipeEvt);
|
|
9513
9713
|
if (!swipeEvt.defaultPrevented) {
|
|
9514
9714
|
let { delta } = this._delta(this._init, state);
|
|
9515
|
-
|
|
9715
|
+
// (the merged options: the swiper's own `options` may well be unset, defaults apply)
|
|
9716
|
+
if (!this.#options.bouncy) {
|
|
9516
9717
|
// clamp delta just in case
|
|
9517
|
-
const snaps = swiper.snaps.slice().sort();
|
|
9718
|
+
const snaps = swiper.snaps.slice().sort((a, b) => a - b);
|
|
9518
9719
|
const snapFirst = snaps[0], snapLast = snaps[snaps.length - 1];
|
|
9519
9720
|
const dir = this._swiper.direction;
|
|
9520
9721
|
const { x, y } = delta;
|
|
@@ -9534,25 +9735,26 @@
|
|
|
9534
9735
|
console.log('How come?!');
|
|
9535
9736
|
}
|
|
9536
9737
|
else {
|
|
9537
|
-
const args = this._buildSwipeArgsFromState();
|
|
9538
|
-
const swipeEvt = new SwipeEvent(SwipeEventType.Swipe, args, { cancelable: true, bubbles: false });
|
|
9539
9738
|
const swiper = this._swiper;
|
|
9739
|
+
// where the element is going to rest: the snap nearest to where its momentum carries it (known before
|
|
9740
|
+
// dispatching, so that every event of the release tells it: `detail.snap`, 0 meaning back home)
|
|
9741
|
+
const estimate = this._buildSwipeArgsFromState();
|
|
9742
|
+
// (a numeric copy: the swiper's own array stays as it is)
|
|
9743
|
+
const snaps = (swiper.snaps ?? [0.0]).slice().sort((a, b) => a - b);
|
|
9744
|
+
const target = this.#options.bouncy ? estimate.predictedDelta : estimate.predictedDelta.clamp(snaps[0], snaps[snaps.length - 1]);
|
|
9745
|
+
const snap = snaps.reduce((acc, v) => {
|
|
9746
|
+
const distance = Math.abs(v - target);
|
|
9747
|
+
const current = Math.abs(acc - target);
|
|
9748
|
+
return distance < current ? v : acc;
|
|
9749
|
+
}, 0);
|
|
9750
|
+
const args = this._buildSwipeArgsFromState(this.#state, snap);
|
|
9751
|
+
const swipeEvt = new SwipeEvent(SwipeEventType.Swipe, args, { cancelable: true, bubbles: false });
|
|
9540
9752
|
swiper.dispatchEvent(swipeEvt);
|
|
9541
9753
|
if (!swipeEvt.defaultPrevented) {
|
|
9542
9754
|
const swipe1Evt = new SwipeEvent(("swipe" + args.direction), args, { cancelable: true, bubbles: false });
|
|
9543
9755
|
swiper.dispatchEvent(swipe1Evt);
|
|
9544
9756
|
if (!swipe1Evt.defaultPrevented) {
|
|
9545
|
-
//
|
|
9546
|
-
const snaps = swiper.snaps ?? [0.0];
|
|
9547
|
-
snaps.sort();
|
|
9548
|
-
const target = swiper.options.bouncy ? args.predictedDelta : args.predictedDelta.clamp(snaps[0], snaps[snaps.length - 1]);
|
|
9549
|
-
// then animate toward that target,
|
|
9550
|
-
// otherwise bounce back
|
|
9551
|
-
const snap = snaps.reduce((acc, v) => {
|
|
9552
|
-
const distance = Math.abs(v - target);
|
|
9553
|
-
const current = Math.abs(acc - target);
|
|
9554
|
-
return distance < current ? v : acc;
|
|
9555
|
-
}, 0);
|
|
9757
|
+
// animate toward the target, then settle on the snap (or bounce back home)
|
|
9556
9758
|
const vertical = swiper.direction === 'vertical';
|
|
9557
9759
|
const duration = args.predictedDuration;
|
|
9558
9760
|
const delta0 = vertical ? { x: 0, y: target } : { x: target, y: 0 };
|
|
@@ -9566,7 +9768,11 @@
|
|
|
9566
9768
|
};
|
|
9567
9769
|
if (snap.isCloseTo(0)) {
|
|
9568
9770
|
this._animateOffsetBy(delta0, duration).then(() => {
|
|
9569
|
-
this._animateOffsetBy({ x: 0, y: 0 }, .3, 'cubic-bezier(.37,-0.01,.34,1.43)').then(() =>
|
|
9771
|
+
this._animateOffsetBy({ x: 0, y: 0 }, .3, 'cubic-bezier(.37,-0.01,.34,1.43)').then(() => {
|
|
9772
|
+
// back home exactly: the committed (overshooting) animation leaves float noise behind
|
|
9773
|
+
this._element.style.transform = this.#originalInlineTransform;
|
|
9774
|
+
swipeAnimationEnd();
|
|
9775
|
+
});
|
|
9570
9776
|
});
|
|
9571
9777
|
}
|
|
9572
9778
|
else {
|
|
@@ -9596,6 +9802,7 @@
|
|
|
9596
9802
|
const el = _element;
|
|
9597
9803
|
this.#options = Utils.extend({}, DEFAULT_OPTIONS, _swiper.options ?? {});
|
|
9598
9804
|
this.#originalTransform = Utils.deserializeTransform(getComputedStyle(el));
|
|
9805
|
+
this.#originalInlineTransform = el.style.transform;
|
|
9599
9806
|
window.addEventListener('pointermove', this._moveHandler, false);
|
|
9600
9807
|
window.addEventListener('pointerup', this._endHandler, false);
|
|
9601
9808
|
window.addEventListener('pointercancel', this._endHandler, false);
|
|
@@ -9633,7 +9840,12 @@
|
|
|
9633
9840
|
};
|
|
9634
9841
|
return state;
|
|
9635
9842
|
}
|
|
9636
|
-
|
|
9843
|
+
/**
|
|
9844
|
+
* Builds the event args of the current state.
|
|
9845
|
+
* @param state The gesture state.
|
|
9846
|
+
* @param snap The snap the element is going to rest at, once known (on release).
|
|
9847
|
+
*/
|
|
9848
|
+
_buildSwipeArgsFromState(state = this.#state, snap) {
|
|
9637
9849
|
const options = this.#options;
|
|
9638
9850
|
const speed = this.speed;
|
|
9639
9851
|
const dir = this._swiper.direction;
|
|
@@ -9648,7 +9860,7 @@
|
|
|
9648
9860
|
// console.log(`v speed: ${verticalspeed}`);
|
|
9649
9861
|
const args = SwipeEventArgsClass.fromArgs({
|
|
9650
9862
|
position: state.position, element: this._element, t0: this._init, timestamp: state.timestamp, inertia: options.inertia, fling: options.fling,
|
|
9651
|
-
horizontalspeed, verticalspeed, vertical
|
|
9863
|
+
horizontalspeed, verticalspeed, vertical, snap
|
|
9652
9864
|
});
|
|
9653
9865
|
//console.log(args);
|
|
9654
9866
|
return args;
|
|
@@ -9677,6 +9889,8 @@
|
|
|
9677
9889
|
#options;
|
|
9678
9890
|
#samples;
|
|
9679
9891
|
#originalTransform;
|
|
9892
|
+
/** The element's inline `transform` before the gesture, restored as is on a bounce-back home. */
|
|
9893
|
+
#originalInlineTransform;
|
|
9680
9894
|
#state;
|
|
9681
9895
|
dispose() {
|
|
9682
9896
|
const el = this._element;
|
|
@@ -9688,6 +9902,11 @@
|
|
|
9688
9902
|
/**
|
|
9689
9903
|
* Pacem Swipe element adapter: implements {@link Swiper} on top of {@link PacemBehavior} to make
|
|
9690
9904
|
* registered elements draggable along one axis, with snap points and fling/bounce-back detection.
|
|
9905
|
+
* @fires pan {@link SwipeEvent} - while the element follows the pointer: cancelable.
|
|
9906
|
+
* @fires swipe {@link SwipeEvent} - on release, once a swipe is detected (dragged past a snap, or flung): cancelable (stops the chain).
|
|
9907
|
+
* @fires swipe{direction} {@link SwipeEvent} - right after `swipe`, named after the direction (`swipeleft`, `swiperight`, `swipeup`, `swipedown`): cancelable.
|
|
9908
|
+
* @fires swipeanimationend {@link SwipeEvent} - when the element reached its snap: cancelable (`preventDefault()` keeps it there instead of returning).
|
|
9909
|
+
* @fires swipe{direction}animationend {@link SwipeEvent} - right after `swipeanimationend`, named after the direction.
|
|
9691
9910
|
*/
|
|
9692
9911
|
let PacemSwipeElement = class PacemSwipeElement extends PacemBehavior {
|
|
9693
9912
|
constructor() {
|