Merge pull request #770 from umap-project/permalink

Feature permalink
This commit is contained in:
Yohan Boniface 2020-03-22 14:42:22 +01:00 committed by GitHub
commit 15068cfcfe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 72 additions and 19 deletions

View file

@ -1049,7 +1049,8 @@ L.U.IframeExporter = L.Evented.extend({
options: { options: {
includeFullScreenLink: true, includeFullScreenLink: true,
currentView: false, currentView: false,
keepCurrentDatalayers: false keepCurrentDatalayers: false,
viewCurrentFeature: false
}, },
queryString: { queryString: {
@ -1074,7 +1075,7 @@ L.U.IframeExporter = L.Evented.extend({
initialize: function (map) { initialize: function (map) {
this.map = map; this.map = map;
this.baseUrl = '//' + window.location.host + window.location.pathname; this.baseUrl = L.Util.getBaseUrl();
// Use map default, not generic default // Use map default, not generic default
this.queryString.onLoadPanel = this.map.options.onLoadPanel; this.queryString.onLoadPanel = this.map.options.onLoadPanel;
}, },
@ -1085,6 +1086,9 @@ L.U.IframeExporter = L.Evented.extend({
build: function () { build: function () {
var datalayers = []; var datalayers = [];
if (this.options.viewCurrentFeature && this.map.currentFeature) {
this.queryString.feature = this.map.currentFeature.getSlug();
}
if (this.options.keepCurrentDatalayers) { if (this.options.keepCurrentDatalayers) {
this.map.eachDataLayer(function (datalayer) { this.map.eachDataLayer(function (datalayer) {
if (datalayer.isVisible() && datalayer.umap_id) { if (datalayer.isVisible() && datalayer.umap_id) {
@ -1096,7 +1100,7 @@ L.U.IframeExporter = L.Evented.extend({
delete this.queryString.datalayers; delete this.queryString.datalayers;
} }
var currentView = this.options.currentView ? window.location.hash : '', var currentView = this.options.currentView ? window.location.hash : '',
iframeUrl = this.baseUrl + '?' + this.map.xhr.buildQueryString(this.queryString) + currentView, iframeUrl = this.baseUrl + '?' + L.Util.buildQueryString(this.queryString) + currentView,
code = '<iframe width="' + this.dimensions.width + '" height="' + this.dimensions.height + '" frameborder="0" allowfullscreen src="' + iframeUrl + '"></iframe>'; code = '<iframe width="' + this.dimensions.width + '" height="' + this.dimensions.height + '" frameborder="0" allowfullscreen src="' + iframeUrl + '"></iframe>';
if (this.options.includeFullScreenLink) { if (this.options.includeFullScreenLink) {
code += '<p><a href="' + this.baseUrl + '">' + L._('See full screen') + '</a></p>'; code += '<p><a href="' + this.baseUrl + '">' + L._('See full screen') + '</a></p>';

View file

@ -175,6 +175,19 @@ L.Util.flattenCoordinates = function (coords) {
return coords; return coords;
}; };
L.Util.buildQueryString = function (params) {
var query_string = [];
for (var key in params) {
query_string.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
}
return query_string.join('&');
};
L.Util.getBaseUrl = function () {
return '//' + window.location.host + window.location.pathname;
};
L.DomUtil.add = function (tagName, className, container, content) { L.DomUtil.add = function (tagName, className, container, content) {
var el = L.DomUtil.create(tagName, className, container); var el = L.DomUtil.create(tagName, className, container);
if (content) { if (content) {
@ -428,6 +441,7 @@ L.U.Help = L.Class.extend({
shortCredit: L._('Will be displayed in the bottom right corner of the map'), shortCredit: L._('Will be displayed in the bottom right corner of the map'),
longCredit: L._('Will be visible in the caption of the map'), longCredit: L._('Will be visible in the caption of the map'),
sortKey: L._('Property to use for sorting features'), sortKey: L._('Property to use for sorting features'),
slugKey: L._('The name of the property to use as feature unique identifier.'),
filterKey: L._('Comma separated list of properties to use when filtering features'), filterKey: L._('Comma separated list of properties to use when filtering features'),
interactive: L._('If false, the polygon will act as a part of the underlying map.'), interactive: L._('If false, the polygon will act as a part of the underlying map.'),
outlink: L._('Define link to open in a new window on polygon click.'), outlink: L._('Define link to open in a new window on polygon click.'),

View file

@ -45,6 +45,15 @@ L.U.FeatureMixin = {
return this.datalayer && this.datalayer.isRemoteLayer(); return this.datalayer && this.datalayer.isRemoteLayer();
}, },
getSlug: function () {
return this.properties[this.map.options.slugKey || 'name'] || '';
},
getPermalink: function () {
const slug = this.getSlug();
if (slug) return L.Util.getBaseUrl() + "?" + L.Util.buildQueryString({feature: slug}) + window.location.hash;
},
view: function(e) { view: function(e) {
if (this.map.editEnabled) return; if (this.map.editEnabled) return;
var outlink = this.properties._umap_options.outlink, var outlink = this.properties._umap_options.outlink,
@ -64,6 +73,7 @@ L.U.FeatureMixin = {
} }
// TODO deal with an event instead? // TODO deal with an event instead?
if (this.map.slideshow) this.map.slideshow.current = this; if (this.map.slideshow) this.map.slideshow.current = this;
this.map.currentFeature = this;
this.attachPopup(); this.attachPopup();
this.openPopup(e && e.latlng || this.getCenter()); this.openPopup(e && e.latlng || this.getCenter());
}, },
@ -351,7 +361,9 @@ L.U.FeatureMixin = {
}, },
getContextMenuItems: function (e) { getContextMenuItems: function (e) {
var items = []; var permalink = this.getPermalink(),
items = [];
if (permalink) items.push({text: L._('Permalink'), callback: function() {window.open(permalink);}});
if (this.map.editEnabled && !this.isReadOnly()) { if (this.map.editEnabled && !this.isReadOnly()) {
items = items.concat(this.getContextMenuEditItems(e)); items = items.concat(this.getContextMenuEditItems(e));
} }

View file

@ -122,10 +122,11 @@ L.U.Map.include({
this.initTileLayers(this.options.tilelayers); this.initTileLayers(this.options.tilelayers);
// Global storage for retrieving datalayers // Global storage for retrieving datalayers and features
this.datalayers = {}; this.datalayers = {};
this.datalayers_index = []; this.datalayers_index = [];
this.dirty_datalayers = []; this.dirty_datalayers = [];
this.features_index = {};
// Retrocompat // Retrocompat
if (this.options.slideshow && this.options.slideshow.delay && this.options.slideshow.active === undefined) this.options.slideshow.active = true; if (this.options.slideshow && this.options.slideshow.delay && this.options.slideshow.active === undefined) this.options.slideshow.active = true;
@ -208,6 +209,10 @@ L.U.Map.include({
if (this.options.onLoadPanel === 'databrowser') this.openBrowser(); if (this.options.onLoadPanel === 'databrowser') this.openBrowser();
else if (this.options.onLoadPanel === 'caption') this.displayCaption(); else if (this.options.onLoadPanel === 'caption') this.displayCaption();
}); });
this.onceDataLoaded(function () {
const slug = L.Util.queryString('feature');
if (slug && this.features_index[slug]) this.features_index[slug].view();
});
window.onbeforeunload = function (e) { window.onbeforeunload = function (e) {
@ -292,9 +297,9 @@ L.U.Map.include({
}, },
initDatalayers: function () { initDatalayers: function () {
var toload = this.options.datalayers.length, var toload = dataToload = seen = this.options.datalayers.length,
datalayer, seen = this.options.datalayers.length, self = this,
self = this; datalayer;
var loaded = function () { var loaded = function () {
self.datalayersLoaded = true; self.datalayersLoaded = true;
self.fire('datalayersloaded'); self.fire('datalayersloaded');
@ -303,12 +308,22 @@ L.U.Map.include({
toload--; toload--;
if (toload === 0) loaded(); if (toload === 0) loaded();
}; };
var dataLoaded = function () {
self.dataLoaded = true;
self.fire('dataloaded');
};
var decrementDataToLoad = function () {
dataToload--;
if (dataToload === 0) dataLoaded();
};
for (var j = 0; j < this.options.datalayers.length; j++) { for (var j = 0; j < this.options.datalayers.length; j++) {
datalayer = this.createDataLayer(this.options.datalayers[j]); datalayer = this.createDataLayer(this.options.datalayers[j]);
if (datalayer.displayedOnLoad()) datalayer.onceLoaded(decrementToLoad); if (datalayer.displayedOnLoad()) datalayer.onceLoaded(decrementToLoad);
else decrementToLoad(); else decrementToLoad();
if (datalayer.displayedOnLoad()) datalayer.onceDataLoaded(decrementDataToLoad);
else decrementDataToLoad();
} }
if (seen === 0) loaded(); // no datalayer if (seen === 0) loaded() && dataLoaded(); // no datalayer
}, },
indexDatalayers: function () { indexDatalayers: function () {
@ -330,6 +345,7 @@ L.U.Map.include({
}, },
onceDatalayersLoaded: function (callback, context) { onceDatalayersLoaded: function (callback, context) {
// Once datalayers **metadata** have been loaded
if (this.datalayersLoaded) { if (this.datalayersLoaded) {
callback.call(context || this, this); callback.call(context || this, this);
} else { } else {
@ -338,6 +354,16 @@ L.U.Map.include({
return this; return this;
}, },
onceDataLoaded: function (callback, context) {
// Once datalayers **data** have been loaded
if (this.dataLoaded) {
callback.call(context || this, this);
} else {
this.once('dataloaded', callback, context);
}
return this;
},
updateDatalayersControl: function () { updateDatalayersControl: function () {
if (this._controls.datalayers) this._controls.datalayers.update(); if (this._controls.datalayers) this._controls.datalayers.update();
}, },
@ -579,6 +605,7 @@ L.U.Map.include({
['options.includeFullScreenLink', {handler: 'Switch', label: L._('Include full screen link?')}], ['options.includeFullScreenLink', {handler: 'Switch', label: L._('Include full screen link?')}],
['options.currentView', {handler: 'Switch', label: L._('Current view instead of default map view?')}], ['options.currentView', {handler: 'Switch', label: L._('Current view instead of default map view?')}],
['options.keepCurrentDatalayers', {handler: 'Switch', label: L._('Keep current visible layers')}], ['options.keepCurrentDatalayers', {handler: 'Switch', label: L._('Keep current visible layers')}],
['options.viewCurrentFeature', {handler: 'Switch', label: L._('Open current item')}],
'queryString.moreControl', 'queryString.moreControl',
'queryString.scrollWheelZoom', 'queryString.scrollWheelZoom',
'queryString.miniMap', 'queryString.miniMap',
@ -1016,6 +1043,7 @@ L.U.Map.include({
'sortKey', 'sortKey',
'labelKey', 'labelKey',
'filterKey', 'filterKey',
'slugKey',
'showLabel', 'showLabel',
'labelDirection', 'labelDirection',
'labelInteractive', 'labelInteractive',
@ -1209,7 +1237,8 @@ L.U.Map.include({
['options.easing', {handler: 'Switch', label: L._('Advanced transition')}], ['options.easing', {handler: 'Switch', label: L._('Advanced transition')}],
'options.labelKey', 'options.labelKey',
['options.sortKey', {handler: 'BlurInput', helpEntries: 'sortKey', placeholder: L._('Default: name'), label: L._('Sort key'), inheritable: true}], ['options.sortKey', {handler: 'BlurInput', helpEntries: 'sortKey', placeholder: L._('Default: name'), label: L._('Sort key'), inheritable: true}],
['options.filterKey', {handler: 'Input', helpEntries: 'filterKey', placeholder: L._('Default: name'), label: L._('Filter keys'), inheritable: true}] ['options.filterKey', {handler: 'Input', helpEntries: 'filterKey', placeholder: L._('Default: name'), label: L._('Filter keys'), inheritable: true}],
['options.slugKey', {handler: 'BlurInput', helpEntries: 'slugKey', placeholder: L._('Default: name'), label: L._('Feature identifier key')}]
]; ];
builder = new L.U.FormBuilder(this, optionsFields, { builder = new L.U.FormBuilder(this, optionsFields, {

View file

@ -421,6 +421,7 @@ L.U.DataLayer = L.Evented.extend({
this.layer.addLayer(feature); this.layer.addLayer(feature);
this.indexProperties(feature); this.indexProperties(feature);
if (this.hasDataLoaded()) this.fire('datachanged'); if (this.hasDataLoaded()) this.fire('datachanged');
this.map.features_index[feature.getSlug()] = feature;
}, },
removeLayer: function (feature) { removeLayer: function (feature) {
@ -429,6 +430,7 @@ L.U.DataLayer = L.Evented.extend({
this._index.splice(this._index.indexOf(id), 1); this._index.splice(this._index.indexOf(id), 1);
delete this._layers[id]; delete this._layers[id];
this.layer.removeLayer(feature); this.layer.removeLayer(feature);
delete this.map.features_index[feature.getSlug()];
if (this.hasDataLoaded()) this.fire('datachanged'); if (this.hasDataLoaded()) this.fire('datachanged');
}, },

View file

@ -46,7 +46,7 @@ L.U.Slideshow = L.Class.extend({
// Certainly IE8, which has a limited version of defineProperty // Certainly IE8, which has a limited version of defineProperty
} }
if (this.options.autoplay) { if (this.options.autoplay) {
this.map.onceDatalayersLoaded(function () { this.map.onceDataLoaded(function () {
this.play(); this.play();
}, this); }, this);
} }

View file

@ -280,14 +280,6 @@ L.U.Xhr = L.Evented.extend({
logout: function(url) { logout: function(url) {
this.get(url); this.get(url);
},
buildQueryString: function (params) {
var query_string = [];
for (var key in params) {
query_string.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
}
return query_string.join('&');
} }
}); });