UNPKG

google-maps-promise

Version:

Wrapper for asynchronously load Google Maps API with Promise.

254 lines (218 loc) 4.73 kB
// Wrapper for asynchronously load Google Maps API with Promise. /// <reference types="googlemaps" /> /** * Default settings used to build URL. */ const defaultUrlSettings: Readonly<UrlSettings> = { url: 'https://maps.googleapis.com/maps/api/js', key: null, client: null, version: '3.32', channel: null, libraries: [], language: null, region: null, windowCallbackName: '__google_maps_api_provider_initializator__', }; /** * Window object with any property. */ const windowWithAnything = window as any; /** * Current settings used to build URL. */ let urlSettings: UrlSettings = Object.assign( {}, defaultUrlSettings ); /** * Function to resolve promise. */ let resolvePromise: ( maps: typeof google.maps ) => void; /** * Function to reject promise. */ let rejectPromise: ( error: Error ) => void; /** * API loading Promise. */ let promise: Promise<typeof google.maps>; /** * Is loading process already executed? */ let loaded: boolean; /** * Script element used to load API. */ let scriptElement: HTMLScriptElement | null; init(); /** * Asynchronously load Google Maps API. * * @returns Promise with `google.maps` object. */ function load(): Promise<typeof google.maps> { if ( !loaded ) { loaded = true; createLoader(); } return promise; } /** * Remove scripts and variables and reset settings. * * @returns When it's done. */ function release(): Promise<void> { if ( !loaded ) { cleanupEnvironment(); return Promise.resolve(); } return promise.then( cleanupEnvironment ); } /** * Initialize variables. */ function init(): void { urlSettings = Object.assign( {}, defaultUrlSettings ); loaded = false; promise = new Promise<typeof google.maps>( ( resolve, reject ): void => { resolvePromise = resolve; rejectPromise = reject; }, ); } /** * Create API loader script. */ function createLoader(): void { if ( windowWithAnything.google && windowWithAnything.google.maps ) { resolvePromise( windowWithAnything.google.maps ); return; } const onError = () => rejectPromise( new URIError( `The script ${scriptElement && scriptElement.src} is not accessible.`, ), ); scriptElement = document.createElement( 'script' ); scriptElement.type = 'text/javascript'; scriptElement.src = createUrl(); scriptElement.onerror = onError; windowWithAnything[urlSettings.windowCallbackName] = () => resolvePromise( windowWithAnything.google.maps ); document.body.appendChild( scriptElement ); } /** * Create URL address to API. * * @returns URL address. */ function createUrl(): string { const parts: string[] = [ 'callback=' + ( urlSettings.windowCallbackName || defaultUrlSettings.windowCallbackName ), ]; if ( urlSettings.key ) { parts.push( 'key=' + urlSettings.key ); } if ( urlSettings.client ) { parts.push( 'client=' + urlSettings.client, 'v=' + ( urlSettings.version || defaultUrlSettings.version ), ); } else if ( urlSettings.version ) { parts.push( 'v=' + urlSettings.version ); } if ( urlSettings.channel ) { parts.push( 'channel=' + urlSettings.channel ); } if ( urlSettings.libraries.length > 0 ) { parts.push( 'libraries=' + urlSettings.libraries.join( ',' ) ); } if ( urlSettings.language ) { parts.push( 'language=' + urlSettings.language ); } if ( urlSettings.region ) { parts.push( 'region=' + urlSettings.region ); } return `${urlSettings.url || defaultUrlSettings.url}?${parts.join( '&' )}`; } /** * Reset settings and variables */ function cleanupEnvironment(): void { init(); if ( typeof windowWithAnything.google !== 'undefined' ) { delete windowWithAnything.google; } if ( typeof windowWithAnything[urlSettings.windowCallbackName] !== 'undefined' ) { delete windowWithAnything[urlSettings.windowCallbackName]; } if ( scriptElement ) { if ( scriptElement.parentElement ) { scriptElement.parentElement.removeChild( scriptElement ); } scriptElement = null; } } /** * Settings used to build URL. */ export interface UrlSettings { /** Base URL address to Google Maps JS API */ url: string; /** API key */ key: string | null; /** Client ID for Premium Plan */ client: string | null; /** Required version of the API */ version: string | null; /** Application channel for Premium Plan */ channel: string | null; /** Additional libraries to load */ libraries: string[]; /** Force map language */ language: string | null; /** Biasing API results towards the region */ region: string | null; /** Name of callback function in global space */ windowCallbackName: string; } /** * Module. */ export { load, release, urlSettings, defaultUrlSettings, // UrlSettings, };