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.

258 lines (257 loc) 8.39 kB
/*! * NENT 2022 */ import { Component, Element, h, Host, Method, Prop, State, } from '@stencil/core'; import { ActionActivationStrategy, } from '../../services/actions'; import { debugIf, isValue, warn } from '../../services/common'; /** * This element defines how or when a group of actions are * activated. The actions activated must be included between * this elements tags. * * @system actions */ export class ActionActivator { constructor() { this.actions = []; this.activated = false; /** * The activation strategy to use for the contained actions. */ this.activate = 'on-element-event'; /** * This is the name of the event/s to listen to on the target element * separated by comma. */ this.targetEvent = 'click,keydown'; /** * Turn on debug statements for load, update and render events. */ this.debug = false; /** * Limit the activation to ONCE. This could be helpful if an action * has side-effects if it is run multiple times. * * Note: the activation * state is stored in memory and does not persist across refreshes. */ this.once = false; } /** * Manually activate all actions within this activator. */ async activateActions(once = false) { if ((once || this.once) && this.activated) return; const values = {}; let isValid = true; this.childInputs.forEach((el, index) => { var _a, _b; if (((_a = el.checkValidity) === null || _a === void 0 ? void 0 : _a.call(el)) === false) { (_b = el.reportValidity) === null || _b === void 0 ? void 0 : _b.call(el); isValid = false; } else { values[el.id || el.name || index] = el.value || (el.type == 'checkbox' ? el.checked : null); } }); if (!isValid) return; await Promise.all(this.childActions.map(async (a) => { const action = await a.getAction(); if (!action) return; const dataString = JSON.stringify(action.data); debugIf(this.debug, `n-action-activator: activating [${this.activate}~{topic: ${action === null || action === void 0 ? void 0 : action.topic}, command:${action === null || action === void 0 ? void 0 : action.command}, data: ${dataString}]`); await a.sendAction(values); })); this.activated = true; } get childInputs() { return this.el.querySelectorAll('input,select,textarea'); } get childActions() { const actions = Array.from(this.el.childNodes) .filter(n => n.nodeName.toLocaleLowerCase().includes('action')) .map(n => n); return actions; } async componentDidLoad() { debugIf(this.debug, `n-action-activator: loading`); if (this.childActions.length === 0) { warn(`n-action-activator: no children actions detected`); return; } if (this.activate === ActionActivationStrategy.OnElementEvent) { const elements = this.targetElement ? this.el.ownerDocument.querySelectorAll(this.targetElement) : this.el.querySelectorAll('a,button,input[type=button]'); if (!elements || elements.length == 0) { warn(`n-action-activator: no elements found for '${this.targetElement}'`); } else { debugIf(this.debug, `n-action-activator: elements found ${elements.length}`); elements.forEach(element => { debugIf(this.debug, `n-action-activator: element found ${element.nodeName}`); const events = this.targetEvent .split(',') .filter(e => isValue(e)); events.forEach(event => { this.debug, `n-action-activator: element event ${event} registered on ${element.nodeName}`, element.addEventListener(event, async () => { debugIf(this.debug, `n-action-activator: received ${element.nodeName} ${this.targetEvent} event`); await this.activateActions(); }); }); }); } } else if (this.activate === ActionActivationStrategy.OnRender) { await this.activateActions(); } } render() { return (h(Host, { style: { display: 'contents' } }, h("slot", null))); } static get is() { return "n-action-activator"; } static get properties() { return { "activate": { "type": "string", "mutable": false, "complexType": { "original": "| 'on-render'\n | 'on-element-event'\n | 'on-enter'\n | 'at-time'\n | 'at-time-end'\n | 'on-exit'", "resolved": "\"at-time\" | \"at-time-end\" | \"on-element-event\" | \"on-enter\" | \"on-exit\" | \"on-render\"", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The activation strategy to use for the contained actions." }, "attribute": "activate", "reflect": false, "defaultValue": "'on-element-event'" }, "targetElement": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The element or elements to watch for events when using the OnElementEvent\nactivation strategy. This element uses the HTML Element querySelectorAll\nfunction to find the element/s based on the query in this attribute.\n\nIf left blank, this element looks for child elements matching:\n'a,button,input[type=button]'\n\nFor use with activate=\"on-element-event\" and \"at-time\"" }, "attribute": "target-element", "reflect": false }, "targetEvent": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "This is the name of the event/s to listen to on the target element\nseparated by comma." }, "attribute": "target-event", "reflect": false, "defaultValue": "'click,keydown'" }, "time": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The time, in seconds at which the contained actions should be submitted.\n\nFor use with activate=\"at-time\" Only!" }, "attribute": "time", "reflect": false }, "debug": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Turn on debug statements for load, update and render events." }, "attribute": "debug", "reflect": false, "defaultValue": "false" }, "once": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Limit the activation to ONCE. This could be helpful if an action\nhas side-effects if it is run multiple times.\n\nNote: the activation\nstate is stored in memory and does not persist across refreshes." }, "attribute": "once", "reflect": false, "defaultValue": "false" } }; } static get states() { return { "actions": {}, "activated": {} }; } static get methods() { return { "activateActions": { "complexType": { "signature": "(once?: boolean) => Promise<void>", "parameters": [{ "tags": [], "text": "" }], "references": { "Promise": { "location": "global" }, "Record": { "location": "global" } }, "return": "Promise<void>" }, "docs": { "text": "Manually activate all actions within this activator.", "tags": [] } } }; } static get elementRef() { return "el"; } }