react-oembed-container
Version:
React container for locating and injecting oembed scripts in string content.
75 lines (68 loc) • 2.58 kB
JavaScript
export const ANY_SCRIPT = /<script[\s\S]*?>[\s\S]*?<\/script>/gi;
export const EXTERNAL_SCRIPT = /<script[^>]+src=(['"])(.*?)\1/i;
export const INJECTED_SCRIPT = /<script[\s\S]*?>[\s\S]*?createElement[\s\S]*?src\s?=\s?(['"])(.*?)\1/i;
/**
* Find the URI for the external file loaded from a script tag.
*
* @param {String} script The string HTML of a <script> tag.
* @returns {String|null} The URI of the requested external script, otherwise null.
*/
const extractExternalScriptURL = ( script ) => {
const match = script.match( EXTERNAL_SCRIPT );
// Return null if no match, otherwise return the second capture group.
return match && match[2];
};
/**
* Find the URI for a script being injected from inline JS.
*
* @param {String} script The string HTML of a <script> tag.
* @returns {String|null} The URI of a script being injected from inline JS, otherwise null.
*/
const extractInjectedScriptURL = ( script ) => {
const match = script.match( INJECTED_SCRIPT );
// Return null if no match, otherwise return the second capture group.
return match && match[2];
};
/**
* Match either external or inline-script-injected script tag source URIs.
*
* @param {String} script The string HTML of a <script> tag
* @returns {String|null} The URI of the script file this script tag loads, or null.
*/
const extractScriptURL = ( script ) => (
extractExternalScriptURL( script ) || extractInjectedScriptURL( script )
);
/**
* Remove duplicate or undefined values from an array of strings.
*
* @param {String[]} Array script file URIs.
*/
const uniqueURIs = ( scripts ) => Object.keys( scripts.reduce( ( keys, script ) => (
script ? {
...keys,
[script]: true,
} : keys
), {} ) );
/**
* Parse a string of HTML and identify the JS files loaded by any contained script tags.
*
* @param {String} string String containing HTML markup which may include script tags.
* @returns {String[]} Array of any script URIs we believe to be loaded in this HTML.
*/
export const getScripts = ( string ) => {
const scripts = string.match( /<script[\s\S]*?<\/script>/gi );
return scripts ? uniqueURIs( scripts.map( extractScriptURL ) ) : [];
};
/**
* Create & inject a new <script> tag into the page.
*
* @param {String} src A script URL.
* @returns {HTMLElement} The injected script tag.
*/
export const injectScriptTag = ( src ) => {
const scriptTag = document.createElement( 'script' );
// Workaround for HTML-encoded entities in URI (relevant to Facebook)
scriptTag.src = src.replace( '&', '&' );
document.head.appendChild( scriptTag );
return scriptTag;
};