|
1 | 1 | const BASE_URL = 'https://maps';
|
2 | 2 | const DEFAULT_URL = `${BASE_URL}.googleapis.com`;
|
3 |
| -const API_PATH = '/maps/api/js?callback=googleMapsAPILoadedPromise'; |
4 |
| -const EVENT_GMAPS_LOADED = 'EVENT_GMAPS_LOADED'; |
| 3 | +const API_PATH = '/maps/api/js?callback=_$_google_map_initialize_$_'; |
5 | 4 |
|
6 |
| -const getBaseUrl = region => { |
| 5 | +const getUrl = region => { |
7 | 6 | if (region && region.toLowerCase() === 'cn') {
|
8 | 7 | return `${BASE_URL}.google.cn`;
|
9 | 8 | }
|
10 | 9 | return DEFAULT_URL;
|
11 | 10 | };
|
12 | 11 |
|
13 |
| -let currentResolver = null; |
14 |
| -let lastBaseUrl = ''; |
15 |
| -let lastScriptUrl = ''; |
16 |
| -let googleMapsPromise; |
| 12 | +let $script_ = null; |
17 | 13 |
|
18 |
| -const destroyOldGoogleMapsInstance = url => { |
19 |
| - document |
20 |
| - .querySelectorAll(`script[src^='${url}']`) |
21 |
| - .forEach(script => script.remove()); |
22 |
| - if (window.google) delete window.google.maps; |
23 |
| -}; |
24 |
| - |
25 |
| -// Callback for the Google Maps API src |
26 |
| -window.googleMapsAPILoadedPromise = () => |
27 |
| - window.dispatchEvent(new CustomEvent(EVENT_GMAPS_LOADED)); |
28 |
| - |
29 |
| -const getScriptUrl = bootstrapURLKeys => { |
30 |
| - const baseUrl = getBaseUrl(bootstrapURLKeys.region); |
31 |
| - const params = Object.keys(bootstrapURLKeys).reduce( |
32 |
| - (r, key) => `${r}&${key}=${bootstrapURLKeys[key]}`, |
33 |
| - '' |
34 |
| - ); |
35 |
| - return `${baseUrl}${API_PATH}${params}`; |
36 |
| -}; |
| 14 | +let loadPromise_; |
37 | 15 |
|
38 |
| -const loadScript = url => { |
39 |
| - const script = document.createElement('script'); |
| 16 | +let resolveCustomPromise_; |
40 | 17 |
|
41 |
| - script.type = 'text/javascript'; |
42 |
| - script.async = true; |
43 |
| - script.src = url; |
44 |
| - document.querySelector('head').appendChild(script); |
| 18 | +const _customPromise = new Promise(resolve => { |
| 19 | + resolveCustomPromise_ = resolve; |
| 20 | +}); |
45 | 21 |
|
46 |
| - return new Promise(resolve => { |
47 |
| - if (currentResolver) { |
48 |
| - window.removeEventListener(EVENT_GMAPS_LOADED, currentResolver); |
49 |
| - } |
50 |
| - currentResolver = () => { |
51 |
| - resolve(); |
52 |
| - }; |
53 |
| - window.addEventListener(EVENT_GMAPS_LOADED, currentResolver); |
54 |
| - }); |
55 |
| -}; |
| 22 | +// TODO add libraries language and other map options |
| 23 | +export default (bootstrapURLKeys, heatmapLibrary) => { |
| 24 | + if (!$script_) { |
| 25 | + $script_ = require('scriptjs'); // eslint-disable-line |
| 26 | + } |
56 | 27 |
|
57 |
| -const loadGoogleMaps = bootstrapURLKeys => |
58 |
| - new Promise(async resolve => { |
59 |
| - lastScriptUrl = getScriptUrl(bootstrapURLKeys); |
60 |
| - await loadScript(lastScriptUrl); |
61 |
| - resolve(window.google.maps); |
62 |
| - }); |
| 28 | + // call from outside google-map-react |
| 29 | + // will be as soon as loadPromise_ resolved |
| 30 | + if (!bootstrapURLKeys) { |
| 31 | + return _customPromise; |
| 32 | + } |
63 | 33 |
|
64 |
| -export default bootstrapURLKeys => { |
65 |
| - if (typeof window === 'undefined') { |
66 |
| - throw new Error('google map cannot be loaded outside browser env'); |
| 34 | + if (loadPromise_) { |
| 35 | + return loadPromise_; |
67 | 36 | }
|
68 | 37 |
|
69 |
| - if (process.env.NODE_ENV !== 'production') { |
70 |
| - if (Object.keys(bootstrapURLKeys).includes('callback')) { |
71 |
| - const message = `'callback' key in bootstrapURLKeys is not allowed, use onGoogleapiLoadedPromise property instead`; |
72 |
| - // eslint-disable-next-line no-console |
73 |
| - console.error(message); |
74 |
| - throw new Error(message); |
| 38 | + loadPromise_ = new Promise((resolve, reject) => { |
| 39 | + if (typeof window === 'undefined') { |
| 40 | + reject(new Error('google map cannot be loaded outside browser env')); |
| 41 | + return; |
75 | 42 | }
|
76 |
| - } |
77 |
| - if (googleMapsPromise) { |
78 |
| - if (lastScriptUrl !== getScriptUrl(bootstrapURLKeys)) { |
79 |
| - destroyOldGoogleMapsInstance(lastBaseUrl); |
80 |
| - googleMapsPromise = loadGoogleMaps(bootstrapURLKeys); |
| 43 | + |
| 44 | + if (window.google && window.google.maps) { |
| 45 | + resolve(window.google.maps); |
| 46 | + return; |
81 | 47 | }
|
82 |
| - return googleMapsPromise; |
83 |
| - } |
84 | 48 |
|
85 |
| - googleMapsPromise = loadGoogleMaps(bootstrapURLKeys); |
86 |
| - lastBaseUrl = getBaseUrl(bootstrapURLKeys.region); |
| 49 | + if (typeof window._$_google_map_initialize_$_ !== 'undefined') { |
| 50 | + reject(new Error('google map initialization error')); |
| 51 | + } |
| 52 | + |
| 53 | + window._$_google_map_initialize_$_ = () => { |
| 54 | + delete window._$_google_map_initialize_$_; |
| 55 | + resolve(window.google.maps); |
| 56 | + }; |
| 57 | + |
| 58 | + if (process.env.NODE_ENV !== 'production') { |
| 59 | + if (Object.keys(bootstrapURLKeys).indexOf('callback') > -1) { |
| 60 | + const message = `"callback" key in bootstrapURLKeys is not allowed, |
| 61 | + use onGoogleApiLoaded property instead`; |
| 62 | + // eslint-disable-next-line no-console |
| 63 | + console.error(message); |
| 64 | + throw new Error(message); |
| 65 | + } |
| 66 | + } |
| 67 | + |
| 68 | + const params = Object.keys(bootstrapURLKeys).reduce( |
| 69 | + (r, key) => `${r}&${key}=${bootstrapURLKeys[key]}`, |
| 70 | + '' |
| 71 | + ); |
| 72 | + |
| 73 | + const baseUrl = getUrl(bootstrapURLKeys.region); |
| 74 | + const libraries = heatmapLibrary ? '&libraries=visualization' : ''; |
| 75 | + |
| 76 | + $script_( |
| 77 | + `${baseUrl}${API_PATH}${params}${libraries}`, |
| 78 | + () => |
| 79 | + typeof window.google === 'undefined' && |
| 80 | + reject(new Error('google map initialization error (not loaded)')) |
| 81 | + ); |
| 82 | + }); |
| 83 | + |
| 84 | + resolveCustomPromise_(loadPromise_); |
87 | 85 |
|
88 |
| - return googleMapsPromise; |
| 86 | + return loadPromise_; |
89 | 87 | };
|
0 commit comments