import { getBrowserFamily } from './browser' ; import { AlertMessage } from './detection' ; import { BrowserFamily , GenericMessage , GenericMessageType } from './types' ; /**
 * Additinal window instance
 */ let handler = null ; /**
 * Function will create a popup (is separeted from getAdditionalWindow because requires user gesture)
 * This popup is used for Safari, Chrome and Firefox installed apps detection
 * Since we don't want to open multiple popups it has the memoization
 */ export function createAdditionalWindow ( ) { const params = `width=50,height=50,left=9999,top=9999` ; handler = window . open ( getInitialUrlForPopup ( ) , '' , params ) ; if ( ! handler ) { throw AlertMessage . Unexpected ; } return handler ; } export function listenOnce ( type , callback ) { handler ?. addEventListener ( type , callback , { once : true } ) ; return ( ) => handler ?. removeEventListener ( type , callback ) ; } /**
 * For dev debugging only
 */ export function debugEvents < T > ( target ) { const keys = Object . keys ( window ) ; const start = performance . now ( ) ; for ( const key of keys ) { if ( key . slice ( 0 , 2 ) === 'on' ) { target [ key ] = ( e ) => console . log ( performance . now ( ) - start , handler ?. location . href , e ) ; } } } function getInitialUrlForPopup ( ) { const target = getBrowserFamily ( ) ; return target === BrowserFamily . Safari ? '/popup' : 'about:blank' ; } /**
 * Checks if the current window instance is the main frame or popup window
 */ export function isPopupWindow ( ) { return ! ! window . opener ; } /**
 * Some instructions should be executed in main window and others in popup
 */ export async function invokeWithFrame ( type , callback ) { if ( type === 'popup' && isPopupWindow ( ) ) { await callback ( ) ; } if ( type === 'main' && ! isPopupWindow ( ) ) { await callback ( ) ; } } /**
 * Used for duplex cross-window communtication
 */ export function sendWindowMessage ( type ) { const targetWindow = window . opener || handler ; targetWindow . postMessage ( { type , crossBrowserDemo : true , } , document . location . origin ) ; } /**
 * Also used for duplex cross-window communtication
 */ const messageListeners = { } ; export function onMessage ( type , callback ) { messageListeners [ type ] = callback ; } /**
 * Cross-window communication
 */ export function initWindowMessaging ( ) { window . onmessage = ( event ) => { const data = event . data as GenericMessage ; if ( data . crossBrowserDemo ) { handler = event . source as Window ; } if ( messageListeners [ data . type ] ) { messageListeners [ data . type ] ( ) ; } } ; } /**
 * Returns additional popup window instance
 */ export function getAdditionalWindow ( silent = false ) { if ( ! silent && ! isAdditinalWindowOpened ( ) && ! isPopupWindow ( ) ) { throw AlertMessage . MissingPopup ; } return handler || createAdditionalWindow ( ) ; } /**
 * Checks if popup wasn't closed
 */ export function isAdditinalWindowOpened ( ) { if ( getBrowserFamily ( ) === BrowserFamily . TorBrowser ) { return true ; } return handler && ! handler . closed ; } /**
 * Wait until the Chrome PDF extension is loaded
 */ export function waitForEmbedElemet ( ) { return new Promise < void > ( ( resolve ) => { const intervalId = setInterval ( ( ) => { const iframe = handler ?. document . getElementsByTagName ( 'iframe' ) [ 0 ] ; const embeds = iframe ?. contentDocument ?. embeds ; if ( embeds && embeds . length > 0 ) { clearInterval ( intervalId ) ; setTimeout ( ( ) => { resolve ( ) ; } , 200 ) ; } } ) ; } ) ; } /**
 * Wait after cross-origin loading
 */ export function waitForLocation ( href ) { return new Promise < void > ( ( resolve ) => { const intervalId = setInterval ( ( ) => { try { if ( handler ?. location . href === href ) { clearInterval ( intervalId ) ; resolve ( ) ; } } catch ( e ) { if ( href === '-1' ) { clearInterval ( intervalId ) ; resolve ( ) ; } } } ) ; } ) ; }