import { EmbedBuilder } from './embed_builder' ; import { Chatty , ChattyHost , ChattyHostBuilder } from '@looker/chatty' ; const IS_URL = /^https?:\/\// ; /**
 * Wrapper for Looker embedded content. Provides a mechanism for creating the embedded content element,
 * and for establishing two-way communication between the parent window and the embedded content.
 */ export class EmbedClient < T > { _hostBuilder : ChattyHostBuilder | null = null ; _host : ChattyHost | null = null ; _connection : Promise < T > | null = null ; _client : T | null = null ; hidden constructor ( private _builder ) { } /**
     * Returns a promise that resolves to a client that can be used to send messages to the
     * embedded content.
     */ get connection ( ) { return this . _connection ; } /**
     * Indicates whether two way communication has successfully been established with the embedded content.
     */ get isConnected ( ) { return ! ! this . _connection ; } get targetOrigin ( ) { if ( this . _builder . sandboxedHost ) { return '*' ; } const apiHost = this . _builder . apiHost ; return IS_URL . test ( apiHost ) ? apiHost : `https://${ apiHost }` ; } private async createIframe ( url ) { this . _hostBuilder = Chatty . createHost ( url ) ; for ( const eventType in this . _builder . handlers ) { for ( const handler of this . _builder . handlers [ eventType ] ) { this . _hostBuilder . on ( eventType , ( ... args ) => handler . apply ( this . _client , args ) ) ; } } for ( const attr of this . _builder . sandboxAttrs ) { this . _hostBuilder . withSandboxAttribute ( attr ) ; } this . _host = this . _hostBuilder . frameBorder ( this . _builder . frameBorder ) . withTargetOrigin ( this . targetOrigin ) . appendTo ( this . _builder . el ) . build ( ) ; if ( this . _builder . classNames . length ) { this . _host . iframe . classList . add ( ... this . _builder . classNames ) ; } return this . _host . connect ( ) . then ( ( host ) => { this . _client = new this . _builder . clientConstructor ( host ) ; return this . _client ; } ) ; } private async createUrl ( ) { const src = this . _builder . embedUrl ; const auth = this . _builder . auth ; if ( ! auth ?. url ) return `${ this . _builder . apiHost }${ src }` ; let url = `${ auth . url }?src=${ encodeURIComponent ( src ) }` ; if ( auth . params ) { for ( const param of auth . params ) { url += `&${ encodeURIComponent ( param . name ) }=${ encodeURIComponent ( param . value ) }` ; } } return new Promise < string > ( async ( resolve , reject ) => { const xhr = new XMLHttpRequest ( ) ; xhr . open ( 'GET' , url ) ; if ( auth . withCredentials ) { xhr . withCredentials = auth . withCredentials ; } xhr . setRequestHeader ( 'Cache-Control' , 'no-cache' ) ; if ( auth . headers ) { for ( const header of auth . headers ) { xhr . setRequestHeader ( header . name , header . value ) ; } } xhr . onload = ( ) => { if ( xhr . status === 200 ) { resolve ( JSON . parse ( xhr . responseText ) . url ) ; } else { reject ( xhr . statusText ) ; } } ; xhr . onerror = ( ) => reject ( xhr . statusText ) ; xhr . send ( ) ; } ) ; } /**
     * Establish two way communication with embedded content. Returns a promise that resolves to a
     * client that can be used to send messages to the embedded content.
     */ async connect ( ) { if ( this . _connection ) return this . _connection ; if ( this . _builder . url ) { this . _connection = this . createIframe ( this . _builder . url ) ; } else { this . _connection = this . createUrl ( ) . then ( async ( url ) => this . createIframe ( url ) ) ; } return this . _connection ; } }