import { generateUrl } from '@nextcloud/router';
import { Timer, getLetterColor, hslToRgb } from './utils';
function generateSharingUrl(token) {
return window.location.origin + OC.generateUrl("/apps/maps/s/favorites/" + token);
}
function FavoritesController(optionsController, timeFilterController) {
this.CLUSTER_MARKER_VIEW_SIZE = 27;
this.optionsController = optionsController;
this.timeFilterController = timeFilterController;
this.cluster = null;
// indexed by category name
this.categoryLayers = {};
this.categoryDivIcon = {};
this.categoryColors = {};
this.categoryDeletionTimer = {};
// indexed by category name and then by favorite id
this.categoryMarkers = {};
// indexed by favorite id
this.markers = {};
this.favorites = {};
this.firstDate = null;
this.lastDate = null;
this.addFavoriteMode = false;
this.addFavoriteCategory = null;
this.defaultCategory = t('maps', 'Personal');
this.lastUsedCategory = null;
this.movingFavoriteId = null;
this.sharingFavoriteId = null;
// used by optionsController to know if favorite loading
// was done before or after option restoration
this.favoritesLoaded = false;
}
FavoritesController.prototype = {
// set up favorites-related UI stuff
initFavorites : function(map) {
this.map = map;
var that = this;
// UI events
// toggle favorites
$('body').on('click', '#navigation-favorites > a', function(e) {
that.toggleFavorites();
that.optionsController.saveOptionValues({favoritesEnabled: that.map.hasLayer(that.cluster)});
that.updateTimeFilterRange();
that.timeFilterController.setSliderToMaxInterval();
// expand category list if we just enabled favorites and category list was folded
if (that.map.hasLayer(that.cluster) && !$('#navigation-favorites').hasClass('open')) {
that.toggleCategoryList();
that.optionsController.saveOptionValues({favoriteCategoryListShow: $('#navigation-favorites').hasClass('open')});
}
});
// expand category list
$('body').on('click', '#navigation-favorites', function(e) {
if (e.target.tagName === 'LI' && $(e.target).attr('id') === 'navigation-favorites') {
that.toggleCategoryList();
that.optionsController.saveOptionValues({favoriteCategoryListShow: $('#navigation-favorites').hasClass('open')});
}
});
// toggle a category
$('body').on('click', '.category-line .category-name', function(e) {
var cat = $(this).text();
that.toggleCategory(cat, true);
that.saveEnabledCategories();
});
// zoom to category
$('body').on('click', '.zoomCategoryButton', function(e) {
var cat = $(this).parent().parent().parent().parent().attr('category');
that.zoomOnCategory(cat);
});
// show/hide all categories
$('body').on('click', '#toggle-all-categories', function(e) {
var allEnabled = true;
for (var cat in that.categoryLayers) {
if (!that.map.hasLayer(that.categoryLayers[cat])) {
allEnabled = false;
break;
}
}
if (allEnabled) {
that.hideAllCategories();
}
else {
that.showAllCategories();
}
that.saveEnabledCategories();
that.optionsController.saveOptionValues({favoritesEnabled: that.map.hasLayer(that.cluster)});
});
// export a category
$('body').on('click', '.exportCategoryButton', function(e) {
var cat = $(this).parent().parent().parent().parent().attr('category');
that.exportCategory(cat);
});
// click on + button
$('body').on('click', '#addFavoriteButton', function(e) {
if (that.addFavoriteMode) {
that.leaveAddFavoriteMode();
}
else {
if (that.movingFavoriteId !== null) {
that.leaveMoveFavoriteMode();
}
that.enterAddFavoriteMode(that.defaultCategory);
}
});
$('body').on('click', '.addFavoriteInCategory', function(e) {
var cat = $(this).parent().parent().parent().parent().attr('category');
if (that.movingFavoriteId !== null) {
that.leaveMoveFavoriteMode();
}
that.enterAddFavoriteMode(cat);
});
// Stop click propagation on shareCategory action to prevent menu from closing
$('body').on('click', '.shareCategory', function(e) {
e.stopPropagation();
});
$('body').on('click', '.favorite-share-link-clipboard-button', function(e) {
var clipboardText = $(this).attr('data-clipboard-text');
var $temp = $("");
$("body").append($temp);
$temp.val(clipboardText).select();
document.execCommand("copy");
$temp.remove();
var clipboardButton = $(this);
clipboardButton.addClass('tooltip-visible');
setTimeout(() => {
if (clipboardButton) {
clipboardButton.removeClass('tooltip-visible');
}
}, 1500);
});
$('body').on('change', '.category-sharing-checkbox', function(e) {
var category = $(this).attr('data-category');
var shareMenuEntry = $(this).parent();
if (!this.checked) {
$.ajax({
type: 'POST',
url: OC.generateUrl('/apps/maps/favorites-category/' + category + '/un-share'),
data: {},
async: true
}).done(function () {
var clipboardButton = shareMenuEntry.children('.favorite-share-link-clipboard-button');
clipboardButton.removeClass('visible');
clipboardButton.attr('data-clipboard-text', null);
}).always(function () {
}).fail(function() {
OC.Notification.showTemporary(t('maps', 'Failed to remove favorites category share'));
});
} else {
$.ajax({
type: 'POST',
url: OC.generateUrl('/apps/maps/favorites-category/' + category + '/share'),
data: {},
async: true
}).done(function (response) {
var clipboardButton = shareMenuEntry.children('.favorite-share-link-clipboard-button');
clipboardButton.addClass('visible');
clipboardButton.attr('data-clipboard-text', generateSharingUrl(response.token));
}).always(function () {
}).fail(function() {
OC.Notification.showTemporary(t('maps', 'Failed to share favorites category'));
});
}
});
// cancel favorite edition
$('body').on('click', '.canceleditfavorite', function(e) {
that.map.clickpopup = null;
that.map.closePopup();
});
$('body').on('click', '.valideditfavorite', function(e) {
that.editFavoriteFromPopup($(this));
that.map.clickpopup = null;
that.map.closePopup();
});
$('body').on('click', '.deletefavorite', function(e) {
var favid = parseInt($(this).parent().parent().attr('favid'));
that.deleteFavoriteDB(favid);
that.map.clickpopup = null;
that.map.closePopup();
});
$('body').on('click', '.valideditdeletefavorite', function(e) {
var favid = parseInt($(this).parent().parent().attr('favid'));
that.deleteFavoriteDB(favid);
that.map.clickpopup = null;
that.map.closePopup();
});
$('body').on('click', '.movefavorite', function(e) {
var ul = $(this).parent().parent();
var favid = ul.attr('favid');
that.movingFavoriteId = favid;
if (that.addFavoriteMode) {
that.leaveAddFavoriteMode();
}
that.enterMoveFavoriteMode();
that.map.closePopup();
});
// key events on popup fields
$('body').on('keyup', 'input[role=category], input[role=name]', function(e) {
if (e.key === 'Enter') {
that.editFavoriteFromPopup($(this).parent().parent().parent().parent().find('.valideditfavorite'));
that.map.clickpopup = null;
that.map.closePopup();
}
});
// rename category
$('body').on('click', '.renameCategory', function(e) {
$(this).parent().parent().parent().parent().find('.renameCategoryInput').focus().select();
$('#category-list > li').removeClass('editing');
$(this).parent().parent().parent().parent().addClass('editing');
});
$('body').on('click', '.renameCategoryOk', function(e) {
var cat = $(this).parent().parent().parent().attr('category');
$(this).parent().parent().parent().removeClass('editing').addClass('icon-loading-small');
var newCategoryName = $(this).parent().find('.renameCategoryInput').val() || that.defaultCategory;
that.renameCategoryDB(cat, newCategoryName);
});
$('body').on('keyup', '.renameCategoryInput', function(e) {
if (e.key === 'Enter') {
var cat = $(this).parent().parent().parent().attr('category');
$(this).parent().parent().parent().removeClass('editing').addClass('icon-loading-small');
var newCategoryName = $(this).parent().find('.renameCategoryInput').val() || that.defaultCategory;
that.renameCategoryDB(cat, newCategoryName);
}
else if (e.key === 'Escape') {
$(this).parent().parent().parent().removeClass('editing');
}
});
$('body').on('click', '.renameCategoryClose', function(e) {
$(this).parent().parent().parent().removeClass('editing');
});
// delete category
$('body').on('click', '.deleteCategory', function(e) {
var cat = $(this).parent().parent().parent().parent().attr('category');
$(this).parent().parent().parent().parent().addClass('deleted');
that.categoryDeletionTimer[cat] = new Timer(function() {
that.deleteCategoryFavoritesDB(cat);
}, 7000);
});
$('body').on('click', '.undoDeleteCategory', function(e) {
var cat = $(this).parent().parent().attr('category');
$(this).parent().parent().removeClass('deleted');
that.categoryDeletionTimer[cat].pause();
delete that.categoryDeletionTimer[cat];
});
// export favorites
$('body').on('click', '#export-displayed-favorites', function(e) {
that.exportDisplayedFavorites();
});
// import favorites
$('body').on('click', '#import-favorites', function(e) {
OC.dialogs.filepicker(
t('maps', 'Import favorites from GeoJSON (Google Maps), gpx (OsmAnd, Nextcloud Maps) or kmz/kml (F-Droid Maps, Maps.me, Marble)'),
function(targetPath) {
that.importFavorites(targetPath);
},
false,
['application/gpx+xml', 'application/vnd.google-earth.kmz', 'application/vnd.google-earth.kml+xml', 'application/json', 'application/geo+json'],
true
);
});
this.cluster = L.markerClusterGroup({
iconCreateFunction: this.getClusterIconCreateFunction(),
spiderfyOnMaxZoom: false,
maxClusterRadius: 28,
zoomToBoundsOnClick: false,
chunkedLoading: true,
icon: {
iconSize: [this.CLUSTER_MARKER_VIEW_SIZE, this.CLUSTER_MARKER_VIEW_SIZE]
}
});
this.cluster.on('clusterclick', function (a) {
if (a.layer.getChildCount() > 20 && that.map.getZoom() !== that.map.getMaxZoom()) {
a.layer.zoomToBounds();
}
else {
a.layer.spiderfy();
that.map.clickpopup = true;
}
});
},
getClusterIconCreateFunction: function() {
var that = this;
return function(cluster) {
var fid = parseInt(cluster.getAllChildMarkers()[0].favid);
var category = that.favorites[fid].category;
category = category.replace(/\s+/g, '-');
var label = cluster.getChildCount();
return new L.DivIcon(L.extend({
iconAnchor: [14, 14],
className: 'leaflet-marker-favorite-cluster cluster-marker',
html: '
' + label + ''
}, this.icon));
};
},
zoomOnCategory: function(cat) {
var catLayer = this.categoryLayers[cat];
if (this.map.hasLayer(this.cluster) && this.map.hasLayer(catLayer)) {
this.map.fitBounds(catLayer.getBounds(), {padding: [30, 30]});
}
},
saveEnabledCategories: function() {
var categoryList = [];
var layer;
for (var cat in this.categoryLayers) {
layer = this.categoryLayers[cat];
if (this.map.hasLayer(layer)) {
categoryList.push(cat);
}
}
var categoryStringList = categoryList.join('|');
this.optionsController.saveOptionValues({enabledFavoriteCategories: categoryStringList});
// this is used when favorites are loaded again (when importing for example)
this.optionsController.enabledFavoriteCategories = categoryList;
},
showAllCategories: function() {
if (!this.map.hasLayer(this.cluster)) {
this.toggleFavorites();
}
for (var cat in this.categoryLayers) {
if (!this.map.hasLayer(this.categoryLayers[cat])) {
this.toggleCategory(cat);
}
}
this.updateMyFirstLastDates();
},
hideAllCategories: function() {
for (var cat in this.categoryLayers) {
if (this.map.hasLayer(this.categoryLayers[cat])) {
this.toggleCategory(cat);
}
}
this.updateMyFirstLastDates();
},
toggleCategory: function(cat, updateSlider=false) {
var subgroup = this.categoryLayers[cat];
var catLine = $('#category-list > li[category="'+cat+'"]');
var catName = catLine.find('.category-name');
var catCounter = catLine.find('.app-navigation-entry-utils-counter');
var showAgain = false;
if (this.map.hasLayer(this.cluster)) {
// remove and add cluster to avoid a markercluster bug when spiderfied
this.map.removeLayer(this.cluster);
showAgain = true;
}
// hide category
if (this.map.hasLayer(subgroup)) {
this.map.removeLayer(subgroup);
catName.removeClass('active');
catCounter.hide();
$('#map').focus();
}
// show category
else {
this.map.addLayer(subgroup);
catName.addClass('active');
catCounter.show();
}
if (showAgain) {
this.map.addLayer(this.cluster);
}
if (updateSlider) {
this.updateTimeFilterRange();
this.timeFilterController.setSliderToMaxInterval();
}
},
// expand or fold categories in sidebar and save state in user options
toggleCategoryList: function() {
$('#navigation-favorites').toggleClass('open');
},
// toggle favorites layer on map and save state in user options
toggleFavorites: function() {
if (!this.favoritesLoaded) {
this.getFavorites();
}
if (this.map.hasLayer(this.cluster)) {
this.map.removeLayer(this.cluster);
$('#navigation-favorites').removeClass('active');
$('#map').focus();
}
else {
this.map.addLayer(this.cluster);
$('#navigation-favorites').addClass('active');
}
},
updateMyFirstLastDates: function() {
if (!this.map.hasLayer(this.cluster)) {
this.firstDate = null;
this.lastDate = null;
return;
}
var id, cat;
var first = Math.floor(Date.now() / 1000) + 1000000;
var last = 0;
for (cat in this.categoryMarkers) {
if (this.map.hasLayer(this.categoryLayers[cat])) {
for (id in this.categoryMarkers[cat]) {
if (this.favorites[id].date_created < first) {
first = this.favorites[id].date_created;
}
if (this.favorites[id].date_created > last) {
last = this.favorites[id].date_created;
}
}
}
}
if (first !== (Math.floor(Date.now() / 1000) + 1000000)
&& last !== 0) {
this.firstDate = first;
this.lastDate = last;
}
else {
this.firstDate = null;
this.lastDate = null;
}
},
updateTimeFilterRange: function() {
this.updateMyFirstLastDates();
this.timeFilterController.updateSliderRangeFromController();
},
// add/remove markers from layers considering current filter values
updateFilterDisplay: function() {
var startFilter = this.timeFilterController.valueBegin;
var endFilter = this.timeFilterController.valueEnd;
var cat, favid, markers, i, date_created;
// markers to hide
for (cat in this.categoryLayers) {
markers = this.categoryLayers[cat].getLayers();
for (i=0; i < markers.length; i++) {
favid = markers[i].favid;
date_created = this.favorites[favid].date_created;
if (date_created < startFilter || date_created > endFilter) {
this.categoryLayers[cat].removeLayer(markers[i]);
}
}
}
// markers to show
for (cat in this.categoryMarkers) {
for (favid in this.categoryMarkers[cat]) {
date_created = this.favorites[favid].date_created;
if (date_created >= startFilter && date_created <= endFilter) {
this.categoryLayers[cat].addLayer(this.categoryMarkers[cat][favid]);
}
}
}
},
// get favorites from server and create map layers
// show map layers if favorites are enabled
getFavorites: function() {
var that = this;
$('#navigation-favorites').addClass('icon-loading-small');
var favorites = [];
var sharedCategories = [];
$.when(
$.ajax({
url: generateUrl('/apps/maps/favorites'),
data: {},
type: 'GET',
async: true,
success: function(response) {
favorites = response;
},
fail: function(response) {
OC.Notification.showTemporary(t('maps', 'Failed to load favorites'));
}
}), $.ajax({
url: OC.generateUrl('/apps/maps/favorites-category/shared'),
data: {},
type: 'GET',
async: true,
success: function(response) {
for (var i = 0; i < response.length; i++) {
sharedCategories[response[i].category] = response[i].token;
}
},
fail: function(response) {
OC.Notification.showTemporary(t('maps', 'Failed to load favorite share token'));
}
})
).then(function() {
for (var i=0; i < favorites.length; i++) {
var token = sharedCategories[favorites[i].category] || null;
const enableCategory = that.optionsController.enabledFavoriteCategories.includes(favorites[i].category)
that.addFavoriteMap(favorites[i], enableCategory, false, token);
}
that.updateCategoryCounters();
that.favoritesLoaded = true;
that.updateTimeFilterRange();
that.timeFilterController.setSliderToMaxInterval();
$('#navigation-favorites').removeClass('icon-loading-small');
});
},
// add category in side menu
// add layer
// set color and icon
addCategory: function(rawName, enable=false, shareToken = null) {
var name = rawName.replace(/\s+/g, '-');
// color
var color = '0000EE';
if (rawName.length > 1) {
var hsl = getLetterColor(rawName[0], rawName[1]);
color = hslToRgb(hsl.h/360, hsl.s/100, hsl.l/100);
}
if (rawName === this.defaultCategory) {
color = (OCA.Theming ? OCA.Theming.color : '#0082c9').replace('#', '');
}
this.categoryColors[rawName] = color;
$('').appendTo('body');
// subgroup layer
this.categoryLayers[rawName] = L.featureGroup.subGroup(this.cluster, []);
this.categoryMarkers[rawName] = {};
// icon for markers
this.categoryDivIcon[rawName] = L.divIcon({
iconAnchor: [9, 9],
className: 'leaflet-marker-favorite',
html: ''
});
var checkboxId = 'checkbox-' + name.toLowerCase();
// side menu entry
var imgurl = generateUrl('/svg/core/actions/star?color='+color);
var li = '' +
' '+rawName+'' +
' ' +
' ' +
' ' +
'
'+t('maps', 'Category deleted')+'
' +
'
' +
'
' +
' ' +
'';
var beforeThis = null;
var rawLower = rawName.toLowerCase();
$('#category-list > li').each(function() {
var catName = $(this).attr('category');
if (rawLower.localeCompare(catName) < 0) {
beforeThis = $(this);
return false;
}
});
if (beforeThis !== null) {
$(li).insertBefore(beforeThis);
}
else {
$('#category-list').append(li);
}
// enable if in saved options or if it should be enabled for another reason :
// * added because a favorite was added by the user in this category which didn't exist
// * added because a favorite was edited by the user and triggered creation of this category
if (enable || this.optionsController.enabledFavoriteCategories.indexOf(rawName) !== -1) {
this.toggleCategory(rawName);
}
},
renameCategoryDB: function(cat, newCategoryName) {
var that = this;
var origCatList = [cat];
$('#navigation-favorites').addClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'wait');
var req = {
categories: origCatList,
newName: newCategoryName
};
var url = generateUrl('/apps/maps/favorites-category');
$.ajax({
type: 'PUT',
url: url,
data: req,
async: true
}).done(function (response) {
var markers = that.categoryMarkers[cat];
var favid, favname;
for (favid in markers) {
that.editFavoriteMap(favid, null, null, newCategoryName, null, null);
}
that.updateCategoryCounters();
}).always(function (response) {
$('#navigation-favorites').removeClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'grab');
}).fail(function() {
OC.Notification.showTemporary(t('maps', 'Failed to rename category'));
});
},
deleteCategoryFavoritesDB: function(cat) {
var markers = this.categoryMarkers[cat];
var favids = [];
for (var favid in markers) {
favids.push(favid);
}
var that = this;
$('#navigation-favorites').addClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'wait');
var req = {
ids: favids
};
var url = generateUrl('/apps/maps/favorites');
$.ajax({
type: 'DELETE',
url: url,
data: req,
async: true
}).done(function (response) {
that.deleteCategoryMap(cat, true);
}).always(function (response) {
$('#navigation-favorites').removeClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'grab');
}).fail(function() {
OC.Notification.showTemporary(t('maps', 'Failed to delete category favorites'));
});
},
deleteCategoryMap: function(cat, updateSlider=false) {
// favorites (just in case the category is not empty)
var favids = [];
for (favid in this.categoryMarkers[cat]) {
favids.push(favid);
}
for (var i=0; i < favids.length; i++) {
var favid = favids[i];
this.categoryLayers[cat].removeLayer(this.markers[favid]);
delete this.favorites[favid];
delete this.markers[favid];
delete this.categoryMarkers[cat][favid];
}
// category
this.map.removeLayer(this.categoryLayers[cat]);
delete this.categoryLayers[cat];
delete this.categoryMarkers[cat];
delete this.categoryDivIcon[cat];
delete this.categoryColors[cat];
$('#category-list #' + cat.replace(/\s+/g, '-') + '-category').fadeOut('slow', function() {
$(this).remove();
});
if (updateSlider) {
this.updateTimeFilterRange();
this.timeFilterController.setSliderToMaxInterval();
}
},
updateCategoryCounters: function() {
var count;
var total = 0;
for (var cat in this.categoryMarkers) {
count = Object.keys(this.categoryMarkers[cat]).length;
$('#' + cat.replace(/\s+/g, '-')+'-category .app-navigation-entry-utils-counter').text(count);
total = total + count;
}
//$('#navigation-favorites > .app-navigation-entry-utils .app-navigation-entry-utils-counter').text(total);
},
enterAddFavoriteMode: function(categoryName) {
this.addFavoriteCategory = categoryName;
$('.leaflet-container, .mapboxgl-map').css('cursor','crosshair');
this.map.on('click', this.addFavoriteClickMap);
this.map.leftClickLock = true;
$('#addFavoriteButton button').removeClass('icon-add').addClass('icon-history');
$('#explainaddpoint').show();
this.addFavoriteMode = true;
OC.Notification.showTemporary(t('maps', 'Click on the map to add a favorite, press Esc to cancel'));
},
leaveAddFavoriteMode: function() {
$('.leaflet-container, .mapboxgl-map').css('cursor','grab');
this.map.off('click', this.addFavoriteClickMap);
this.map.leftClickLock = false;
$('#addFavoriteButton button').addClass('icon-add').removeClass('icon-history');
this.addFavoriteMode = false;
this.addFavoriteCategory = null;
},
addFavoriteClickMap: function(e) {
var categoryName = this.favoritesController.addFavoriteCategory;
if (categoryName === this.favoritesController.defaultCategory && this.favoritesController.lastUsedCategory !== null) {
categoryName = this.favoritesController.lastUsedCategory;
}
this.favoritesController.leaveAddFavoriteMode();
this.favoritesController.addFavoriteDB(categoryName, e.latlng.lat.toFixed(6), e.latlng.lng.toFixed(6), null);
},
contextAddFavorite: function(e) {
var categoryName = this.favoritesController.defaultCategory;
if (this.favoritesController.lastUsedCategory !== null) {
categoryName = this.favoritesController.lastUsedCategory;
}
this.favoritesController.addFavoriteDB(categoryName, e.latlng.lat.toFixed(6), e.latlng.lng.toFixed(6), null);
},
// make the request
addFavoriteDB: function(category, lat, lng, name, comment=null, extensions=null) {
var that = this;
$('#navigation-favorites').addClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'wait');
var req = {
name: name,
lat: lat,
lng: lng,
category: category,
comment: comment,
extensions: extensions
};
var url = generateUrl('/apps/maps/favorites');
$.ajax({
type: 'POST',
url: url,
data: req,
async: true
}).done(function (response) {
that.addFavoriteMap(response, true, true);
that.updateCategoryCounters();
// show edition popup
that.openEditionPopup(response.id);
}).always(function (response) {
$('#navigation-favorites').removeClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'grab');
}).fail(function() {
OC.Notification.showTemporary(t('maps', 'Failed to add favorite'));
});
},
// add a marker to the corresponding layer
addFavoriteMap: function(fav, enableCategory=false, fromUserAction=false, shareToken = null) {
// manage category first
var cat = fav.category;
if (!this.categoryLayers.hasOwnProperty(cat)) {
this.addCategory(cat, enableCategory, shareToken);
if (enableCategory && fromUserAction) {
this.saveEnabledCategories();
}
}
else {
// if favorites are hidden, show them
if (fromUserAction && !this.map.hasLayer(this.cluster)) {
this.toggleFavorites();
this.optionsController.saveOptionValues({favoritesEnabled: this.map.hasLayer(this.cluster)});
}
// if the category is disabled, enable it
if (fromUserAction && !this.map.hasLayer(this.categoryLayers[cat])) {
this.toggleCategory(cat);
this.saveEnabledCategories();
}
}
// create the marker and related events
// put favorite id as marker attribute
var marker = L.marker(L.latLng(fav.lat, fav.lng), {
icon: this.categoryDivIcon[cat]
});
marker.favid = fav.id;
marker.on('mouseover', this.favoriteMouseover);
marker.on('mouseout', this.favoriteMouseout);
marker.on('click', this.favoriteMouseClick);
marker.on('contextmenu', this.favoriteMouseRightClick);
// add to map and arrays
this.favorites[fav.id] = fav;
this.markers[fav.id] = marker;
this.categoryMarkers[cat][fav.id] = marker;
this.categoryLayers[cat].addLayer(marker);
if (fromUserAction) {
// we make sure created favorite is displayed
var minFilter = this.timeFilterController.min;
var maxFilter = this.timeFilterController.max;
var startFilter = this.timeFilterController.valueBegin;
var endFilter = this.timeFilterController.valueEnd;
var favDate = fav.date_created;
if (favDate < minFilter) {
minFilter = favDate;
}
if (favDate < startFilter) {
startFilter = favDate;
}
if (favDate > maxFilter) {
maxFilter = favDate;
}
if (favDate > endFilter) {
endFilter = favDate;
}
this.timeFilterController.updateSliderRange(minFilter, maxFilter);
this.timeFilterController.setSlider(startFilter, endFilter);
// and make sure slider will reset to correct values (dblclick)
this.updateMyFirstLastDates();
}
},
favoriteMouseover: function(e) {
var favid = e.target.favid;
var fav = this._map.favoritesController.favorites[favid];
var cat = fav.category.replace(/\s+/g, '-');
var favTooltip = this._map.favoritesController.getFavoriteTooltipContent(fav);
e.target.bindTooltip(favTooltip, {
className: 'leaflet-marker-favorite-tooltip tooltipfav-' + cat,
direction: 'top'
});
e.target.openTooltip();
},
favoriteMouseout: function(e) {
e.target.unbindTooltip();
e.target.closeTooltip();
},
getFavoriteTooltipContent: function(fav) {
var content = '' + t('maps', 'Name') + ': ' + (fav.name || t('maps', 'No name'));
content = content + '
' + t('maps', 'Category') + ': ' + fav.category;
if (fav.comment) {
content = content + '
' + t('maps', 'Comment') + ': ' + fav.comment;
}
return content;
},
favoriteMouseClick: function(e) {
var favid = e.target.favid;
this._map.favoritesController.openEditionPopup(favid);
},
openEditionPopup: function(favid) {
var that = this;
var fav = this.favorites[favid];
//e.target.unbindPopup();
var popupContent = this.getFavoritePopupContent(fav);
var popup = L.popup({
closeOnClick: true,
className: 'popovermenu open popupMarker',
offset: L.point(-5, 9)
})
.setLatLng([fav.lat, fav.lng])
.setContent(popupContent)
.openOn(this.map);
$(popup._closeButton).one('click', function(e){
that.map.clickpopup = null;
});
// add completion to category field
var catList = [];
for (var c in this.categoryLayers) {
catList.push(c);
}
$('input[role="category"]').autocomplete({
source: catList
});
$('input[role="name"]').focus().select();
this.map.clickpopup = true;
},
getFavoritePopupContent: function(fav) {
var validText = t('maps', 'Submit');
var deleteText = t('maps', 'Delete');
var namePH = t('maps', 'Favorite name');
var categoryPH = t('maps', 'Category');
var commentPH = t('maps', 'Comment');
var res =
'' +
' - ' +
' ' +
'
' +
' - ' +
' ' +
'
' +
' - ' +
' ' +
'
' +
' - ' +
' ' +
'
' +
' - ' +
' ' +
'
' +
'
';
return res;
},
favoriteMouseRightClick: function(e) {
var that = this;
var favid = e.target.favid;
var fav = this._map.favoritesController.favorites[favid];
this._map.clickpopup = true;
e.target.unbindPopup();
var popupContent = this._map.favoritesController.getFavoriteContextPopupContent(fav);
var popup = L.popup({
closeOnClick: true,
className: 'popovermenu open popupMarker',
offset: L.point(-5, 9)
})
.setLatLng([fav.lat, fav.lng])
.setContent(popupContent)
.openOn(this._map);
$(popup._closeButton).one('click', function (e) {
that._map.clickpopup = null;
});
},
getFavoriteContextPopupContent: function(fav) {
var moveText = t('maps', 'Move');
var deleteText = t('maps', 'Delete');
var res =
'' +
' - ' +
' ' +
'
' +
' - ' +
' ' +
'
' +
'
';
return res;
},
deleteFavoriteDB: function(favid) {
var that = this;
$('#navigation-favorites').addClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'wait');
var req = {
};
var url = generateUrl('/apps/maps/favorites/'+favid);
$.ajax({
type: 'DELETE',
url: url,
data: req,
async: true
}).done(function (response) {
that.deleteFavoriteMap(favid);
that.updateCategoryCounters();
}).always(function (response) {
$('#navigation-favorites').removeClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'grab');
}).fail(function() {
OC.Notification.showTemporary(t('maps', 'Failed to delete favorite'));
});
},
deleteFavoriteMap: function(favid) {
var marker = this.markers[favid];
var fav = this.favorites[favid];
var cat = fav.category;
this.categoryLayers[cat].removeLayer(marker);
delete this.categoryMarkers[cat][favid];
delete this.markers[favid];
delete this.favorites[favid];
// delete category if empty
if (Object.keys(this.categoryMarkers[cat]).length === 0) {
this.deleteCategoryMap(cat, true);
this.saveEnabledCategories();
}
// as this was triggered by user action :
this.updateMyFirstLastDates();
},
editFavoriteFromPopup: function(button) {
var ul = button.parent().parent();
var favid = parseInt(ul.attr('favid'));
var fav = this.favorites[favid];
var newName = ul.find('input[role=name]').val();
var newCategory = ul.find('input[role=category]').val() || this.defaultCategory;
var newComment = ul.find('textarea[role=comment]').val();
this.lastUsedCategory = newCategory;
this.editFavoriteDB(favid, newName, newComment, newCategory, null, null);
},
editFavoriteDB: function(favid, name, comment, category, lat, lng) {
var that = this;
$('#navigation-favorites').addClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'wait');
var req = {
name: name,
extensions: null
};
if (comment !== null) {
req.comment = comment;
}
if (category !== null) {
req.category = category;
}
if (lat) {
req.lat = lat;
}
if (lng) {
req.lng = lng;
}
var url = generateUrl('/apps/maps/favorites/'+favid);
$.ajax({
type: 'PUT',
url: url,
data: req,
async: true
}).done(function (response) {
that.editFavoriteMap(favid, name, comment, category, lat, lng);
that.updateCategoryCounters();
}).always(function (response) {
$('#navigation-favorites').removeClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'grab');
}).fail(function() {
OC.Notification.showTemporary(t('maps', 'Failed to edit favorite'));
});
},
editFavoriteMap: function(favid, name, comment, category, lat, lng) {
if (name !== null) {
this.favorites[favid].name = name;
}
if (comment !== null) {
this.favorites[favid].comment = comment;
}
if (category !== null) {
var oldCategory = this.favorites[favid].category;
var newCategory = category;
if (newCategory !== oldCategory) {
var marker = this.markers[favid];
delete this.categoryMarkers[oldCategory][favid];
this.categoryLayers[oldCategory].removeLayer(marker);
var shouldSaveCategories = false;
// delete old category if empty
if (Object.keys(this.categoryMarkers[oldCategory]).length === 0) {
this.deleteCategoryMap(oldCategory, true);
shouldSaveCategories = true;
}
// create category if necessary
if (!this.categoryLayers.hasOwnProperty(newCategory)) {
this.addCategory(newCategory, true);
shouldSaveCategories = true;
} else {
// enable category if it's not
if (!this.map.hasLayer(this.categoryLayers[newCategory])) {
this.toggleCategory(newCategory)
shouldSaveCategories = true;
}
}
if (shouldSaveCategories) {
this.saveEnabledCategories();
}
marker.setIcon(this.categoryDivIcon[newCategory]);
this.categoryLayers[newCategory].addLayer(marker);
this.categoryMarkers[newCategory][favid] = marker;
// the real value goes here
this.favorites[favid].category = category;
}
}
if (lat !== null && lng !== null) {
this.favorites[favid].lat = lat;
this.favorites[favid].lng = lng;
var marker = this.markers[favid];
marker.setLatLng([lat, lng]);
}
},
enterMoveFavoriteMode: function() {
$('.leaflet-container, .mapboxgl-map').css('cursor', 'crosshair');
this.map.on('click', this.moveFavoriteClickMap);
OC.Notification.showTemporary(t('maps', 'Click on the map to move the favorite, press Esc to cancel'));
},
leaveMoveFavoriteMode: function() {
$('.leaflet-container, .mapboxgl-map').css('cursor', 'grab');
this.map.off('click', this.moveFavoriteClickMap);
this.movingFavoriteId = null;
},
moveFavoriteClickMap: function(e) {
var lat = e.latlng.lat;
var lng = e.latlng.lng;
var favid = this.favoritesController.movingFavoriteId;
var name = this.favoritesController.favorites[favid].name;
this.favoritesController.leaveMoveFavoriteMode();
this.favoritesController.editFavoriteDB(favid, name, null, null, lat, lng);
},
exportCategory: function(cat) {
var catList = [cat];
this.exportDisplayedFavorites(catList);
},
exportDisplayedFavorites: function(catList=null) {
$('#navigation-favorites').addClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'wait');
if (catList === null) {
catList = [];
if (this.map.hasLayer(this.cluster)) {
for (var cat in this.categoryLayers) {
if (this.map.hasLayer(this.categoryLayers[cat])) {
catList.push(cat);
}
}
}
}
var begin = this.timeFilterController.valueBegin;
var end = this.timeFilterController.valueEnd;
var req = {
categoryList: catList,
begin: begin,
end: end
};
var url = generateUrl('/apps/maps/export/favorites');
$.ajax({
type: 'POST',
url: url,
data: req,
async: true
}).done(function (response) {
OC.Notification.showTemporary(t('maps', 'Favorites exported in {path}', {path: response}));
}).always(function (response) {
$('#navigation-favorites').removeClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'grab');
}).fail(function(response) {
OC.Notification.showTemporary(t('maps', 'Failed to export favorites') + ': ' + response.responseText);
});
},
importFavorites: function(path) {
$('#navigation-favorites').addClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'wait');
var that = this;
var req = {
path: path
};
var url = generateUrl('/apps/maps/import/favorites');
$.ajax({
type: 'POST',
url: url,
data: req,
async: true
}).done(function (response) {
OC.Notification.showTemporary(t('maps', '{nb} favorites imported from {path}', {nb: response.nbImported, path: path}));
var catToDel = [];
for (var cat in that.categoryLayers) {
catToDel.push(cat);
}
for (var i=0; i < catToDel.length; i++) {
that.deleteCategoryMap(catToDel[i]);
}
that.getFavorites();
if (response.linesFound === true) {
OC.Notification.showTemporary(
t('maps', 'Warning: tracks or routes were found in imported files, they were ignored.'));
}
}).always(function (response) {
$('#navigation-favorites').removeClass('icon-loading-small');
$('.leaflet-container, .mapboxgl-map').css('cursor', 'grab');
}).fail(function() {
OC.Notification.showTemporary(t('maps', 'Failed to import favorites'));
});
},
getAutocompData: function() {
var that = this;
var fav, layer;
var data = [];
if (that.map.hasLayer(that.cluster)) {
for (var cat in this.categoryLayers) {
layer = this.categoryLayers[cat];
if (this.map.hasLayer(layer)) {
layer.eachLayer(function (l) {
fav = that.favorites[l.favid];
if (fav.name) {
data.push({
type: 'favorite',
label: fav.name,
value: fav.name,
lat: fav.lat,
lng: fav.lng
});
}
});
}
}
}
return data;
},
}
export default FavoritesController;