diff --git a/.eslintrc.json b/.eslintrc.json index 9b9141d..8b4be5a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,6 +5,6 @@ "es2021": true }, "settings": { - "polyfills": ["URL", "Promise", "navigator", "Uint8Array", "performance", "location.hostname"] + "polyfills": ["URL", "Promise", "navigator", "Uint8Array", "performance", "location.hostname", "document.body"] } } diff --git a/js/util/MaplibreGlLazyLoader.js b/js/util/MaplibreGlLazyLoader.js index 05a1969..362f426 100644 --- a/js/util/MaplibreGlLazyLoader.js +++ b/js/util/MaplibreGlLazyLoader.js @@ -1,68 +1,102 @@ -/** - * Only load Maplibre bundles when layer is actually added, using dynamic imports - */ -BR.MaplibreGlLazyLoader = L.Layer.extend({ - initialize: function (options) { - this.options = options; - }, +(function () { + // import() uses path relative to calling script, script injection relative to index.html, + // so figure out script-relative path without hard-coding it (only as fallback) for the latter + // eslint-disable-next-line + const baseUrl = document.currentScript?.src.split('/').slice(0, -1).join('/') || window.location.origin + '/dist'; + const getAbsoluteScriptUrl = (src) => new URL(src, baseUrl + '/').href; - onAdd: function (map) { - if (!('maplibreGL' in L)) { - this._load(); - } else { - this._addGlLayer(); - } - return this; - }, - - onRemove: function (map) { - this._map.removeLayer(this.glLayer); - this.glLayer = null; - return this; - }, - - // needed when overlay, also requires `position: absolute` (see css) - setZIndex: function (zIndex) { - this.options.zIndex = zIndex; - return this; - }, - - setOpacity: function (opacity) { - if (this.glLayer) { - const glMap = this.glLayer.getMaplibreMap(); - if (glMap.getLayer('hillshading')) { - glMap.setPaintProperty('hillshading', 'hillshade-exaggeration', opacity); - } else { - glMap.getCanvas().style.opacity = opacity; + // simple custom import() polyfill that doesn't need module support and can't load modules + // (derived from various sources) + function importPolyfill(src) { + return new Promise((resolve, reject) => { + try { + // `import` is a reserved keyword even in old browsers not supporting it, + // so it needs to be evaluated at runtime, otherwise causes a parse error on load + new Function('return import("' + src + '")')().then(() => resolve()); + } catch (e) { + const url = getAbsoluteScriptUrl(src); + var script = document.createElement('script'); + script.onload = () => { + resolve(); + }; + script.onerror = () => { + reject(new Error(`Error importing: "${url}"`)); + script.remove(); + }; + script.src = url; + document.body.appendChild(script); } - } - }, + }); + } - _load: async function () { - await import('./maplibre-gl.js'); - await import('./leaflet-maplibre-gl.js'); + /** + * Only load Maplibre bundles when layer is actually added, using dynamic imports + */ + BR.MaplibreGlLazyLoader = L.Layer.extend({ + initialize: function (options) { + this.options = options; + }, - this._addGlLayer(); - }, + onAdd: function (map) { + if (!('maplibreGL' in L)) { + this._load(); + } else { + this._addGlLayer(); + } + return this; + }, - _addGlLayer: function () { - this.glLayer = L.maplibreGL(this.options); - // see LayersConfig.createLayer - this.glLayer.getAttribution = function () { - return this.options.mapLink; - }; - this._map.addLayer(this.glLayer); + onRemove: function (map) { + if (this.glLayer) { + this._map.removeLayer(this.glLayer); + } + this.glLayer = null; + return this; + }, - this._updateZIndex(); - }, + // needed when overlay, also requires `position: absolute` (see css) + setZIndex: function (zIndex) { + this.options.zIndex = zIndex; + return this; + }, - _updateZIndex: function () { - if (this.glLayer && this.glLayer.getContainer() && this.options.zIndex != null) { - this.glLayer.getContainer().style.zIndex = this.options.zIndex; - } - }, -}); + setOpacity: function (opacity) { + if (this.glLayer) { + const glMap = this.glLayer.getMaplibreMap(); + if (glMap.getLayer('hillshading')) { + glMap.setPaintProperty('hillshading', 'hillshade-exaggeration', opacity); + } else { + glMap.getCanvas().style.opacity = opacity; + } + } + }, -BR.maplibreGlLazyLoader = function (options) { - return new BR.MaplibreGlLazyLoader(options); -}; + _load: async function () { + await importPolyfill('./maplibre-gl.js'); + await importPolyfill('./leaflet-maplibre-gl.js'); + + this._addGlLayer(); + }, + + _addGlLayer: function () { + this.glLayer = L.maplibreGL(this.options); + // see LayersConfig.createLayer + this.glLayer.getAttribution = function () { + return this.options.mapLink; + }; + this._map.addLayer(this.glLayer); + + this._updateZIndex(); + }, + + _updateZIndex: function () { + if (this.glLayer && this.glLayer.getContainer() && this.options.zIndex != null) { + this.glLayer.getContainer().style.zIndex = this.options.zIndex; + } + }, + }); + + BR.maplibreGlLazyLoader = function (options) { + return new BR.MaplibreGlLazyLoader(options); + }; +})(); diff --git a/package.json b/package.json index ed36344..b3c261a 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "> 0.5%", "last 2 versions", "Firefox ESR", + "Firefox >= 56", "not dead", "Explorer >= 10", "Android >= 4.1", @@ -44,6 +45,7 @@ "@maplibre/maplibre-gl-leaflet": "^0.0.17", "@turf/turf": "^6.2.0", "Leaflet.vector-markers": "nrenner/Leaflet.vector-markers#2ef80c9", + "abortcontroller-polyfill": "^1.7.3", "async": "~2.6.0", "bootbox": "~5.5.2", "bootstrap": "4.6.1", @@ -380,6 +382,11 @@ "dist/maplibre-gl.js.map", "dist/maplibre-gl.css" ] + }, + "abortcontroller-polyfill": { + "main": [ + "dist/polyfill-patch-fetch.js" + ] } } } diff --git a/yarn.lock b/yarn.lock index 82847f5..2891958 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3418,6 +3418,11 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abortcontroller-polyfill@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz#1b5b487bd6436b5b764fd52a612509702c3144b5" + integrity sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q== + accepts@~1.3.4: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"