/**
* External dependencies
*/
import { isString } from '@woocommerce/types';
interface lazyLoadScriptParams {
handle: string;
src: string;
version?: string;
after?: string;
before?: string;
translations?: string;
}
interface appendScriptAttributesParam {
id: string;
innerHTML?: string;
onerror?: OnErrorEventHandlerNonNull;
onload?: () => void;
src?: string;
}
/**
* In WP, registered scripts are loaded into the page with an element like this:
* ``
* This function checks whether an element matching that selector exists.
* Useful to know if a script has already been appended to the page.
*/
const isScriptTagInDOM = ( scriptId: string ): boolean => {
const scriptElements = document.querySelectorAll( `script#${ scriptId }` );
return scriptElements.length > 0;
};
/**
* Appends a script element to the document body if a script with the same id
* doesn't exist.
*/
const appendScript = ( attributes: appendScriptAttributesParam ): void => {
// Abort if id is not valid or a script with the same id exists.
if ( ! isString( attributes.id ) || isScriptTagInDOM( attributes.id ) ) {
return;
}
const scriptElement = document.createElement( 'script' );
for ( const attr in attributes ) {
// We could technically be iterating over inherited members here, so
// if this is the case we should skip it.
if ( ! attributes.hasOwnProperty( attr ) ) {
continue;
}
const key = attr as keyof appendScriptAttributesParam;
// Skip the keys that aren't strings, because TS can't be sure which
// key in the scriptElement object we're assigning to.
if ( key === 'onload' || key === 'onerror' ) {
continue;
}
// This assignment stops TS complaining about the value maybe being
// undefined following the isString check below.
const value = attributes[ key ];
if ( isString( value ) ) {
scriptElement[ key ] = value;
}
}
// Now that we've assigned all the strings, we can explicitly assign to the
// function keys.
if ( typeof attributes.onload === 'function' ) {
scriptElement.onload = attributes.onload;
}
if ( typeof attributes.onerror === 'function' ) {
scriptElement.onerror = attributes.onerror;
}
document.body.appendChild( scriptElement );
};
/**
* Appends a `