UNPKG

@nent/core

Version:

Functional elements to add routing, data-binding, dynamic HTML, declarative actions, audio, video, and so much more. Supercharge static HTML files into web apps without script or builds.

190 lines (184 loc) 6.25 kB
/*! * NENT 2022 */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const index$1 = require('./index-1829aebc.js'); const index = require('./index-637e8c28.js'); const interfaces$1 = require('./interfaces-1da33056.js'); const state = require('./state-246c735d.js'); const interfaces = require('./interfaces-023ea612.js'); const time = require('./time-95d533f4.js'); const logging = require('./logging-37c154cf.js'); const promises = require('./promises-463f4e01.js'); require('./index-96f3ab3f.js'); /* It's a timer that uses the browser's animation frame to emit events at a given interval */ class FrameTimer extends index.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; logging.debugIf(this.debug, `presentation-timer: starting timer w/ ${this.durationSeconds} duration`); this.currentTime = time.getTimeDetails(this.start, this.start, this.durationMs); if (this.interval > 0) this.debouncedInterval = promises.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 = time.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$1) { var _a; this.currentTime = time.getTimeDetails(this.start, time$1, this.durationMs); if (this.currentTime.ended) { this.stop(); this.emit(interfaces.TIMER_EVENTS.OnEnd, this.currentTime); } else { this.emit(interfaces.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 = class { constructor(hostRef) { index$1.registerInstance(this, hostRef); this.ready = index$1.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 = () => 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.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 index$1.h(index$1.Host, null, this.display ? this.elapsed : null); } componentDidLoad() { var _a, _b; this.ready.emit(true); if (this.currentRoute) { logging.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 = index.eventBus.on(interfaces$1.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 index$1.getElement(this); } }; exports.n_presentation_timer = PresentationTimer;