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.

225 lines (219 loc) 7.84 kB
/*! * NENT 2022 */ import { r as registerInstance, a as getElement } from './index-916ca544.js'; import { E as EventEmitter, a as actionBus, e as eventBus } from './index-f7016b94.js'; import { f as debugIf } from './logging-5a93c8af.js'; import { a as state, o as onChange } from './state-27a8a5bc.js'; import { r as resolveChildElementXAttributes } from './elements-1b845a48.js'; import { a as addDataProvider, r as removeDataProvider } from './factory-acbf0d3d.js'; import { D as DATA_EVENTS } from './interfaces-8c5cd1b8.js'; import { d as debounce } from './promises-584c4ece.js'; import './index-4bfabbbd.js'; import './expressions-2c27c47c.js'; import './tokens-78f8cdbe.js'; import './values-ddfac998.js'; import './strings-47d55561.js'; /* istanbul ignore file */ const ELEMENTS_TOPIC = 'elements'; var ELEMENTS_COMMANDS; (function (ELEMENTS_COMMANDS) { ELEMENTS_COMMANDS["toggleClass"] = "toggle-class"; ELEMENTS_COMMANDS["addClasses"] = "add-classes"; ELEMENTS_COMMANDS["removeClasses"] = "remove-classes"; ELEMENTS_COMMANDS["setAttribute"] = "set-attribute"; ELEMENTS_COMMANDS["removeAttribute"] = "remove-attribute"; ELEMENTS_COMMANDS["callMethod"] = "call-method"; })(ELEMENTS_COMMANDS || (ELEMENTS_COMMANDS = {})); /* It listens for actions on the `ELEMENTS_TOPIC` topic and executes the corresponding command on the element(s) specified by the `selector` property */ class ElementsActionListener { constructor() { this.changed = new EventEmitter(); } /** * It listens for events on the action bus, and when it receives one, it calls the `commandReceived` * function * @param {Window} win - Window - the window object of the browser * @param {IEventEmitter} actionBus - This is the event bus that the extension listens to for * commands from the extension. * @param {IEventEmitter} eventBus - This is the event bus that the plugin is using to communicate * with the rest of the application. */ initialize(win, actionBus, eventBus) { this.body = win.document.body; this.eventBus = eventBus; this.actionsSubscription = actionBus.on(ELEMENTS_TOPIC, async (ev) => { debugIf(state.debug, `elements-listener: action received ${ev.topic}:${ev.command}`); await this.commandReceived(ev.command, ev.data); this.changed.emit('changed'); }); } async commandReceived(command, data) { switch (command) { case ELEMENTS_COMMANDS.toggleClass: { this.toggleClass(data); break; } case ELEMENTS_COMMANDS.addClasses: { this.addClasses(data); break; } case ELEMENTS_COMMANDS.removeClasses: { this.removeClasses(data); break; } case ELEMENTS_COMMANDS.setAttribute: { this.setAttribute(data); break; } case ELEMENTS_COMMANDS.removeAttribute: { this.removeAttribute(data); break; } case ELEMENTS_COMMANDS.callMethod: { this.callMethod(data); break; } } } toggleClass(args) { const { selector, className } = args; if (!className) return; const element = this.body.querySelector(selector); if (element && className) element.classList.toggle(className); } addClasses(args) { const { selector, classes } = args; if (!classes) return; const element = this.body.querySelector(selector); if (element && classes) classes.split(' ').forEach((c) => { element.classList.add(c); }); } removeClasses(args) { const { selector, classes } = args; const element = this.body.querySelector(selector); if (element && classes) classes === null || classes === void 0 ? void 0 : classes.split(' ').forEach((c) => { element === null || element === void 0 ? void 0 : element.classList.remove(c); }); } setAttribute(args) { const { selector, attribute, value } = args; if (!attribute) return; const element = this.body.querySelector(selector); if (element && attribute) element.setAttribute(attribute, value || ''); } removeAttribute(args) { const { selector, attribute } = args; if (!attribute) return; const element = this.body.querySelector(selector); if (element && attribute) element === null || element === void 0 ? void 0 : element.removeAttribute(attribute); } callMethod(args) { const { selector, method, data } = args; if (!method) return; const element = this.body.querySelector(selector); if (element) { const elementMethod = element[method]; if (elementMethod && typeof element === 'function') { elementMethod(data); } } } destroy() { this.actionsSubscription(); } } /* It listens to changes in the DOM and emits a `changed` event when it detects a change */ class ElementsDataProvider { /** * A constructor function that takes in two parameters, a document and an elementListener. It then * creates a new EventEmitter and assigns it to the changed property. It then creates a new variable * called change and assigns it to a debounce function. The debounce function takes in three * parameters, a number, a function, and a boolean. The function that is passed in as a parameter * emits a DataChanged event. The listenerSubscription property is assigned to the * elementListener.changed property and is passed in a function that calls the change function. * @param {Document} doc - Document - this is the document object that is used to create the * elements. * @param {ElementsActionListener} elementListener - ElementsActionListener - this is the service * that listens to the changes in the elements. */ constructor(doc, elementListener) { this.doc = doc; this.elementListener = elementListener; this.changed = new EventEmitter(); const change = debounce(1000, () => { this.changed.emit(DATA_EVENTS.DataChanged, { provider: 'element', }); }, true); this.listenerSubscription = this.elementListener.changed.on('changed', () => { change(); }); } async get(key) { const element = this.doc.querySelector('#' + key); return (element === null || element === void 0 ? void 0 : element.value) || element.innerText || null; } /** * The function unsubscribes from the listenerSubscription, which is a subscription to the listener * function */ destroy() { this.listenerSubscription(); } } const Elements = class { constructor(hostRef) { registerInstance(this, hostRef); /** * Turn on debug statements for load, update and render events. */ this.debug = false; } componentWillLoad() { debugIf(this.debug, `n-elements: initialized`); this.listener = new ElementsActionListener(); this.listener.initialize(window, actionBus, eventBus); state.elementsEnabled = true; if (state.dataEnabled) { this.subscribeToDataEvents(); } else { const dispose = onChange('dataEnabled', (enabled) => { if (enabled) { this.subscribeToDataEvents(); } dispose(); }); } } subscribeToDataEvents() { this.dataSubscription = eventBus.on(DATA_EVENTS.DataChanged, () => { debugIf(this.debug, `n-elements: data changed `); resolveChildElementXAttributes(this.el.ownerDocument.body); }); this.provider = new ElementsDataProvider(this.el.ownerDocument, this.listener); addDataProvider('elements', this.provider); } disconnectedCallback() { var _a; this.listener.destroy(); state.elementsEnabled = false; (_a = this.dataSubscription) === null || _a === void 0 ? void 0 : _a.call(this); removeDataProvider('elements'); } get el() { return getElement(this); } }; export { Elements as n_elements };