Addressing @elemoine's review comments.
Now the application no longer needs to care about the tile origin, because the CacheWrite control modifies the url if the CORS image loading is disabled and it is from a different origin. This only requires OpenLayers.ProxyHost to be properly configured. Also local storage keys use the original url instead of the proxied url, to make the CacheRead control work without proxy settings. No deferred exceptions are thrown any more. Instead, OpenLayers.Console is used to show an error message for security exceptions. We now check for OpenLayers.Tile.Image, because other tile types (e.g. UTFGrid) are not supported (yet). To make the same origin handling in the CacheWrite control easier, OpenLayers.Request now exposes the same origin logic from request.issue as a separate function, so it can also be used by other components.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
var map, cacheRead;
|
var map, cacheRead;
|
||||||
function init(){
|
function init() {
|
||||||
map = new OpenLayers.Map({
|
map = new OpenLayers.Map({
|
||||||
div: "map",
|
div: "map",
|
||||||
projection: "EPSG:900913",
|
projection: "EPSG:900913",
|
||||||
@@ -8,15 +8,11 @@ function init(){
|
|||||||
layers: "basic"
|
layers: "basic"
|
||||||
}, {
|
}, {
|
||||||
eventListeners: {
|
eventListeners: {
|
||||||
tileloadstart: function(evt) {
|
|
||||||
// send requests through proxy
|
|
||||||
evt.tile.url = "proxy.cgi?url=" + encodeURIComponent(evt.tile.url);
|
|
||||||
},
|
|
||||||
tileloaded: updateHits
|
tileloaded: updateHits
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
center: [0,0],
|
center: [0, 0],
|
||||||
zoom: 1
|
zoom: 1
|
||||||
});
|
});
|
||||||
cacheRead = new OpenLayers.Control.CacheRead();
|
cacheRead = new OpenLayers.Control.CacheRead();
|
||||||
@@ -25,8 +21,8 @@ function init(){
|
|||||||
|
|
||||||
|
|
||||||
// User interface
|
// User interface
|
||||||
var status = document.getElementById("status");
|
var status = document.getElementById("status"),
|
||||||
var hits = 0;
|
hits = 0;
|
||||||
|
|
||||||
// update the number of cached tiles and detect local storage support
|
// update the number of cached tiles and detect local storage support
|
||||||
function updateHits(evt) {
|
function updateHits(evt) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<link rel="stylesheet" href="../theme/default/style.css" type="text/css">
|
<link rel="stylesheet" href="../theme/default/style.css" type="text/css">
|
||||||
<link rel="stylesheet" href="style.css" type="text/css">
|
<link rel="stylesheet" href="style.css" type="text/css">
|
||||||
<script src="../lib/OpenLayers.js"></script>
|
<script src="../lib/OpenLayers.js"></script>
|
||||||
|
<script>OpenLayers.Console = window.console;</script>
|
||||||
<script src="cache-write.js"></script>
|
<script src="cache-write.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body onload="init()">
|
<body onload="init()">
|
||||||
|
|||||||
@@ -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;
|
var map, cacheWrite;
|
||||||
function init(){
|
|
||||||
|
function init() {
|
||||||
map = new OpenLayers.Map({
|
map = new OpenLayers.Map({
|
||||||
div: "map",
|
div: "map",
|
||||||
projection: "EPSG:900913",
|
projection: "EPSG:900913",
|
||||||
@@ -8,15 +12,11 @@ function init(){
|
|||||||
layers: "basic"
|
layers: "basic"
|
||||||
}, {
|
}, {
|
||||||
eventListeners: {
|
eventListeners: {
|
||||||
tileloadstart: function(evt) {
|
|
||||||
// send requests through proxy
|
|
||||||
evt.tile.url = "proxy.cgi?url=" + encodeURIComponent(evt.tile.url);
|
|
||||||
},
|
|
||||||
tileloaded: updateStatus
|
tileloaded: updateStatus
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
center: [0,0],
|
center: [0, 0],
|
||||||
zoom: 1
|
zoom: 1
|
||||||
});
|
});
|
||||||
cacheWrite = new OpenLayers.Control.CacheWrite({
|
cacheWrite = new OpenLayers.Control.CacheWrite({
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="../lib/OpenLayers.js"></script>
|
<script src="../lib/OpenLayers.js"></script>
|
||||||
|
<script>OpenLayers.Console = window.console;</script>
|
||||||
<script src="offline-storage.js"></script>
|
<script src="offline-storage.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body onload="init()">
|
<body onload="init()">
|
||||||
|
|||||||
@@ -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;
|
var map, cacheWrite, cacheRead1, cacheRead2;
|
||||||
function init(){
|
|
||||||
|
function init() {
|
||||||
map = new OpenLayers.Map({
|
map = new OpenLayers.Map({
|
||||||
div: "map",
|
div: "map",
|
||||||
projection: "EPSG:900913",
|
projection: "EPSG:900913",
|
||||||
@@ -14,28 +18,13 @@ function init(){
|
|||||||
layers: "basic"
|
layers: "basic"
|
||||||
}, {
|
}, {
|
||||||
eventListeners: {
|
eventListeners: {
|
||||||
tileloadstart: function(evt) {
|
|
||||||
// send requests through proxy
|
|
||||||
evt.tile.url = "proxy.cgi?url=" + encodeURIComponent(evt.tile.url);
|
|
||||||
},
|
|
||||||
tileloaded: updateStatus
|
tileloaded: updateStatus
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
center: [0,0],
|
center: [0, 0],
|
||||||
zoom: 1
|
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
|
// try cache before loading from remote resource
|
||||||
cacheRead1 = new OpenLayers.Control.CacheRead({
|
cacheRead1 = new OpenLayers.Control.CacheRead({
|
||||||
eventListeners: {
|
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();
|
var layerSwitcher = new OpenLayers.Control.LayerSwitcher();
|
||||||
map.addControls([cacheWrite, cacheRead1, cacheRead2, layerSwitcher]);
|
map.addControls([cacheRead1, cacheRead2, cacheWrite, layerSwitcher]);
|
||||||
layerSwitcher.maximizeControl();
|
layerSwitcher.maximizeControl();
|
||||||
|
|
||||||
|
|
||||||
@@ -63,7 +63,6 @@ function init(){
|
|||||||
// add UI and behavior
|
// add UI and behavior
|
||||||
var status = document.getElementById("status"),
|
var status = document.getElementById("status"),
|
||||||
hits = document.getElementById("hits"),
|
hits = document.getElementById("hits"),
|
||||||
previousCount = -1,
|
|
||||||
cacheHits = 0,
|
cacheHits = 0,
|
||||||
seeding = false;
|
seeding = false;
|
||||||
var read = document.getElementById("read");
|
var read = document.getElementById("read");
|
||||||
@@ -107,7 +106,7 @@ function init(){
|
|||||||
} else {
|
} else {
|
||||||
status.innerHTML = "Local storage not supported. Try a different browser.";
|
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++;
|
cacheHits++;
|
||||||
}
|
}
|
||||||
hits.innerHTML = cacheHits + " cache hits.";
|
hits.innerHTML = cacheHits + " cache hits.";
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* APIProperty: layers
|
* APIProperty: layers
|
||||||
* {Array(<OpenLayers.Layer.HTTPRequest>)}. Optional. If provided, only
|
* {Array(<OpenLayers.Layer.Grid>)}. Optional. If provided, only these
|
||||||
* these layers will receive tiles from the cache.
|
* layers will receive tiles from the cache.
|
||||||
*/
|
*/
|
||||||
layers: null,
|
layers: null,
|
||||||
|
|
||||||
@@ -61,12 +61,12 @@ OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
*/
|
*/
|
||||||
setMap: function(map) {
|
setMap: function(map) {
|
||||||
OpenLayers.Control.prototype.setMap.apply(this, arguments);
|
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) {
|
for (i=layers.length-1; i>=0; --i) {
|
||||||
this.addLayer({layer: layers[i]});
|
this.addLayer({layer: layers[i]});
|
||||||
}
|
}
|
||||||
if (!this.layers) {
|
if (!this.layers) {
|
||||||
this.map.events.on({
|
map.events.on({
|
||||||
addlayer: this.addLayer,
|
addlayer: this.addLayer,
|
||||||
removeLayer: this.removeLayer,
|
removeLayer: this.removeLayer,
|
||||||
scope: this
|
scope: this
|
||||||
@@ -109,9 +109,17 @@ OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
* evt - {Object} Event object with a tile property.
|
* evt - {Object} Event object with a tile property.
|
||||||
*/
|
*/
|
||||||
fetch: function(evt) {
|
fetch: function(evt) {
|
||||||
if (this.active && window.localStorage) {
|
if (this.active && window.localStorage &&
|
||||||
|
evt.tile instanceof OpenLayers.Tile.Image) {
|
||||||
var tile = evt.tile,
|
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) {
|
if (dataURI) {
|
||||||
tile.url = dataURI;
|
tile.url = dataURI;
|
||||||
if (evt.type === "tileerror") {
|
if (evt.type === "tileerror") {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @requires OpenLayers/Control.js
|
* @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) {
|
setMap: function(map) {
|
||||||
OpenLayers.Control.prototype.setMap.apply(this, arguments);
|
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) {
|
for (i=layers.length-1; i>=0; --i) {
|
||||||
this.addLayer({layer: layers[i]});
|
this.addLayer({layer: layers[i]});
|
||||||
}
|
}
|
||||||
if (!this.layers) {
|
if (!this.layers) {
|
||||||
this.map.events.on({
|
map.events.on({
|
||||||
addlayer: this.addLayer,
|
addlayer: this.addLayer,
|
||||||
removeLayer: this.removeLayer,
|
removeLayer: this.removeLayer,
|
||||||
scope: this
|
scope: this
|
||||||
@@ -107,7 +109,11 @@ OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
* <OpenLayers.Layer> instance
|
* <OpenLayers.Layer> instance
|
||||||
*/
|
*/
|
||||||
addLayer: function(evt) {
|
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, {
|
|||||||
* <OpenLayers.Layer> instance
|
* <OpenLayers.Layer> instance
|
||||||
*/
|
*/
|
||||||
removeLayer: function(evt) {
|
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 - {<OpenLayers.Event>}
|
||||||
|
*/
|
||||||
|
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) {
|
cache: function(obj) {
|
||||||
if (this.active && window.localStorage) {
|
if (this.active && window.localStorage) {
|
||||||
var tile = obj.tile;
|
var tile = obj.tile;
|
||||||
if (tile.url.substr(0, 5) !== 'data:') {
|
if (tile instanceof OpenLayers.Tile.Image &&
|
||||||
|
tile.url.substr(0, 5) !== 'data:') {
|
||||||
try {
|
try {
|
||||||
var canvasContext = tile.getCanvasContext();
|
var canvasContext = tile.getCanvasContext();
|
||||||
if (canvasContext) {
|
if (canvasContext) {
|
||||||
window.localStorage.setItem(
|
window.localStorage.setItem(
|
||||||
"olCache_" + tile.url,
|
"olCache_" + OpenLayers.Control.CacheWrite.urlMap[tile.url],
|
||||||
canvasContext.canvas.toDataURL(this.imageFormat)
|
canvasContext.canvas.toDataURL(this.imageFormat)
|
||||||
);
|
);
|
||||||
|
delete OpenLayers.Control.CacheWrite.urlMap[tile.url];
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// local storage full or CORS violation
|
// local storage full or CORS violation
|
||||||
@@ -150,8 +185,7 @@ OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
if (reason && this.quotaRegEx.test(reason)) {
|
if (reason && this.quotaRegEx.test(reason)) {
|
||||||
this.events.triggerEvent("cachefull", {tile: tile});
|
this.events.triggerEvent("cachefull", {tile: tile});
|
||||||
} else {
|
} else {
|
||||||
// throw exception in the next cycle
|
OpenLayers.Console.error(e.toString());
|
||||||
window.setTimeout(function() { throw(e); }, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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 = {};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,47 @@ OpenLayers.Request = {
|
|||||||
*/
|
*/
|
||||||
events: new OpenLayers.Events(this),
|
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
|
* APIMethod: issue
|
||||||
* Create a new XMLHttpRequest object, open it, set any headers, bind
|
* Create a new XMLHttpRequest object, open it, set any headers, bind
|
||||||
@@ -153,30 +194,7 @@ OpenLayers.Request = {
|
|||||||
var request = new OpenLayers.Request.XMLHttpRequest();
|
var request = new OpenLayers.Request.XMLHttpRequest();
|
||||||
var url = OpenLayers.Util.urlAppend(config.url,
|
var url = OpenLayers.Util.urlAppend(config.url,
|
||||||
OpenLayers.Util.getParameterString(config.params || {}));
|
OpenLayers.Util.getParameterString(config.params || {}));
|
||||||
var sameOrigin = !(url.indexOf("http") == 0);
|
url = OpenLayers.Request.makeSameOrigin(url, config.proxy);
|
||||||
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});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
request.open(
|
request.open(
|
||||||
config.method, url, config.async, config.user, config.password
|
config.method, url, config.async, config.user, config.password
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user