Merge pull request #12955 from ahocevar/mapbox-vector-layer

Make MapboxVector layer work in more access key scenarios
This commit is contained in:
Andreas Hocevar
2021-11-03 13:45:17 +01:00
committed by GitHub
2 changed files with 67 additions and 9 deletions
+41 -7
View File
@@ -92,13 +92,19 @@ export function normalizeStyleUrl(url, token) {
* Turns mapbox:// source URLs into vector tile URL templates. * Turns mapbox:// source URLs into vector tile URL templates.
* @param {string} url The source URL. * @param {string} url The source URL.
* @param {string} token The access token. * @param {string} token The access token.
* @param {string} tokenParam The access token key.
* @return {string} A vector tile template. * @return {string} A vector tile template.
* @private * @private
*/ */
export function normalizeSourceUrl(url, token) { export function normalizeSourceUrl(url, token, tokenParam) {
const mapboxPath = getMapboxPath(url); const mapboxPath = getMapboxPath(url);
if (!mapboxPath) { if (!mapboxPath) {
return url; if (!token) {
return url;
}
const urlObject = new URL(url, location.href);
urlObject.searchParams.set(tokenParam, token);
return decodeURI(urlObject.href);
} }
return `https://{a-d}.tiles.mapbox.com/v4/${mapboxPath}/{z}/{x}/{y}.vector.pbf?access_token=${token}`; return `https://{a-d}.tiles.mapbox.com/v4/${mapboxPath}/{z}/{x}/{y}.vector.pbf?access_token=${token}`;
} }
@@ -133,6 +139,7 @@ class ErrorEvent extends BaseEvent {
* @typedef {Object} SourceObject * @typedef {Object} SourceObject
* @property {string} url The source URL. * @property {string} url The source URL.
* @property {SourceType} type The source type. * @property {SourceType} type The source type.
* @property {Array<string>} [tiles] TileJSON tiles.
*/ */
/** /**
@@ -155,8 +162,8 @@ const SourceType = {
* style created with Mapbox Studio and hosted on Mapbox, this will look like * style created with Mapbox Studio and hosted on Mapbox, this will look like
* 'mapbox://styles/you/your-style'. * 'mapbox://styles/you/your-style'.
* @property {string} [accessToken] The access token for your Mapbox style. This has to be provided * @property {string} [accessToken] The access token for your Mapbox style. This has to be provided
* for `mapbox://` style urls. For `https://` and other urls, access keys must be part of the style * for `mapbox://` style urls. For `https://` and other urls, any access key must be the last query
* url. * parameter of the style url.
* @property {string} [source] If your style uses more than one source, you need to use either the * @property {string} [source] If your style uses more than one source, you need to use either the
* `source` property or the `layers` property to limit rendering to a single vector source. The * `source` property or the `layers` property to limit rendering to a single vector source. The
* `source` property corresponds to the id of a vector source in your Mapbox style. * `source` property corresponds to the id of a vector source in your Mapbox style.
@@ -284,7 +291,16 @@ class MapboxVectorLayer extends VectorTileLayer {
this.sourceId = options.source; this.sourceId = options.source;
this.layers = options.layers; this.layers = options.layers;
this.accessToken = options.accessToken; if (options.accessToken) {
this.accessToken = options.accessToken;
} else {
const url = new URL(options.styleUrl, location.href);
// The last search parameter is the access token
url.searchParams.forEach((value, key) => {
this.accessToken = value;
this.accessTokenParam_ = key;
});
}
this.fetchStyle(options.styleUrl); this.fetchStyle(options.styleUrl);
} }
@@ -384,7 +400,13 @@ class MapboxVectorLayer extends VectorTileLayer {
styleSource.url.indexOf('{z}') !== -1 styleSource.url.indexOf('{z}') !== -1
) { ) {
// Tile source url, handle it directly // Tile source url, handle it directly
source.setUrl(normalizeSourceUrl(styleSource.url, this.accessToken)); source.setUrl(
normalizeSourceUrl(
styleSource.url,
this.accessToken,
this.accessTokenParam_
)
);
applyStyle(this, style, sourceIdOrLayersList) applyStyle(this, style, sourceIdOrLayersList)
.then(() => { .then(() => {
source.setState(SourceState.READY); source.setState(SourceState.READY);
@@ -394,7 +416,19 @@ class MapboxVectorLayer extends VectorTileLayer {
}); });
} else { } else {
// TileJSON url, let ol-mapbox-style handle it // TileJSON url, let ol-mapbox-style handle it
setupVectorSource(styleSource, styleSource.url).then((source) => { if (styleSource.tiles) {
styleSource.tiles = styleSource.tiles.map((url) =>
normalizeSourceUrl(url, this.accessToken, this.accessTokenParam_)
);
}
setupVectorSource(
styleSource,
normalizeSourceUrl(
styleSource.url,
this.accessToken,
this.accessTokenParam_
)
).then((source) => {
applyStyle(this, style, sourceIdOrLayersList) applyStyle(this, style, sourceIdOrLayersList)
.then(() => { .then(() => {
this.setSource(source); this.setSource(source);
@@ -80,14 +80,20 @@ describe('ol/layer/MapboxVector', () => {
}, },
{ {
url: 'https://example.com/source/{z}/{x}/{y}.pbf', url: 'https://example.com/source/{z}/{x}/{y}.pbf',
expected: 'https://example.com/source/{z}/{x}/{y}.pbf', expected: 'https://example.com/source/{z}/{x}/{y}.pbf?token=test-token',
},
{
url: 'https://example.com/source/{z}/{x}/{y}.pbf?foo=bar',
expected:
'https://example.com/source/{z}/{x}/{y}.pbf?foo=bar&token=test-token',
}, },
]; ];
const token = 'test-token'; const token = 'test-token';
const tokenParam = 'token';
for (const c of cases) { for (const c of cases) {
it(`works for ${c.url}`, () => { it(`works for ${c.url}`, () => {
expect(normalizeSourceUrl(c.url, token)).to.be(c.expected); expect(normalizeSourceUrl(c.url, token, tokenParam)).to.be(c.expected);
}); });
} }
}); });
@@ -116,4 +122,22 @@ describe('ol/layer/MapboxVector', () => {
}); });
}); });
}); });
describe('Access token', function () {
it('applies correct access token from access_token', function () {
const layer = new MapboxVectorLayer({
styleUrl: 'mapbox://styles/mapbox/streets-v7',
accessToken: '123',
});
expect(layer.accessToken).to.be('123');
expect(layer.accessTokenParam_).to.be(undefined);
});
it('applies correct access token from url', function () {
const layer = new MapboxVectorLayer({
styleUrl: 'foo?key=123',
});
expect(layer.accessToken).to.be('123');
expect(layer.accessTokenParam_).to.be('key');
});
});
}); });