@nent/core
Version:
214 lines (209 loc) • 6.88 kB
JavaScript
/*!
* NENT 2022
*/
import { proxyCustomElement, HTMLElement, createEvent, Build, h, Host } from '@stencil/core/internal/client';
import { E as EventEmitter, e as eventBus } from './index2.js';
import { R as ROUTE_EVENTS } from './interfaces4.js';
import { s as state } from './state4.js';
import { T as TIMER_EVENTS } from './interfaces8.js';
import { g as getTimeDetails } from './time.js';
import { f as debugIf } from './logging.js';
import { t as throttle } from './promises.js';
/* It's a timer that uses the browser's animation frame to emit events at a given interval */
class FrameTimer extends EventEmitter {
/**
* It creates a new timer object that will fire an event every `interval` milliseconds, and will fire
* a final event when the timer has run for `durationSeconds`
* @param {AnimationFrameProvider} provider - AnimationFrameProvider
* @param {number} interval - The interval at which to emit the current time.
* @param {number} durationSeconds - The duration of the timer in seconds.
* @param getStart - () => number = performance.now,
* @param {null | (() => void)} [onInterval=null] - a callback that will be called every interval
* milliseconds.
* @param {boolean} [debug=false] - boolean - if true, will log to console.log
*/
constructor(provider, interval, durationSeconds, getStart = performance.now, onInterval = null, debug = false) {
super();
this.provider = provider;
this.interval = interval;
this.durationSeconds = durationSeconds;
this.getStart = getStart;
this.onInterval = onInterval;
this.debug = debug;
this.timer = 0;
this.start = 0;
this.durationMs = 0;
this.durationMs = this.durationSeconds * 1000;
debugIf(this.debug, `presentation-timer: starting timer w/ ${this.durationSeconds} duration`);
this.currentTime = getTimeDetails(this.start, this.start, this.durationMs);
if (this.interval > 0)
this.debouncedInterval = throttle(this.interval, () => {
this.timer = this.provider.requestAnimationFrame(current => {
this.doInterval(current);
});
}, true, true);
else
this.debouncedInterval = () => {
this.timer = this.provider.requestAnimationFrame(current => {
this.doInterval(current);
});
};
}
/**
* We start the timer by setting the start time, and then we call the `doInterval` function
*/
begin() {
if (this.timer)
this.stop();
this.start = this.getStart();
this.currentTime = getTimeDetails(this.start, this.start, this.durationMs);
this.provider.requestAnimationFrame(async (current) => {
await this.doInterval(current);
});
}
/**
* It stops the animation by cancelling the requestAnimationFrame
*/
stop() {
this.provider.cancelAnimationFrame(this.timer);
}
async doInterval(time) {
var _a;
this.currentTime = getTimeDetails(this.start, time, this.durationMs);
if (this.currentTime.ended) {
this.stop();
this.emit(TIMER_EVENTS.OnEnd, this.currentTime);
}
else {
this.emit(TIMER_EVENTS.OnInterval, this.currentTime);
await this.debouncedInterval();
}
(_a = this.onInterval) === null || _a === void 0 ? void 0 : _a.call(this);
}
/**
* It stops the timer and removes all listeners.
*/
destroy() {
this.stop();
this.removeAllListeners();
}
}
const PresentationTimer = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
constructor() {
super();
this.__registerHost();
this.ready = createEvent(this, "ready", 7);
this.elapsed = 0;
/**
* To debug timed elements, set this value to true.
*/
this.debug = false;
/**
* Duration before the timer stops and raises
* the ended event (seconds). 0 = never
*/
this.duration = 0;
/**
* Interval in milliseconds to request
* between the getAnimationFrame. This
* affects the precision.
*/
this.interval = 200;
/**
* Display elapsed seconds
*/
this.display = false;
/**
* If set, disables auto-starting the timer
* on render. This will be removed if in a view,
* when the view is activated or when the start
* method is called.
*/
this.deferLoad = false;
this.now = Build.isTesting || Build.isServer
? () => new Date().getTime()
: () => performance.now();
}
get currentRoute() {
var _a;
const parent = this.el.closest('n-view-prompt') || this.el.closest('n-view');
if (parent)
return parent.route;
return ((_a = state.router) === null || _a === void 0 ? void 0 : _a.exactRoute) || null;
}
/**
* Begin the timer. This is called automatically
* by the presentation element.
*/
async begin() {
this.timer.begin();
}
/**
* Stop the timer.
*/
async stop() {
this.timer.stop();
}
componentWillLoad() {
this.timer = new FrameTimer(window, this.interval, this.duration, () => this.now(), () => {
this.elapsed = this.timer.currentTime.elapsedSeconds;
}, this.debug);
}
render() {
return h(Host, null, this.display ? this.elapsed : null);
}
componentDidLoad() {
var _a, _b;
this.ready.emit(true);
if (this.currentRoute) {
debugIf(this.debug, `n-presentation-timer: syncing to route ${this.currentRoute.path}`);
if ((_b = (_a = this.currentRoute) === null || _a === void 0 ? void 0 : _a.match) === null || _b === void 0 ? void 0 : _b.isExact) {
this.timer.begin();
}
this.navigationSubscription = eventBus.on(ROUTE_EVENTS.RouteChanged, () => {
var _a, _b;
if ((_b = (_a = this.currentRoute) === null || _a === void 0 ? void 0 : _a.match) === null || _b === void 0 ? void 0 : _b.isExact) {
this.timer.begin();
}
else {
this.timer.stop();
}
});
}
else {
this.timer.begin();
}
}
disconnectedCallback() {
var _a;
this.timer.destroy();
(_a = this.navigationSubscription) === null || _a === void 0 ? void 0 : _a.call(this);
}
get el() { return this; }
}, [0, "n-presentation-timer", {
"debug": [4],
"timer": [1040],
"duration": [2],
"interval": [2],
"display": [4],
"deferLoad": [1028, "defer-load"],
"elapsed": [32],
"begin": [64],
"stop": [64]
}]);
function defineCustomElement$1() {
if (typeof customElements === "undefined") {
return;
}
const components = ["n-presentation-timer"];
components.forEach(tagName => { switch (tagName) {
case "n-presentation-timer":
if (!customElements.get(tagName)) {
customElements.define(tagName, PresentationTimer);
}
break;
} });
}
const NPresentationTimer = PresentationTimer;
const defineCustomElement = defineCustomElement$1;
export { NPresentationTimer, defineCustomElement };