Replace permalink/Share URL feature with automatic URL rewriting on change.

This commit is contained in:
Gautier Pelloux-Prayer 2017-04-04 10:24:10 +02:00
parent 3cc0a3b9ee
commit e82f360d9c
9 changed files with 308 additions and 170 deletions

View file

@ -60,8 +60,8 @@ BR.NogoAreas = L.Control.Draw.extend({
setOptions: function(options) {
var nogos = options.nogos;
this.drawnItems.clearLayers();
if (nogos) {
this.drawnItems.clearLayers();
for (var i = 0; i < nogos.length; i++) {
this.drawnItems.addLayer(nogos[i]);
}

View file

@ -1,105 +0,0 @@
//#include "Permalink.js
// patch to not encode URL (beside 'layer', better readable/hackable, Browser can handle)
L.Control.Permalink.include({
_update_href: function () {
//var params = L.Util.getParamString(this._params);
var params = this.getParamString(this._params);
var sep = '?';
if (this.options.useAnchor) sep = '#';
var url = this._url_base + sep + params.slice(1);
if (this._href) this._href.setAttribute('href', url);
if (this.options.useLocation)
location.replace('#' + params.slice(1));
return url;
},
getParamString: function (obj, existingUrl, uppercase) {
var params = [];
for (var i in obj) {
// do encode layer (e.g. spaces)
if (i === 'layer') {
params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
} else {
params.push(uppercase ? i.toUpperCase() : i + '=' + obj[i]);
}
}
return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
}
});
// patch: no animation when setting the map view, strange effects with nogo circles
L.Control.Permalink.include({
_set_center: function(e)
{
//console.info('Update center', e);
var params = e.params;
if (params.zoom === undefined ||
params.lat === undefined ||
params.lon === undefined) return;
this._map.setView(new L.LatLng(params.lat, params.lon), params.zoom, { reset: true });
}
});
L.Control.Permalink.include({
initialize_routing: function () {
this.on('update', this._set_routing, this);
this.on('add', this._onadd_routing, this);
},
_onadd_routing: function (e) {
this.options.routingOptions.on('update', this._update_routing, this);
this.options.nogos.on('update', this._update_routing, this);
// waypoint add, move, delete (but last)
this.options.routing.on('routing:routeWaypointEnd', this._update_routing, this);
// delete last waypoint
this.options.routing.on('waypoint:click', function (evt) {
var r = evt.marker._routing;
if (!r.prevMarker && !r.nextMarker) {
this._update_routing(evt);
}
}, this);
},
_update_routing: function (evt) {
var router = this.options.router,
routing = this.options.routing,
routingOptions = this.options.routingOptions,
latLngs = routing.getWaypoints(),
params = router.getUrlParams(latLngs);
if (evt && evt.options) {
router.setOptions(evt.options);
}
// don't permalink to custom profile, as these are only stored temporarily
if (params.profile && params.profile === routingOptions.getCustomProfile()) {
params.profile = null;
}
this._update(params);
//console.log('permalink: ' + this._href.href);
},
_set_routing: function (e) {
var router = this.options.router,
routing = this.options.routing,
routingOptions = this.options.routingOptions,
nogos = this.options.nogos,
profile = this.options.profile;
var opts = router.parseUrlParams(e.params);
router.setOptions(opts);
routingOptions.setOptions(opts);
nogos.setOptions(opts);
profile.update(opts);
if (opts.lonlats) {
routing.draw(false);
routing.clear();
routing.setWaypoints(opts.lonlats);
}
}
});

View file

@ -0,0 +1,212 @@
(function(window) {
var HAS_HASHCHANGE = (function() {
var doc_mode = window.documentMode;
return ('onhashchange' in window) &&
(doc_mode === undefined || doc_mode > 7);
})();
L.Hash = function(map, layers, additionalCb, onHashChangeCb) {
this.onHashChange = L.Util.bind(this.onHashChange, this);
this.additionalCb = additionalCb;
this.onHashChangeCb = onHashChangeCb;
if (map) {
this.init(map, layers);
}
};
L.Hash.parseHash = function(hash) {
if(hash.indexOf('#map=') === 0) {
hash = hash.substr(5);
}
var args = hash.split("/");
if (args.length >= 4) {
var zoom = parseInt(args[0], 10),
lat = parseFloat(args[1]),
lon = parseFloat(args[2]),
layer = args[3];
additional = args[4];
if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) {
return false;
} else {
return {
center: new L.LatLng(lat, lon),
zoom: zoom,
layer: layer,
additional: additional
};
}
} else {
return false;
}
};
L.Hash.formatHash = function(map) {
var center = map.getCenter(),
zoom = map.getZoom(),
precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)),
layer = null;
var options = this.options;
//Check active layer
for(var key in options) {
if (options.hasOwnProperty(key)) {
if (map.hasLayer(options[key])) {
layer = key;
break;
};
};
};
var params = [
zoom,
center.lat.toFixed(precision),
center.lng.toFixed(precision),
layer
];
url = "#map=" + params.join("/");
if (this.additionalCb != null) {
var additional = this.additionalCb();
if (additional != null) {
return url + additional;
}
}
return url;
},
L.Hash.prototype = {
map: null,
lastHash: null,
parseHash: L.Hash.parseHash,
formatHash: L.Hash.formatHash,
init: function(map, options) {
this.map = map;
L.Util.setOptions(this, options);
// reset the hash
this.lastHash = null;
this.onHashChange();
if (!this.isListening) {
this.startListening();
}
},
removeFrom: function(map) {
if (this.changeTimeout) {
clearTimeout(this.changeTimeout);
}
if (this.isListening) {
this.stopListening();
}
this.map = null;
},
updateHash: function() {
// bail if we're moving the map (updating from a hash),
// or if the map is not yet loaded
if (this.isUpdatingHash || !this.map._loaded) {
return false;
}
var hash = this.formatHash(this.map);
if (this.lastHash != hash) {
location.replace(hash);
this.lastHash = hash;
}
},
isUpdatingHash: false,
update: function() {
var hash = location.hash;
if (hash === this.lastHash) {
return;
}
var parsed = this.parseHash(hash);
if (parsed) {
this.isUpdatingHash = true;
this.map.setView(parsed.center, parsed.zoom);
if (this.onHashChangeCb != null) {
this.onHashChangeCb(parsed.additional);
}
var options = this.options,
layer = parsed.layer in options ? parsed.layer : Object.keys(options)[0],
that = this;
//Add/remove layer
this.map.eachLayer(function(layer) {
that.map.removeLayer(layer);
});
that.map.addLayer(options[layer]);
this.isUpdatingHash = false;
} else {
this.updateHash(this.map);
}
},
// defer hash change updates every 100ms
changeDefer: 100,
changeTimeout: null,
onHashChange: function() {
// throttle calls to update() so that they only happen every
// `changeDefer` ms
if (!this.changeTimeout) {
var that = this;
this.changeTimeout = setTimeout(function() {
that.update();
that.changeTimeout = null;
}, this.changeDefer);
}
},
isListening: false,
hashChangeInterval: null,
startListening: function() {
this.map.on("moveend layeradd layerremove", this.updateHash, this);
if (HAS_HASHCHANGE) {
L.DomEvent.addListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
this.hashChangeInterval = setInterval(this.onHashChange, 50);
}
this.isListening = true;
},
stopListening: function() {
this.map.off("moveend layeradd layerremove", this.updateHash, this);
if (HAS_HASHCHANGE) {
L.DomEvent.removeListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
}
this.isListening = false;
},
_keyByValue: function(obj, value) {
for(var key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] === value) {
return key;
} else { return null; };
};
};
}
};
L.hash = function(map, options) {
return new L.Hash(map, options);
};
L.Map.prototype.addHash = function() {
this._hash = L.hash(this, this.options);
};
L.Map.prototype.removeHash = function() {
this._hash.removeFrom();
};
})(window);