diff --git a/src/ol/layer/MapboxVector.js b/src/ol/layer/MapboxVector.js index 2fbab09e9b..fe7b65e929 100644 --- a/src/ol/layer/MapboxVector.js +++ b/src/ol/layer/MapboxVector.js @@ -35,13 +35,14 @@ export function getMapboxPath(url) { * Turns mapbox:// sprite URLs into resolvable URLs. * @param {string} url The sprite URL. * @param {string} token The access token. + * @param {string} styleUrl The style URL. * @return {string} A resolvable URL. * @private */ -export function normalizeSpriteUrl(url, token) { +export function normalizeSpriteUrl(url, token, styleUrl) { const mapboxPath = getMapboxPath(url); if (!mapboxPath) { - return url; + return decodeURI(new URL(url, styleUrl).href); } const startsWith = 'sprites/'; if (mapboxPath.indexOf(startsWith) !== 0) { @@ -56,13 +57,14 @@ export function normalizeSpriteUrl(url, token) { * Turns mapbox:// glyphs URLs into resolvable URLs. * @param {string} url The glyphs URL. * @param {string} token The access token. + * @param {string} styleUrl The style URL. * @return {string} A resolvable URL. * @private */ -export function normalizeGlyphsUrl(url, token) { +export function normalizeGlyphsUrl(url, token, styleUrl) { const mapboxPath = getMapboxPath(url); if (!mapboxPath) { - return url; + return decodeURI(new URL(url, styleUrl).href); } const startsWith = 'fonts/'; if (mapboxPath.indexOf(startsWith) !== 0) { @@ -83,7 +85,7 @@ export function normalizeGlyphsUrl(url, token) { export function normalizeStyleUrl(url, token) { const mapboxPath = getMapboxPath(url); if (!mapboxPath) { - return url; + return decodeURI(new URL(url, location.href).href); } const startsWith = 'styles/'; if (mapboxPath.indexOf(startsWith) !== 0) { @@ -99,16 +101,17 @@ export function normalizeStyleUrl(url, token) { * @param {string} url The source URL. * @param {string} token The access token. * @param {string} tokenParam The access token key. + * @param {string} styleUrl The style URL. * @return {string} A vector tile template. * @private */ -export function normalizeSourceUrl(url, token, tokenParam) { +export function normalizeSourceUrl(url, token, tokenParam, styleUrl) { + const urlObject = new URL(url, styleUrl); const mapboxPath = getMapboxPath(url); if (!mapboxPath) { if (!token) { - return url; + return decodeURI(urlObject.href); } - const urlObject = new URL(url, location.href); urlObject.searchParams.set(tokenParam, token); return decodeURI(urlObject.href); } @@ -336,7 +339,7 @@ class MapboxVectorLayer extends VectorTileLayer { return response.json(); }) .then((style) => { - this.onStyleLoad(style); + this.onStyleLoad(style, url.startsWith('data:') ? location.href : url); }) .catch((error) => { this.handleError(error); @@ -346,9 +349,10 @@ class MapboxVectorLayer extends VectorTileLayer { /** * Handle the loaded style object. * @param {StyleObject} style The loaded style. + * @param {string} styleUrl The URL of the style. * @protected */ - onStyleLoad(style) { + onStyleLoad(style, styleUrl) { let sourceId; let sourceIdOrLayersList; if (this.layers) { @@ -394,11 +398,19 @@ class MapboxVectorLayer extends VectorTileLayer { } if (style.sprite) { - style.sprite = normalizeSpriteUrl(style.sprite, this.accessToken); + style.sprite = normalizeSpriteUrl( + style.sprite, + this.accessToken, + styleUrl + ); } if (style.glyphs) { - style.glyphs = normalizeGlyphsUrl(style.glyphs, this.accessToken); + style.glyphs = normalizeGlyphsUrl( + style.glyphs, + this.accessToken, + styleUrl + ); } const styleSource = style.sources[sourceId]; @@ -416,7 +428,8 @@ class MapboxVectorLayer extends VectorTileLayer { normalizeSourceUrl( styleSource.url, this.accessToken, - this.accessTokenParam_ + this.accessTokenParam_, + styleUrl ) ); applyStyle(this, style, sourceIdOrLayersList) @@ -430,7 +443,12 @@ class MapboxVectorLayer extends VectorTileLayer { // TileJSON url, let ol-mapbox-style handle it if (styleSource.tiles) { styleSource.tiles = styleSource.tiles.map((url) => - normalizeSourceUrl(url, this.accessToken, this.accessTokenParam_) + normalizeSourceUrl( + url, + this.accessToken, + this.accessTokenParam_, + styleUrl + ) ); } setupVectorSource( @@ -439,7 +457,8 @@ class MapboxVectorLayer extends VectorTileLayer { ? normalizeSourceUrl( styleSource.url, this.accessToken, - this.accessTokenParam_ + this.accessTokenParam_, + styleUrl ) : undefined ).then((source) => { diff --git a/test/browser/spec/ol/layer/MapboxVector.test.js b/test/browser/spec/ol/layer/MapboxVector.test.js index 2862b40840..38b783597d 100644 --- a/test/browser/spec/ol/layer/MapboxVector.test.js +++ b/test/browser/spec/ol/layer/MapboxVector.test.js @@ -63,12 +63,30 @@ describe('ol/layer/MapboxVector', () => { url: 'https://example.com/sprite', expected: 'https://example.com/sprite', }, + { + url: '../sprite', + expected: 'https://example.com:8000/sprite', + }, + { + url: '/sprite', + expected: 'https://example.com:8000/sprite', + }, + { + url: './sprite', + expected: 'https://example.com:8000/mystyle/sprite', + }, ]; const token = 'test-token'; for (const c of cases) { it(`works for ${c.url}`, () => { - expect(normalizeSpriteUrl(c.url, token)).to.be(c.expected); + expect( + normalizeSpriteUrl( + c.url, + token, + 'https://example.com:8000/mystyle/style.json' + ) + ).to.be(c.expected); }); } });