import IAttr from '../attr/IAttr.js';
import HTMLElement from '../html-element/HTMLElement.js';
import IHTMLScriptElement from './IHTMLScriptElement.js';
import HTMLScriptElementUtility from './HTMLScriptElementUtility.js';
import Event from '../../event/Event.js';
import ErrorEvent from '../../event/events/ErrorEvent.js';
import INode from '../../nodes/node/INode.js';
/**
* HTML Script Element.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement.
*/
export default class HTMLScriptElement extends HTMLElement implements IHTMLScriptElement {
public onerror: (event: ErrorEvent) => void = null;
public onload: (event: Event) => void = null;
public _evaluateScript = true;
/**
* Returns type.
*
* @returns Type.
*/
public get type(): string {
return this.getAttribute('type') || '';
}
/**
* Sets type.
*
* @param type Type.
*/
public set type(type: string) {
this.setAttribute('type', type);
}
/**
* Returns source.
*
* @returns Source.
*/
public get src(): string {
return this.getAttribute('src') || '';
}
/**
* Sets source.
*
* @param source Source.
*/
public set src(src: string) {
this.setAttribute('src', src);
}
/**
* Returns charset.
*
* @returns Charset.
*/
public get charset(): string {
return this.getAttribute('charset') || '';
}
/**
* Sets charset.
*
* @param charset Charset.
*/
public set charset(charset: string) {
this.setAttribute('charset', charset);
}
/**
* Returns lang.
*
* @returns Lang.
*/
public get lang(): string {
return this.getAttribute('lang') || '';
}
/**
* Sets lang.
*
* @param lang Lang.
*/
public set lang(lang: string) {
this.setAttribute('lang', lang);
}
/**
* Returns async.
*
* @returns Async.
*/
public get async(): boolean {
return this.getAttribute('async') !== null;
}
/**
* Sets async.
*
* @param async Async.
*/
public set async(async: boolean) {
if (!async) {
this.removeAttribute('async');
} else {
this.setAttribute('async', '');
}
}
/**
* Returns defer.
*
* @returns Defer.
*/
public get defer(): boolean {
return this.getAttribute('defer') !== null;
}
/**
* Sets defer.
*
* @param defer Defer.
*/
public set defer(defer: boolean) {
if (!defer) {
this.removeAttribute('defer');
} else {
this.setAttribute('defer', '');
}
}
/**
* Returns text.
*
* @returns Text.
*/
public get text(): string {
return this.textContent;
}
/**
* Sets text.
*
* @param text Text.
*/
public set text(text: string) {
this.textContent = text;
}
/**
* The setAttributeNode() method adds a new Attr node to the specified element.
*
* @override
* @param attribute Attribute.
* @returns Replaced attribute.
*/
public setAttributeNode(attribute: IAttr): IAttr {
const replacedAttribute = super.setAttributeNode(attribute);
if (attribute.name === 'src' && attribute.value !== null && this.isConnected) {
HTMLScriptElementUtility.loadExternalScript(this);
}
return replacedAttribute;
}
/**
* Clones a node.
*
* @override
* @param [deep=false] "true" to clone deep.
* @returns Cloned node.
*/
public cloneNode(deep = false): IHTMLScriptElement {
return super.cloneNode(deep);
}
/**
* @override
*/
public override _connectToNode(parentNode: INode = null): void {
const isConnected = this.isConnected;
const isParentConnected = parentNode ? parentNode.isConnected : false;
super._connectToNode(parentNode);
if (isParentConnected && isConnected !== isParentConnected && this._evaluateScript) {
const src = this.getAttribute('src');
if (src !== null) {
HTMLScriptElementUtility.loadExternalScript(this);
} else if (!this.ownerDocument.defaultView.happyDOM.settings.disableJavaScriptEvaluation) {
const textContent = this.textContent;
const type = this.getAttribute('type');
if (
textContent &&
(type === null ||
type === 'application/x-ecmascript' ||
type === 'application/x-javascript' ||
type.startsWith('text/javascript'))
) {
HTMLScriptElementUtility.eval(this, textContent);
}
}
}
}
}