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.

273 lines (272 loc) 7.3 kB
/*! * NENT 2022 */ import { Component, Element, Event, h, Host, Method, Prop, State, Build, } from '@stencil/core'; import { eventBus } from '../../services/actions'; import { debugIf } from '../../services/common'; import { ROUTE_EVENTS } from '../n-views/services/interfaces'; import { routingState } from '../n-views/services/state'; import { FrameTimer } from './services/timer'; /** * This element creates a timer for the presentation * element to use in place of a video, to time actions * or manipulate HTML by time. * * @system presentation */ export class PresentationTimer { constructor() { 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 = routingState.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); } static get is() { return "n-presentation-timer"; } static get properties() { return { "debug": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "To debug timed elements, set this value to true." }, "attribute": "debug", "reflect": false, "defaultValue": "false" }, "timer": { "type": "unknown", "mutable": true, "complexType": { "original": "ITimer", "resolved": "ITimer", "references": { "ITimer": { "location": "import", "path": "../n-presentation/services/interfaces" } } }, "required": true, "optional": false, "docs": { "tags": [], "text": "Normalized timer." } }, "duration": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Duration before the timer stops and raises\nthe ended event (seconds). 0 = never" }, "attribute": "duration", "reflect": false, "defaultValue": "0" }, "interval": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Interval in milliseconds to request\nbetween the getAnimationFrame. This\naffects the precision." }, "attribute": "interval", "reflect": false, "defaultValue": "200" }, "display": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Display elapsed seconds" }, "attribute": "display", "reflect": false, "defaultValue": "false" }, "deferLoad": { "type": "boolean", "mutable": true, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "If set, disables auto-starting the timer\non render. This will be removed if in a view,\nwhen the view is activated or when the start\nmethod is called." }, "attribute": "defer-load", "reflect": false, "defaultValue": "false" } }; } static get states() { return { "elapsed": {} }; } static get events() { return [{ "method": "ready", "name": "ready", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Ready event letting the presentation layer know it can\nbegin." }, "complexType": { "original": "any", "resolved": "any", "references": {} } }]; } static get methods() { return { "begin": { "complexType": { "signature": "() => Promise<void>", "parameters": [], "references": { "Promise": { "location": "global" } }, "return": "Promise<void>" }, "docs": { "text": "Begin the timer. This is called automatically\nby the presentation element.", "tags": [] } }, "stop": { "complexType": { "signature": "() => Promise<void>", "parameters": [], "references": { "Promise": { "location": "global" } }, "return": "Promise<void>" }, "docs": { "text": "Stop the timer.", "tags": [] } } }; } static get elementRef() { return "el"; } }