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.

295 lines (294 loc) 8.3 kB
/*! * NENT 2022 */ import { Component, Element, Event, Method, Prop, } from '@stencil/core'; import { warn } from '../../services/common/logging'; import { hasReference, markReference, ReferenceType, } from '../../services/content'; /** * This element makes a single reference to script and css sources. It can * be used by HTML fragment to ensure a reference is made, without worrying * that it will create duplicate references. * * @system content */ export class ContentReference { constructor() { /** * Import the script file as a module. */ this.module = false; /** * Declare the script only for use when * modules aren't supported */ this.noModule = false; /** * When inline the link/script tags are rendered in-place * rather than added to the head. */ this.inline = false; /** * If set, disables auto-rendering of this instance. * To fetch the contents change to false or remove * attribute. */ this.deferLoad = false; /** * Timeout (in milliseconds) to wait for the references * to load. */ this.timeout = 1000; } /** * Force the 'load' event of the script or link element. * This is meant for testing. * */ async forceLoad() { var _a, _b; (_a = this.scriptElement) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent('load')); (_b = this.linkElement) === null || _b === void 0 ? void 0 : _b.dispatchEvent(new CustomEvent('load')); } registered(type, loaded) { this.reference.emit({ type, loaded }); } async getStylePromise(element) { const url = this.styleSrc; return new Promise(async (resolve) => { if (url == undefined) { return resolve(false); } const reffed = await hasReference(url); if (reffed) { return resolve(true); } this.linkElement = this.el.ownerDocument.createElement('link'); this.linkElement.href = url; this.linkElement.rel = 'stylesheet'; let loaded = false; this.linkElement.addEventListener('load', async () => { loaded = true; return resolve(loaded); }); element.append(this.linkElement); await markReference(url); setTimeout(() => { if (!loaded) { warn(`Stylesheet '${url}' did not load before the ${this.timeout} timeout.`); resolve(false); } }, this.timeout); }); } getScriptPromise(element) { const url = this.scriptSrc; return new Promise(async (resolve) => { if (url == undefined) { return resolve(false); } const reffed = await hasReference(url); if (reffed) { return resolve(true); } this.scriptElement = this.el.ownerDocument.createElement('script'); this.scriptElement.src = url; let loaded = false; if (this.module) { this.scriptElement.type = 'module'; } else if (this.noModule) { this.scriptElement.setAttribute('nomodule', ''); } this.scriptElement.addEventListener('load', async () => { loaded = true; await markReference(url); return resolve(loaded); }); element.append(this.scriptElement); await markReference(url); setTimeout(() => { if (!loaded) { warn(`Script '${url}' did not load before the ${this.timeout} timeout.`); resolve(false); } }, this.timeout); }); } async componentWillRender() { if (this.deferLoad) { return; } const element = this.inline ? this.el : this.el.ownerDocument.head; await this.getStylePromise(element).then(loaded => this.registered(ReferenceType.styles, loaded)); await this.getScriptPromise(element).then(loaded => this.registered(ReferenceType.script, loaded)); } disconnectedCallback() { } static get is() { return "n-content-reference"; } static get properties() { return { "styleSrc": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The css file to reference" }, "attribute": "style-src", "reflect": false }, "scriptSrc": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The script file to reference." }, "attribute": "script-src", "reflect": false }, "module": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Import the script file as a module." }, "attribute": "module", "reflect": false, "defaultValue": "false" }, "noModule": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Declare the script only for use when\nmodules aren't supported" }, "attribute": "no-module", "reflect": false, "defaultValue": "false" }, "inline": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "When inline the link/script tags are rendered in-place\nrather than added to the head." }, "attribute": "inline", "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-rendering of this instance.\nTo fetch the contents change to false or remove\nattribute." }, "attribute": "defer-load", "reflect": false, "defaultValue": "false" }, "timeout": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Timeout (in milliseconds) to wait for the references\nto load." }, "attribute": "timeout", "reflect": false, "defaultValue": "1000" } }; } static get events() { return [{ "method": "reference", "name": "referenced", "bubbles": true, "cancelable": false, "composed": true, "docs": { "tags": [], "text": "This event is fired when the script and style\nelements are loaded or timed out. The value for each\nstyle and script will be true or false, for loaded\nor timedout, respectively." }, "complexType": { "original": "ReferenceCompleteResults", "resolved": "{ type: ReferenceType; loaded: boolean; }", "references": { "ReferenceCompleteResults": { "location": "import", "path": "../../services/content" } } } }]; } static get methods() { return { "forceLoad": { "complexType": { "signature": "() => Promise<void>", "parameters": [], "references": { "Promise": { "location": "global" } }, "return": "Promise<void>" }, "docs": { "text": "Force the 'load' event of the script or link element.\nThis is meant for testing.", "tags": [] } } }; } static get elementRef() { return "el"; } }