import assetsLoaderHelper from './assets.helper' ; import { IAppOption } from '../model/IAppOption' ; import { hashCode } from './app.helper' ; import { generateIFrameID } from './dom.utils' ; function loadScriptPromise ( src , iframeEl ) { return new Promise ( ( resolve , reject ) => { if ( document . getElementById ( hashCode ( src ) ) ) { return resolve ( ) ; } const script = assetsLoaderHelper . createScriptTag ( src ) ; script . onload = ( ) => { resolve ( ) ; } ; script . onerror = err => { reject ( err ) ; } ; if ( iframeEl ) { if ( iframeEl && iframeEl . contentWindow ) { iframeEl . contentWindow . document . head . appendChild ( script ) ; } } else { document . head . appendChild ( script ) ; } } ) ; } const loadScriptTag = ( src , iframeEl ? ) => { return ( ) => { return loadScriptPromise ( src , iframeEl ) ; } ; } ; const loadLinkTag = ( url , iframeEl ? ) => { return ( ) => { return new Promise ( ( resolve , reject ) => { if ( document . getElementById ( hashCode ( url ) ) ) { return resolve ( ) ; } const link = assetsLoaderHelper . createLinkTag ( url ) ; link . onload = ( ) => { resolve ( ) ; } ; link . onerror = err => { reject ( err ) ; } ; if ( iframeEl ) { if ( iframeEl && iframeEl . contentWindow ) { iframeEl . contentWindow . document . head . appendChild ( link ) ; } } else { document . head . appendChild ( link ) ; } } ) ; } ; } ; function loadAllAssets ( opts ) { return new Promise ( ( resolve , reject ) => { const scriptsPromise = opts . scripts . reduce ( ( prev , fileName ) => prev . then ( loadScriptTag ( `${ opts . baseScriptUrl }/${ fileName }` ) ) , Promise . resolve ( undefined ) ) ; const stylesPromise = opts . styles . reduce ( ( prev , fileName ) => prev . then ( loadLinkTag ( `${ opts . baseScriptUrl }/${ fileName }` ) ) , Promise . resolve ( undefined ) ) ; Promise . all ( [ scriptsPromise , stylesPromise ] ) . then ( resolve , reject ) ; } ) ; } function loadAllAssetsForIframe ( opts ) { const iframeId = generateIFrameID ( opts . name ) ; let iframeEl = document . getElementById ( iframeId ) ; if ( ! iframeEl ) { return new Promise ( ( resolve , reject ) => { reject ( ) ; } ) ; } return new Promise ( ( resolve , reject ) => { const scriptsPromise = opts . scripts . reduce ( ( prev , fileName ) => prev . then ( loadScriptTag ( `${ opts . baseScriptUrl }/${ fileName }` , iframeEl ) ) , Promise . resolve ( undefined ) ) ; const stylesPromise = opts . styles . reduce ( ( prev , fileName ) => prev . then ( loadLinkTag ( `${ opts . baseScriptUrl }/${ fileName }` ) ) , Promise . resolve ( undefined ) ) ; let promiseArray = [ scriptsPromise , stylesPromise ] ; if ( opts . includeZone ) { const zonejsPromise = loadScriptPromise ( `/assets/zone.min.js` , iframeEl ) ; promiseArray . push ( zonejsPromise ) ; } Promise . all ( promiseArray ) . then ( resolve , reject ) ; } ) ; } function loadAllAssetsForIframeAndUrl ( opts ) { const iframeId = generateIFrameID ( opts . name ) ; let iframeEl = document . getElementById ( iframeId ) ; if ( ! iframeEl ) { return new Promise ( ( resolve , reject ) => { reject ( ) ; } ) ; } return new Promise ( ( resolve , reject ) => { transformOptsWithAssets ( opts ) . then ( ( ) => { const scriptsPromise = opts . scripts . reduce ( ( prev , fileName ) => prev . then ( loadScriptTag ( `${ opts . baseScriptUrl }/${ fileName }` , iframeEl ) ) , Promise . resolve ( undefined ) ) ; const stylesPromise = opts . styles . reduce ( ( prev , fileName ) => prev . then ( loadLinkTag ( `${ opts . baseScriptUrl }/${ fileName }` ) ) , Promise . resolve ( undefined ) ) ; let promiseArray = [ scriptsPromise , stylesPromise ] ; if ( opts . includeZone ) { const zonejsPromise = loadScriptPromise ( `/assets/zone.min.js` , iframeEl ) ; promiseArray . push ( zonejsPromise ) ; } Promise . all ( promiseArray ) . then ( resolve , reject ) ; } ) ; } ) ; } const xmlToAssets = ( xml ) : { styles : ( string | null ) [ ] ; scripts : ( string | null ) [ ] ; } => { let dom = document . createElement ( 'html' ) ; let urlRegex = /^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ ; dom . innerHTML = xml ; const linksEls = dom . querySelectorAll ( 'link[rel="stylesheet"]' ) ; const scriptsEls = dom . querySelectorAll ( 'script[type="text/javascript"]' ) ; return { styles : Array . from ( linksEls ) . map ( el => el . getAttribute ( 'href' ) ) . filter ( src => { if ( src ) { return ! urlRegex . test ( src ) ; } } ) , scripts : Array . from ( scriptsEls ) . map ( el => el . getAttribute ( 'src' ) ) . filter ( src => { if ( src ) { return ! ( /zone\.js/ . test ( src ) && urlRegex . test ( src ) ) ; } } ) } ; } ; const transformOptsWithAssets = ( opts ) : Promise < null > => { const url = `${ opts . baseScriptUrl }/index.html` ; return new Promise ( ( resolve , reject ) => { const req = new XMLHttpRequest ( ) ; req . onreadystatechange = ( ) => { if ( req . readyState === XMLHttpRequest . DONE ) { if ( req . status >= 200 && req . status < 400 ) { const res = xmlToAssets ( req . responseText ) ; opts . styles = res . styles ; opts . scripts = res . scripts ; resolve ( null ) ; } else { reject ( `Try to load ${ url }, status : ${ req . status } => ${ req . statusText }` ) ; } } } ; req . open ( 'GET' , url , true ) ; req . send ( null ) ; } ) ; } ; const loadAllAssetsByUrl = ( opts ) => { return new Promise ( ( resolve , reject ) => { transformOptsWithAssets ( opts ) . then ( ( ) => { const scriptsPromise = opts . scripts . reduce ( ( prev , fileName ) => prev . then ( loadScriptTag ( `${ opts . baseScriptUrl }/${ fileName }` ) ) , Promise . resolve ( undefined ) ) ; const stylesPromise = opts . styles . reduce ( ( prev , fileName ) => prev . then ( loadLinkTag ( `${ opts . baseScriptUrl }/${ fileName }` ) ) , Promise . resolve ( undefined ) ) ; Promise . all ( [ scriptsPromise , stylesPromise ] ) . then ( resolve , reject ) ; } , reject ) ; } ) ; } ; function unloadTag ( opts , scriptName ) { return ( ) => { return new Promise ( ( resolve , reject ) => { const tag = document . getElementById ( hashCode ( `${ opts . baseScriptUrl }/${ scriptName }` ) ) ; if ( tag ) { document . head . removeChild ( tag ) ; } resolve ( ) ; } ) ; } ; } const LoaderHelper = { loadAllAssets : loadAllAssets , loadAllAssetsByUrl : loadAllAssetsByUrl , loadAllAssetsForIframe : loadAllAssetsForIframe , loadAllAssetsForIframeAndUrl : loadAllAssetsForIframeAndUrl , unloadTag : unloadTag } ; export default LoaderHelper ;