tiny-essentials
Version:
Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.
210 lines (209 loc) • 8.8 kB
JavaScript
import TinyHtmlTemplate from './TinyHtmlTemplate.mjs';
/**
* TinyHtmlScript is a helper class for creating and managing <script> elements.
* Supports both inline and external scripts, with attributes for async, defer, modules, etc.
*
* @extends TinyHtmlTemplate<HTMLScriptElement>
*/
class TinyHtmlScript extends TinyHtmlTemplate {
/**
* Creates a new TinyHtmlScript instance.
* @param {Object} config - Configuration object.
* @param {string} [config.src] - URI of an external script.
* @param {string} [config.type] - The type of script (e.g., "module", "importmap", "speculationrules", or JS MIME type).
* @param {boolean} [config.async=false] - Whether the script should be executed asynchronously (requires src).
* @param {boolean} [config.defer=false] - Whether the script should be deferred until after parsing (requires src).
* @param {string|string[]|Set<string>} [config.tags=[]] - Initial CSS classes.
* @param {string} [config.mainClass=""] - Main CSS class.
* @param {string} [config.content=""] - Inline script content (ignored if src is provided).
* @param {string|string[]} [config.blocking] - Space-separated list of blocking tokens (currently only "render").
* @param {"anonymous" | "use-credentials"} [config.crossorigin] - CORS setting ("anonymous" or "use-credentials").
* @param {"auto"|"high"|"low"} [config.fetchpriority="auto"] - Fetch priority.
* @param {string} [config.integrity] - Subresource integrity hash (only valid with src).
* @param {boolean} [config.nomodule=false] - Whether to prevent execution in browsers supporting modules.
* @param {string} [config.nonce] - Cryptographic nonce for CSP.
* @param {string} [config.referrerpolicy] - Referrer policy.
* @param {boolean|string|string[]} [config.attributionsrc] - Boolean or list of URLs for attribution reporting.
*/
constructor({ src, type, async = false, defer = false, tags = [], mainClass = '', content = '', blocking, crossorigin, fetchpriority = 'auto', integrity, nomodule = false, nonce, referrerpolicy, attributionsrc, } = {}) {
super(document.createElement('script'), tags, mainClass);
if (src !== undefined)
this.src = src;
if (type !== undefined)
this.type = type;
this.async = async;
this.defer = defer;
if (blocking !== undefined)
this.blocking = blocking;
if (crossorigin !== undefined)
this.crossorigin = crossorigin;
this.fetchpriority = fetchpriority;
if (integrity !== undefined)
this.integrity = integrity;
this.nomodule = nomodule;
if (nonce !== undefined)
this.nonce = nonce;
if (referrerpolicy !== undefined)
this.referrerpolicy = referrerpolicy;
if (attributionsrc !== undefined)
this.attributionsrc = attributionsrc;
if (!src && content)
this.content = content;
}
/** @param {string} src */
set src(src) {
if (typeof src !== 'string')
throw new TypeError('TinyHtmlScript: "src" must be a string.');
this.setAttr('src', src);
}
/** @returns {string|null} */
get src() {
return this.attrString('src');
}
/** @param {string} type */
set type(type) {
if (typeof type !== 'string')
throw new TypeError('TinyHtmlScript: "type" must be a string.');
this.setAttr('type', type);
}
/** @returns {string|null} */
get type() {
return this.attrString('type');
}
/** @param {boolean} async */
set async(async) {
if (typeof async !== 'boolean')
throw new TypeError('TinyHtmlScript: "async" must be a boolean.');
if (async && !this.src)
throw new Error('TinyHtmlScript: "async" requires a "src" attribute.');
this.toggleProp('async', async);
}
/** @returns {boolean} */
get async() {
return this.hasProp('async');
}
/** @param {boolean} defer */
set defer(defer) {
if (typeof defer !== 'boolean')
throw new TypeError('TinyHtmlScript: "defer" must be a boolean.');
if (defer && !this.src)
throw new Error('TinyHtmlScript: "defer" requires a "src" attribute.');
this.toggleProp('defer', defer);
}
/** @returns {boolean} */
get defer() {
return this.hasProp('defer');
}
/** @param {string|string[]} blocking */
set blocking(blocking) {
const values = Array.isArray(blocking) ? blocking : String(blocking).trim().split(/\s+/);
for (const v of values) {
if (v !== 'render')
throw new Error(`TinyHtmlScript: invalid blocking token "${v}".`);
}
this.setAttr('blocking', values.join(' '));
}
/** @returns {string[]|null} */
get blocking() {
const val = this.attrString('blocking');
return val ? val.split(/\s+/) : null;
}
/** @param {"anonymous"|"use-credentials"} crossorigin */
set crossorigin(crossorigin) {
if (!['anonymous', 'use-credentials'].includes(crossorigin))
throw new Error('TinyHtmlScript: "crossorigin" must be "anonymous" or "use-credentials".');
this.setAttr('crossorigin', crossorigin);
}
/** @returns {string|null} */
get crossorigin() {
return this.attrString('crossorigin');
}
/** @param {"auto"|"high"|"low"} fetchpriority */
set fetchpriority(fetchpriority) {
if (!['auto', 'high', 'low'].includes(fetchpriority))
throw new Error('TinyHtmlScript: "fetchpriority" must be "auto", "high", or "low".');
this.setAttr('fetchpriority', fetchpriority);
}
/** @returns {string|null} */
get fetchpriority() {
return this.attrString('fetchpriority');
}
/** @param {string} integrity */
set integrity(integrity) {
if (!this.src)
throw new Error('TinyHtmlScript: "integrity" requires "src".');
if (typeof integrity !== 'string')
throw new TypeError('TinyHtmlScript: "integrity" must be a string.');
this.setAttr('integrity', integrity);
}
/** @returns {string|null} */
get integrity() {
return this.attrString('integrity');
}
/** @param {boolean} nomodule */
set nomodule(nomodule) {
if (typeof nomodule !== 'boolean')
throw new TypeError('TinyHtmlScript: "nomodule" must be a boolean.');
this.toggleProp('nomodule', nomodule);
}
/** @returns {boolean} */
get nomodule() {
return this.hasProp('nomodule');
}
/** @param {string} nonce */
set nonce(nonce) {
if (typeof nonce !== 'string')
throw new TypeError('TinyHtmlScript: "nonce" must be a string.');
this.setAttr('nonce', nonce);
}
/** @returns {string|null} */
get nonce() {
return this.attrString('nonce');
}
/** @param {string} referrerpolicy */
set referrerpolicy(referrerpolicy) {
if (typeof referrerpolicy !== 'string')
throw new TypeError('TinyHtmlScript: "referrerpolicy" must be a string.');
this.setAttr('referrerpolicy', referrerpolicy);
}
/** @returns {string|null} */
get referrerpolicy() {
return this.attrString('referrerpolicy');
}
/** @param {boolean|string|string[]} attributionsrc */
set attributionsrc(attributionsrc) {
if (attributionsrc === true) {
this.addProp('attributionsrc');
}
else if (typeof attributionsrc === 'string') {
this.setAttr('attributionsrc', attributionsrc);
}
else if (Array.isArray(attributionsrc) &&
attributionsrc.every((v) => typeof v === 'string')) {
this.setAttr('attributionsrc', attributionsrc.join(' '));
}
else {
throw new TypeError('TinyHtmlScript: "attributionsrc" must be boolean, string, or string[].');
}
}
/** @returns {boolean|string[]|null} */
get attributionsrc() {
if (this.hasProp('attributionsrc'))
return true;
const val = this.attrString('attributionsrc');
return val ? val.split(/\s+/) : null;
}
/** @param {string} code */
set content(code) {
if (typeof code !== 'string')
throw new TypeError('TinyHtmlScript: "content" must be a string.');
if (this.src)
throw new Error('TinyHtmlScript: Cannot set inline content when "src" is defined.');
this._preHtmlElem('content').textContent = code;
}
/** @returns {string|null} */
get content() {
return this._preHtmlElem('content').textContent || null;
}
}
export default TinyHtmlScript;