diff --git a/Makefile b/Makefile index 3e9fb34c42..5ae4e9291f 100644 --- a/Makefile +++ b/Makefile @@ -181,7 +181,7 @@ build/timestamps/check-%-timestamp: $(BUILD_HOSTED)/examples/%.html \ $(BUILD_HOSTED)/build/ol.js \ $(BUILD_HOSTED)/css/ol.css @mkdir -p $(@D) - ./node_modules/.bin/phantomjs --ssl-protocol=any --ignore-ssl-errors=true bin/check-example.js $< + ./node_modules/.bin/phantomjs --local-to-remote-url-access=true --ssl-protocol=any --ignore-ssl-errors=true bin/check-example.js $< @touch $@ build/timestamps/check-requires-timestamp: $(SRC_JS) $(EXAMPLES_JS) \ diff --git a/src/ol/events/condition.js b/src/ol/events/condition.js index 514b67d004..c5c63f530a 100644 --- a/src/ol/events/condition.js +++ b/src/ol/events/condition.js @@ -86,7 +86,7 @@ ol.events.condition.click = function(mapBrowserEvent) { ol.events.condition.mouseActionButton = function(mapBrowserEvent) { var browserEvent = mapBrowserEvent.originalEvent; return browserEvent.button == 0 && - !(goog.userAgent.WEBKIT && goog.userAgent.MAC && browserEvent.ctrlKey); + !(goog.userAgent.WEBKIT && ol.has.MAC && browserEvent.ctrlKey); }; @@ -168,7 +168,7 @@ ol.events.condition.platformModifierKeyOnly = function(mapBrowserEvent) { var browserEvent = mapBrowserEvent.originalEvent; return ( !browserEvent.altKey && - (goog.userAgent.MAC ? browserEvent.metaKey : browserEvent.ctrlKey) && + (ol.has.MAC ? browserEvent.metaKey : browserEvent.ctrlKey) && !browserEvent.shiftKey); }; diff --git a/src/ol/featureloader.js b/src/ol/featureloader.js index 0945799344..ccc1e3cd68 100644 --- a/src/ol/featureloader.js +++ b/src/ol/featureloader.js @@ -3,10 +3,6 @@ goog.provide('ol.FeatureUrlFunction'); goog.provide('ol.featureloader'); goog.require('goog.asserts'); -goog.require('ol.events'); -goog.require('goog.net.EventType'); -goog.require('goog.net.XhrIo'); -goog.require('goog.net.XhrIo.ResponseType'); goog.require('ol.TileState'); goog.require('ol.VectorTile'); goog.require('ol.format.FormatType'); @@ -67,59 +63,46 @@ ol.featureloader.loadFeaturesXhr = function(url, format, success, failure) { * @this {ol.source.Vector|ol.VectorTile} */ function(extent, resolution, projection) { - var xhrIo = new goog.net.XhrIo(); - xhrIo.setResponseType( - format.getType() == ol.format.FormatType.ARRAY_BUFFER ? - goog.net.XhrIo.ResponseType.ARRAY_BUFFER : - goog.net.XhrIo.ResponseType.TEXT); - ol.events.listen(xhrIo, goog.net.EventType.COMPLETE, - /** - * @param {Event} event Event. - * @private - * @this {ol.source.Vector} - */ - function(event) { - var xhrIo = event.target; - goog.asserts.assertInstanceof(xhrIo, goog.net.XhrIo, - 'event.target/xhrIo is an instance of goog.net.XhrIo'); - if (xhrIo.isSuccess()) { - var type = format.getType(); - /** @type {Document|Node|Object|string|undefined} */ - var source; - if (type == ol.format.FormatType.JSON) { - source = xhrIo.getResponseText(); - } else if (type == ol.format.FormatType.TEXT) { - source = xhrIo.getResponseText(); - } else if (type == ol.format.FormatType.XML) { - if (!goog.userAgent.IE) { - source = xhrIo.getResponseXml(); - } - if (!source) { - source = ol.xml.parse(xhrIo.getResponseText()); - } - } else if (type == ol.format.FormatType.ARRAY_BUFFER) { - source = xhrIo.getResponse(); - } else { - goog.asserts.fail('unexpected format type'); - } - if (source) { - success.call(this, format.readFeatures(source, - {featureProjection: projection}), - format.readProjection(source)); - } else { - goog.asserts.fail('undefined or null source'); - } - } else { - failure.call(this); - } - goog.dispose(xhrIo); - }, false, this); - if (goog.isFunction(url)) { - xhrIo.send(url(extent, resolution, projection)); - } else { - xhrIo.send(url); + var xhr = new XMLHttpRequest(); + xhr.open('GET', + goog.isFunction(url) ? url(extent, resolution, projection) : url); + if (format.getType() == ol.format.FormatType.ARRAY_BUFFER) { + xhr.responseType = 'arraybuffer'; } - + /** + * @param {Event} event Event. + * @private + */ + xhr.onload = function(event) { + if (xhr.status < 400) { + var type = format.getType(); + /** @type {Document|Node|Object|string|undefined} */ + var source; + if (type == ol.format.FormatType.JSON || + type == ol.format.FormatType.TEXT) { + source = /** @type {string} */ (xhr.responseText); + } else if (type == ol.format.FormatType.XML) { + source = xhr.responseXML; + if (!source) { + source = ol.xml.parse(xhr.responseText); + } + } else if (type == ol.format.FormatType.ARRAY_BUFFER) { + source = /** @type {ArrayBuffer} */ (xhr.response); + } else { + goog.asserts.fail('unexpected format type'); + } + if (source) { + success.call(this, format.readFeatures(source, + {featureProjection: projection}), + format.readProjection(source)); + } else { + goog.asserts.fail('undefined or null source'); + } + } else { + failure.call(this); + } + }.bind(this); + xhr.send(); }); }; diff --git a/src/ol/has.js b/src/ol/has.js index 61d4d33199..95e407052c 100644 --- a/src/ol/has.js +++ b/src/ol/has.js @@ -20,6 +20,12 @@ ol.has.FIREFOX = ua.indexOf('firefox') !== -1; */ ol.has.SAFARI = ua.indexOf('safari') !== -1 && ua.indexOf('chrom') === -1; +/** + * User agent string says we are dealing with a Mac as platform. + * @type {boolean} + */ +ol.has.MAC = ua.indexOf('Macintosh') !== -1; + /** * The ratio between physical pixels and device-independent pixels diff --git a/src/ol/map.js b/src/ol/map.js index 5ad2974019..cee10e9489 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -6,7 +6,6 @@ goog.provide('ol.Map'); goog.provide('ol.MapProperty'); goog.require('goog.asserts'); -goog.require('goog.async.AnimationDelay'); goog.require('goog.async.nextTick'); goog.require('goog.debug.Console'); goog.require('goog.dom'); @@ -199,11 +198,17 @@ ol.Map = function(options) { /** * @private - * @type {goog.async.AnimationDelay} + * @type {number|undefined} */ - this.animationDelay_ = - new goog.async.AnimationDelay(this.renderFrame_, undefined, this); - this.registerDisposable(this.animationDelay_); + this.animationDelayKey_; + + /** + * @private + */ + this.animationDelay_ = function() { + this.animationDelayKey_ = undefined; + this.renderFrame_.call(this, Date.now()); + }.bind(this); /** * @private @@ -1200,7 +1205,10 @@ ol.Map.prototype.isRendered = function() { * @api stable */ ol.Map.prototype.renderSync = function() { - this.animationDelay_.fire(); + if (this.animationDelayKey_) { + goog.global.cancelAnimationFrame(this.animationDelayKey_); + } + this.animationDelay_(); }; @@ -1209,8 +1217,9 @@ ol.Map.prototype.renderSync = function() { * @api stable */ ol.Map.prototype.render = function() { - if (!this.animationDelay_.isActive()) { - this.animationDelay_.start(); + if (this.animationDelayKey_ === undefined) { + this.animationDelayKey_ = goog.global.requestAnimationFrame( + this.animationDelay_); } }; diff --git a/src/ol/net.js b/src/ol/net.js new file mode 100644 index 0000000000..ae890a991d --- /dev/null +++ b/src/ol/net.js @@ -0,0 +1,29 @@ +goog.provide('ol.net.Jsonp'); + + +/** + * @param {string} url Request url. A 'callback' query parameter will be + * appended. + * @param {Function} callback Callback on success. + * @param {function()=} opt_errback Callback on error. + * @param {string=} opt_callbackParam Callback parameter. Default is 'callback'. + */ +ol.net.Jsonp = function(url, callback, opt_errback, opt_callbackParam) { + var script = goog.global.document.createElement('script'); + script.async = true; + var key = 'ol_callback_' + goog.getUid(callback); + script.src = url + (url.indexOf('?') == -1 ? '?' : '&') + + (opt_callbackParam || 'callback') + '=' + key; + var timer = goog.global.setTimeout(function() { + delete goog.global[key]; + if (opt_errback) { + opt_errback(); + } + }, 10000); + goog.global[key] = function(data) { + goog.global.clearTimeout(timer); + delete goog.global[key]; + callback(data); + }; + goog.global.document.getElementsByTagName('head')[0].appendChild(script); +}; diff --git a/src/ol/source/bingmapssource.js b/src/ol/source/bingmapssource.js index dd5b8635ac..ba92981f67 100644 --- a/src/ol/source/bingmapssource.js +++ b/src/ol/source/bingmapssource.js @@ -1,12 +1,11 @@ goog.provide('ol.source.BingMaps'); -goog.require('goog.Uri'); goog.require('goog.asserts'); -goog.require('goog.net.Jsonp'); goog.require('ol.Attribution'); goog.require('ol.TileRange'); goog.require('ol.TileUrlFunction'); goog.require('ol.extent'); +goog.require('ol.net.Jsonp'); goog.require('ol.proj'); goog.require('ol.source.State'); goog.require('ol.source.TileImage'); @@ -46,16 +45,12 @@ ol.source.BingMaps = function(options) { */ this.maxZoom_ = options.maxZoom !== undefined ? options.maxZoom : -1; - var uri = new goog.Uri( - 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/' + - options.imagerySet); + var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/' + + options.imagerySet + + '?uriScheme=https&include=ImageryProviders&key=' + options.key; - var jsonp = new goog.net.Jsonp(uri, 'jsonp'); - jsonp.send({ - 'include': 'ImageryProviders', - 'uriScheme': 'https', - 'key': options.key - }, this.handleImageryMetadataResponse.bind(this)); + ol.net.Jsonp(url, this.handleImageryMetadataResponse.bind(this), undefined, + 'jsonp'); }; goog.inherits(ol.source.BingMaps, ol.source.TileImage); diff --git a/src/ol/source/tilejsonsource.js b/src/ol/source/tilejsonsource.js index 83b0bdf090..f7ccb4c4f1 100644 --- a/src/ol/source/tilejsonsource.js +++ b/src/ol/source/tilejsonsource.js @@ -8,15 +8,11 @@ goog.provide('ol.source.TileJSON'); goog.provide('ol.tilejson'); goog.require('goog.asserts'); -goog.require('ol.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'); goog.require('ol.TileRange'); goog.require('ol.TileUrlFunction'); goog.require('ol.extent'); +goog.require('ol.net.Jsonp'); goog.require('ol.proj'); goog.require('ol.source.State'); goog.require('ol.source.TileImage'); @@ -44,21 +40,20 @@ ol.source.TileJSON = function(options) { }); if (options.jsonp) { - var request = new goog.net.Jsonp(options.url); - request.send(undefined, this.handleTileJSONResponse.bind(this), + ol.net.Jsonp(options.url, this.handleTileJSONResponse.bind(this), this.handleTileJSONError.bind(this)); } else { - var xhr = new goog.net.XhrIo(new goog.net.CorsXmlHttpFactory()); - ol.events.listen(xhr, goog.net.EventType.COMPLETE, function(e) { - if (xhr.isSuccess()) { - var response = /** @type {TileJSON} */(xhr.getResponseJson()); + var xhr = new XMLHttpRequest(); + xhr.open('GET', options.url); + xhr.onload = function(e) { + if (xhr.status < 400) { + var response = /** @type {TileJSON} */(JSON.parse(xhr.responseText)); this.handleTileJSONResponse(response); } else { this.handleTileJSONError(); } - xhr.dispose(); - }, false, this); - xhr.send(options.url); + }.bind(this); + xhr.send(); } }; diff --git a/src/ol/source/tileutfgridsource.js b/src/ol/source/tileutfgridsource.js index e051bd709e..7a089b4298 100644 --- a/src/ol/source/tileutfgridsource.js +++ b/src/ol/source/tileutfgridsource.js @@ -2,9 +2,6 @@ goog.provide('ol.source.TileUTFGrid'); goog.require('goog.asserts'); goog.require('goog.async.nextTick'); -goog.require('ol.events'); -goog.require('ol.events.EventType'); -goog.require('goog.net.Jsonp'); goog.require('ol.Attribution'); goog.require('ol.Tile'); goog.require('ol.TileState'); @@ -12,6 +9,7 @@ goog.require('ol.TileUrlFunction'); goog.require('ol.events'); goog.require('ol.events.EventType'); goog.require('ol.extent'); +goog.require('ol.net.Jsonp'); goog.require('ol.proj'); goog.require('ol.source.State'); goog.require('ol.source.Tile'); @@ -51,8 +49,7 @@ ol.source.TileUTFGrid = function(options) { */ this.template_ = undefined; - var request = new goog.net.Jsonp(options.url); - request.send(undefined, this.handleTileJSONResponse.bind(this)); + ol.net.Jsonp(options.url, this.handleTileJSONResponse.bind(this)); }; goog.inherits(ol.source.TileUTFGrid, ol.source.Tile); @@ -362,9 +359,8 @@ ol.source.TileUTFGridTile_.prototype.handleLoad_ = function(json) { ol.source.TileUTFGridTile_.prototype.loadInternal_ = function() { if (this.state == ol.TileState.IDLE) { this.state = ol.TileState.LOADING; - var request = new goog.net.Jsonp(this.src_); - request.send(undefined, this.handleLoad_.bind(this), - this.handleError_.bind(this)); + ol.net.Jsonp(this.src_, this.handleLoad_.bind(this), + this.handleError_.bind(this)); } }; diff --git a/test/spec/ol/source/bingmapssource.test.js b/test/spec/ol/source/bingmapssource.test.js index b7e1191840..bec185aa4f 100644 --- a/test/spec/ol/source/bingmapssource.test.js +++ b/test/spec/ol/source/bingmapssource.test.js @@ -7,24 +7,21 @@ describe('ol.source.BingMaps', 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/bing_aerialwithlabels.json', true); - client.onload = function() { - callback(JSON.parse(client.responseText)); - }; - client.send(); + var olNetJsonp = ol.net.Jsonp; + // mock ol.net.Jsonp (used in the ol.source.TileJSON constructor) + ol.net.Jsonp = function(url, callback) { + var client = new XMLHttpRequest(); + client.open('GET', 'spec/ol/data/bing_aerialwithlabels.json', true); + client.onload = function() { + callback(JSON.parse(client.responseText)); }; + client.send(); }; source = new ol.source.BingMaps({ imagerySet: 'AerialWithLabels', key: '' }); - goog.net.Jsonp = googNetJsonp; + ol.net.Jsonp = olNetJsonp; var key = source.on('change', function() { if (source.getState() === 'ready') { ol.Observable.unByKey(key); @@ -75,7 +72,7 @@ describe('ol.source.BingMaps', function() { }); -goog.require('goog.net.Jsonp'); +goog.require('ol.net.Jsonp'); goog.require('ol.source.BingMaps'); goog.require('ol.tilecoord'); goog.require('ol.Observable');