diff --git a/examples/cache-read.js b/examples/cache-read.js index f8c42a9115..1f7988984e 100644 --- a/examples/cache-read.js +++ b/examples/cache-read.js @@ -1,5 +1,5 @@ var map, cacheRead; -function init(){ +function init() { map = new OpenLayers.Map({ div: "map", projection: "EPSG:900913", @@ -8,15 +8,11 @@ function init(){ layers: "basic" }, { eventListeners: { - tileloadstart: function(evt) { - // send requests through proxy - evt.tile.url = "proxy.cgi?url=" + encodeURIComponent(evt.tile.url); - }, tileloaded: updateHits } }) ], - center: [0,0], + center: [0, 0], zoom: 1 }); cacheRead = new OpenLayers.Control.CacheRead(); @@ -25,8 +21,8 @@ function init(){ // User interface - var status = document.getElementById("status"); - var hits = 0; + var status = document.getElementById("status"), + hits = 0; // update the number of cached tiles and detect local storage support function updateHits(evt) { diff --git a/examples/cache-write.html b/examples/cache-write.html index e36f3de9b7..ca59f68d80 100644 --- a/examples/cache-write.html +++ b/examples/cache-write.html @@ -8,6 +8,7 @@ + diff --git a/examples/cache-write.js b/examples/cache-write.js index b47cb60134..8f4ec9e081 100644 --- a/examples/cache-write.js +++ b/examples/cache-write.js @@ -1,5 +1,9 @@ +// Use proxy to get same origin URLs for tiles that don't support CORS. +OpenLayers.ProxyHost = "proxy.cgi?url="; + var map, cacheWrite; -function init(){ + +function init() { map = new OpenLayers.Map({ div: "map", projection: "EPSG:900913", @@ -8,15 +12,11 @@ function init(){ layers: "basic" }, { eventListeners: { - tileloadstart: function(evt) { - // send requests through proxy - evt.tile.url = "proxy.cgi?url=" + encodeURIComponent(evt.tile.url); - }, tileloaded: updateStatus } }) ], - center: [0,0], + center: [0, 0], zoom: 1 }); cacheWrite = new OpenLayers.Control.CacheWrite({ diff --git a/examples/offline-storage.html b/examples/offline-storage.html index 3cf235fdd4..1c510ca537 100644 --- a/examples/offline-storage.html +++ b/examples/offline-storage.html @@ -13,6 +13,7 @@ } + diff --git a/examples/offline-storage.js b/examples/offline-storage.js index b82470159b..e0b5929791 100644 --- a/examples/offline-storage.js +++ b/examples/offline-storage.js @@ -1,5 +1,9 @@ +// Use proxy to get same origin URLs for tiles that don't support CORS. +OpenLayers.ProxyHost = "proxy.cgi?url="; + var map, cacheWrite, cacheRead1, cacheRead2; -function init(){ + +function init() { map = new OpenLayers.Map({ div: "map", projection: "EPSG:900913", @@ -14,28 +18,13 @@ function init(){ layers: "basic" }, { eventListeners: { - tileloadstart: function(evt) { - // send requests through proxy - evt.tile.url = "proxy.cgi?url=" + encodeURIComponent(evt.tile.url); - }, tileloaded: updateStatus } }) ], - center: [0,0], + center: [0, 0], zoom: 1 }); - cacheWrite = new OpenLayers.Control.CacheWrite({ - imageFormat: "image/jpeg", - eventListeners: { - cachefull: function() { - if (seeding) { - stopSeeding(); - } - status.innerHTML = "Cache full."; - } - } - }); // try cache before loading from remote resource cacheRead1 = new OpenLayers.Control.CacheRead({ eventListeners: { @@ -54,8 +43,19 @@ function init(){ } } }); + cacheWrite = new OpenLayers.Control.CacheWrite({ + imageFormat: "image/jpeg", + eventListeners: { + cachefull: function() { + if (seeding) { + stopSeeding(); + } + status.innerHTML = "Cache full."; + } + } + }); var layerSwitcher = new OpenLayers.Control.LayerSwitcher(); - map.addControls([cacheWrite, cacheRead1, cacheRead2, layerSwitcher]); + map.addControls([cacheRead1, cacheRead2, cacheWrite, layerSwitcher]); layerSwitcher.maximizeControl(); @@ -63,7 +63,6 @@ function init(){ // add UI and behavior var status = document.getElementById("status"), hits = document.getElementById("hits"), - previousCount = -1, cacheHits = 0, seeding = false; var read = document.getElementById("read"); @@ -107,7 +106,7 @@ function init(){ } else { status.innerHTML = "Local storage not supported. Try a different browser."; } - if (evt.tile.url.substr(0, 5) === "data:") { + if (evt && evt.tile.url.substr(0, 5) === "data:") { cacheHits++; } hits.innerHTML = cacheHits + " cache hits."; diff --git a/lib/OpenLayers/Control/CacheRead.js b/lib/OpenLayers/Control/CacheRead.js index 6f44c7bbab..2589fdf6ca 100644 --- a/lib/OpenLayers/Control/CacheRead.js +++ b/lib/OpenLayers/Control/CacheRead.js @@ -33,8 +33,8 @@ OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, { /** * APIProperty: layers - * {Array()}. Optional. If provided, only - * these layers will receive tiles from the cache. + * {Array()}. Optional. If provided, only these + * layers will receive tiles from the cache. */ layers: null, @@ -61,12 +61,12 @@ OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, { */ setMap: function(map) { OpenLayers.Control.prototype.setMap.apply(this, arguments); - var i, layers = this.layers || this.map.layers; + var i, layers = this.layers || map.layers; for (i=layers.length-1; i>=0; --i) { this.addLayer({layer: layers[i]}); } if (!this.layers) { - this.map.events.on({ + map.events.on({ addlayer: this.addLayer, removeLayer: this.removeLayer, scope: this @@ -109,9 +109,17 @@ OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, { * evt - {Object} Event object with a tile property. */ fetch: function(evt) { - if (this.active && window.localStorage) { + if (this.active && window.localStorage && + evt.tile instanceof OpenLayers.Tile.Image) { var tile = evt.tile, - dataURI = window.localStorage.getItem("olCache_" + tile.url); + url = tile.url; + // deal with modified tile urls when both CacheWrite and CacheRead + // are active + if (!tile.layer.crossOriginKeyword && OpenLayers.ProxyHost && + url.indexOf(OpenLayers.ProxyHost) === 0) { + url = OpenLayers.Control.CacheWrite.urlMap[url]; + } + var dataURI = window.localStorage.getItem("olCache_" + tile.url); if (dataURI) { tile.url = dataURI; if (evt.type === "tileerror") { diff --git a/lib/OpenLayers/Control/CacheWrite.js b/lib/OpenLayers/Control/CacheWrite.js index 0311fde801..85ece0b1dd 100644 --- a/lib/OpenLayers/Control/CacheWrite.js +++ b/lib/OpenLayers/Control/CacheWrite.js @@ -5,6 +5,8 @@ /** * @requires OpenLayers/Control.js + * @requires OpenLayers/Request.js + * @requires OpenLayers/Console.js */ /** @@ -84,12 +86,12 @@ OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { */ setMap: function(map) { OpenLayers.Control.prototype.setMap.apply(this, arguments); - var i, layers = this.layers || this.map.layers; + var i, layers = this.layers || map.layers; for (i=layers.length-1; i>=0; --i) { this.addLayer({layer: layers[i]}); } if (!this.layers) { - this.map.events.on({ + map.events.on({ addlayer: this.addLayer, removeLayer: this.removeLayer, scope: this @@ -107,7 +109,11 @@ OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { * instance */ addLayer: function(evt) { - evt.layer.events.register("tileloaded", this, this.cache); + evt.layer.events.on({ + tileloadstart: this.makeSameOrigin, + tileloaded: this.cache, + scope: this + }); }, /** @@ -120,7 +126,34 @@ OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { * instance */ removeLayer: function(evt) { - evt.layer.events.unregister("tileloaded", this, this.cache); + evt.layer.events.un({ + tileloadstart: this.makeSameOrigin, + tileloaded: this.cache, + scope: this + }); + }, + + /** + * Method: makeSameOrigin + * If the tile does not have CORS image loading enabled and is from a + * different origin, use OpenLayers.ProxyHost to make it a same origin url. + * + * Parameters: + * evt - {} + */ + makeSameOrigin: function(evt) { + if (this.active) { + var tile = evt.tile; + if (tile instanceof OpenLayers.Tile.Image && + !tile.crossOriginKeyword && + tile.url.substr(0, 5) !== "data:") { + var sameOriginUrl = OpenLayers.Request.makeSameOrigin( + tile.url, OpenLayers.ProxyHost + ); + OpenLayers.Control.CacheWrite.urlMap[sameOriginUrl] = tile.url; + tile.url = sameOriginUrl; + } + } }, /** @@ -135,14 +168,16 @@ OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { cache: function(obj) { if (this.active && window.localStorage) { var tile = obj.tile; - if (tile.url.substr(0, 5) !== 'data:') { + if (tile instanceof OpenLayers.Tile.Image && + tile.url.substr(0, 5) !== 'data:') { try { var canvasContext = tile.getCanvasContext(); if (canvasContext) { window.localStorage.setItem( - "olCache_" + tile.url, + "olCache_" + OpenLayers.Control.CacheWrite.urlMap[tile.url], canvasContext.canvas.toDataURL(this.imageFormat) ); + delete OpenLayers.Control.CacheWrite.urlMap[tile.url]; } } catch(e) { // local storage full or CORS violation @@ -150,8 +185,7 @@ OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { if (reason && this.quotaRegEx.test(reason)) { this.events.triggerEvent("cachefull", {tile: tile}); } else { - // throw exception in the next cycle - window.setTimeout(function() { throw(e); }, 0); + OpenLayers.Console.error(e.toString()); } } } @@ -198,3 +232,12 @@ OpenLayers.Control.CacheWrite.clearCache = function() { } } }; + +/** + * Property: OpenLayers.Control.CacheWrite.urlMap + * {Object} Mapping of same origin urls to cache url keys. Entries will be + * deleted as soon as a tile was cached. + */ +OpenLayers.Control.CacheWrite.urlMap = {}; + + diff --git a/lib/OpenLayers/Request.js b/lib/OpenLayers/Request.js index a5de46fdee..86e15d8099 100644 --- a/lib/OpenLayers/Request.js +++ b/lib/OpenLayers/Request.js @@ -65,6 +65,47 @@ OpenLayers.Request = { */ events: new OpenLayers.Events(this), + /** + * Method: makeSameOrigin + * Using the specified proxy, returns a same origin url of the provided url. + * + * Parameters: + * url - {String} An arbitrary url + * proxy {String|Function} The proxy to use to make the provided url a + * same origin url. + * + * Returns + * {String} the same origin url. If no proxy is provided, the returned url + * will be the same as the provided url. + */ + makeSameOrigin: function(url, proxy) { + var sameOrigin = !(url.indexOf("http") == 0); + var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX); + if (urlParts) { + var location = window.location; + sameOrigin = + urlParts[1] == location.protocol && + urlParts[3] == location.hostname; + var uPort = urlParts[4], lPort = location.port; + if (uPort != 80 && uPort != "" || lPort != "80" && lPort != "") { + sameOrigin = sameOrigin && uPort == lPort; + } + } + if (!sameOrigin) { + if (proxy) { + if (typeof proxy == "function") { + url = proxy(url); + } else { + url = proxy + encodeURIComponent(url); + } + } else { + OpenLayers.Console.warn( + OpenLayers.i18n("proxyNeeded"), {url: url}); + } + } + return url; + }, + /** * APIMethod: issue * Create a new XMLHttpRequest object, open it, set any headers, bind @@ -153,30 +194,7 @@ OpenLayers.Request = { var request = new OpenLayers.Request.XMLHttpRequest(); var url = OpenLayers.Util.urlAppend(config.url, OpenLayers.Util.getParameterString(config.params || {})); - var sameOrigin = !(url.indexOf("http") == 0); - var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX); - if (urlParts) { - var location = window.location; - sameOrigin = - urlParts[1] == location.protocol && - urlParts[3] == location.hostname; - var uPort = urlParts[4], lPort = location.port; - if (uPort != 80 && uPort != "" || lPort != "80" && lPort != "") { - sameOrigin = sameOrigin && uPort == lPort; - } - } - if (!sameOrigin) { - if (config.proxy) { - if (typeof config.proxy == "function") { - url = config.proxy(url); - } else { - url = config.proxy + encodeURIComponent(url); - } - } else { - OpenLayers.Console.warn( - OpenLayers.i18n("proxyNeeded"), {url: url}); - } - } + url = OpenLayers.Request.makeSameOrigin(url, config.proxy); request.open( config.method, url, config.async, config.user, config.password );