diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index 1b9b66073a..5deadfa72f 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -12,6 +12,18 @@ import proj4 from 'proj4'; ol.proj.setProj4(proj4); ``` +#### `ol.source.TileJSON` changes + +The `ol.source.TileJSON` now uses `XmlHttpRequest` to load the TileJSON instead of JSONP with callback. +When using server without proper CORS support, `jsonp: true` option can be passed to the constructor to get the same behavior as before: +```js +new ol.source.TileJSON({ + url: 'http://serverwithoutcors.com/tilejson.json', + jsonp: true +}) +``` +Also for Mapbox v3, make sure you use urls ending with `.json` (which are able to handle both `XmlHttpRequest` and JSONP) instead of `.jsonp`. + ### v3.12.0 #### `ol.Map#forEachFeatureAtPixel` changes diff --git a/examples/custom-interactions.js b/examples/custom-interactions.js index 5ca3b305b4..5c659ef00e 100644 --- a/examples/custom-interactions.js +++ b/examples/custom-interactions.js @@ -158,7 +158,7 @@ var map = new ol.Map({ layers: [ new ol.layer.Tile({ source: new ol.source.TileJSON({ - url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.jsonp' + url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.json' }) }), new ol.layer.Vector({ diff --git a/examples/icon.js b/examples/icon.js index 5ef4099a7c..1f2a74332a 100644 --- a/examples/icon.js +++ b/examples/icon.js @@ -40,7 +40,7 @@ var vectorLayer = new ol.layer.Vector({ var rasterLayer = new ol.layer.Tile({ source: new ol.source.TileJSON({ - url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.jsonp', + url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.json', crossOrigin: '' }) }); diff --git a/examples/layer-extent.js b/examples/layer-extent.js index cee45691af..474469d4da 100644 --- a/examples/layer-extent.js +++ b/examples/layer-extent.js @@ -19,7 +19,7 @@ var extents = { var base = new ol.layer.Tile({ source: new ol.source.TileJSON({ url: 'http://api.tiles.mapbox.com/v3/' + - 'mapbox.world-black.jsonp', + 'mapbox.world-black.json', crossOrigin: 'anonymous' }) }); @@ -28,7 +28,7 @@ var overlay = new ol.layer.Tile({ extent: extents.northwest, source: new ol.source.TileJSON({ url: 'http://api.tiles.mapbox.com/v3/' + - 'mapbox.world-glass.jsonp', + 'mapbox.world-glass.json', crossOrigin: 'anonymous' }) }); diff --git a/examples/layer-group.js b/examples/layer-group.js index f3e6f1400b..e2342beaaf 100644 --- a/examples/layer-group.js +++ b/examples/layer-group.js @@ -15,14 +15,14 @@ var map = new ol.Map({ new ol.layer.Tile({ source: new ol.source.TileJSON({ url: 'http://api.tiles.mapbox.com/v3/' + - 'mapbox.20110804-hoa-foodinsecurity-3month.jsonp', + 'mapbox.20110804-hoa-foodinsecurity-3month.json', crossOrigin: 'anonymous' }) }), new ol.layer.Tile({ source: new ol.source.TileJSON({ url: 'http://api.tiles.mapbox.com/v3/' + - 'mapbox.world-borders-light.jsonp', + 'mapbox.world-borders-light.json', crossOrigin: 'anonymous' }) }) diff --git a/examples/min-max-resolution.js b/examples/min-max-resolution.js index f251269708..b91cf77fca 100644 --- a/examples/min-max-resolution.js +++ b/examples/min-max-resolution.js @@ -19,7 +19,7 @@ var map = new ol.Map({ new ol.layer.Tile({ source: new ol.source.TileJSON({ url: 'http://api.tiles.mapbox.com/v3/' + - 'mapbox.natural-earth-hypso-bathy.jsonp', + 'mapbox.natural-earth-hypso-bathy.json', crossOrigin: 'anonymous' }), minResolution: 2000, diff --git a/examples/popup.js b/examples/popup.js index fe619a2db6..2afbbd125d 100644 --- a/examples/popup.js +++ b/examples/popup.js @@ -46,7 +46,7 @@ var map = new ol.Map({ new ol.layer.Tile({ source: new ol.source.TileJSON({ url: 'http://api.tiles.mapbox.com/v3/' + - 'mapbox.natural-earth-hypso-bathy.jsonp', + 'mapbox.natural-earth-hypso-bathy.json', crossOrigin: 'anonymous' }) }) diff --git a/examples/semi-transparent-layer.js b/examples/semi-transparent-layer.js index 9582046b24..c7022d1f49 100644 --- a/examples/semi-transparent-layer.js +++ b/examples/semi-transparent-layer.js @@ -13,7 +13,7 @@ var map = new ol.Map({ }), new ol.layer.Tile({ source: new ol.source.TileJSON({ - url: 'http://api.tiles.mapbox.com/v3/mapbox.va-quake-aug.jsonp', + url: 'http://api.tiles.mapbox.com/v3/mapbox.va-quake-aug.json', crossOrigin: 'anonymous' }) }) diff --git a/examples/tile-load-events.js b/examples/tile-load-events.js index b6610b0327..b4da086502 100644 --- a/examples/tile-load-events.js +++ b/examples/tile-load-events.js @@ -79,7 +79,7 @@ Progress.prototype.hide = function() { var progress = new Progress(document.getElementById('progress')); var source = new ol.source.TileJSON({ - url: 'http://api.tiles.mapbox.com/v3/mapbox.world-bright.jsonp', + url: 'http://api.tiles.mapbox.com/v3/mapbox.world-bright.json', crossOrigin: 'anonymous' }); diff --git a/examples/tilejson.js b/examples/tilejson.js index 4483f0e43c..14c2f02c39 100644 --- a/examples/tilejson.js +++ b/examples/tilejson.js @@ -8,7 +8,7 @@ var map = new ol.Map({ layers: [ new ol.layer.Tile({ source: new ol.source.TileJSON({ - url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.jsonp', + url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.json', crossOrigin: 'anonymous' }) }) diff --git a/examples/topojson.js b/examples/topojson.js index 7d226d672f..6f2a6d84d8 100644 --- a/examples/topojson.js +++ b/examples/topojson.js @@ -12,7 +12,7 @@ goog.require('ol.style.Style'); var raster = new ol.layer.Tile({ source: new ol.source.TileJSON({ - url: 'http://api.tiles.mapbox.com/v3/mapbox.world-dark.jsonp' + url: 'http://api.tiles.mapbox.com/v3/mapbox.world-dark.json' }) }); diff --git a/externs/olx.js b/externs/olx.js index 24da980b50..5b9b418418 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -5206,10 +5206,10 @@ olx.source.TileArcGISRestOptions.prototype.urls; /** * @typedef {{attributions: (Array.|undefined), * crossOrigin: (null|string|undefined), + * jsonp: (boolean|undefined), * reprojectionErrorThreshold: (number|undefined), * tileLoadFunction: (ol.TileLoadFunctionType|undefined), * url: string, - * useXhr: (boolean|undefined), * wrapX: (boolean|undefined)}} * @api */ @@ -5238,6 +5238,15 @@ olx.source.TileJSONOptions.prototype.attributions; olx.source.TileJSONOptions.prototype.crossOrigin; +/** + * Use JSONP with callback to load the TileJSON. Useful when the server + * does not support CORS. Default is `false`. + * @type {boolean|undefined} + * @api + */ +olx.source.TileJSONOptions.prototype.jsonp; + + /** * Maximum allowed reprojection error (in pixels). Default is `0.5`. * Higher values can increase reprojection performance, but decrease precision. @@ -5263,14 +5272,6 @@ olx.source.TileJSONOptions.prototype.tileLoadFunction; olx.source.TileJSONOptions.prototype.url; -/** - * Use XmlHttpRequest to load the TileJSON. Default is `false`. - * @type {boolean|undefined} - * @api - */ -olx.source.TileJSONOptions.prototype.useXhr; - - /** * Whether to wrap the world horizontally. Default is `true`. * @type {boolean|undefined} diff --git a/src/ol/source/tilejsonsource.js b/src/ol/source/tilejsonsource.js index 53377a8c3a..16e744bf22 100644 --- a/src/ol/source/tilejsonsource.js +++ b/src/ol/source/tilejsonsource.js @@ -8,6 +8,9 @@ goog.provide('ol.source.TileJSON'); goog.provide('ol.tilejson'); goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.net.CorsXmlHttpFactory'); +goog.require('goog.net.EventType'); goog.require('goog.net.Jsonp'); goog.require('goog.net.XhrIo'); goog.require('ol.Attribution'); @@ -41,20 +44,22 @@ ol.source.TileJSON = function(options) { wrapX: options.wrapX !== undefined ? options.wrapX : true }); - if (options.useXhr) { - goog.net.XhrIo.send(options.url, goog.bind(function(e) { - var xhr = /** @type {goog.net.XhrIo} */(e.target); + if (options.jsonp) { + var request = new goog.net.Jsonp(options.url); + request.send(undefined, goog.bind(this.handleTileJSONResponse, this), + goog.bind(this.handleTileJSONError, this)); + } else { + var xhr = new goog.net.XhrIo(new goog.net.CorsXmlHttpFactory()); + goog.events.listen(xhr, goog.net.EventType.COMPLETE, function(e) { if (xhr.isSuccess()) { var response = /** @type {TileJSON} */(xhr.getResponseJson()); this.handleTileJSONResponse(response); } else { this.handleTileJSONError(); } - }, this)); - } else { - var request = new goog.net.Jsonp(options.url); - request.send(undefined, goog.bind(this.handleTileJSONResponse, this), - goog.bind(this.handleTileJSONError, this)); + xhr.dispose(); + }, false, this); + xhr.send(options.url); } }; diff --git a/test/spec/ol/source/tilejsonsource.test.js b/test/spec/ol/source/tilejsonsource.test.js index 68ee73caa2..2fec2c3d43 100644 --- a/test/spec/ol/source/tilejsonsource.test.js +++ b/test/spec/ol/source/tilejsonsource.test.js @@ -21,23 +21,9 @@ describe('ol.source.TileJSON', function() { var source, tileGrid; beforeEach(function(done) { - var googNetJsonp = goog.net.Jsonp; - // mock goog.net.Jsonp (used in the ol.source.TileJSON constructor) - goog.net.Jsonp = function() { - this.send = function() { - var callback = arguments[1]; - var client = new XMLHttpRequest(); - client.open('GET', 'spec/ol/data/tilejson.json', true); - client.onload = function() { - callback(JSON.parse(client.responseText)); - }; - client.send(); - }; - }; source = new ol.source.TileJSON({ - url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.jsonp' + url: 'spec/ol/data/tilejson.json' }); - goog.net.Jsonp = googNetJsonp; var key = source.on('change', function() { if (source.getState() === 'ready') { ol.Observable.unByKey(key); @@ -88,7 +74,6 @@ describe('ol.source.TileJSON', function() { }); goog.require('goog.events'); -goog.require('goog.net.Jsonp'); goog.require('ol.source.State'); goog.require('ol.source.TileJSON'); goog.require('ol.Observable');