import each from 'lodash/each' ; import sortBy from 'lodash/sortBy' ; import uniq from 'lodash/uniq' ; returns { boolean } export const isBrowser = ( ) => typeof window !== 'undefined' && typeof document !== 'undefined' ; const loadPromises = { } ; param str param namespace returns { string } export const generateStringHash = ( str , namespace = '' ) => { const nmspace = namespace || '' ; let hash = 0 ; let i ; let chr ; if ( str . length === 0 ) return `${ nmspace }__${ hash }` ; const strr = `${ nmspace }_${ str }` ; for ( i = 0 ; i < strr . length ; i += 1 ) { chr = strr . charCodeAt ( i ) ; hash = ( ( hash << 5 ) - hash ) + chr ; hash |= 0 ; } return `${ nmspace }__${ hash }` ; } ; param path returns { Promise } export const loadStyle = ( path ) => { const pathHash = generateStringHash ( path , 'CSS' ) ; if ( loadPromises [ pathHash ] ) return loadPromises [ pathHash ] ; loadPromises [ pathHash ] = new Promise ( ( resolve , reject ) => { if ( ! isBrowser ( ) ) { return reject ( new Error ( 'Cannot call from server. Function can be executed only from browser' ) ) ; } const previousLink = document . getElementById ( pathHash . toString ( ) ) ; if ( previousLink ) { resolve ( null ) ; return previousLink ; } const head = document . getElementsByTagName ( 'head' ) [ 0 ] ; const link = document . createElement ( 'link' ) ; link . setAttribute ( 'href' , path ) ; link . setAttribute ( 'id' , pathHash . toString ( ) ) ; link . setAttribute ( 'rel' , 'stylesheet' ) ; link . setAttribute ( 'type' , 'text/css' ) ; let sheet ; let cssRules ; if ( 'sheet' in link ) { sheet = 'sheet' ; cssRules = 'cssRules' ; } else { sheet = 'styleSheet' ; cssRules = 'rules' ; } const intervalId = setInterval ( ( ) => { try { if ( link [ sheet ] && link [ sheet ] [ cssRules ] . length ) { clearInterval ( intervalId ) ; clearTimeout ( timeoutId ) ; resolve ( null ) ; } } catch ( e ) { } } , 10 ) ; const timeoutId = setTimeout ( ( ) => { clearInterval ( intervalId ) ; clearTimeout ( timeoutId ) ; head . removeChild ( link ) ; return reject ( new Error ( 'Timeout, unable to load css file' ) ) ; } , 15000 ) ; head . appendChild ( link ) ; return link ; } ) ; return loadPromises [ pathHash ] ; } ; param path param attributes returns { Promise } export const loadScript = ( path , attributes = { } ) => { const pathHash = generateStringHash ( path , 'JS' ) . toString ( ) ; if ( loadPromises [ pathHash ] ) return loadPromises [ pathHash ] ; loadPromises [ pathHash ] = new Promise ( ( resolve , reject ) => { if ( ! isBrowser ( ) ) { return reject ( new Error ( 'Cannot call from server. Function can be executed only from browser' ) ) ; } const previousLink = document . getElementById ( pathHash ) ; if ( previousLink ) { resolve ( null ) ; return previousLink ; } let r ; r = false ; const s = document . createElement ( 'script' ) ; s . type = 'text/javascript' ; s . id = pathHash ; s . src = path ; s . defer = true ; s . onload = s . onreadystatechange = function onReadyStateChange ( ) { if ( ! r && ( ! this . readyState || this . readyState === 'complete' ) ) { r = true ; resolve ( null ) ; } } ; Object . keys ( attributes ) . forEach ( ( attr ) => { s [ attr ] = attributes [ attr ] ; } ) ; const t = document . getElementsByTagName ( 'script' ) [ 0 ] ; t . parentNode . insertBefore ( s , t ) ; return s ; } ) ; return loadPromises [ pathHash ] ; } ; param assets returns { Array } export const assetsToArray = ( assets ) => { let allAssets = [ ] ; if ( assets instanceof Object ) { each ( assets , ( a ) => { if ( typeof a === 'string' ) { allAssets . push ( a ) ; } else if ( a instanceof Object ) { allAssets = allAssets . concat ( assetsToArray ( a ) ) ; } } ) ; } else if ( typeof assets === 'string' ) { allAssets . push ( assets ) ; } allAssets = sortBy ( allAssets , ( a ) => a . indexOf ( 'hot-update' ) !== - 1 ) ; return uniq ( allAssets ) ; } ;