diff --git a/.eslintignore b/.eslintignore index bf2095309..aa1a45c5b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,12 +1,4 @@ js/ l10n/ src/adminSettings.js -src/contactsController.js -src/devicesController.js -src/favoritesController.js -src/filetypes.js -src/nonLocalizedPhotosController.js -src/photosController.js -src/script.js -src/tracksController.js src/utils.js diff --git a/appinfo/routes_old.php b/appinfo/routes_old.php deleted file mode 100644 index 0755ca545..000000000 --- a/appinfo/routes_old.php +++ /dev/null @@ -1,41 +0,0 @@ -, Vinzenz Rosenkranz - * @copyright Sander Brand 2014, Vinzenz Rosenkranz 2016, 2017 - */ - -namespace OCA\Maps\AppInfo; - -/** - * Create your routes in here. The name is the lowercase name of the controller - * without the controller part, the stuff after the hash is the method. - * e.g. page#index -> PageController->index() - * - * The controller class has to be registered in the application.php file since - * it's instantiated in there - */ -$application = new Application(); - -$application->registerRoutes($this, array('routes' => array( - array('name' => 'page#index', 'url' => '/', 'verb' => 'GET'), - array('name' => 'page#do_proxy', 'url' => '/router', 'verb' => 'GET'), - array('name' => 'page#getlayer', 'url' => '/layer', 'verb' => 'GET'), - array('name' => 'page#adresslookup', 'url' => '/adresslookup', 'verb' => 'GET'), - array('name' => 'page#geodecode', 'url' => '/geodecode', 'verb' => 'GET'), - array('name' => 'page#search', 'url' => '/search', 'verb' => 'GET'), - - array('name' => 'favorite#add_favorite', 'url' => '/api/1.0/favorite/addToFavorites', 'verb' => 'POST'), - array('name' => 'favorite#get_favorites', 'url' => '/api/1.0/favorite/getFavorites', 'verb' => 'POST'), - array('name' => 'favorite#remove_favorite', 'url' => '/api/1.0/favorite/removeFromFavorites', 'verb' => 'POST'), - array('name' => 'favorite#update_favorite', 'url' => '/api/1.0/favorite/updateFavorite', 'verb' => 'POST'), - array('name' => 'favorite#get_favorites_by_name', 'url' => '/api/1.0/favorite/getFavoritesByName', 'verb' => 'POST'), - - array('name' => 'apikey#get_key', 'url' => '/api/1.0/apikey/getKey', 'verb' => 'POST'), - array('name' => 'apikey#add_key', 'url' => '/api/1.0/apikey/addKey', 'verb' => 'POST'), - -))); diff --git a/src/contactsController.js b/src/contactsController.js deleted file mode 100644 index 119e07fbc..000000000 --- a/src/contactsController.js +++ /dev/null @@ -1,862 +0,0 @@ -import { generateUrl } from '@nextcloud/router'; - -import { basename, formatAddress } from './utils'; -import escapeHTML from 'escape-html'; - -function ContactsController (optionsController, searchController) { - this.contact_MARKER_VIEW_SIZE = 40; - this.contactLayer = null; - this.contactsDataLoaded = false; - this.contactsRequestInProgress = false; - this.optionsController = optionsController; - this.searchController = searchController; - // indexed by group name, contains number of contacts in the group - this.groupsCount = {'0': 0}; - this.groups = {}; - this.contactMarkers = []; - - this.movingBookid = null; - this.movingUri = null; - this.movingUid = null; -} - -ContactsController.prototype = { - - initLayer: function(map) { - this.map = map; - var that = this; - this.contactLayer = L.markerClusterGroup({ - iconCreateFunction : this.getClusterIconCreateFunction(), - spiderfyOnMaxZoom: false, - showCoverageOnHover : false, - zoomToBoundsOnClick: false, - maxClusterRadius: this.contact_MARKER_VIEW_SIZE + 10, - icon: { - iconSize: [this.contact_MARKER_VIEW_SIZE, this.contact_MARKER_VIEW_SIZE] - } - }); - this.contactLayer.on('click', this.getContactMarkerOnClickFunction()); - this.contactLayer.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; - } - }); - // click on contact menu entry - $('body').on('click', '#navigation-contacts > a', function(e) { - that.toggleLayer(); - that.optionsController.saveOptionValues({contactLayer: that.map.hasLayer(that.contactLayer)}); - // expand group list if we just enabled favorites and category list was folded - if (that.map.hasLayer(that.contactLayer) && !$('#navigation-contacts').hasClass('open')) { - that.toggleGroupList(); - that.optionsController.saveOptionValues({contactGroupListShow: $('#navigation-contacts').hasClass('open')}); - } - }); - // expand group list - $('body').on('click', '#navigation-contacts', function(e) { - if (e.target.tagName === 'LI' && $(e.target).attr('id') === 'navigation-contacts') { - that.toggleGroupList(); - that.optionsController.saveOptionValues({contactGroupListShow: $('#navigation-contacts').hasClass('open')}); - } - }); - // toggle a group - $('body').on('click', '.contact-group-line .contact-group-name', function(e) { - var groupName = $(this).parent().attr('contact-group'); - that.toggleGroup(groupName, true); - that.saveDisabledGroups(); - that.addMarkersToLayer(); - }); - // show/hide all groups - $('body').on('click', '#toggle-all-contact-groups', function(e) { - var allEnabled = true; - for (var gn in that.groups) { - if (!that.groups[gn].enabled) { - allEnabled = false; - break; - } - } - - if (allEnabled) { - that.hideAllGroups(); - } - else { - that.showAllGroups(); - } - that.saveDisabledGroups(); - that.optionsController.saveOptionValues({contactLayer: that.map.hasLayer(that.contactLayer)}); - that.addMarkersToLayer(); - }); - // zoom to group - $('body').on('click', '.zoomContactGroupButton', function(e) { - var groupName = $(this).parent().parent().parent().parent().attr('contact-group'); - that.zoomOnGroup(groupName); - }); - // zoom to all contacts - $('body').on('click', '#zoom-all-contact-groups', function(e) { - that.zoomOnGroup(); - }); - // delete address - $('body').on('click', '.deleteContactAddress', function(e) { - var bookid = $(this).attr('bookid'); - var uri = $(this).attr('uri'); - var uid = $(this).attr('uid'); - var vcardAddress = $(this).attr('vcardaddress'); - that.deleteContactAddress(bookid, uri, uid, vcardAddress); - }); - $('body').on('click', '#submitPlaceContactButton', function(e) { - that.submitPlaceContact(); - }); - }, - - showLayer: function() { - if (!this.contactsDataLoaded && !this.contactsRequestInProgress) { - this.callForContacts(); - } - if (!this.map.hasLayer(this.contactLayer)) { - this.map.addLayer(this.contactLayer); - } - }, - - hideLayer: function() { - if (this.map.hasLayer(this.contactLayer)) { - this.map.removeLayer(this.contactLayer); - } - }, - - toggleLayer: function() { - if (this.map.hasLayer(this.contactLayer)) { - this.hideLayer(); - $('#navigation-contacts').removeClass('active'); - $('#navigation-contacts > .app-navigation-entry-utils .app-navigation-entry-utils-counter').hide(); - $('#map').focus(); - } else { - this.showLayer(); - $('#navigation-contacts > .app-navigation-entry-utils .app-navigation-entry-utils-counter').show(); - $('#navigation-contacts').addClass('active'); - } - }, - - // expand or fold groups in sidebar - toggleGroupList: function() { - $('#navigation-contacts').toggleClass('open'); - }, - - toggleGroup: function(groupName) { - var groupLine = $('#contact-group-list > li[contact-group="'+groupName+'"]'); - var groupCounter = groupLine.find('.app-navigation-entry-utils-counter'); - var showAgain = false; - if (this.map.hasLayer(this.contactLayer)) { - // remove and add cluster to avoid a markercluster bug when spiderfied - this.map.removeLayer(this.contactLayer); - showAgain = true; - } - // hide - if (this.groups[groupName].enabled) { - this.groups[groupName].enabled = false; - groupLine.removeClass('active'); - groupLine.find('.contact-group-name').removeClass('active'); - groupCounter.hide(); - $('#map').focus(); - } - // show - else { - this.groups[groupName].enabled = true; - groupLine.addClass('active'); - groupLine.find('.contact-group-name').addClass('active'); - groupCounter.show(); - } - if (showAgain) { - this.map.addLayer(this.contactLayer); - } - }, - - showAllGroups: function() { - if (!this.map.hasLayer(this.contactLayer)) { - this.showLayer(); - } - for (var gn in this.groups) { - if (!this.groups[gn].enabled) { - this.toggleGroup(gn); - } - } - }, - - hideAllGroups: function() { - for (var gn in this.groups) { - if (this.groups[gn].enabled) { - this.toggleGroup(gn); - } - } - }, - - saveDisabledGroups: function() { - var groupList = []; - for (var gn in this.groups) { - if (!this.groups[gn].enabled) { - groupList.push(gn); - } - } - var groupStringList = groupList.join('|'); - this.optionsController.saveOptionValues({disabledContactGroups: groupStringList}); - // this is used when contacts are loaded again - this.optionsController.disabledContactGroups = groupList; - }, - - zoomOnGroup: function(groupName=null) { - // zoom on all groups only if there are contacts - if (groupName === null && this.contactLayer.getLayers().length > 0) { - var b = this.contactLayer.getBounds(); - this.map.fitBounds(b, { padding: [30, 30] }); - } - // zoom on a specific group - else { - // enable the group if it was not - if (!$('li.contact-group-line[contact-group="'+groupName+'"]').hasClass('active')) { - this.toggleGroup(groupName); - this.addMarkersToLayer(); - this.saveDisabledGroups(); - } - // determine the bounds - var lat, lng; - var minLat = null; - var maxLat = null; - var minLng = null; - var maxLng = null; - if (this.contactMarkers.length > 0) { - for (var i=0; i < this.contactMarkers.length; i++) { - // if contact is in the group we zoom on - if ((groupName === '0' && this.contactMarkers[i].data.groups.length === 0) - || this.contactMarkers[i].data.groups.indexOf(groupName) !== -1) { - lat = this.contactMarkers[i].data.lat; - lng = this.contactMarkers[i].data.lng; - if (minLat === null) { - minLat = lat; - maxLat = lat; - minLng = lng; - maxLng = lng; - } - else { - if (lat < minLat) { - minLat = lat; - } - if (lat > maxLat) { - maxLat = lat; - } - if (lng < minLng) { - minLng = lng; - } - if (lng > maxLng) { - maxLng = lng; - } - } - } - } - } - if (minLat !== null) { - var b = L.latLngBounds(L.latLng(minLat, minLng), L.latLng(maxLat, maxLng)); - this.map.fitBounds(b, {padding: [30, 30]}); - } - else { - OC.Notification.showTemporary(t('maps', 'There are no contacts to zoom on')); - } - } - }, - - getContactMarkerOnClickFunction: function() { - var _app = this; - return function(evt) { - var marker = evt.layer; - var popupContent = _app.getContactPopupContent(marker.data); - marker.unbindTooltip(); - this._map.clickpopup = true; - - var popup = L.popup({ - closeOnClick: true, - className: 'popovermenu open popupMarker contactPopup', - offset: L.point(-5, 10) - }) - .setLatLng(marker.getLatLng()) - .setContent(popupContent) - .openOn(_app.map); - $(popup._closeButton).one('click', function (e) { - _app.map.clickpopup = null; - }); - }; - }, - - getClusterIconCreateFunction: function() { - var _app = this; - return function(cluster) { - var marker = cluster.getAllChildMarkers()[0].data; - var iconUrl = marker.avatar; - var label = cluster.getChildCount(); - return new L.DivIcon(L.extend({ - className: 'leaflet-marker-contact cluster-marker', - html: '
' + label + '' - }, this.icon)); - }; - }, - - createContactView: function(markerData) { - var avatar = markerData.avatar; - //this.generatePreviewUrl(markerData.path); - return L.divIcon(L.extend({ - html: '
​', - className: 'leaflet-marker-contact contact-marker' - }, markerData, { - iconSize: [this.contact_MARKER_VIEW_SIZE, this.contact_MARKER_VIEW_SIZE], - iconAnchor: [this.contact_MARKER_VIEW_SIZE / 2, this.contact_MARKER_VIEW_SIZE] - })); - }, - - addContactsToMap: function(contacts) { - var markers = this.prepareContactMarkers(contacts); - $('#navigation-contacts .app-navigation-entry-utils-counter span').text(markers.length); - for (var gn in this.groupsCount) { - this.addGroup(gn); - } - this.contactMarkers.push.apply(this.contactMarkers, markers); - this.contactMarkers.sort(function (a, b) { return a.data.date - b.data.date;}); - - // we put them in the layer - this.addMarkersToLayer(); - }, - - addMarkersToLayer: function() { - this.contactLayer.clearLayers(); - var displayedMarkers = []; - var i, j, m; - for (i=0; i < this.contactMarkers.length; i++) { - m = this.contactMarkers[i]; - // not grouped - if (m.data.groups.length === 0 && this.groups['0'].enabled) { - displayedMarkers.push(m); - continue; - } - // in at least a group - else { - for (j=0; j < m.data.groups.length; j++) { - if (this.groups[m.data.groups[j]].enabled) { - displayedMarkers.push(m); - continue; - } - } - } - } - this.contactLayer.addLayers(displayedMarkers); - }, - - addGroup: function(rawName, enable=false) { - this.groups[rawName] = {}; - var name = rawName.replace(/\s+/g, '-'); - - var color = '000000'; - var displayName = rawName; - if (rawName === '0') { - displayName = t('maps', 'Not grouped'); - } - this.groups[rawName].color = color; - - // side menu entry - var imgurl = generateUrl('/svg/core/places/contacts?color='+color); - var li = '
  • ' + - ' '+displayName+'' + - '
    ' + - '
      ' + - ' ' + - '
    • ' + - ' ' + - '
    • ' + - '
    ' + - '
    ' + - '
    ' + - ' ' + - '
    ' + - '
  • '; - - var beforeThis = null; - var rawLower = rawName.toLowerCase(); - $('#contact-group-list > li').each(function() { - let groupName = $(this).attr('contact-group'); - if (rawLower.localeCompare(groupName) < 0) { - beforeThis = $(this); - return false; - } - }); - if (beforeThis !== null) { - $(li).insertBefore(beforeThis); - } - else { - $('#contact-group-list').append(li); - } - - // enable if in saved options - if (enable || this.optionsController.disabledContactGroups.indexOf(rawName) === -1) { - this.toggleGroup(rawName); - } - }, - - resetGroupList: function() { - $('#contact-group-list li').remove(); - }, - - prepareContactMarkers: function(contacts) { - var j, groupName; - var markers = []; - for (var i = 0; i < contacts.length; i++) { - - var geo = []; - if (contacts[i].GEO.slice(0,4) === "geo:") { - geo = contacts[i].GEO.slice(4).split(","); - } else { - geo = contacts[i].GEO.split(";"); - } - var date; - if (contacts[i].hasOwnProperty('REV')) { - date = Date.parse(contacts[i].REV); - } - else { - date = new Date(); - } - if (isNaN(date)) { - var year = parseInt(contacts[i].REV.slice(0,4)); - var month = parseInt(contacts[i].REV.slice(4,6))-1; - var day = parseInt(contacts[i].REV.slice(6,8))-1; - var hour = parseInt(contacts[i].REV.slice(9,11))-1; - var min = parseInt(contacts[i].REV.slice(11,13))-1; - var sec = parseInt(contacts[i].REV.slice(13,15))-1; - date = new Date(year,month,day,hour,min,sec); - date = date.getTime(); - } - - // format address - var adrTab = contacts[i].ADR.split(';'); - var formattedAddress = ''; - if (adrTab.length > 6) { - // check if street name is set - if(adrTab[2] !== '') { - formattedAddress += adrTab[2] + '
    '; - } - formattedAddress += adrTab[5] + ' ' + adrTab[3] + '
    ' + adrTab[4] + ' ' + adrTab[6]; - } - - var markerData = { - name: contacts[i].FN, - lat: parseFloat(geo[0]), - lng: parseFloat(geo[1]), - uid: contacts[i].UID, - uri: contacts[i].URI, - adr: contacts[i].ADR, - has_photo: contacts[i].HAS_PHOTO, - address: formattedAddress, - addressType: contacts[i].ADRTYPE.toLowerCase(), - bookid: contacts[i].BOOKID, - bookuri: contacts[i].BOOKURI, - date: date/1000, - groups: contacts[i].GROUPS ? contacts[i].GROUPS.split(',') : [] - }; - // manage groups - if (markerData.groups.length === 0) { - this.groupsCount['0'] = this.groupsCount['0'] + 1; - } - else { - for (j = 0; j < markerData.groups.length; j++) { - groupName = markerData.groups[j]; - this.groupsCount[groupName] = this.groupsCount[groupName] ? this.groupsCount[groupName] + 1 : 1; - } - } - if (contacts[i].HAS_PHOTO) { - markerData.avatar = this.generateAvatar(markerData) || this.getUserImageIconUrl(); - } - else { - markerData.avatar = this.getLetterAvatarUrl(basename(markerData.name)); - } - - var marker = L.marker([markerData.lat, markerData.lng], { - icon: this.createContactView(markerData) - }); - - // disabled for the moment - //marker.on('contextmenu', this.onContactRightClick); - marker.on('mouseover', this.onContactMouseover); - marker.on('mouseout', this.onContactMouseout); - marker.data = markerData; - - markers.push(marker); - } - return markers; - }, - - getContactTooltipContent: function(markerData) { - var contactTooltip = '
    '; - var contactName = '

    ' + escapeHTML(basename(markerData.name)) + '

    '; - contactTooltip += contactName; - if (markerData.addressType === 'home') { - contactTooltip += '

    '+t('maps', 'Home')+'

    '; - } - else if (markerData.addressType === 'work') { - contactTooltip += '

    '+t('maps', 'Work')+'

    '; - } - contactTooltip += '

    ' + markerData.address + '

    '; - return contactTooltip; - }, - - getContactPopupContent: function(markerData) { - var deleteText = t('maps', 'Delete this address'); - var contactPopup = '
    '; - var contactName = '

    ' + escapeHTML(basename(markerData.name)) + '

    '; - contactPopup += contactName; - if (markerData.addressType === 'home') { - contactPopup += '

    '+t('maps', 'Home'); - } - else if (markerData.addressType === 'work') { - contactPopup += '

    '+t('maps', 'Work'); - } - /* Hide contact address deletion for now - contactPopup += '';*/ - contactPopup += '

    ' + markerData.address + '

    '; - var contactUrl = generateUrl('/apps/contacts/'+t('contacts', 'All contacts')+'/'+encodeURIComponent(markerData.uid+"~contacts")); - contactPopup += ''+t('maps', 'Open in Contacts')+'
    '; - return contactPopup; - }, - - onContactMouseover: function(e) { - var data = e.target.data; - if (!e.target.getPopup() || !e.target.getPopup().isOpen()) { - var tooltipContent = this._map.contactsController.getContactTooltipContent(data); - e.target.bindTooltip(tooltipContent, { - permanent: true, - className: 'leaflet-marker-contact-tooltip', - direction: 'top', - offset: L.point(0, 0) - }); - } - }, - - onContactMouseout: function(e) { - e.target.unbindTooltip(); - }, - - /* hide delete address functionality on right click for now to keep simple - onContactRightClick: function(e) { - var data = e.target.data; - var bookid = data.bookid; - var uri = data.uri; - var uid = data.uid; - var vcardAddress = data.adr; - - e.target.unbindPopup(); - var popupContent = this._map.contactsController.getContactContextPopupContent(bookid, uri, uid, vcardAddress); - e.target.bindPopup(popupContent, { - closeOnClick: true, - className: 'popovermenu open popupMarker', - offset: L.point(-5, -19) - }); - e.target.openPopup(); - this._map.clickpopup = true; - }, - - getContactContextPopupContent: function(bookid, uri, uid, vcardAddress) { - var deleteText = t('maps', 'Delete this address'); - var res = - ''; - return res; - }, - - deleteContactAddress: function(bookid, uri, uid, vcardAddress) { - var that = this; - $('#navigation-contacts').addClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'wait'); - var req = { - uid: uid, - adr: vcardAddress - }; - var url = generateUrl('/apps/maps/contacts/'+bookid+'/'+uri); - $.ajax({ - type: 'DELETE', - url: url, - data: req, - async: true - }).done(function (response) { - }).always(function (response) { - that.map.closePopup(); - that.map.clickpopup = null; - $('#navigation-contacts').removeClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'grab'); - that.reloadContacts(); - }).fail(function(response) { - OC.Notification.showTemporary(t('maps', 'Failed to delete contact address') + ': ' + response.responseText); - }); - },*/ - - callForContacts: function() { - this.contactsRequestInProgress = true; - $('#navigation-contacts').addClass('icon-loading-small'); - $.ajax({ - url: generateUrl('apps/maps/contacts'), - type: 'GET', - async: true, - context: this - }).done(function (response) { - if (response.length == 0) { - //showNocontactsMessage(); - } else { - this.addContactsToMap(response); - } - this.contactsDataLoaded = true; - }).always(function (response) { - this.contactsRequestInProgress = false; - $('#navigation-contacts').removeClass('icon-loading-small'); - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to load contacts')); - }); - }, - - generateAvatar: function (data) { - // data is supposed to be a base64 string - // but if this is a 'user' contact, avatar is and address like - // VALUE=uri:http://host/remote.php/dav/addressbooks/system/system/system/Database:toto.vcf?photo - //return data ? data.replace(/^VALUE=uri:/, '') : data; - var url = generateUrl('/remote.php/dav/addressbooks/users/' + OC.getCurrentUser().uid + - '/' + data.bookuri + '/' + data.uri + '?photo').replace(/index\.php\//, ''); - return url; - }, - - getImageIconUrl: function() { - return generateUrl('/apps/theming/img/core/places') + '/contacts.svg?v=2'; - }, - - getUserImageIconUrl: function() { - return generateUrl('/apps/theming/img/core/actions') + '/user.svg?v=2'; - }, - - getLetterAvatarUrl: function(name) { - return generateUrl('/apps/maps/contacts-avatar?name='+encodeURIComponent(name)); - }, - - contextPlaceContact: function(e) { - var that = this.contactsController; - var lat = e.latlng.lat; - var lng = e.latlng.lng; - that.openPlaceContactPopup(lat, lng); - }, - - openPlaceContactPopup: function(lat, lng) { - var that = this; - var popupText = '

    ' + t('maps', 'New contact address') + '

    '; - popupText += '
    '; - popupText += ''; - popupText += ''; - popupText += ''; - popupText += '
    '; - popupText += ''; - popupText += '
    '; - this.map.openPopup(popupText, [lat, lng]); - this.map.clickpopup = true; - - that.currentPlaceContactAddress = null; - that.currentPlaceContactLat = lat; - that.currentPlaceContactLng = lng; - that.currentPlaceContactFormattedAddress = null; - that.currentPlaceContactContact = null; - - // get the reverse geocode address - var strLatLng = lat+','+lng; - that.searchController.geocode(strLatLng).then(function(results) { - var address = {}; - if (results.address) { - address = results.address; - that.currentPlaceContactAddress = address; - var strAddress = formatAddress(address); - //console.log(address); - $('#placeContactPopupAddress').text(strAddress); - that.currentPlaceContactFormattedAddress = strAddress; - } - }); - // get the contact list - var req = {}; - var url = generateUrl('/apps/maps/contacts-all'); - $.ajax({ - type: 'GET', - url: url, - data: req, - async: true - }).done(function (response) { - var d, c; - var data = []; - for (var i=0; i < response.length; i++) { - c = response[i]; - if (!c.READONLY) { - d = { - id: c.URI, - label: c.FN, - value: c.FN, - uri: c.URI, - uid: c.UID, - bookid: c.BOOKID - }; - data.push(d); - } - } - $('#place-contact-input').autocomplete({ - source: data, - select: function (e, ui) { - var it = ui.item; - that.currentPlaceContactContact = ui.item; - $('#placeContactValidIcon').show(); - //that.submitPlaceContactPopup(it.bookid, it.uri, it.uid, lat, lng, address, type, editedAddress); - } - }) - $('#place-contact-input').focus().select(); - }).always(function (response) { - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to get contact list')); - }); - }, - - submitPlaceContact: function() { - var that = this; - var lat = that.currentPlaceContactLat; - var lng = that.currentPlaceContactLng; - var currentContact = that.currentPlaceContactContact; - var currentAddress = that.currentPlaceContactAddress; - var currentFormattedAddress = that.currentPlaceContactFormattedAddress; - var bookid = currentContact.bookid; - var uri = currentContact.uri; - var uid = currentContact.uid; - var editedAddress = $('#placeContactPopupAddress').val().trim().replace(/(\r\n|\n|\r)/gm, ' ').replace(/\s+/g, ' '); - var type = $('#addressTypeSelect').val(); - - $('#submitPlaceContactButton').addClass('loading'); - - // we didn't change the address => place - if (currentFormattedAddress === editedAddress) { - that.placeContact(bookid, uri, uid, lat, lng, currentAddress, type); - that.map.panTo([lat, lng], { animate: true }); - } - // we changed the address, search the new one - else { - that.searchController.search(editedAddress, 1).then(function(results) { - var address = {}; - //console.log(results); - // there was a result - if (results.length > 0 && results[0].address && results[0].lat && results[0].lon) { - address = results[0].address; - //var strAddress = formatAddress(address); - lat = results[0].lat; - lng = results[0].lon; - } - // nope, no result, keep the original one - else { - address = currentAddress; - } - that.placeContact(bookid, uri, uid, lat, lng, address, type); - if (that.map.getBounds().contains(L.latLng(lat, lng))) { - that.map.panTo([lat, lng], { animate: true }); - } - else { - that.map.flyTo([lat, lng], 15, { animate: true }); - } - }); - } - }, - - placeContact: function(bookid, uri, uid, lat, lng, address, type='home') { - var that = this; - $('#navigation-contacts').addClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'wait'); - var road = (address.road || '') + ' ' + (address.pedestrian || '') + ' ' + (address.suburb || '') + ' ' + (address.city_district || ''); - road = road.replace(/\s+/g, ' ').trim(); - var city = address.village || address.town || address.city || ''; - city = city.replace(/\s+/g, ' ').trim(); - var req = { - lat: lat, - lng: lng, - uid: uid, - attraction: address.attraction, - house_number: address.house_number, - road: road, - postcode: address.postcode, - city: city, - state: address.state, - country: address.country, - type: type - }; - var url = generateUrl('/apps/maps/contacts/'+bookid+'/'+uri); - $.ajax({ - type: 'PUT', - url: url, - data: req, - async: true - }).done(function (response) { - }).always(function (response) { - that.map.closePopup(); - that.map.clickpopup = null; - $('#navigation-contacts').removeClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'grab'); - that.reloadContacts(); - }).fail(function(response) { - OC.Notification.showTemporary(t('maps', 'Failed to place contact') + ': ' + response.responseText); - }); - }, - - reloadContacts: function() { - this.contactsDataLoaded = false; - this.contactsRequestInProgress = false; - - for (var i=0; i < this.contactMarkers.length; i++) { - this.contactLayer.removeLayer(this.contactMarkers[i]); - } - - this.resetGroupList(); - - this.groupsCount = {'0': 0}; - this.groups = {}; - this.contactMarkers = []; - - this.showLayer(); - }, - - getAutocompData: function() { - var that = this; - var mData; - var data = []; - if (this.map.hasLayer(this.contactLayer)) { - this.contactLayer.eachLayer(function (l) { - mData = l.data; - data.push({ - type: 'contact', - label: mData.name, - value: mData.name, - lat: mData.lat, - lng: mData.lng - }); - }); - } - return data; - }, - -}; - -export default ContactsController; diff --git a/src/devicesController.js b/src/devicesController.js deleted file mode 100644 index 68ba44c00..000000000 --- a/src/devicesController.js +++ /dev/null @@ -1,1151 +0,0 @@ -import { generateUrl } from '@nextcloud/router'; - -import { Timer, brify, isComputer, isPhone, getDeviceInfoFromUserAgent2 } from './utils'; - -function DevicesController(optionsController, timeFilterController) { - this.device_MARKER_VIEW_SIZE = 30; - this.optionsController = optionsController; - this.timeFilterController = timeFilterController; - - this.mainLayer = null; - // indexed by device id - // those actually added to map, those which get toggled - this.mapDeviceLayers = {}; - // layers which contain lines/markers - this.deviceLineLayers = {}; - this.deviceMarkerLayers = {}; - this.devices = {}; - - this.firstDate = null; - this.lastDate = null; - - // used by optionsController to know if devices loading - // was done before or after option restoration - this.deviceListLoaded = false; - - this.changingColorOf = null; - this.deviceDeletionTimer = {}; - this.sendPositionTimer = null; - this.currentPrecisionCircle = null; - this.lastZIndex = 1000; - this.lineMarker = null; -} - -DevicesController.prototype = { - - initController : function(map) { - this.map = map; - this.mainLayer = L.featureGroup(); - var that = this; - // toggle a device - $('body').on('click', '.device-line .device-name', function(e) { - var id = $(this).parent().attr('device'); - that.toggleDevice(id, true, true); - }); - // zoom to bounds - $('body').on('click', '.zoomDeviceButton', function(e) { - var id = $(this).parent().parent().parent().parent().attr('device'); - that.zoomOnDevice(id); - }); - $('body').on('click', '.contextZoomDevice', function(e) { - var id = $(this).parent().parent().attr('devid'); - that.zoomOnDevice(id); - that.map.closePopup(); - }); - // export one device - $('body').on('click', '.exportDeviceButton', function(e) { - var id = $(this).parent().parent().parent().parent().attr('device'); - that.exportDevices([id]); - }); - $('body').on('click', '.contextExportDevice', function(e) { - var id = $(this).parent().parent().attr('devid'); - that.exportDevices([id]); - that.map.closePopup(); - }); - // toggle a device line - $('body').on('click', '.toggleDeviceLine', function(e) { - var id = $(this).parent().parent().parent().parent().attr('device'); - that.toggleDeviceLine(id, true); - }); - $('body').on('click', '.contextToggleLine', function(e) { - var id = $(this).parent().parent().attr('devid'); - that.toggleDeviceLine(id, true); - that.map.closePopup(); - }); - // toggle devices - $('body').on('click', '#navigation-devices > a', function(e) { - that.toggleDevices(); - that.optionsController.saveOptionValues({devicesEnabled: that.map.hasLayer(that.mainLayer)}); - that.updateMyFirstLastDates(true); - if (that.map.hasLayer(that.mainLayer) && !$('#navigation-devices').hasClass('open')) { - that.toggleDeviceList(); - that.optionsController.saveOptionValues({deviceListShow: $('#navigation-devices').hasClass('open')}); - } - }); - // expand device list - $('body').on('click', '#navigation-devices', function(e) { - if (e.target.tagName === 'LI' && $(e.target).attr('id') === 'navigation-devices') { - that.toggleDeviceList(); - that.optionsController.saveOptionValues({deviceListShow: $('#navigation-devices').hasClass('open')}); - } - }); - // color management - $('body').on('click', '.changeDeviceColor', function(e) { - var id = $(this).parent().parent().parent().parent().attr('device'); - that.askChangeDeviceColor(id); - }); - $('body').on('click', '.contextChangeDeviceColor', function(e) { - var id = $(this).parent().parent().attr('devid'); - that.askChangeDeviceColor(id); - that.map.closePopup(); - }); - $('body').on('change', '#devicecolorinput', function(e) { - that.okColor(); - }); - // rename device - $('body').on('click', '.renameDeviceButton', function(e) { - $(this).parent().parent().parent().parent().find('.renameDeviceInput').focus().select(); - $('#device-list > li').removeClass('editing'); - $(this).parent().parent().parent().parent().addClass('editing'); - }); - $('body').on('click', '.renameDeviceOk', function(e) { - var devid = $(this).parent().parent().parent().attr('device'); - $(this).parent().parent().parent().removeClass('editing').addClass('icon-loading-small'); - var newDeviceName = $(this).parent().find('.renameDeviceInput').val(); - that.renameDeviceDB(devid, newDeviceName); - }); - $('body').on('keyup', '.renameDeviceInput', function(e) { - if (e.key === 'Enter') { - var devid = $(this).parent().parent().parent().attr('device'); - $(this).parent().parent().parent().removeClass('editing').addClass('icon-loading-small'); - var newDeviceName = $(this).parent().find('.renameDeviceInput').val(); - that.renameDeviceDB(devid, newDeviceName); - } - else if (e.key === 'Escape') { - $(this).parent().parent().parent().removeClass('editing'); - } - }); - $('body').on('click', '.renameDeviceClose', function(e) { - $(this).parent().parent().parent().removeClass('editing'); - }); - // delete a device - $('body').on('click', '.deleteDevice', function(e) { - var devid = $(this).parent().parent().parent().parent().attr('device'); - $(this).parent().parent().parent().parent().addClass('deleted'); - that.deviceDeletionTimer[devid] = new Timer(function() { - that.deleteDeviceDB(devid); - }, 7000); - }); - $('body').on('click', '.undoDeleteDevice', function(e) { - var devid = $(this).parent().parent().attr('device'); - $(this).parent().parent().removeClass('deleted'); - that.deviceDeletionTimer[devid].pause(); - delete that.deviceDeletionTimer[devid]; - }); - // show/hide all device - $('body').on('click', '#select-all-devices', function(e) { - that.showAllDevices(); - var deviceList = Object.keys(that.mapDeviceLayers); - var deviceStringList = deviceList.join('|'); - that.optionsController.saveOptionValues({enabledDevices: deviceStringList}); - that.optionsController.enabledDevices = deviceList; - that.optionsController.saveOptionValues({devicesEnabled: that.map.hasLayer(that.mainLayer)}); - }); - $('body').on('click', '#select-no-devices', function(e) { - that.hideAllDevices(); - var deviceStringList = ''; - that.optionsController.saveOptionValues({enabledDevices: deviceStringList}); - that.optionsController.enabledDevices = []; - that.optionsController.saveOptionValues({devicesEnabled: that.map.hasLayer(that.mainLayer)}); - }); - // export devices - $('body').on('click', '#export-all-devices', function(e) { - that.exportAllDevices(); - }); - // import devices - $('body').on('click', '#import-devices', function(e) { - OC.dialogs.filepicker( - t('maps', 'Import devices from gpx (Nextcloud Maps) or kml/kmz (Google Timeline) file'), - function(targetPath) { - that.importDevices(targetPath); - }, - false, - ['application/gpx+xml', 'application/vnd.google-earth.kmz', 'application/vnd.google-earth.kml+xml'], - true - ); - }); - // refresh devices positions - $('body').on('click', '#refresh-all-devices', function(e) { - that.refreshAllDevices(); - }); - $('body').on('click', '#track-me', function(e) { - if ($(this).is(':checked')) { - that.launchTrackLoop(); - that.optionsController.saveOptionValues({trackMe: true}); - } - else { - that.stopTrackLoop(); - that.optionsController.saveOptionValues({trackMe: false}); - } - }); - - this.map.on('click', function (e) { - if (that.lineMarker) { - that.lineMarker.remove(); - that.lineMarker = null; - } - }); - }, - - // expand or fold device list in sidebar - toggleDeviceList: function() { - $('#navigation-devices').toggleClass('open'); - }, - - // toggle devices general layer on map and save state in user options - toggleDevices: function() { - if (this.map.hasLayer(this.mainLayer)) { - this.map.removeLayer(this.mainLayer); - // color of the eye - $('#navigation-devices').removeClass('active'); - $('#map').focus(); - // remove potential line marker - if (this.lineMarker) { - this.lineMarker.remove(); - this.lineMarker = null; - } - } - else { - if (!this.deviceListLoaded) { - this.getDevices(); - } - this.map.addLayer(this.mainLayer); - $('#navigation-devices').addClass('active'); - } - }, - - showAllDevices: function() { - if (!this.map.hasLayer(this.mainLayer)) { - this.toggleDevices(); - } - for (var id in this.mapDeviceLayers) { - if (!this.mainLayer.hasLayer(this.mapDeviceLayers[id])) { - this.toggleDevice(id); - } - } - this.updateMyFirstLastDates(true); - }, - - hideAllDevices: function() { - for (var id in this.mapDeviceLayers) { - if (this.mainLayer.hasLayer(this.mapDeviceLayers[id])) { - this.toggleDevice(id); - } - } - this.updateMyFirstLastDates(true); - }, - - getDevices: function(show=false) { - var that = this; - $('#navigation-devices').addClass('icon-loading-small'); - var req = {}; - var url = generateUrl('/apps/maps/devices'); - $.ajax({ - type: 'GET', - url: url, - data: req, - async: true - }).done(function (response) { - var i, device; - for (i=0; i < response.length; i++) { - device = response[i]; - if (!that.devices.hasOwnProperty(device.id)) { - that.addDeviceMap(device, show, true); - } - } - that.deviceListLoaded = true; - }).always(function (response) { - $('#navigation-devices').removeClass('icon-loading-small'); - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to load device list')); - }); - }, - - addDeviceMap: function(device, show=false, pageLoad=false) { - var id = device.id; - // color - var color = device.color || (OCA.Theming ? OCA.Theming.color : '#0082c9'); - this.devices[id] = device; - this.devices[id].color = color; - // points data indexed by point id - this.devices[id].points = {}; - // points coordinates (with id as third element) - this.devices[id].pointsLatLngId = []; - - this.devices[id].icon = L.divIcon(L.extend({ - html: '
    ​', - className: 'leaflet-marker-device device-marker device-marker-'+id - }, null, { - iconSize: [this.device_MARKER_VIEW_SIZE, this.device_MARKER_VIEW_SIZE], - iconAnchor: [this.device_MARKER_VIEW_SIZE / 2, this.device_MARKER_VIEW_SIZE] - })); - var radius = 8; - this.devices[id].overicon = L.divIcon({ - iconAnchor: [radius, radius], - className: 'device-over-marker device-over-marker-' + id, - html: '' - }); - this.setDeviceCss(id, color); - - this.mapDeviceLayers[id] = L.featureGroup(); - this.deviceLineLayers[id] = L.featureGroup(); - this.deviceMarkerLayers[id] = L.featureGroup(); - this.devices[id].loaded = false; - this.mapDeviceLayers[id].addLayer(this.deviceLineLayers[id]); - this.mapDeviceLayers[id].addLayer(this.deviceMarkerLayers[id]); - - var name = device.user_agent; - device.name = name; - - // side menu entry - var imgurl; - if (isComputer(name)) { - imgurl = generateUrl('/svg/core/clients/desktop?color='+color.replace('#', '')); - } - else { - imgurl = generateUrl('/svg/core/clients/phone?color='+color.replace('#', '')); - } - var li = '
  • ' + - ' '+name+'' + - '
    ' + - '
      ' + - '
    • ' + - ' ' + - '
    • ' + - '
    ' + - '
    ' + - '
    ' + - ' ' + - '
    ' + - '
    ' + - '
    '+t('maps', 'Device deleted')+'
    ' + - ' ' + - '
    ' + - '
    ' + - '
    ' + - ' ' + - ' ' + - ' ' + - '
    ' + - '
    ' + - '
  • '; - - var beforeThis = null; - var nameLower = name.toLowerCase(); - var deviceName; - $('#device-list > li').each(function() { - deviceName = $(this).attr('name'); - if (nameLower.localeCompare(deviceName) < 0) { - beforeThis = $(this); - return false; - } - }); - if (beforeThis !== null) { - $(li).insertBefore(beforeThis); - } - else { - $('#device-list').append(li); - } - - // enable if in saved options or if it should be enabled for another reason - if (show || this.optionsController.enabledDevices.indexOf(id) !== -1) { - this.toggleDevice(id, false, pageLoad); - } - }, - - setDeviceCss: function(id, color) { - $('style[device='+id+']').remove(); - - var imgurl; - if (isComputer(this.devices[id].user_agent)) { - imgurl = generateUrl('/svg/core/clients/desktop?color='+color.replace('#', '')); - } - else { - imgurl = generateUrl('/svg/core/clients/phone?color='+color.replace('#', '')); - } - $('').appendTo('body'); - }, - - renameDeviceDB: function(id, newDeviceName) { - var that = this; - $('#device-list > li[device="'+id+'"]').addClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'wait'); - var req = { - name: newDeviceName - }; - var url = generateUrl('/apps/maps/devices/'+id); - $.ajax({ - type: 'PUT', - url: url, - data: req, - async: true - }).done(function (response) { - that.devices[id].user_agent = newDeviceName; - var device = that.devices[id]; - var color = device.color; - var imgurl; - if (isComputer(newDeviceName)) { - imgurl = generateUrl('/svg/core/clients/desktop?color='+color.replace('#', '')); - } - else { - imgurl = generateUrl('/svg/core/clients/phone?color='+color.replace('#', '')); - } - var name = device.user_agent; - device.name = name; - - var deviceNameElem = $('#device-list > li[device='+id+'] .device-name'); - deviceNameElem.attr('style', 'background-image: url('+imgurl+')'); - deviceNameElem.text(name); - deviceNameElem.attr('title', name); - - that.setDeviceCss(id, color); - }).always(function (response) { - $('#device-list > li[device="'+id+'"]').removeClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'grab'); - }).fail(function(response) { - OC.Notification.showTemporary(t('maps', 'Failed to rename device') + ': ' + response.responseText); - }); - }, - - deleteDeviceDB: function(id) { - var that = this; - $('#navigation-devices').addClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'wait'); - var req = {}; - var url = generateUrl('/apps/maps/devices/'+id); - $.ajax({ - type: 'DELETE', - url: url, - data: req, - async: true - }).done(function (response) { - that.deleteDeviceMap(id); - }).always(function (response) { - $('#navigation-devices').removeClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'grab'); - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to delete device')); - }); - }, - - deleteDeviceMap: function(id) { - this.mainLayer.removeLayer(this.mapDeviceLayers[id]); - this.mapDeviceLayers[id].removeLayer(this.deviceLineLayers[id]); - this.mapDeviceLayers[id].removeLayer(this.deviceMarkerLayers[id]); - delete this.mapDeviceLayers[id]; - delete this.deviceLineLayers[id]; - delete this.deviceMarkerLayers[id]; - delete this.devices[id]; - - $('style[device='+id+']').remove(); - - $('#device-list > li[device="'+id+'"]').fadeOut('slow', function() { - $(this).remove(); - }); - }, - - saveEnabledDevices: function(additionalIds=[]) { - var deviceList = []; - var deviceWithLineList = []; - var layer; - for (var id in this.mapDeviceLayers) { - layer = this.mapDeviceLayers[id]; - if (this.mainLayer.hasLayer(layer)) { - deviceList.push(id); - } - if (this.devices[id].line && this.deviceLineLayers[id].hasLayer(this.devices[id].line)) { - deviceWithLineList.push(id); - } - } - for (var i=0; i < additionalIds.length; i++) { - deviceList.push(additionalIds[i]); - } - var deviceStringList = deviceList.join('|'); - var deviceWithLineStringList = deviceWithLineList.join('|'); - this.optionsController.saveOptionValues({enabledDevices: deviceStringList}); - this.optionsController.saveOptionValues({enabledDeviceLines: deviceWithLineStringList}); - // this is used when devices are loaded again - this.optionsController.enabledDevices = deviceList; - this.optionsController.enabledDeviceLines = deviceWithLineList; - }, - - toggleDevice: function(id, save=false, updateSlider=false) { - if (!this.devices[id].loaded) { - this.loadDevicePoints(id, save, updateSlider); - } - this.toggleMapDeviceLayer(id); - if (save) { - this.saveEnabledDevices(); - this.updateMyFirstLastDates(true); - } - }, - - toggleMapDeviceLayer: function(id) { - var mapDeviceLayer = this.mapDeviceLayers[id]; - var deviceLi = $('#device-list > li[device="'+id+'"]'); - var deviceName = deviceLi.find('.device-name'); - // hide device - if (this.mainLayer.hasLayer(mapDeviceLayer)) { - this.mainLayer.removeLayer(mapDeviceLayer); - deviceName.removeClass('active'); - $('#map').focus(); - // remove potential line marker - if (this.lineMarker) { - this.lineMarker.remove(); - this.lineMarker = null; - } - } - // show device - else { - this.mainLayer.addLayer(mapDeviceLayer); - if (this.devices[id].marker) { - this.devices[id].marker.setZIndexOffset(this.lastZIndex++); - } - deviceName.addClass('active'); - } - }, - - toggleDeviceLine: function(id, save=false) { - var deviceLineLayer = this.deviceLineLayers[id]; - var line = this.devices[id].line; - // if line layer already exist - if (line) { - // hide line - if (deviceLineLayer.hasLayer(line)) { - deviceLineLayer.removeLayer(line); - // remove potential line marker - if (this.lineMarker) { - this.lineMarker.remove(); - this.lineMarker = null; - } - } - // show line - else { - deviceLineLayer.addLayer(line); - } - this.devices[id].marker.setZIndexOffset(this.lastZIndex++); - if (save) { - this.saveEnabledDevices(); - } - } - }, - - // load all available points and create marker/line - loadDevicePoints: function(id, save=false, updateSlider=false) { - var that = this; - $('#device-list > li[device="'+id+'"]').addClass('icon-loading-small'); - var req = {}; - var url = generateUrl('/apps/maps/devices/'+id); - $.ajax({ - type: 'GET', - url: url, - data: req, - async: true - }).done(function (response) { - that.addPoints(id, response); - that.devices[id].loaded = true; - that.updateMyFirstLastDates(updateSlider); - }).always(function (response) { - $('#device-list > li[device="'+id+'"]').removeClass('icon-loading-small'); - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to load device points')); - }); - }, - - // handle first data received for the device - addPoints: function(id, points) { - var lastPoint = points[points.length - 1]; - this.devices[id].marker = L.marker([lastPoint.lat, lastPoint.lng, lastPoint.id], { - icon: this.devices[id].icon - }); - this.devices[id].marker.devid = id; - this.devices[id].marker.lastPosMarker = true; - this.devices[id].marker.on('mouseover', this.deviceMarkerMouseover); - this.devices[id].marker.on('mouseout', this.deviceMarkerMouseout); - this.devices[id].marker.on('contextmenu', this.deviceMarkerMouseRightClick); - //this.devices[id].marker.on('click', this.deviceMouseClick); - for (var i=0; i < points.length; i++) { - this.devices[id].pointsLatLngId.push([points[i].lat, points[i].lng, points[i].id]); - this.devices[id].points[points[i].id] = points[i]; - } - this.devices[id].line = L.polyline(this.devices[id].pointsLatLngId, { - weight: 4, - opacity : 1, - className: 'devline'+id, - }); - this.devices[id].line.devid = id; - this.devices[id].line.on('mouseover', this.deviceLineMouseover); - this.devices[id].line.on('mouseout', this.deviceLineMouseout); - this.devices[id].line.on('contextmenu', this.deviceMarkerMouseRightClick); - this.deviceMarkerLayers[id].addLayer(this.devices[id].marker); - if (this.optionsController.enabledDeviceLines.indexOf(id) !== -1) { - this.deviceLineLayers[id].addLayer(this.devices[id].line); - } - }, - - // device already exists and has points, check if there are new points - updateDevicePoints: function(id) { - var that = this; - // get last device point - var ts = null; - if (this.devices[id].pointsLatLngId && this.devices[id].pointsLatLngId.length > 0) { - var pid = this.devices[id].pointsLatLngId[this.devices[id].pointsLatLngId.length - 1][2]; - ts = this.devices[id].points[pid].timestamp; - } - $('#device-list > li[device="'+id+'"]').addClass('icon-loading-small'); - var req = {}; - if (ts) { - req.pruneBefore = ts; - } - var url = generateUrl('/apps/maps/devices/'+id); - $.ajax({ - type: 'GET', - url: url, - data: req, - async: true - }).done(function (response) { - that.appendPoints(id, response); - that.updateMyFirstLastDates(true); - that.updateFilterDisplay(); - }).always(function (response) { - $('#device-list > li[device="'+id+'"]').removeClass('icon-loading-small'); - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to update device points')); - }); - }, - - appendPoints: function(id, points) { - for (var i=0; i < points.length; i++) { - this.devices[id].pointsLatLngId.push([points[i].lat, points[i].lng, points[i].id]); - this.devices[id].points[points[i].id] = points[i]; - } - }, - - updateMyFirstLastDates: function(updateSlider=false) { - if (!this.map.hasLayer(this.mainLayer)) { - this.firstDate = null; - this.lastDate = null; - } - else { - var id; - - // we update dates only if nothing is currently loading - for (id in this.mapDeviceLayers) { - if (this.mainLayer.hasLayer(this.mapDeviceLayers[id]) && !this.devices[id].loaded) { - return; - } - } - - var initMinDate = Math.floor(Date.now() / 1000) + 1000000 - var initMaxDate = 0; - - var first = initMinDate; - var last = initMaxDate; - var fpId, lpId, firstPoint, lastPoint; - for (id in this.mapDeviceLayers) { - if (this.mainLayer.hasLayer(this.mapDeviceLayers[id]) && this.devices[id].loaded) { - fpId = this.devices[id].pointsLatLngId[0][2]; - lpId = this.devices[id].pointsLatLngId[this.devices[id].pointsLatLngId.length - 1][2]; - firstPoint = this.devices[id].points[fpId]; - lastPoint = this.devices[id].points[lpId]; - if (firstPoint.timestamp && firstPoint.timestamp < first) { - first = firstPoint.timestamp; - } - if (lastPoint.timestamp && lastPoint.timestamp > last) { - last = lastPoint.timestamp; - } - } - } - if (first !== initMinDate - && last !== initMaxDate) { - this.firstDate = first; - this.lastDate = last; - } - else { - this.firstDate = null; - this.lastDate = null; - } - } - if (updateSlider) { - this.timeFilterController.updateSliderRangeFromController(); - this.timeFilterController.setSliderToMaxInterval(); - } - }, - - updateFilterDisplay: function() { - var startFilter = this.timeFilterController.valueBegin; - var endFilter = this.timeFilterController.valueEnd; - var id, i, pointsLLI, points, latLngToDisplay; - for (id in this.devices) { - if (this.devices[id].loaded) { - latLngToDisplay = []; - pointsLLI = this.devices[id].pointsLatLngId; - points = this.devices[id].points; - i = 0; - while (i < pointsLLI.length && points[pointsLLI[i][2]].timestamp < startFilter) { - i++; - } - while (i < pointsLLI.length && points[pointsLLI[i][2]].timestamp <= endFilter) { - latLngToDisplay.push(pointsLLI[i]); - i++; - } - if (latLngToDisplay.length > 0) { - this.devices[id].line.setLatLngs(latLngToDisplay); - this.devices[id].marker.setLatLng(latLngToDisplay[latLngToDisplay.length - 1]); - if (!this.mapDeviceLayers[id].hasLayer(this.deviceLineLayers[id])) { - this.mapDeviceLayers[id].addLayer(this.deviceLineLayers[id]); - } - if (!this.mapDeviceLayers[id].hasLayer(this.deviceMarkerLayers[id])) { - this.mapDeviceLayers[id].addLayer(this.deviceMarkerLayers[id]); - } - } - else { - this.mapDeviceLayers[id].removeLayer(this.deviceLineLayers[id]); - this.mapDeviceLayers[id].removeLayer(this.deviceMarkerLayers[id]); - } - } - } - }, - - refreshAllDevices: function() { - // first get new positions for devices we already have - for (var id in this.devices) { - this.updateDevicePoints(id); - } - // then get potentially missing devices - this.getDevices(); - }, - - launchTrackLoop: function() { - this.sendPositionLoop(); - }, - - stopTrackLoop: function() { - if (this.sendPositionTimer) { - this.sendPositionTimer.pause(); - delete this.sendPositionTimer; - this.sendPositionTimer = null; - } - }, - - sendPositionLoop: function() { - var that = this; - // start a loop which get and send my position - if (navigator.geolocation && window.isSecureContext) { - navigator.geolocation.getCurrentPosition(function (position) { - var lat = position.coords.latitude; - var lng = position.coords.longitude; - var acc = position.coords.accuracy; - that.sendMyPosition(lat, lng, acc); - // loop - that.stopTrackLoop(); - that.sendPositionTimer = new Timer(function() { - that.sendPositionLoop(); - }, 5 * 60 * 1000); - }); - } - else { - OC.Notification.showTemporary(t('maps', 'Impossible to get current location')); - } - }, - - sendMyPosition: function(lat, lng, acc) { - var that = this; - var uaString = navigator.userAgent; - var info = getDeviceInfoFromUserAgent2(uaString); - var name = uaString; - if (info.client && info.os) { - if (isPhone(info.os)) { - name = t('maps', 'Phone'); - } - else if (isComputer(info.os)) { - name = t('maps', 'Computer'); - } - else { - name = t('maps', 'Unknown device type'); - } - name += ' (' + info.client; - name += '/' + info.os; - name += ')'; - } - var ts = Math.floor(Date.now() / 1000); - var req = { - lat: lat, - lng: lng, - user_agent: name, - accuracy: acc, - timestamp: ts - }; - var url = generateUrl('/apps/maps/devices'); - $.ajax({ - type: 'POST', - url: url, - data: req, - async: true - }).done(function (response) { - // TODO get new positions - }).always(function (response) { - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to send current position')); - }); - }, - - zoomOnDevice: function(id) { - if (this.mainLayer.hasLayer(this.mapDeviceLayers[id])) { - this.map.fitBounds(this.mapDeviceLayers[id].getBounds(), {padding: [30, 30], maxZoom: 15}); - this.mapDeviceLayers[id].bringToFront(); - this.devices[id].marker.setZIndexOffset(this.lastZIndex++); - } - }, - - askChangeDeviceColor: function(id) { - this.changingColorOf = id; - var currentColor = this.devices[id].color; - $('#devicecolorinput').val(currentColor); - $('#devicecolorinput').click(); - }, - - okColor: function() { - var color = $('#devicecolorinput').val(); - var id = this.changingColorOf; - this.devices[id].color = color; - this.changeDeviceColor(id, color); - }, - - changeDeviceColor: function(id, color) { - var that = this; - $('#device-list > li[device="'+id+'"]').addClass('icon-loading-small'); - var req = { - color: color - }; - var url = generateUrl('/apps/maps/devices/'+id); - $.ajax({ - type: 'PUT', - url: url, - data: req, - async: true - }).done(function (response) { - var imgurl; - var device = that.devices[id]; - if (isComputer(device.user_agent)) { - imgurl = generateUrl('/svg/core/clients/desktop?color='+color.replace('#', '')); - } - else { - imgurl = generateUrl('/svg/core/clients/phone?color='+color.replace('#', '')); - } - $('#device-list > li[device='+id+'] .device-name').attr('style', 'background-image: url('+imgurl+')'); - - that.setDeviceCss(id, color); - }).always(function (response) { - $('#device-list > li[device="'+id+'"]').removeClass('icon-loading-small'); - }).fail(function(response) { - OC.Notification.showTemporary(t('maps', 'Failed to change device color') + ': ' + response.responseText); - }); - }, - - deviceMarkerMouseover: function(e) { - var that = this._map.devicesController; - var id = e.target.devid; - var pointId = e.target.getLatLng().alt; - var device = that.devices[id]; - var yOffset = 0; - if (e.target.lastPosMarker) { - yOffset = -20; - } - // tooltip - var markerTooltip = that.getDeviceMarkerTooltipContent(device, pointId); - e.target.bindTooltip(markerTooltip, { - className: 'leaflet-marker-device-tooltip tooltip-dev-' + id, - direction: 'top', - offset: L.point(0, yOffset) - }); - e.target.openTooltip(); - // accuracy circle - var latlng = e.target.getLatLng(); - var acc = that.devices[id].points[pointId].accuracy; - if (acc) { - that.currentPrecisionCircle = L.circle(latlng, {radius: acc}); - that.map.addLayer(that.currentPrecisionCircle); - } - else { - that.currentPrecisionCircle = null; - } - }, - - deviceMarkerMouseout: function(e) { - // tooltip - e.target.unbindTooltip(); - e.target.closeTooltip(); - // accuracy circle - var that = this._map.devicesController; - if (that.currentPrecisionCircle !== null && - that.map.hasLayer(that.currentPrecisionCircle) - ) { - that.map.removeLayer(that.currentPrecisionCircle); - that.currentPrecisionCircle = null; - } - }, - - getDeviceMarkerTooltipContent: function(device, pointId) { - var point = device.points[pointId]; - var content = '⊙ ' + t('maps', 'Device') + ': ' + brify(device.name, 30); - content = content + '
    ' + '⊙ ' + t('maps', 'Date') + ': ' + (new Date(point.timestamp * 1000)).toIsoString(); - if (point.altitude !== null) { - content = content + '
    ' + '⊙ ' + t('maps', 'Elevation') + ': ' + point.altitude.toFixed(2); - } - if (point.accuracy !== null) { - content = content + '
    ' + '⊙ ' + t('maps', 'Accuracy') + ': ' + point.accuracy.toFixed(2); - } - if (point.battery !== null) { - content = content + '
    ' + '⊙ ' + t('maps', 'Battery') + ': ' + point.battery.toFixed(2); - } - return content; - }, - - deviceLineMouseover: function(e) { - var that = this._map.devicesController; - if (that.lineMarker) { - that.lineMarker.remove(); - that.lineMarker = null; - } - var id = e.target.devid; - var overLatLng = this._map.layerPointToLatLng(e.layerPoint); - var minDist = 40000000; - var markerLatLng = null; - var tmpDist; - var lineLatLngs = e.target.getLatLngs(); - for (var i=0; i < lineLatLngs.length; i++) { - tmpDist = this._map.distance(overLatLng, lineLatLngs[i]); - if (tmpDist < minDist) { - markerLatLng = lineLatLngs[i]; - minDist = tmpDist; - } - } - that.lineMarker = L.marker(markerLatLng, - {icon: that.devices[id].overicon} - ); - that.lineMarker.devid = id; - that.lineMarker.on('mouseover', that.deviceMarkerMouseover); - that.lineMarker.on('mouseout', that.deviceMarkerMouseout); - that.lineMarker.on('contextmenu', that.deviceMarkerMouseRightClick); - that.map.addLayer(that.lineMarker); - }, - - deviceLineMouseout: function(e) { - }, - - deviceMarkerMouseRightClick: function(e) { - var that = this; - var id = e.target.devid; - - var yOffset = 7; - if (e.target.lastPosMarker) { - yOffset = -14; - } - this._map.clickpopup = true; - var popupContent = this._map.devicesController.getDeviceContextPopupContent(id); - var popup = L.popup({ - closeOnClick: true, - className: 'popovermenu open popupMarker', - offset: L.point(-6, yOffset) - }) - .setLatLng(e.latlng) - .setContent(popupContent) - .openOn(this._map); - $(popup._closeButton).one('click', function (e) { - that._map.clickpopup = null; - }); - }, - - getDeviceContextPopupContent: function(id) { - var colorText = t('maps', 'Change color'); - var lineText = t('maps', 'Toggle history'); - var exportText = t('maps', 'Export'); - var zoomText = t('maps', 'Zoom to bounds'); - var res = - ''; - return res; - }, - - getAutocompData: function() { - var that = this; - var marker, devid; - var data = []; - var subtype; - if (this.map.hasLayer(this.mainLayer)) { - for (devid in this.devices) { - // is activated - if (this.mainLayer.hasLayer(this.mapDeviceLayers[devid])) { - // is not filtered - if (this.mapDeviceLayers[devid].hasLayer(this.deviceMarkerLayers[devid])) { - marker = this.devices[devid].marker; - if (isComputer(this.devices[devid].user_agent)) { - subtype = 'computer'; - } else { - subtype = 'mobile'; - } - data.push({ - type: 'device', - id: devid, - subtype: subtype, - label: this.devices[devid].name, - value: this.devices[devid].name, - lat: marker.getLatLng().lat, - lng: marker.getLatLng().lng - }); - } - } - } - } - return data; - }, - - exportAllDevices: function() { - var idList = Object.keys(this.devices); - this.exportDevices(idList, true); - }, - - exportDevices: function(idList, all=false) { - var that = this; - $('#navigation-devices').addClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'wait'); - var req = { - deviceIdList: idList, - begin: null, - end: null, - all: all - }; - var url = generateUrl('/apps/maps/export/devices'); - $.ajax({ - type: 'POST', - url: url, - data: req, - async: true - }).done(function (response) { - OC.Notification.showTemporary(t('maps', 'Devices exported in {path}', {path: response})); - }).always(function (response) { - $('#navigation-devices').removeClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'grab'); - }).fail(function(response) { - OC.Notification.showTemporary(t('maps', 'Failed to export devices') + ': ' + response.responseText); - }); - }, - - importDevices: function(path) { - $('#navigation-devices').addClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'wait'); - var that = this; - var req = { - path: path - }; - var url = generateUrl('/apps/maps/import/devices'); - $.ajax({ - type: 'POST', - url: url, - data: req, - async: true - }).done(function (response) { - OC.Notification.showTemporary(t('maps', '{nb} devices imported from {path}', {nb: response, path: path})); - var devIdsToRemove = Object.keys(that.devices); - for (var i=0; i < devIdsToRemove.length; i++) { - that.deleteDeviceMap(devIdsToRemove[i]); - } - that.getDevices(); - }).always(function (response) { - $('#navigation-devices').removeClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'grab'); - }).fail(function(response) { - OC.Notification.showTemporary(t('maps', 'Failed to import devices') + ': ' + response.responseText); - }); - }, - -} - -export default DevicesController; diff --git a/src/favoritesController.js b/src/favoritesController.js deleted file mode 100644 index 08b54ac5a..000000000 --- a/src/favoritesController.js +++ /dev/null @@ -1,1324 +0,0 @@ -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; diff --git a/src/filetypes.js b/src/filetypes.js deleted file mode 100644 index 1bff2c775..000000000 --- a/src/filetypes.js +++ /dev/null @@ -1,144 +0,0 @@ -import { generateUrl } from '@nextcloud/router'; - -$(document).ready(function() { - - if (OCA.Files && OCA.Files.fileActions) { - - function openFile(file, data) { - var token = $('#sharingToken').val(); - // if we are logged - if (!token) { - var dir = (data.dir === '/') ? '' : data.dir; - var url = generateUrl('apps/maps/?track={dir}%2F{file}',{'dir': dir, 'file': file}); - } - window.open(url, '_blank'); - } - - function importFavoritesFile(file, data) { - $('#content').css('cursor', 'wait'); - var dir = (data.dir === '/') ? '' : data.dir; - var path = dir + '/' + file; - 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, path: path})); - }).always(function (response) { - $('#content').css('cursor', 'default'); - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to import favorites')); - }); - } - - function importDevicesFile(file, data) { - $('#content').css('cursor', 'wait'); - var dir = (data.dir === '/') ? '' : data.dir; - var path = dir + '/' + file; - var req = { - path: path - }; - var url = generateUrl('/apps/maps/import/devices'); - $.ajax({ - type: 'POST', - url: url, - data: req, - async: true - }).done(function (response) { - OC.Notification.showTemporary(t('maps', '{nb} devices imported from {path}', {nb: response, path: path})); - }).always(function (response) { - $('#content').css('cursor', 'default'); - }).fail(function(response) { - OC.Notification.showTemporary(t('maps', 'Failed to import devices') + ': ' + response.responseText); - }); - } - - // default action is set only for logged in users - if (!$('#sharingToken').val()){ - - OCA.Files.fileActions.registerAction({ - name: 'viewTrackMaps', - displayName: t('maps', 'View in Maps'), - mime: 'application/gpx+xml', - permissions: OC.PERMISSION_READ, - iconClass: 'icon-maps-black', - actionHandler: openFile - }); - - OCA.Files.fileActions.register('application/gpx+xml', 'viewTrackMapsDefault', OC.PERMISSION_READ, '', openFile); - OCA.Files.fileActions.setDefault('application/gpx+xml', 'viewTrackMapsDefault'); - - // import gpx files as favorites - OCA.Files.fileActions.registerAction({ - name: 'importGpxFavoritesMaps', - displayName: t('maps', 'Import as favorites in Maps'), - mime: 'application/gpx+xml', - permissions: OC.PERMISSION_READ, - iconClass: 'icon-maps-black', - actionHandler: importFavoritesFile - }); - // import kmz files as favorites - OCA.Files.fileActions.registerAction({ - name: 'importKmzFavoritesMaps', - displayName: t('maps', 'Import as favorites in Maps'), - mime: 'application/vnd.google-earth.kmz', - permissions: OC.PERMISSION_READ, - iconClass: 'icon-maps-black', - actionHandler: importFavoritesFile - }); - // import kml files as favorites - OCA.Files.fileActions.registerAction({ - name: 'importKmlFavoritesMaps', - displayName: t('maps', 'Import as favorites in Maps'), - mime: 'application/vnd.google-earth.kml+xml', - permissions: OC.PERMISSION_READ, - iconClass: 'icon-maps-black', - actionHandler: importFavoritesFile - }); - // import geojson files as favorites - OCA.Files.fileActions.registerAction({ - name: 'importGeoJsonFavoritesMaps', - displayName: t('maps', 'Import as favorites in Maps'), - mime: 'application/geo+json', - permissions: OC.PERMISSION_READ, - iconClass: 'icon-maps-black', - actionHandler: importFavoritesFile - }); - - // import gpx files as devices - OCA.Files.fileActions.registerAction({ - name: 'importGpxDevicesMaps', - displayName: t('maps', 'Import as devices in Maps'), - mime: 'application/gpx+xml', - permissions: OC.PERMISSION_READ, - iconClass: 'icon-maps-black', - actionHandler: importDevicesFile - }); - // import kmz files as devices - OCA.Files.fileActions.registerAction({ - name: 'importKmzDevicesMaps', - displayName: t('maps', 'Import as devices in Maps'), - mime: 'application/vnd.google-earth.kmz', - permissions: OC.PERMISSION_READ, - iconClass: 'icon-maps-black', - actionHandler: importDevicesFile - }); - // import kml files as devicess - OCA.Files.fileActions.registerAction({ - name: 'importKmlDevicesMaps', - displayName: t('maps', 'Import as devices in Maps'), - mime: 'application/vnd.google-earth.kml+xml', - permissions: OC.PERMISSION_READ, - iconClass: 'icon-maps-black', - actionHandler: importDevicesFile - }); - } - } - -}); - diff --git a/src/nonLocalizedPhotosController.js b/src/nonLocalizedPhotosController.js deleted file mode 100644 index fda31a77b..000000000 --- a/src/nonLocalizedPhotosController.js +++ /dev/null @@ -1,347 +0,0 @@ -import { generateUrl } from '@nextcloud/router'; -import escapeHTML from 'escape-html'; - -function NonLocalizedPhotosController (optionsController, timeFilterController, photosController) { - this.PHOTO_MARKER_VIEW_SIZE = 40; - this.nonLocalizedPhotosDataLoaded = false; - this.lat = 0; - this.lng = 0; - this.nonLocalizedPhotosRequestInProgress = false; - this.optionsController = optionsController; - this.timeFilterController = timeFilterController; - this.photosController = photosController; - this.nonLocalizedPhotoMarkers = []; - this.nonLocalizedPhotoMarkersOldest = null; - this.nonLocalizedPhotoMarkersNewest = null; - this.nonLocalizedPhotoMarkersFirstVisible = 0; - this.nonLocalizedPhotoMarkersLastVisible = -1; - this.timeFilterBegin = 0; - this.timeFilterEnd = Date.now(); -} - -NonLocalizedPhotosController.prototype = { - - initLayer : function(map) { - this.map = map; - var that = this; - this.nonLocalizedPhotoLayer = L.markerClusterGroup({ - iconCreateFunction : this.getClusterIconCreateFunction(), - spiderfyOnMaxZoom: false, - showCoverageOnHover : false, - zoomToBoundsOnClick: false, - maxClusterRadius: this.PHOTO_MARKER_VIEW_SIZE + 10, - icon: { - iconSize: [this.PHOTO_MARKER_VIEW_SIZE, this.PHOTO_MARKER_VIEW_SIZE] - } - }); - this.nonLocalizedPhotoLayer.on('click', this.getNonLocalizedPhotoMarkerOnClickFunction()); - this.nonLocalizedPhotoLayer.on('clusterclick', function (a) { - if (a.layer.getChildCount() > 20 && that.map.getZoom() !== that.map.getMaxZoom()) { - a.layer.zoomToBounds(); - } - else { - a.layer.spiderfy(); - } - }); - // menu entry icon - var picimgurl = generateUrl('/svg/core/places/picture?color=eca700'); - $('#navigation-nonLocalizedPhotos > a.icon-picture').attr('style', 'background-image: url('+picimgurl+');') - // click on nonLocalizedPhoto menu entry - $('body').on('click', '#navigation-nonLocalizedPhotos > a', function(e) { - that.toggleLayer(); - that.optionsController.saveOptionValues({nonLocalizedPhotosLayer: that.map.hasLayer(that.nonLocalizedPhotoLayer)}); - that.updateTimeFilterRange(); - that.timeFilterController.setSliderToMaxInterval(); - }); - - //save geolocations to pictures - $('body').on('click', '.save-all-nonlocalized', function(e) { - that.menuSaveAllVisible(); - }); - - if (navigator.geolocation && window.isSecureContext) { - navigator.geolocation.getCurrentPosition(function (position) { - that.lat = position.coords.latitude; - that.lng = position.coords.longitude; - }); - } - else { - this.lat = 0; - this.lng = 0; - OC.Notification.showTemporary(t('maps', 'Impossible to get current location')); - } - }, - - updateMyFirstLastDates: function() { - var nbMarkers = this.nonLocalizedPhotoMarkers.length; - var layerVisible = this.map.hasLayer(this.nonLocalizedPhotoLayer); - this.nonLocalizedPhotoMarkersOldest = (layerVisible && nbMarkers > 0) ? this.nonLocalizedPhotoMarkers[0].data.date : null; - this.nonLocalizedPhotoMarkersNewest = (layerVisible && nbMarkers > 0) ? this.nonLocalizedPhotoMarkers[nbMarkers - 1].data.date : null; - }, - - showLayer: function() { - if (!this.nonLocalizedPhotosDataLoaded && !this.nonLocalizedPhotosRequestInProgress) { - this.callForImages(); - } - if (!this.map.hasLayer(this.nonLocalizedPhotoLayer)) { - this.map.addLayer(this.nonLocalizedPhotoLayer); - } - }, - - hideLayer: function() { - if (this.map.hasLayer(this.nonLocalizedPhotoLayer)) { - this.map.removeLayer(this.nonLocalizedPhotoLayer); - } - }, - - toggleLayer: function() { - if (this.map.hasLayer(this.nonLocalizedPhotoLayer)) { - this.hideLayer(); - $('#navigation-nonLocalizedPhotos').removeClass('active'); - $('#map').focus(); - } else { - this.showLayer(); - $('#navigation-nonLocalizedPhotos').addClass('active'); - } - }, - - getNonLocalizedPhotoMarkerOnClickFunction: function() { - var _app = this; - return function(evt) { - return null; - }; - }, - - - getClusterIconCreateFunction: function() { - var _app = this; - return function(cluster) { - var marker = cluster.getAllChildMarkers()[0].data; - var iconUrl; - if (marker.hasPreview) { - iconUrl = _app.generatePreviewUrl(marker.fileId); - } else { - iconUrl = _app.getImageIconUrl(); - } - var label = cluster.getChildCount(); - return new L.DivIcon(L.extend({ - className: 'leaflet-marker-nonLocalizedPhoto cluster-marker', - html: '
    ' + label + '' - }, this.icon)); - }; - }, - - createNonLocalizedPhotoView: function(markerData) { - var iconUrl; - if (markerData.hasPreview) { - iconUrl = this.generatePreviewUrl(markerData.fileId); - } else { - iconUrl = this.getImageIconUrl(); - } - return L.divIcon(L.extend({ - html: '
    ​', - className: 'leaflet-marker-nonLocalizedPhoto nonLocalizedPhoto-marker' - }, markerData, { - iconSize: [this.PHOTO_MARKER_VIEW_SIZE, this.PHOTO_MARKER_VIEW_SIZE], - iconAnchor: [this.PHOTO_MARKER_VIEW_SIZE / 2, this.PHOTO_MARKER_VIEW_SIZE] - })); - }, - - addNonLocalizedPhotosToMap : function(nonLocalizedPhotos) { - var markers = this.prepareNonLocalizedPhotoMarkers(nonLocalizedPhotos); - this.nonLocalizedPhotoMarkers.push.apply(this.nonLocalizedPhotoMarkers, markers); - this.nonLocalizedPhotoMarkers.sort(function (a, b) { return a.data.date - b.data.date;}); - - // we put them all in the layer - this.nonLocalizedPhotoMarkersFirstVisible = 0; - this.nonLocalizedPhotoMarkersLastVisible = this.nonLocalizedPhotoMarkers.length - 1; - this.nonLocalizedPhotoLayer.addLayers(this.nonLocalizedPhotoMarkers); - - this.updateTimeFilterRange(); - this.timeFilterController.setSliderToMaxInterval(); - }, - - prepareNonLocalizedPhotoMarkers : function(nonLocalizedPhotos) { - var that = this; - var markers = []; - for (var i = 0; i < nonLocalizedPhotos.length; i++) { - var markerData = { - lat: nonLocalizedPhotos[i].lat || this.lat, - lng: nonLocalizedPhotos[i].lng || this.lng, - path: nonLocalizedPhotos[i].path, - albumId: nonLocalizedPhotos[i].folderId, - fileId: nonLocalizedPhotos[i].fileId, - hasPreview : nonLocalizedPhotos[i].hasPreview, - date: nonLocalizedPhotos[i].dateTaken - }; - var marker = L.marker(markerData, { - draggable: true, - icon: this.createNonLocalizedPhotoView(markerData) - }); - marker.data = markerData; - var previewUrl = this.generatePreviewUrl(marker.data.fileId); - var dateStr = OC.Util.formatDate(nonLocalizedPhotos[i].dateTaken*1000); - var img = '' + - '

    ' + dateStr + '

    ' + - '

    ' + escapeHTML(basename(markerData.path)) + '

    '; - marker.bindTooltip(img, {permanent: false, className: "leaflet-marker-photo-tooltip"}); - marker.on('dragstart', function (e) { - e.target.closeTooltip(); - e.target.unbindTooltip(); - e.target.lastdrag = Date.now(); - e.target.lastdragactive = true; - }); - marker.on('dragend', function (e) { - e.target.lastdragactive = false; - setTimeout(function () { - var diff = Date.now() - e.target.lastdrag; - if ( diff > 2000 && !e.target.lastdragactive) { - that.saveCordinatesToImage(e.target); - } - }, 2001); - }); - - marker.on('click', function (e) { - that.saveCordinatesToImage(e.target); - }); - - markers.push(marker); - } - return markers; - }, - - updateTimeFilterRange: function() { - this.updateMyFirstLastDates(); - this.timeFilterController.updateSliderRangeFromController(); - }, - - updateTimeFilterBegin: function (date) { - if (date <= this.timeFilterEnd) { - var i = this.nonLocalizedPhotoMarkersFirstVisible; - if (date < this.timeFilterBegin) { - i = i-1; - while (i >= 0 && i <= this.nonLocalizedPhotoMarkersLastVisible && this.nonLocalizedPhotoMarkers[i].data.date >= date) { - this.nonLocalizedPhotoLayer.addLayer(this.nonLocalizedPhotoMarkers[i]); - i = i-1; - } - this.nonLocalizedPhotoMarkersFirstVisible = i + 1; - } - else { - while (i < this.nonLocalizedPhotoMarkers.length && i >= 0 && i <= this.nonLocalizedPhotoMarkersLastVisible && this.nonLocalizedPhotoMarkers[i].data.date < date) { - this.nonLocalizedPhotoLayer.removeLayer(this.nonLocalizedPhotoMarkers[i]); - i = i + 1; - } - this.nonLocalizedPhotoMarkersFirstVisible = i; - } - this.timeFilterBegin = date; - } - else { - this.updateTimeFilterBegin(this.timeFilterEnd); - } - }, - - updateTimeFilterEnd: function (date){ - if (date >= this.timeFilterBegin) { - var i = this.nonLocalizedPhotoMarkersLastVisible; - if (date < this.timeFilterEnd) { - while (i >= 0 && i >= this.nonLocalizedPhotoMarkersFirstVisible && this.nonLocalizedPhotoMarkers[i].data.date > date ) { - this.nonLocalizedPhotoLayer.removeLayer(this.nonLocalizedPhotoMarkers[i]); - i = i-1; - } - this.nonLocalizedPhotoMarkersLastVisible = i; - } - else { - i = i+1; - while (i >= this.nonLocalizedPhotoMarkersFirstVisible && i < this.nonLocalizedPhotoMarkers.length && this.nonLocalizedPhotoMarkers[i].data.date <= date) { - this.nonLocalizedPhotoLayer.addLayer(this.nonLocalizedPhotoMarkers[i]); - i = i+1; - } - this.nonLocalizedPhotoMarkersLastVisible = i - 1; - } - this.timeFilterEnd = date; - } - else { - this.updateTimeFilterEnd(this.timeFilterBegin); - } - }, - - callForImages: function() { - this.nonLocalizedPhotosRequestInProgress = true; - $('#navigation-nonLocalizedPhotos').addClass('icon-loading-small'); - $.ajax({ - url: generateUrl('apps/maps/photos/nonlocalized'), - type: 'GET', - async: true, - context: this - }).done(function (response) { - if (response.length == 0) { - //showNoPhotosMessage(); - } - else { - this.addNonLocalizedPhotosToMap(response); - } - this.nonLocalizedPhotosDataLoaded = true; - }).always(function (response) { - this.nonLocalizedPhotosRequestInProgress = false; - $('#navigation-nonLocalizedPhotos').removeClass('icon-loading-small'); - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to load non-geolocalized photos')); - }); - }, - - saveCordinatesToImage : function (marker) { - var latlng = marker.getLatLng(); - this.photosController.placePhotos([marker.data.path], [latlng.lat], [latlng.lng]); - var date = marker.data.date; - var path = marker.data.path; - var removedMarkers = []; - for (var i = this.nonLocalizedPhotoMarkersFirstVisible; i < this.nonLocalizedPhotoMarkers.length && this.nonLocalizedPhotoMarkers[i].data.date <= date; i++) { - if (this.nonLocalizedPhotoMarkers[i].data.path === path) { - var j = i + 1; - while (j < this.nonLocalizedPhotoMarkers.length && this.nonLocalizedPhotoMarkers[j].data.path === path) { - j++; - } - removedMarkers.push(...this.nonLocalizedPhotoMarkers.splice(i, j-i)); - i--; - } - } - var that = this; - removedMarkers.forEach(function (m) { - that.nonLocalizedPhotoLayer.removeLayer(m); - }); - this.nonLocalizedPhotoMarkersLastVisible = this.nonLocalizedPhotoMarkersLastVisible - removedMarkers.length; - }, - - /* Preview size 32x32 is used in files view, so it sould be generated */ - generateThumbnailUrl: function (filename) { - return generateUrl('core') + '/preview.png?file=' + encodeURI(filename) + '&x=32&y=32'; - }, - - /* Preview size 341x256 is commonly found in preview folder */ - generatePreviewUrl: function (fileId) { - return generateUrl('core') + '/preview?fileId=' + fileId + '&x=341&y=256&a=1'; - }, - - getImageIconUrl: function() { - return generateUrl('/apps/theming/img/core/filetypes') + '/image.svg?v=2'; - }, - - menuSaveAllVisible: function(e) { - var paths = []; - var lats = []; - var lngs = []; - for (var i=this.nonLocalizedPhotoMarkersFirstVisible; i<=this.nonLocalizedPhotoMarkersLastVisible; i++) { - var markerData = this.nonLocalizedPhotoMarkers[i].data; - paths.push( markerData.path); - lats.push(markerData.lat); - lngs.push(markerData.lng); - this.nonLocalizedPhotoLayer.removeLayer(this.nonLocalizedPhotoMarkers[i]); - delete this.nonLocalizedPhotoMarkers[i]; - } - this.photosController.placePhotos(paths, lats, lngs); - this.nonLocalizedPhotoMarkers.splice(this.nonLocalizedPhotoMarkersFirstVisible, this.nonLocalizedPhotoMarkersLastVisible - this.nonLocalizedPhotoMarkersFirstVisible + 1); - this.nonLocalizedPhotoMarkersLastVisible = this.nonLocalizedPhotoMarkersFirstVisible -1; - }, -}; - -export default NonLocalizedPhotosController; diff --git a/src/photosController.js b/src/photosController.js deleted file mode 100644 index 709bef53a..000000000 --- a/src/photosController.js +++ /dev/null @@ -1,716 +0,0 @@ -import {generateUrl} from '@nextcloud/router'; - -import {basename} from './utils'; - -import escapeHTML from 'escape-html'; - -function PhotosController (optionsController, timeFilterController) { - this.PHOTO_MARKER_VIEW_SIZE = 40; - this.photosDataLoaded = false; - this.photosRequestInProgress = false; - this.optionsController = optionsController; - this.timeFilterController = timeFilterController; - this.photoMarkers = []; - this.photoMarkersOldest = null; - this.photoMarkersNewest = null; - this.photoMarkersFirstVisible = 0; - this.photoMarkersLastVisible = -1; - this.timeFilterBegin = 0; - this.timeFilterEnd = Date.now(); - - this.movingPhotoPath = null; - this.isPhotosInstalled = OCP.InitialState.loadState('maps', 'photos'); -} - -PhotosController.prototype = { - - initLayer: function (map) { - this.map = map; - var that = this; - this.photoLayer = L.markerClusterGroup({ - iconCreateFunction: this.getClusterIconCreateFunction(), - spiderfyOnMaxZoom: false, - showCoverageOnHover: false, - zoomToBoundsOnClick: false, - maxClusterRadius: this.PHOTO_MARKER_VIEW_SIZE + 10, - icon: { - iconSize: [this.PHOTO_MARKER_VIEW_SIZE, this.PHOTO_MARKER_VIEW_SIZE] - } - }); - this.photoLayer.on('click', this.getPhotoMarkerOnClickFunction()); - this.photoLayer.on('clusterclick', function (a) { - if (a.layer.getChildCount() > 20 && that.map.getZoom() !== that.map.getMaxZoom()) { - a.layer.zoomToBounds(); - } else { - if (OCA.Viewer && OCA.Viewer.open) { - var photolist = a.layer.getAllChildMarkers().map(function (m) { - return m.data; - }); - photolist.sort(function (a, b) { - return a.dateTaken - b.dateTaken; - }); - OCA.Viewer.open({path: photolist[0].path, list: photolist}); - } else { - a.layer.spiderfy(); - that.map.clickpopup = true; - } - } - }); - //right click on photo cluster: - this.photoLayer.on('clustercontextmenu', this.photoClusterContextmenu); - // click on photo menu entry - $('body').on('click', '#navigation-photos > a', function (e) { - that.toggleLayer(); - that.optionsController.saveOptionValues({photosLayer: that.map.hasLayer(that.photoLayer)}); - that.updateTimeFilterRange(); - that.timeFilterController.setSliderToMaxInterval(); - }); - $('body').on('click', '.movephoto', function (e) { - var ul = $(this).parent().parent(); - var filePath = ul.attr('filepath'); - that.movingPhotoPath = filePath; - that.enterMovePhotoMode(); - that.map.closePopup(); - }); - $('body').on('click', '.resetphoto', function (e) { - var ul = $(this).parent().parent(); - var filePath = ul.attr('filepath'); - that.resetPhotoCoords([filePath]); - that.map.closePopup(); - }); - // expand navigation - $('body').on('click', '#navigation-photos', function (e) { - if (e.target.tagName === 'LI' && $(e.target).attr('id') === 'navigation-photos') { - that.toggleNavigation(); - that.optionsController.saveOptionValues({photosNavigationShow: $('#navigation-favorites').hasClass('open')}); - } - }); - // PhotoClusterMouseRightClick zoom-in - $('body').on('click', '.zoomin-photo-cluster-right-click', function (e) { - var ul = $(this).parent().parent(); - var thisClusterLayerId = ul.attr('layerId'); - if (that.map.getZoom() !== that.map.getMaxZoom()) { - that.map._layers[thisClusterLayerId].zoomToBounds(); - } - that.map.closePopup(); - }); - $('body').on('click', '.viewphotos', function (e) { - var ul = $(this).parent().parent(); - var thisClusterLayerId = ul.attr('layerId'); - if (OCA.Viewer && OCA.Viewer.open) { - var photolist = that.map._layers[thisClusterLayerId].getAllChildMarkers().map(function (m) { - return m.data; - }); - photolist.sort(function (a, b) { - return a.dateTaken - b.dateTaken; - }); - OCA.Viewer.open({path: photolist[0].path, list: photolist}); - } else { - that.map._layers[thisClusterLayerId].spiderfy(); - that.map.clickpopup = true; - } - that.map.closePopup(); - }); - }, - - updateMyFirstLastDates: function () { - var nbMarkers = this.photoMarkers.length; - var layerVisible = this.map.hasLayer(this.photoLayer); - this.photoMarkersOldest = (layerVisible && nbMarkers > 0) ? this.photoMarkers[0].data.dateTaken : null; - this.photoMarkersNewest = (layerVisible && nbMarkers > 0) ? this.photoMarkers[nbMarkers - 1].data.dateTaken : null; - }, - - showLayer: function () { - if (!this.photosDataLoaded && !this.photosRequestInProgress) { - this.callForImages(); - } - if (!this.map.hasLayer(this.photoLayer)) { - this.map.addLayer(this.photoLayer); - } - }, - - hideLayer: function () { - if (this.map.hasLayer(this.photoLayer)) { - this.map.removeLayer(this.photoLayer); - } - }, - - toggleLayer: function () { - if (this.map.hasLayer(this.photoLayer)) { - this.hideLayer(); - $('#navigation-photos').removeClass('active'); - $('#map').focus(); - } else { - this.showLayer(); - $('#navigation-photos').addClass('active'); - } - }, - - toggleNavigation: function () { - $('#navigation-photos').toggleClass('open'); - }, - - getPhotoMarkerOnClickFunction: function () { - var _app = this; - return function (evt) { - var marker = evt.layer; - // use Viewer app if available and recent enough to provide standalone viewer - if (OCA.Viewer && OCA.Viewer.open) { - OCA.Viewer.open({path: marker.data.path, list: [marker.data]}); - } else { - var galleryUrl; - if (_app.isPhotosInstalled) { - var dir = OC.dirname(marker.data.path); - galleryUrl = generateUrl('/apps/photos/albums/' + dir.replace(/^\//, '')); - } else { - galleryUrl = generateUrl('/apps/gallery/#' + encodeURIComponent(marker.data.path.replace(/^\//, ''))); - } - var win = window.open(galleryUrl, '_blank'); - if (win) { - win.focus(); - } - } - }; - }, - - //getPhotoMarkerOnClickFunction() { - // var _app = this; - // return function(evt) { - // var marker = evt.layer; - // var content; - // if (marker.data.hasPreview) { - // var previewUrl = _app.generatePreviewUrl(marker.data.path); - // var img = ''; - // //Workaround for https://github.com/Leaflet/Leaflet/issues/5484 - // $(img).on('load', function() { - // marker.getPopup().update(); - // }); - // content = img; - // } else { - // content = marker.data.path; - // } - // marker.bindPopup(content, { - // className: 'leaflet-popup-photo', - // maxWidth: 'auto' - // }).openPopup(); - // } - //}, - - getClusterIconCreateFunction: function () { - var _app = this; - return function (cluster) { - var availZoomLevels = cluster._map.getMaxZoom() - cluster._map.getZoom(); - var marker = cluster.getAllChildMarkers()[0].data; - var iconUrl; - if (marker.hasPreview) { - iconUrl = _app.generatePreviewUrl(marker.fileId); - } else { - iconUrl = _app.getImageIconUrl(); - } - var label = cluster.getChildCount(); - if (availZoomLevels === 0 && label > 1) { - // lets generate a preview slideshow for cluster of images at max zoom level - var iMarkerList = cluster.getAllChildMarkers(); - // sort by dateTaken - iMarkerList.sort(function (a, b) { - return a.data.dateTaken - b.data.dateTaken; - }); - var firstImageFileId = iMarkerList[0].data.fileId; - var imgList = '
    '; - for (var i = 0; i < cluster.getChildCount(); i++) { - var iMarker = iMarkerList[i].data; - var iIconUrl = _app.generatePreviewUrl(iMarker.fileId); - var iDateStr = OC.Util.formatDate(iMarker.dateTaken * 1000); - var iPhotoName = escapeHTML(basename(iMarker.path)); - var img = ''; - imgList += img; - } - imgList += '
    ' - cluster.bindTooltip(imgList, { - permanent: false, - className: 'leaflet-marker-photo-tooltip', - direction: 'right', - offset: L.point(0, -150) - }); - cluster.on("tooltipopen", function (event, ui) { - var maxI = parseInt(cluster.getChildCount()) - 1; - var imgIndexAttr = $('#imgdiv').parent().parent().attr('imgindex'); - if (imgIndexAttr >= 0) { - // a preview image loop was already running before. - // need to check if again opening the same preview image loop as before to continue or if opening another preview image loop and start at first image. We identify this using the attribute firstImageFileId we stored in 2nd parent above #imgdiv - var lastFirstImageFileId = $('#imgdiv').parent().parent().attr('firstImageFileId'); - if (lastFirstImageFileId == firstImageFileId) { - // we continue the loop that was already running before - } else { - // we start a new preview loop - imgIndexAttr = 0; - // we store imgindex of preview loop in attribute imgindex in 2nd parent above #imgdiv - $('#imgdiv').parent().parent().attr('imgindex', '0'); - } - } - $('#imgdiv').parent().parent().attr('firstImageFileId', firstImageFileId); - $('#imgdiv').show(); - // For some browsers, `attr` is undefined; for others, - // `attr` is false. Check for both. - if (typeof imgIndexAttr == typeof undefined || imgIndexAttr == false) { - // imgindex not yet defined therefore this is the fist time tooltipopen running - // for this cluster. Therefore we start with imgindex 0 - $('#imgdiv').parent().parent().attr('imgindex', '0'); // saving 0 as start value to attribute imgindex - $('#imgdiv0').show(); // showing first image - } else { - // this loop was previously visible therefore we continue with last visible image - $('#imgdiv' + imgIndexAttr).show(); - } - var randomId = Math.random(); // - $('#imgdiv').parent().parent().attr('randomId', randomId); - - function toolTipImgLoop (maxI, randomId) { - // will will only continue the loop if randomId is matching randomId stored in imgdiv - // to prevent running multiple loops in parallel could be caused by to fast mouseout / mouseover events - setTimeout(function (maxI) { // this function content will be executed after timeout of 3 sec (3000 ms) - var randomIdFromImgdiv = $('#imgdiv').parent().parent().attr('randomId'); - if (randomId == randomIdFromImgdiv) { - var i = $('#imgdiv').parent().parent().attr('imgindex'); - var j = (parseInt(i) + 1); - if (i == maxI) { // if i reached max image j need to start with 0 again to continue with 1st image again - j = 0; - } - // now we will fade out the current img and fade in the next image - $('#imgdiv' + i).fadeOut('fast', function () { - $('#imgdiv' + j).fadeIn('fast'); - }); - if (i == maxI) { // and now we also need to switch i back to 0 to contine - i = 0; - } else { - i++; - } - $('#imgdiv').parent().parent().attr('imgindex', i); - // after storing current value of i (loop img index) in imgdiv imgindex attribute - // we will call again toolTipImgLoop to continue the loop - toolTipImgLoop(maxI, randomId); - } - }, 3000, maxI); // timeout and variable of above setTimeout - } - // initial call of toolTipImgLoop - // we will do the inital call of toolTipImgLoop using setTimeout with timeout 500 ms to ensure that tooltipopen has been completed - setTimeout(toolTipImgLoop(maxI, randomId), 500, maxI, randomId); - }); - cluster.on("tooltipclose", function (event, ui) { - // clearing randomId in imgdiv on mouseout to stop the img preview loop (see above) - $('#imgdiv').parent().parent().attr('randomId', 0); - }); - } - return new L.DivIcon(L.extend({ - className: 'leaflet-marker-photo cluster-marker', - html: '
    ' + label + '' - }, this.icon)); - }; - }, - - createPhotoView: function (markerData) { - var iconUrl; - if (markerData.hasPreview) { - iconUrl = this.generatePreviewUrl(markerData.fileId); - } else { - iconUrl = this.getImageIconUrl(); - } - return L.divIcon(L.extend({ - html: '
    ​', - className: 'leaflet-marker-photo photo-marker' - }, markerData, { - iconSize: [this.PHOTO_MARKER_VIEW_SIZE, this.PHOTO_MARKER_VIEW_SIZE], - iconAnchor: [this.PHOTO_MARKER_VIEW_SIZE / 2, this.PHOTO_MARKER_VIEW_SIZE] - })); - }, - - addPhotosToMap: function (photos) { - var markers = this.preparePhotoMarkers(photos); - this.photoMarkers.push.apply(this.photoMarkers, markers); - this.photoMarkers.sort(function (a, b) { - return a.data.dateTaken - b.data.dateTaken; - }); - - // we update the counter - var catCounter = $('#navigation-photos .app-navigation-entry-utils-counter'); - var photoCounter = this.photoMarkers.length; - if (photoCounter >= 10000) { - catCounter.attr('title', photoCounter + ' photos'); - photoCounter = photoCounter = Math.floor(photoCounter / 1000); - catCounter.text(photoCounter + 'k'); - } else { - catCounter.text(photoCounter); - } - - // we put them all in the layer - this.photoMarkersFirstVisible = 0; - this.photoMarkersLastVisible = this.photoMarkers.length - 1; - this.photoLayer.addLayers(this.photoMarkers); - - this.updateTimeFilterRange(); - this.timeFilterController.setSliderToMaxInterval(); - }, - - preparePhotoMarkers: function (photos) { - var markers = []; - for (var i = 0; i < photos.length; i++) { - var markerData = photos[i]; - var marker = L.marker(markerData, { - icon: this.createPhotoView(markerData) - }); - marker.data = markerData; - var previewUrl = this.generatePreviewUrl(marker.data.fileId); - var dateStr = OC.Util.formatDate(photos[i].dateTaken * 1000); - var img = '' + - '

    ' + dateStr + '

    ' + - '

    ' + escapeHTML(basename(markerData.path)) + '

    '; - marker.bindTooltip(img, { - permanent: false, - className: 'leaflet-marker-photo-tooltip', - direction: 'right', - offset: L.point(0, -30) - }); - marker.on('contextmenu', this.photoMouseRightClick); - markers.push(marker); - } - return markers; - }, - - photoClusterContextmenu: function (a) { - var layerId = a.layer._leaflet_id; - a.layer.unbindPopup(); - var popupContent = this._map.photosController.getPhotoClusterContextmenuPopupContent(layerId); - a.layer.bindPopup(popupContent, { - closeOnClick: true, - className: 'popovermenu open popupMarker', - offset: L.point(-5, -20) - }); - a.layer.openPopup(); - }, - - getPhotoClusterContextmenuPopupContent: function (layerId) { - var viewText = t('maps', 'Show batch in viewer'); - var zoomText = t('maps', 'Zoom in'); - var res = - ''; - return res; - }, - - photoMouseRightClick: function (e) { - var that = this; - var filePath = e.target.data.path; - - var popupContent = this._map.photosController.getPhotoContextPopupContent(filePath); - this._map.clickpopup = true; - - var popup = L.popup({ - closeOnClick: true, - className: 'popovermenu open popupMarker', - offset: L.point(-5, -20) - }) - .setLatLng(e.target._latlng) - .setContent(popupContent) - .openOn(this._map); - $(popup._closeButton).one('click', function (e) { - that._map.clickpopup = null; - }); - }, - - getPhotoContextPopupContent: function (filePath) { - var moveText = t('maps', 'Move'); - var resetText = t('maps', 'Remove geo data'); - var res = - ''; - return res; - }, - - enterMovePhotoMode: function () { - $('.leaflet-container, .mapboxgl-map').css('cursor', 'crosshair'); - this.map.on('click', this.movePhotoClickMap); - this.map.clickpopup = true; - OC.Notification.showTemporary(t('maps', 'Click on the map to move the photo, press ESC to cancel')); - }, - - leaveMovePhotoMode: function () { - $('.leaflet-container, .mapboxgl-map').css('cursor', 'grab'); - this.map.off('click', this.movePhotoClickMap); - this.map.clickpopup = null; - this.movingPhotoPath = null; - }, - - movePhotoClickMap: function (e) { - var lat = e.latlng.lat; - var lng = e.latlng.lng; - var filePath = this.photosController.movingPhotoPath; - this.photosController.leaveMovePhotoMode(); - this.photosController.placePhotos([filePath], [lat], [lng]); - }, - - updateTimeFilterRange: function () { - this.updateMyFirstLastDates(); - this.timeFilterController.updateSliderRangeFromController(); - }, - - updateTimeFilterBegin: function (date) { - if (date <= this.timeFilterEnd) { - var i = this.photoMarkersFirstVisible; - if (date < this.timeFilterBegin) { - i = i - 1; - while (i >= 0 && i <= this.photoMarkersLastVisible && this.photoMarkers[i].data.dateTaken >= date) { - this.photoLayer.addLayer(this.photoMarkers[i]); - i = i - 1; - } - this.photoMarkersFirstVisible = i + 1; - } else { - while (i < this.photoMarkers.length && i >= 0 && i <= this.photoMarkersLastVisible && this.photoMarkers[i].data.dateTaken < date) { - this.photoLayer.removeLayer(this.photoMarkers[i]); - i = i + 1; - } - this.photoMarkersFirstVisible = i; - } - this.timeFilterBegin = date; - } else { - this.updateTimeFilterBegin(this.timeFilterEnd); - } - }, - - updateTimeFilterEnd: function (date) { - if (date >= this.timeFilterBegin) { - var i = this.photoMarkersLastVisible; - if (date < this.timeFilterEnd) { - while (i >= 0 && i >= this.photoMarkersFirstVisible && this.photoMarkers[i].data.dateTaken > date) { - this.photoLayer.removeLayer(this.photoMarkers[i]); - i = i - 1; - } - this.photoMarkersLastVisible = i; - } else { - i = i + 1; - while (i >= this.photoMarkersFirstVisible && i < this.photoMarkers.length && this.photoMarkers[i].data.dateTaken <= date) { - this.photoLayer.addLayer(this.photoMarkers[i]); - i = i + 1; - } - this.photoMarkersLastVisible = i - 1; - } - this.timeFilterEnd = date; - } else { - this.updateTimeFilterEnd(this.timeFilterBegin); - } - }, - - callForImages: function () { - this.photosRequestInProgress = true; - $('#navigation-photos').addClass('icon-loading-small'); - $.ajax({ - url: generateUrl('apps/maps/photos'), - type: 'GET', - async: true, - context: this - }).done(function (response) { - if (response.length == 0) { - //showNoPhotosMessage(); - } else { - this.addPhotosToMap(response); - } - this.photosDataLoaded = true; - }).always(function (response) { - this.photosRequestInProgress = false; - $('#navigation-photos').removeClass('icon-loading-small'); - }).fail(function () { - OC.Notification.showTemporary(t('maps', 'Failed to load photos')); - }); - }, - - /* Preview size 32x32 is used in files view, so it sould be generated */ - generateThumbnailUrl: function (filename) { - return generateUrl('core') + '/preview.png?file=' + encodeURI(filename) + '&x=32&y=32'; - }, - - /* Preview size 341x256 is commonly found in preview folder */ - generatePreviewUrl: function (fileId) { - return generateUrl('core') + '/preview?fileId=' + fileId + '&x=341&y=256&a=1'; - }, - - getImageIconUrl: function () { - return generateUrl('/apps/theming/img/core/filetypes') + '/image.svg?v=2'; - }, - - contextPlacePhotosOrFolder: function (e) { - var that = this.photosController; - OC.dialogs.confirmDestructive( - '', - t('maps', 'What do you want to place?'), - { - type: OC.dialogs.YES_NO_BUTTONS, - confirm: t('maps', 'Photo files'), - confirmClasses: '', - cancel: t('maps', 'Photo folders'), - }, - function (result) { - if (result) { - that.contextPlacePhotos(e); - } else { - that.contextPlacePhotoFolder(e); - } - }, - true - ); - }, - - contextPlacePhotos: function (e) { - var that = this; - var latlng = e.latlng; - OC.dialogs.filepicker( - t('maps', 'Choose pictures to place'), - function (targetPath) { - that.placePhotos(targetPath, [latlng.lat], [latlng.lng]); - }, - true, - ['image/jpeg', 'image/tiff'], - true - ); - }, - - contextPlacePhotoFolder: function (e) { - var that = this; - var latlng = e.latlng; - OC.dialogs.filepicker( - t('maps', 'Choose directory of pictures to place'), - function (targetPath) { - if (targetPath === '') { - targetPath = '/'; - } - that.placePhotos([targetPath], [latlng.lat], [latlng.lng], true); - }, - false, - 'httpd/unix-directory', - true - ); - }, - - placePhotos: function (paths, lats, lngs, directory = false) { - var that = this; - $('#navigation-photos').addClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'wait'); - var req = { - paths: paths, - lats: lats, - lngs: lngs, - directory: directory - }; - var url = generateUrl('/apps/maps/photos'); - $.ajax({ - type: 'POST', - url: url, - data: req, - async: true - }).done(function (response) { - OC.Notification.showTemporary(t('maps', '{nb} photos placed', {nb: response})); - if (response > 0) { - that.photosDataLoaded = false; - for (var i = 0; i < that.photoMarkers.length; i++) { - that.photoLayer.removeLayer(that.photoMarkers[i]); - } - that.photoMarkers = []; - that.photoMarkersOldest = null; - that.photoMarkersNewest = null; - that.photoMarkersFirstVisible = 0; - that.photoMarkersLastVisible = -1; - that.timeFilterBegin = 0; - that.timeFilterEnd = Date.now(); - - that.showLayer(); - } - }).always(function (response) { - $('#navigation-photos').removeClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'grab'); - }).fail(function (response) { - OC.Notification.showTemporary(t('maps', 'Failed to place photos') + ': ' + response.responseText); - }); - }, - - resetPhotoCoords: function (paths) { - var that = this; - $('#navigation-photos').addClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'wait'); - var req = { - paths: paths - }; - var url = generateUrl('/apps/maps/photos'); - $.ajax({ - type: 'DELETE', - url: url, - data: req, - async: true - }).done(function (response) { - OC.Notification.showTemporary(t('maps', '{nb} photos reset', {nb: response})); - if (response > 0) { - that.photosDataLoaded = false; - for (var i = 0; i < that.photoMarkers.length; i++) { - that.photoLayer.removeLayer(that.photoMarkers[i]); - } - that.photoMarkers = []; - that.photoMarkersOldest = null; - that.photoMarkersNewest = null; - that.photoMarkersFirstVisible = 0; - that.photoMarkersLastVisible = -1; - that.timeFilterBegin = 0; - that.timeFilterEnd = Date.now(); - - that.showLayer(); - } - }).always(function (response) { - $('#navigation-photos').removeClass('icon-loading-small'); - $('.leaflet-container, .mapboxgl-map').css('cursor', 'grab'); - }).fail(function (response) { - OC.Notification.showTemporary(t('maps', 'Failed to reset photos coordinates') + ': ' + response.responseText); - }); - }, - - getAutocompData: function () { - var that = this; - var mData; - var data = []; - if (this.map.hasLayer(this.photoLayer)) { - this.photoLayer.eachLayer(function (l) { - mData = l.data; - data.push({ - type: 'photo', - label: OC.basename(mData.path), - value: OC.basename(mData.path), - lat: mData.lat, - lng: mData.lng - }); - }); - } - return data; - }, - -}; - -export default PhotosController; diff --git a/src/script.js b/src/script.js deleted file mode 100644 index 48dc9c90a..000000000 --- a/src/script.js +++ /dev/null @@ -1,2243 +0,0 @@ -/** - * Nextcloud - Maps - * - * @author Gary Kim - * - * @copyright Copyright (c) 2020, Gary Kim - * - * @license GNU AGPL version 3 or any later version - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ -import 'leaflet/dist/leaflet'; -import 'leaflet/dist/leaflet.css'; -import 'leaflet.locatecontrol/dist/L.Control.Locate.min'; -import 'leaflet.locatecontrol/dist/L.Control.Locate.min.css'; -import 'leaflet.markercluster/dist/leaflet.markercluster'; -import 'leaflet.markercluster/dist/MarkerCluster.css'; -import 'leaflet.markercluster/dist/MarkerCluster.Default.css' -import 'leaflet.elevation/dist/Leaflet.Elevation-0.0.2.min'; -import 'leaflet.elevation/dist/Leaflet.Elevation-0.0.2.css'; -import 'leaflet-control-geocoder/dist/Control.Geocoder'; -import 'leaflet-control-geocoder/dist/Control.Geocoder.css'; -import 'leaflet-mouse-position/src/L.Control.MousePosition'; -import 'leaflet-mouse-position/src/L.Control.MousePosition.css'; -import 'leaflet-contextmenu/dist/leaflet.contextmenu.min'; -import 'leaflet-contextmenu/dist/leaflet.contextmenu.min.css'; -import 'leaflet-easybutton/src/easy-button'; -import 'leaflet-easybutton/src/easy-button.css'; -import 'leaflet-routing-machine/dist/leaflet-routing-machine'; -import 'leaflet-routing-machine/dist/leaflet-routing-machine.css'; -import 'lrm-graphhopper'; -import 'leaflet.featuregroup.subgroup/dist/leaflet.featuregroup.subgroup'; -import 'd3'; -import 'mapbox-gl/dist/mapbox-gl'; -import 'mapbox-gl-leaflet/leaflet-mapbox-gl'; -import '@fortawesome/fontawesome-free/css/all.min.css'; - -import noUiSlider from 'nouislider'; -import 'nouislider/distribute/nouislider.css'; -import opening_hours from 'opening_hours'; - - -import { generateUrl } from '@nextcloud/router'; -import escapeHTML from 'escape-html'; - -import ContactsController from './contactsController'; -import DevicesController from './devicesController'; -import FavoritesController from './favoritesController'; -import NonLocalizedPhotosController from './nonLocalizedPhotosController'; -import PhotosController from './photosController'; -import TracksController from './tracksController'; - -import { brify, getUrlParameter, formatAddress } from './utils'; - -(function($, OC) { - var geoLinkController = { - marker: null, - lat: null, - lng: null, - showLinkLocation: function() { - var geourlElem = document.getElementById('geourl'); - if (geourlElem) { - var geourl = geourlElem.value; - [this.lat, this.lng] = geourl.substring(4).split(','); - this.marker = L.marker([this.lat, this.lng]); - mapController.map.addLayer(this.marker); - mapController.map.setView([this.lat, this.lng], 15); - } - }, - - shareLocation: function(e) { - var lat = e.latlng.lat; - var lng = e.latlng.lng; - var geoLink = 'geo:' + lat.toFixed(6) + ',' + lng.toFixed(6); - var dummy = $('').val(geoLink).appendTo('body').select(); - document.execCommand('copy'); - $('#dummycopy').remove(); - OC.Notification.showTemporary(t('maps', 'Geo link ({geoLink}) copied to clipboard', {geoLink: geoLink})); - }, - }; - - var optionsController = { - nbRouters: 0, - optionValues: {}, - enabledFavoriteCategories: [], - disabledContactGroups: [], - enabledTracks: [], - enabledDevices: [], - enabledDeviceLines: [], - saveOptionValues: function (optionValues) { - var req = { - options: optionValues - }; - var url = generateUrl('/apps/maps/saveOptionValue'); - $.ajax({ - type: 'POST', - url: url, - data: req, - async: true - }).done(function (response) { - }).fail(function() { - OC.Notification.showTemporary( - t('maps', 'Failed to save option values') - ); - }); - }, - - restoreOptions: function () { - var that = this; - var url = generateUrl('/apps/maps/getOptionsValues'); - var req = {}; - var optionsValues = {}; - $.ajax({ - type: 'POST', - url: url, - data: req, - async: true - }).done(function (response) { - optionsValues = response.values; - - // check if install scan was done - if (optionsValues.hasOwnProperty('installScanDone') && optionsValues.installScanDone === 'no') { - OC.Notification.showTemporary( - t('maps', 'Media scan was not done yet. Wait a few minutes/hours and reload this page to see your photos/tracks.') - ); - } - - // set tilelayer before showing photo layer because it needs a max zoom value - if (optionsValues.hasOwnProperty('displaySlider') && optionsValues.displaySlider === 'true') { - $('#timeRangeSlider').show(); - $('#display-slider').prop('checked', true); - } - - //detect Webgl - var canvas = document.createElement('canvas'); - var experimental = false; - var gl; - - try { gl = canvas.getContext("webgl"); } - catch (x) { gl = null; } - - if (gl == null) { - try { gl = canvas.getContext("experimental-webgl"); experimental = true; } - catch (x) { gl = null; } - } - - if (optionsValues.hasOwnProperty('mapboxAPIKEY') && optionsValues.mapboxAPIKEY !== '' && gl != null) { - // change "button" layers - delete mapController.baseLayers['OpenStreetMap']; - delete mapController.baseLayers['ESRI Aerial']; - mapController.defaultStreetLayer = 'Mapbox vector streets'; - mapController.defaultSatelliteLayer = 'Mapbox satellite'; - // remove dark, esri topo and openTopoMap - // Mapbox outdoors and dark are good enough - mapController.controlLayers.removeLayer(mapController.baseLayers['ESRI Topo']); - mapController.controlLayers.removeLayer(mapController.baseLayers['OpenTopoMap']); - mapController.controlLayers.removeLayer(mapController.baseLayers['Dark']); - delete mapController.baseLayers['ESRI Topo']; - delete mapController.baseLayers['OpenTopoMap']; - delete mapController.baseLayers['Dark']; - - // add mapbox-gl tile servers - var attrib = '© Mapbox '+ - '© OpenStreetMap '+ - ''+t('maps', 'Improve this map')+''; - var attribSat = attrib + '© DigitalGlobe' - - mapController.baseLayers['Mapbox vector streets'] = L.mapboxGL({ - accessToken: optionsValues.mapboxAPIKEY, - style: 'mapbox://styles/mapbox/streets-v8', - minZoom: 1, - maxZoom: 22, - attribution: attrib - }); - //mapController.controlLayers.addBaseLayer(mapController.baseLayers['Mapbox vector streets'], 'Mapbox vector streets'); - - mapController.baseLayers['Topographic'] = L.mapboxGL({ - accessToken: optionsValues.mapboxAPIKEY, - style: 'mapbox://styles/mapbox/outdoors-v11', - minZoom: 1, - maxZoom: 22, - attribution: attrib - }); - mapController.controlLayers.addBaseLayer(mapController.baseLayers['Topographic'], 'Topographic'); - - mapController.baseLayers['Dark'] = L.mapboxGL({ - accessToken: optionsValues.mapboxAPIKEY, - style: 'mapbox://styles/mapbox/dark-v8', - minZoom: 1, - maxZoom: 22, - attribution: attrib - }); - mapController.controlLayers.addBaseLayer(mapController.baseLayers['Dark'], 'Dark'); - - mapController.baseLayers['Mapbox satellite'] = L.mapboxGL({ - accessToken: optionsValues.mapboxAPIKEY, - style: 'mapbox://styles/mapbox/satellite-streets-v9', - minZoom: 1, - maxZoom: 22, - attribution: attribSat - }); - //mapController.controlLayers.addBaseLayer(mapController.baseLayers['Mapbox satellite'], 'Mapbox satellite'); - } - if (optionsValues.hasOwnProperty('tileLayer')) { - mapController.changeTileLayer(optionsValues.tileLayer); - } - else { - mapController.changeTileLayer(mapController.defaultStreetLayer); - } - if (optionsValues.hasOwnProperty('mapBounds')) { - var nsew = optionsValues.mapBounds.split(';'); - if (nsew.length === 4) { - var n = parseFloat(nsew[0]); - var s = parseFloat(nsew[1]); - var e = parseFloat(nsew[2]); - var w = parseFloat(nsew[3]); - if (n && s && e && w) { - mapController.map.fitBounds([ - [n, e], - [s, w] - ]); - } - } - } - if (!optionsValues.hasOwnProperty('photosLayer') || optionsValues.photosLayer === 'true') { - photosController.toggleLayer(); - } - if (!optionsValues.hasOwnProperty('contactGroupListShow') || optionsValues.contactGroupListShow === 'true') { - contactsController.toggleGroupList(); - } - if (optionsValues.hasOwnProperty('disabledContactGroups') - && optionsValues.disabledContactGroups - && optionsValues.disabledContactGroups !== '') - { - that.disabledContactGroups = optionsValues.disabledContactGroups.split('|'); - } - if (!optionsValues.hasOwnProperty('contactLayer') || optionsValues.contactLayer === 'true') { - contactsController.toggleLayer(); - } - if (optionsValues.hasOwnProperty('locControlEnabled') && optionsValues.locControlEnabled === 'true') { - mapController.locControl.start(); - } - if (!optionsValues.hasOwnProperty('favoriteCategoryListShow') || optionsValues.favoriteCategoryListShow === 'true') { - favoritesController.toggleCategoryList(); - } - if (optionsValues.hasOwnProperty('enabledFavoriteCategories') - && optionsValues.enabledFavoriteCategories - && optionsValues.enabledFavoriteCategories !== '') - { - that.enabledFavoriteCategories = optionsValues.enabledFavoriteCategories.split('|'); - } - if (!optionsValues.hasOwnProperty('favoritesEnabled') || optionsValues.favoritesEnabled === 'true') { - favoritesController.toggleFavorites(); - } - if (!optionsValues.hasOwnProperty('trackListShow') || optionsValues.trackListShow === 'true') { - tracksController.toggleTrackList(); - } - if (optionsValues.hasOwnProperty('enabledTracks') - && optionsValues.enabledTracks - && optionsValues.enabledTracks !== '') - { - that.enabledTracks = optionsValues.enabledTracks.split('|').map(function (x) { - return parseInt(x); - }); - } - if (optionsValues.hasOwnProperty('tracksSortOrder') && optionsValues.tracksSortOrder !== '') { - tracksController.sortOrder = optionsValues.tracksSortOrder; - } - else { - tracksController.sortOrder = 'date'; - } - if (getUrlParameter('track') || !optionsValues.hasOwnProperty('tracksEnabled') || optionsValues.tracksEnabled === 'true') { - tracksController.toggleTracks(); - } - if (!optionsValues.hasOwnProperty('deviceListShow') || optionsValues.deviceListShow === 'true') { - devicesController.toggleDeviceList(); - } - if (optionsValues.hasOwnProperty('enabledDevices') - && optionsValues.enabledDevices - && optionsValues.enabledDevices !== '') - { - that.enabledDevices = optionsValues.enabledDevices.split('|').map(function (x) { - return parseInt(x); - }); - } - if (optionsValues.hasOwnProperty('enabledDeviceLines') - && optionsValues.enabledDeviceLines - && optionsValues.enabledDeviceLines !== '') - { - that.enabledDeviceLines = optionsValues.enabledDeviceLines.split('|').map(function (x) { - return parseInt(x); - }); - } - if (!optionsValues.hasOwnProperty('devicesEnabled') || optionsValues.devicesEnabled === 'true') { - devicesController.toggleDevices(); - } - if (optionsValues.hasOwnProperty('trackMe') && optionsValues.trackMe === 'true') { - $('#track-me').prop('checked', true); - devicesController.launchTrackLoop(); - } - - // save tile layer when changed - // do it after restore, otherwise restoring triggers save - mapController.map.on('baselayerchange ', function(e) { - optionsController.saveOptionValues({tileLayer: e.name}); - // make sure map is clean - for (var ol in mapController.baseOverlays) { - mapController.map.removeLayer(mapController.baseOverlays[ol]); - } - for (var tl in mapController.baseLayers) { - if (tl !== e.name) { - mapController.map.removeLayer(mapController.baseLayers[tl]); - } - } - if (e.name === 'Watercolor') { - mapController.map.addLayer(mapController.baseOverlays['Roads and labels']); - } - mapController.layerChanged(e.name); - }); - - // routing - that.nbRouters = 0; - if (optionsValues.hasOwnProperty('osrmCarURL') && optionsValues.osrmCarURL !== '') { - that.nbRouters++; - } - if (optionsValues.hasOwnProperty('osrmBikeURL') && optionsValues.osrmBikeURL !== '') { - that.nbRouters++; - } - if (optionsValues.hasOwnProperty('osrmFootURL') && optionsValues.osrmFootURL !== '') { - that.nbRouters++; - } - if (optionsValues.hasOwnProperty('mapboxAPIKEY') && optionsValues.mapboxAPIKEY !== '') { - that.nbRouters++; - } - if ((optionsValues.hasOwnProperty('graphhopperURL') && optionsValues.graphhopperURL !== '') || - (optionsValues.hasOwnProperty('graphhopperAPIKEY') && optionsValues.graphhopperAPIKEY !== '') ){ - that.nbRouters++; - } - if (that.nbRouters === 0 && !OC.isUserAdmin()) { - // disable routing and hide it to the user - // search bar - $('#route-submit').hide(); - $('#search-submit').css('right', '10px'); - // context menu: remove routing related items - mapController.map.contextmenu.removeItem(mapController.map.contextmenu._items[mapController.map.contextmenu._items.length-1].el); - mapController.map.contextmenu.removeItem(mapController.map.contextmenu._items[mapController.map.contextmenu._items.length-1].el); - mapController.map.contextmenu.removeItem(mapController.map.contextmenu._items[mapController.map.contextmenu._items.length-1].el); - mapController.map.contextmenu.removeItem(mapController.map.contextmenu._items[mapController.map.contextmenu._items.length-1].el); - // and we don't init routingController - } - else { - routingController.initRoutingControl(mapController.map, optionsValues); - } - - //if (optionsValues.hasOwnProperty('routingEnabled') && optionsValues.routingEnabled === 'true') { - // routingController.toggleRouting(); - //} - }).fail(function() { - OC.Notification.showTemporary( - t('maps', 'Failed to restore options values') - ); - }); - } - }; - - var mapController = { - searchMarkerLayerGroup: null, - map: {}, - // those default layers might be changed if we have a Mapbox API key - defaultStreetLayer: 'OpenStreetMap', - defaultSatelliteLayer: 'ESRI Aerial', - locControl: undefined, - baseLayers: undefined, - displaySearchResult: function(results) { - var that = this; - this.searchMarkerLayerGroup.clearLayers(); - var result, searchMarker; - for (var i=0; i < results.length; i++) { - result = results[i]; - searchMarker = L.marker([result.lat, result.lon], { - icon: this.searchIcon - }); - var name = result.display_name; - // popup - if (result.maps_type === "coordinate") { - var popupContent = searchController.parseCoordinateResult(result); - } else { - var popupContent = searchController.parseOsmResult(result); - } - searchMarker.bindPopup(popupContent, {className: 'search-result-popup'}); - searchMarker.on('popupopen', function(e) { - $(e.popup._closeButton).one('click', function (e) { - that.map.clickpopup = null; - }); - }) - searchMarker.on('click', function () { - that.map.clickpopup = true; - }); - // tooltip - var name = ''; - if (result.namedetails && result.namedetails.name) { - name = result.namedetails.name; - } - else { - name = result.display_name; - } - var tooltipContent = brify(name, 40); - searchMarker.bindTooltip(tooltipContent, {className: 'search-result-tooltip'}); - searchMarker.addTo(this.searchMarkerLayerGroup); - } - if (results.length === 1) { - this.searchMarkerLayerGroup.getLayers()[0].openPopup(); - this.map.flyTo([results[0].lat, results[0].lon], 15, {duration: 1}); - this.map.clickpopup = true; - } - }, - initMap: function() { - var that = this; - this.searchIcon = L.divIcon({ - iconAnchor: [12, 25], - className: 'route-waypoint route-middle-waypoint', - html: '' - }); - var attribution = '© OpenStreetMap contributors, CC-BY-SA'; - - var osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { - attribution : attribution, - noWrap: false, - detectRetina: false, - maxZoom: 19 - }); - - var attributionESRI = 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN...'; - var ESRIAerial = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { - attribution : attributionESRI, - noWrap: false, - detectRetina: true, - maxZoom: 19 - }); - var roadsOverlay = L.tileLayer('https://{s}.tile.openstreetmap.se/hydda/roads_and_labels/{z}/{x}/{y}.png', { - maxZoom: 18, - opacity: 0.7, - attribution: 'OpenStreetMap Sweden — Map data © OpenStreetMap contributors' - }); - var ESRITopo = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', { - attribution : attributionESRI, - noWrap: false, - detectRetina: false, - maxZoom: 19 - }); - var attributionOpenTopo = 'Map data: © OpenStreetMap, SRTM | Map style: © OpenTopoMap (CC-BY-SA)'; - var openTopo = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', { - attribution : attributionOpenTopo, - noWrap: false, - detectRetina: false, - maxZoom: 17 - }); - var attributionDark = '© Map tiles by CartoDB, under CC BY 3.0. Data by OpenStreetMap, under ODbL.'; - var dark = L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', { - attribution : attributionDark, - noWrap: false, - detectRetina: false, - maxZoom: 18 - }); - var attributionWatercolor = 'Leaflet | © Map tiles by Stamen Design, under CC BY 3.0, Data by OpenStreetMap, under CC BY SA.'; - var watercolor = L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.{ext}', { - attribution : attributionWatercolor, - noWrap: false, - detectRetina: false, - maxZoom: 18, - ext: 'jpg', - subdomains: 'abcd' - }); - var starImageUrl = generateUrl('/svg/core/actions/star-dark?color=000000'); - var markerRedImageUrl = generateUrl('/svg/core/actions/address?color=EE3333'); - var markerBlueImageUrl = generateUrl('/svg/core/actions/address?color=3333EE'); - var markerGreenImageUrl = generateUrl('/svg/core/actions/address?color=33EE33'); - var photoImageUrl = generateUrl('/svg/core/places/picture?color=000000'); - var contactImageUrl = generateUrl('/svg/core/actions/user?color=000000'); - var shareImageUrl = generateUrl('/svg/core/actions/share?color=000000'); - this.map = L.map('map', { - zoom: 2, - zoomControl: false, - maxZoom: 19, - minZoom: 2, - center: new L.LatLng(0, 0), - maxBounds: new L.LatLngBounds(new L.LatLng(-90, 720), new L.LatLng(90, -720)), - layers: [], - // right click menu - contextmenu: false, - contextmenuWidth: 160, - contextmenuItems: [{ - text: t('maps', 'Add a favorite'), - icon: starImageUrl, - callback: favoritesController.contextAddFavorite - }, { - text: t('maps', 'Place photos'), - icon: photoImageUrl, - callback: photosController.contextPlacePhotosOrFolder - }, { - text: t('maps', 'Place contact'), - icon: contactImageUrl, - callback: contactsController.contextPlaceContact - }, { - text: t('maps', 'Share this location'), - icon: shareImageUrl, - callback: geoLinkController.shareLocation - }, '-', { - text: t('maps', 'Route from here'), - icon: markerGreenImageUrl, - callback: routingController.contextRouteFrom - }, { - text: t('maps', 'Add route point'), - icon: markerBlueImageUrl, - callback: routingController.contextRoutePoint - }, { - text: t('maps', 'Route to here'), - icon: markerRedImageUrl, - callback: routingController.contextRouteTo - }] - }); - this.map.on('contextmenu', function(e) { - if ($(e.originalEvent.target).attr('id') === 'map' || $(e.originalEvent.target).hasClass('mapboxgl-map')) { - that.map.contextmenu.showAt(L.latLng(e.latlng.lat, e.latlng.lng)); - that.map.clickpopup = true; - } - }); - this.map.clickpopup = null; - this.map.leftClickLock = false; - this.map.on('click', function(e) { - if ($(e.originalEvent.target).attr('id') === 'map' || $(e.originalEvent.target).hasClass('mapboxgl-map')) { - if (!that.map.leftClickLock && that.map.clickpopup === null) { - searchController.mapLeftClick(e); - that.map.clickpopup = true; - } - else { - that.map.closePopup(); - that.map.clickpopup = null; - } - } - }); - - this.map.on('moveend', function(e) { - var bounds = that.map.getBounds(); - optionsController.saveOptionValues({ - mapBounds: bounds.getNorth() + ';' + - bounds.getSouth() + ';' + - bounds.getEast() + ';' + - bounds.getWest() - }); - }); - - this.searchMarkerLayerGroup = L.featureGroup(); - this.map.addLayer(this.searchMarkerLayerGroup); - - var locale = OC.getLocale(); - var imperial = ( - locale === 'en_US' || - locale === 'en_GB' || - locale === 'en_AU' || - locale === 'en_IE' || - locale === 'en_NZ' || - locale === 'en_CA' - ); - var metric = !imperial; - L.control.scale({metric: metric, imperial: imperial, position: 'bottomleft'}) - .addTo(this.map); - //L.control.mousePosition().addTo(this.map); - - L.control.zoom({position: 'bottomright'}).addTo(this.map); - - this.locControl = L.control.locate({ - position: 'bottomright', - drawCircle: true, - drawMarker: true, - showPopup: false, - icon: 'fa fa-map-marker-alt', - iconLoading: 'fa fa-spinner fa-spin', - strings: { - title: t('maps', 'Current location') - }, - flyTo: true, - returnToPrevBounds: true, - setView: 'untilPan', - showCompass: true, - locateOptions: {enableHighAccuracy: true, maxZoom: 15}, - onLocationError: function(e) { - optionsController.saveOptionValues({locControlEnabled: false}); - alert(e.message); - } - }).addTo(this.map); - $('.leaflet-control-locate a').click( function(e) { - optionsController.saveOptionValues({locControlEnabled: mapController.locControl._active}); - }); - - this.layersButton = L.easyButton({ - position: 'bottomright', - states: [{ - stateName: 'no-importa', - icon: ' ', - title: t('maps', 'Other maps'), - onClick: function(btn, map) { - $('.leaflet-control-layers').toggle(); - $('.easy-button-container').toggle(); - that.map.clickpopup = true; - } - }] - }); - this.layersButton.addTo(this.map); - - // tile layer selector - this.baseLayers = { - 'OpenStreetMap': osm, - 'ESRI Aerial': ESRIAerial, - 'ESRI Topo': ESRITopo, - 'OpenTopoMap': openTopo, - 'Dark': dark, - 'Watercolor': watercolor - } - this.baseOverlays = { - 'Roads and labels': roadsOverlay - } - this.controlLayers = L.control.layers( - this.baseLayers, - this.baseOverlays, - {position: 'bottomright', collapsed: false} - ).addTo(this.map); - // hide openstreetmap, ESRI Aerial and roads/labels because they are dynamically managed - this.controlLayers.removeLayer(this.baseLayers['OpenStreetMap']); - this.controlLayers.removeLayer(this.baseLayers['ESRI Aerial']); - this.controlLayers.removeLayer(this.baseOverlays['Roads and labels']); - $('.leaflet-control-layers').toggle(); - - // main layers buttons - var esriImageUrl = OC.filePath('maps', 'css/images', 'esri.jpg'); - this.satelliteButton = L.easyButton({ - position: 'bottomright', - states: [{ - stateName: 'no-importa', - icon: '', - title: t('maps', 'Satellite map'), - onClick: function(btn, map) { - that.changeTileLayer(that.defaultSatelliteLayer, true); - } - }] - }); - var osmImageUrl = OC.filePath('maps', 'css/images', 'osm.png'); - this.streetButton = L.easyButton({ - position: 'bottomright', - states: [{ - stateName: 'no-importa', - icon: '', - title: t('maps', 'Street map'), - onClick: function(btn, map) { - that.changeTileLayer(that.defaultStreetLayer, true); - } - }] - }); - }, - - changeTileLayer: function(name, save=false) { - for (var tl in this.baseLayers) { - this.map.removeLayer(this.baseLayers[tl]); - } - for (var ol in this.baseOverlays) { - this.map.removeLayer(this.baseOverlays[ol]); - } - if (!this.baseLayers.hasOwnProperty(name)) { - name = this.defaultStreetLayer; - } - this.map.addLayer(this.baseLayers[name]); - if (name === 'ESRI Aerial' || name === 'Watercolor') { - this.map.addLayer(this.baseOverlays['Roads and labels']); - } - this.layerChanged(name); - if (save) { - optionsController.saveOptionValues({tileLayer: name}); - } - }, - - layerChanged: function(name) { - if (name !== this.defaultStreetLayer) { - this.satelliteButton.remove(); - this.streetButton.addTo(this.map); - } - else { - this.streetButton.remove(); - this.satelliteButton.addTo(this.map); - } - // map maxZoom should be dynamic (if not specified at map creation) but something crashes like that - // so we set it on map creation and - // we change it on tile layer change - if (this.baseLayers[name].options.maxZoom) { - this.map.setMaxZoom(this.baseLayers[name].options.maxZoom); - } - $('.leaflet-control-layers').hide(); - $('.easy-button-container').show(); - this.map.clickpopup = null; - }, - }; - - var routingController = { - control: undefined, - map: undefined, - enabled: false, - routers: {}, - selectedRouter: 'osrmDEMO', - initRoutingControl: function(map, optionsValues) { - this.map = map; - var that = this; - - $('body').on('click', '#routing-close', function(e) { - routingController.toggleRouting(); - }); - - this.beginIcon = L.divIcon({ - iconAnchor: [12, 25], - className: 'route-waypoint route-begin-waypoint', - html: '' - }); - this.middleIcon = L.divIcon({ - iconAnchor: [12, 25], - className: 'route-waypoint route-middle-waypoint', - html: '' - }); - this.endIcon = L.divIcon({ - iconAnchor: [12, 25], - className: 'route-waypoint route-end-waypoint', - html: '' - }); - - var lang = OC.getLocale(); - // this is for all routing engines except OSRM - L.Routing.Localization[lang] = { - directions: { - N: t('maps', 'north'), - NE: t('maps', 'northeast'), - E: t('maps', 'east'), - SE: t('maps', 'southeast'), - S: t('maps', 'south'), - SW: t('maps', 'southwest'), - W: t('maps', 'west'), - NW: t('maps', 'northwest'), - SlightRight: t('maps', 'slight right'), - Right: t('maps', 'right'), - SharpRight: t('maps', 'sharp right'), - SlightLeft: t('maps', 'slight left'), - Left: t('maps', 'left'), - SharpLeft: t('maps', 'sharp left'), - Uturn: t('maps', 'Turn around') - }, - instructions: { - // instruction, postfix if the road is named - 'Head': - [t('maps', 'Head {dir}'), t('maps', ' on {road}')], - 'Continue': - [t('maps', 'Continue {dir}')], - 'TurnAround': - [t('maps', 'Turn around')], - 'WaypointReached': - [t('maps', 'Waypoint reached')], - 'Roundabout': - [t('maps', 'Take the {exitStr} exit in the roundabout'), t('maps', ' onto {road}')], - 'DestinationReached': - [t('maps', 'Destination reached')], - 'Fork': [t('maps', 'At the fork, turn {modifier}'), t('maps', ' onto {road}')], - 'Merge': [t('maps', 'Merge {modifier}'), t('maps', ' onto {road}')], - 'OnRamp': [t('maps', 'Turn {modifier} on the ramp'), t('maps', ' onto {road}')], - 'OffRamp': [t('maps', 'Take the ramp on the {modifier}'), t('maps', ' onto {road}')], - 'EndOfRoad': [t('maps', 'Turn {modifier} at the end of the road'), t('maps', ' onto {road}')], - 'Onto': t('maps', 'onto {road}') - }, - ui: { - startPlaceholder: t('maps', 'Start'), - viaPlaceholder: t('maps', 'Via {viaNumber}'), - endPlaceholder: t('maps', 'Destination') - }, - formatOrder: function(n) { - return n + 'º'; - }, - units: { - meters: t('maps', 'm'), - kilometers: t('maps', 'km'), - yards: t('maps', 'yd'), - miles: t('maps', 'mi'), - hours: t('maps', 'h'), - minutes: t('maps', 'min'), - seconds: t('maps', 's') - } - }; - this.routers.osrmDEMO = { - name: '🚗 ' + t('maps', 'By car (OSRM demo)'), - router: L.Routing.osrmv1({ - serviceUrl: 'https://router.project-osrm.org/route/v1', - //profile: 'driving', // works with demo server - profile: 'car', // works with demo server - //profile: 'bicycle', // does not work with demo server... - //profile: 'foot', // does not work with demo server... - suppressDemoServerWarning: true, - // this makes OSRM use our local translations - // otherwise it uses osrm-text-instructions which requires to import another lib - stepToText: function(e) { - } - }) - }; - this.control = L.Routing.control({ - router: this.routers.osrmDEMO.router, - position: 'topleft', - routeWhileDragging: true, - reverseWaypoints: true, - geocoder: L.Control.Geocoder.nominatim(), - language: lang, - lineOptions: { - styles: [ - {color: 'black', opacity: 0.15, weight: 9}, - {color: 'white', opacity: 0.8, weight: 6}, - {color: 'blue', opacity: 1, weight: 2} - ], - }, - pointMarkerStyle: {radius: 5, color: '#03f', fillColor: 'white', opacity: 1, fillOpacity: 0.7}, - createMarker: this.createMarker - }) - .on('routingerror', this.onRoutingError) - .on('routingstart', this.onRoutingStart) - .on('routesfound', this.onRoutingEnd); - - - //// toggle routing control - //$('body').on('click', '#navigation-routing > a', function(e) { - // that.toggleRouting(); - // optionsController.saveOptionValues({routingEnabled: that.enabled}); - //}); - // export - $('body').on('click', '.exportCurrentRoute', function(e) { - that.exportRoute(); - }); - // select router - $('body').on('change', '#router-select', function(e) { - var type = $(this).val(); - that.selectedRouter = type; - var router = that.routers[type].router; - that.setRouter(type); - optionsController.saveOptionValues({selectedRouter: type}); - that.control.route(); - }); - - // add routers from options values - var nbRoutersAdded = 0; - if (optionsValues.hasOwnProperty('osrmCarURL') && optionsValues.osrmCarURL !== '') { - this.addRouter('osrmCar', '🚗 ' + t('maps', 'By car (OSRM)'), optionsValues.osrmCarURL, null); - nbRoutersAdded++; - } - if (optionsValues.hasOwnProperty('osrmBikeURL') && optionsValues.osrmBikeURL !== '') { - this.addRouter('osrmBike', '🚲 ' + t('maps', 'By bike (OSRM)'), optionsValues.osrmBikeURL, null); - nbRoutersAdded++; - } - if (optionsValues.hasOwnProperty('osrmFootURL') && optionsValues.osrmFootURL !== '') { - this.addRouter('osrmFoot', '🚶 ' + t('maps', 'By foot (OSRM)'), optionsValues.osrmFootURL, null); - nbRoutersAdded++; - } - if (optionsValues.hasOwnProperty('mapboxAPIKEY') && optionsValues.mapboxAPIKEY !== '') { - this.addRouter('mapbox/cycling', '🚲 ' + t('maps', 'By bike (Mapbox)'), null, optionsValues.mapboxAPIKEY); - this.addRouter('mapbox/walking', '🚶 ' + t('maps', 'By foot (Mapbox)'), null, optionsValues.mapboxAPIKEY); - this.addRouter('mapbox/driving-traffic', '🚗 ' + t('maps', 'By car with traffic (Mapbox)'), null, optionsValues.mapboxAPIKEY); - this.addRouter('mapbox/driving', '🚗 ' + t('maps', 'By car without traffic (Mapbox)'), null, optionsValues.mapboxAPIKEY); - nbRoutersAdded++; - } - if ((optionsValues.hasOwnProperty('graphhopperURL') && optionsValues.graphhopperURL !== '') || - (optionsValues.hasOwnProperty('graphhopperAPIKEY') && optionsValues.graphhopperAPIKEY !== '') ){ - var apikey = undefined; - if (optionsValues.hasOwnProperty('graphhopperAPIKEY') && optionsValues.graphhopperAPIKEY !== '') { - apikey = optionsValues.graphhopperAPIKEY; - } - this.addRouter('graphhopperCar', '🚗 ' + t('maps', 'By car (GraphHopper)'), optionsValues.graphhopperURL, apikey); - this.addRouter('graphhopperBike', '🚲 ' + t('maps', 'By bike (GraphHopper)'), optionsValues.graphhopperURL, apikey); - this.addRouter('graphhopperFoot', '🚶 ' + t('maps', 'By Foot (GraphHopper)'), optionsValues.graphhopperURL, apikey); - nbRoutersAdded++; - } - if (nbRoutersAdded === 0 && optionsValues.hasOwnProperty('osrmDEMO') && optionsValues.osrmDEMO === '1') { - this.addRouter('osrmDEMO', '🚗 ' + 'By car (OSRM demo)', null, null); - } - else { - delete this.routers.osrmDEMO; - } - if (optionsValues.hasOwnProperty('selectedRouter') && optionsValues.selectedRouter !== '') { - this.selectedRouter = optionsValues.selectedRouter; - this.setRouter(optionsValues.selectedRouter); - } - else { - var fallback = null; - for (var type in this.routers) { - fallback = type; - break; - } - this.setRouter(fallback); - } - }, - - toggleRouting: function() { - var that = this; - if (this.enabled) { - $('.leaflet-routing-container').fadeOut('fast', function(e) { - that.control.remove(); - //$('#search-form').fadeIn('fast'); - $('#search-form').show(); - $('#navigation-routing').removeClass('active'); - $('#map').focus(); - that.enabled = false; - }); - } - else { - $('#search-form').fadeOut('fast', function(e) { - that.control.addTo(that.map); - //$('.leaflet-routing-container').fadeIn(); - //$('.leaflet-routing-container').hide(0, function(e) { - //}); - $('#navigation-routing').addClass('active'); - that.enabled = true; - $('.leaflet-routing-geocoder input').first().focus(); - - // add router selector - var select = ''; - - var close = ''; - - $('.leaflet-routing-container').prepend(close); - $('.leaflet-routing-geocoders').append(select); - - if (optionsController.nbRouters === 0 && OC.isUserAdmin() ) { - console.log('prepend'); - $('.leaflet-routing-container').prepend( - '

    ' + - t('maps', 'Routing is currently disabled.') + - `${t('maps', 'Add a routing service')}` + - '

    ' - ); - } - - // export route button - var exportTitle = t('maps', 'Export current route to GPX'); - $('').insertAfter('#router-select'); - $('.exportCurrentRoute').hide(); - }); - } - }, - - setRouter: function(routerType) { - if (this.routers.hasOwnProperty(routerType)) { - var router = this.routers[routerType].router; - this.control._router = router; - this.control.options.router = router; - } - }, - - // create router and make it accessible in the interface - addRouter: function(type, name, url, apikey) { - if (type === 'graphhopperBike' || type === 'graphhopperCar' || type === 'graphhopperFoot') { - var options = {}; - if (type === 'graphhopperCar') { - options.urlParameters = { - vehicle: 'car' // available ones : car, foot, bike, bike2, mtb, racingbike, motorcycle - }; - } - if (type === 'graphhopperBike') { - options.urlParameters = { - vehicle: 'bike' - }; - } - if (type === 'graphhopperFoot') { - options.urlParameters = { - vehicle: 'foot' - }; - } - if (url) { - options.serviceUrl = url; - } - this.routers[type] = { - name: name, - router: L.Routing.graphHopper(apikey, options) - }; - } - else if (type === 'osrmBike' || type === 'osrmCar' || type === 'osrmFoot') { - var options = { - serviceUrl: url, - suppressDemoServerWarning: true, - // this makes OSRM use our local translations - // otherwise it uses osrm-text-instructions which requires to import another lib - stepToText: function(e) { - } - }; - if (type === 'osrmCar') { - options.profile = 'car'; - } - else if (type === 'osrmBike') { - options.profile = 'bicycle'; - } - else if (type === 'osrmFoot') { - options.profile = 'foot'; - } - this.routers[type] = { - name: name, - router: L.Routing.osrmv1(options) - }; - } - else if (type === 'mapbox/cycling' || type === 'mapbox/driving-traffic' || type === 'mapbox/driving' || type === 'mapbox/walking') { - var options = { - profile: type - }; - this.routers[type] = { - name: name, - router: L.Routing.mapbox(apikey, options) - }; - } - else if (type === 'osrmDEMO') { - } - }, - - onRoutingError: function(e) { - var msg = e.error.target.responseText - try { - var json = $.parseJSON(e.error.target.responseText); - if (json.message) { - msg = json.message; - } - } - catch (e) { - } - OC.Notification.showTemporary(t('maps', 'Routing error:') + ' ' + msg); - routingController.onRoutingEnd(); - $('.exportCurrentRoute').hide(); - }, - - onRoutingStart: function(e) { - $('#navigation-routing').addClass('icon-loading-small'); - $('.leaflet-routing-reverse-waypoints').addClass('icon-loading-small'); - }, - - onRoutingEnd: function(e) { - $('.exportCurrentRoute').show(); - $('#navigation-routing').removeClass('icon-loading-small'); - $('.leaflet-routing-reverse-waypoints').removeClass('icon-loading-small'); - // TODO understand why routingstart is sometimes triggered after routesfound - // just in case routingstart is triggered again (weird): - setTimeout(function() { - $('#navigation-routing').removeClass('icon-loading-small'); - $('.leaflet-routing-reverse-waypoints').removeClass('icon-loading-small'); - }, 5000); - }, - - //// this has been tested with graphhopper - //setRouterVehicle: function(vehicle) { - // if (this.selectedRouter === 'graphhopper') { - // this.control.getRouter().options.urlParameters.vehicle = vehicle; - // } - // else if (this.selectedRouter === 'osrm') { - // this.control.getRouter().options.profile = vehicle.replace('bike', 'bicycle'); - // } - // this.control.route(); - //}, - - createMarker: function(i, wpt, n) { - var icon; - if (i === 0) { - icon = routingController.beginIcon; - } - else if (i === n - 1) { - icon = routingController.endIcon; - } - else { - icon = routingController.middleIcon; - } - var marker = L.marker(wpt.latLng, {icon: icon, draggable: true}); - return marker; - }, - - exportRoute: function() { - if (this.control.hasOwnProperty('_selectedRoute') - && this.control._selectedRoute.hasOwnProperty('coordinates') - && this.control._selectedRoute.coordinates.length > 0 - ) { - var latLngCoords = this.control._selectedRoute.coordinates; - var gpxRteCoords = ''; - for (var i=0; i < latLngCoords.length; i++) { - gpxRteCoords = gpxRteCoords + ' \n' + - ' \n'; - } - var name = this.control._selectedRoute.name; - var totDist = this.control._selectedRoute.summary.totalDistance; - var totTime = this.control._selectedRoute.summary.totalTime; - - $('#navigation-routing').addClass('icon-loading-small'); - var req = { - coords: gpxRteCoords, - name: name, - totDist: totDist, - totTime: totTime - }; - var url = generateUrl('/apps/maps/exportRoute'); - $.ajax({ - type: 'POST', - url: url, - data: req, - async: true - }).done(function (response) { - OC.Notification.showTemporary(t('maps', 'Route exported in {path}', {path: response})); - }).always(function (response) { - $('#navigation-routing').removeClass('icon-loading-small'); - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to export current route')); - }); - } - else { - OC.Notification.showTemporary(t('maps', 'There is no route to export')); - } - }, - - contextRouteFrom: function(e) { - if (routingController.control) { - if (!routingController.enabled) { - routingController.toggleRouting(); - } - routingController.setRouteFrom(e.latlng); - } - }, - - contextRouteTo: function(e) { - if (routingController.control) { - if (!routingController.enabled) { - routingController.toggleRouting(); - } - routingController.setRouteTo(e.latlng); - } - }, - - contextRoutePoint: function(e) { - if (routingController.control) { - if (!routingController.enabled) { - routingController.toggleRouting(); - } - routingController.addRoutePoint(e.latlng); - } - }, - - setRouteFrom: function(latlng) { - if (this.control) { - this.control.spliceWaypoints(0, 1, latlng); - } - }, - - setRouteTo: function(latlng) { - if (this.control) { - this.control.spliceWaypoints(this.control.getWaypoints().length - 1, 1, latlng); - } - }, - - setRoutePoint: function(i, latlng) { - if (this.control) { - this.control.spliceWaypoints(i, 1, latlng); - } - }, - - addRoutePoint: function(latlng) { - if (this.control) { - this.control.spliceWaypoints(this.control.getWaypoints().length - 1, 0, latlng); - } - }, - }; - - var timeFilterController = { - min: 0, - max: Date.now()/1000, - minInitialized: false, - maxInitialized: false, - valueBegin: null, - valueEnd: null, - updateFilterTimeBegin: [], - updateFilterTimeEnd: [], - onUpdateCallbackBlock: false, - onChangeCallbackBlock: false, - slider : document.getElementById('timeRangeSlider'), - sliderConnect: null, - connect: function () { - noUiSlider.create(this.slider, { - start: [20, 80], - connect: true, - behaviour: 'drag', - tooltips: [{ - to: function (x) { - return new Date(x*1000).toIsoString(); - }, - }, { - to: function (x) { - return new Date(x*1000).toIsoString(); - } - }], - range: { - 'min': 0, - 'max': 1 - } - }); - this.sliderConnect = this.slider.getElementsByClassName('noUi-connect')[0]; - this.updateSliderRange(this.min, this.max); - this.setSlider(this.min, this.max); - var that = this; - this.slider.noUiSlider.on('update', function(values, handle, unencoded, tap, positions) { - if (!that.onUpdateCallbackBlock){ - that.onUpdateCallbackBlock = true; - if (handle === 0) { - that.valueBegin = unencoded[0]; - photosController.updateTimeFilterBegin(that.valueBegin); - nonLocalizedPhotosController.updateTimeFilterBegin(that.valueBegin); - } - else { - that.valueEnd = unencoded[1]; - photosController.updateTimeFilterEnd(that.valueEnd); - nonLocalizedPhotosController.updateTimeFilterEnd(that.valueEnd); - } - favoritesController.updateFilterDisplay(); - tracksController.updateFilterDisplay(); - devicesController.updateFilterDisplay(); - - that.onUpdateCallbackBlock = false; - if (Math.round(unencoded[0]) < Math.round(that.min) || - Math.round(unencoded[1]) > Math.round(that.max) || - positions[1] - positions[0] < 10 - ) { - that.sliderConnect.classList.add('timeRangeSlider-active'); - } else { - that.sliderConnect.classList.remove('timeRangeSlider-active'); - } - } - }); - this.slider.noUiSlider.on('change', function(values, handle, unencoded, tap, positions) { - if (!that.onChangeCallbackBlock) { - that.onChangeCallbackBlock = true; - if (unencoded[0] < that.min) { - var delta = that.min-unencoded[0]; - var r = that.max-that.min; - that.updateSliderRange(that.min - 25* delta*delta/r, that.max); - } - if (unencoded[1] > that.max) { - var delta = -that.max+unencoded[1]; - var r = that.max-that.min; - that.updateSliderRange(that.min, that.max + 25*delta*delta/r); - } - if (positions[1] - positions[0] < 10) { - var m = (unencoded[0] + unencoded[1])/2; - var d = Math.max((unencoded[1] - unencoded[0])/2,1); - that.updateSliderRange(m-2.5*d, m+2.5*d); - that.setSlider(unencoded[0], unencoded[1]); - } - that.sliderConnect.classList.remove('timeRangeSlider-active'); - that.onChangeCallbackBlock = false; - } - }); - this.slider.ondblclick = function() { - that.updateSliderRangeFromController(); - that.setSliderToMaxInterval(); - }; - }, - updateSliderRange: function(min, max) { - var range = max - min; - this.slider.noUiSlider.updateOptions({ - range: { - 'min': min - range/10, - 'max': max + range/10 - }, - }); - this.min = min; - this.max = max; - }, - setSlider: function(min, max) { - this.slider.noUiSlider.set([min, max]); - }, - // when a controller's data has changed - // this changes the min/max slider reachable values (it does not set the values) - // it should be called when there are changes in controller data - // and when user wants to reset the slider to see everything - updateSliderRangeFromController: function() { - var i; - var mins = []; - var maxs = []; - var rawMins = [ - favoritesController.firstDate, - tracksController.firstDate, - photosController.photoMarkersOldest, - nonLocalizedPhotosController.nonLocalizedPhotoMarkersOldest, - devicesController.firstDate - ]; - var rawMaxs = [ - favoritesController.lastDate, - tracksController.lastDate, - photosController.photoMarkersNewest, - nonLocalizedPhotosController.nonLocalizedPhotoMarkersNewest, - devicesController.lastDate - ]; - // get rid of null values - for (i=0; i < rawMins.length; i++) { - if (rawMins[i] !== null) { - mins.push(rawMins[i]); - } - } - for (i=0; i < rawMaxs.length; i++) { - if (rawMaxs[i] !== null) { - maxs.push(rawMaxs[i]); - } - } - - var cmin = null; - var cmax = null; - // get the min of all controllers - if (mins.length > 0) { - cmin = Math.min(...mins); - } - // get the max of all controllers - if (maxs.length > 0) { - cmax = Math.max(...maxs); - } - if (cmin !== null && cmax !== null) { - //$(this.slider).fadeIn(); - this.min = cmin; - this.max = cmax; - // avoid min == max - if (cmin === cmax) { - this.min = cmin - 10; - this.max = cmax + 10; - } - this.updateSliderRange(this.min, this.max); - } - else { - //$(this.slider).fadeOut(); - } - }, - // on first data load, controllers want to set the slider values to global common max - setSliderToMaxInterval: function() { - this.setSlider(this.min, this.max); - } - }; - - - var searchController = { - map: null, - SEARCH_BAR: 1, - ROUTING_FROM: 2, - ROUTING_TO: 3, - ROUTING_POINT: 4, - currentLocalAutocompleteData: [], - initController: function(map) { - this.map = map; - var that = this; - // Search - $('#search-form').submit(function(e) { - e.preventDefault(); - that.submitSearchForm(); - }); - $('#search-submit').click(function(e) { - e.preventDefault(); - that.submitSearchForm(); - }); - $('#route-submit').click(function(e) { - routingController.toggleRouting(); - e.preventDefault(); - }); - $('#search-term').on('focus', function(e) { - $(this).select(); - that.setSearchAutocomplete(that.SEARCH_BAR); - }); - $('body').on('focus', '.leaflet-routing-geocoder input', function(e) { - var inputs = $('.leaflet-routing-geocoder input'); - var nbInputs = inputs.length; - var index = inputs.index($(this)); - if (index === 0) { - that.setSearchAutocomplete(that.ROUTING_FROM); - } - else if (index === nbInputs - 1) { - that.setSearchAutocomplete(that.ROUTING_TO); - } - else { - that.setSearchAutocomplete(that.ROUTING_POINT, index); - } - }); - $('body').on('keyup', '.leaflet-routing-geocoder input', function(e) { - // if we press enter => disable autocomplete to let nominatim results dropdown appear - if (e.key === 'Enter') { - $(this).autocomplete('close'); - $(this).autocomplete('disable'); - } - // if any other key (except arrows up/down) is pressed => enable autocomplete again - else if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') { - $('.leaflet-routing-geocoder-result').removeClass('leaflet-routing-geocoder-result-open'); - $(this).autocomplete('enable'); - $(this).autocomplete('search'); - } - }); - // replace JQuery ui autocomplete matching function - // to make 'one three' match 'one two three' for example. - // search terms in the same order - $.ui.autocomplete.filter = function (array, terms) { - let arrayOfTerms = terms.split(' '); - var term = $.map(arrayOfTerms, function (tm) { - return $.ui.autocomplete.escapeRegex(tm); - }).join('.*'); - var matcher = new RegExp(term, 'i'); - return $.grep(array, function (value) { - return matcher.test(value.label || value.value || value); - }); - }; - // search result add favorite - $('body').on('click', '.search-add-favorite', function(e) { - var lat = parseFloat($(this).attr('lat')); - var lng = parseFloat($(this).attr('lng')); - var name = $(this).parent().find('.location-header').text(); - var categoryName = favoritesController.defaultCategory; - if (favoritesController.lastUsedCategory !== null) { - categoryName = favoritesController.lastUsedCategory; - } - favoritesController.addFavoriteDB(categoryName, lat, lng, name); - that.map.closePopup(); - }); - $('body').on('click', '.search-place-contact', function(e) { - var lat = parseFloat($(this).attr('lat')); - var lng = parseFloat($(this).attr('lng')); - that.map.closePopup(); - that.map.clickpopup = null; - contactsController.openPlaceContactPopup(lat, lng); - }); - $('body').on('click', '#click-search-add-favorite', function(e) { - var lat = that.currentClickSearchLatLng.lat; - var lng = that.currentClickSearchLatLng.lng; - var name = that.currentClickAddress.attraction - || that.currentClickAddress.road - || that.currentClickAddress.city_district; - var strAddress = formatAddress(that.currentClickAddress); - var categoryName = favoritesController.defaultCategory; - if (favoritesController.lastUsedCategory !== null) { - categoryName = favoritesController.lastUsedCategory; - } - favoritesController.addFavoriteDB(categoryName, lat, lng, name, strAddress); - that.map.closePopup(); - that.map.clickpopup = null; - }); - $('body').on('click', '#click-search-place-contact', function(e) { - var lat = that.currentClickSearchLatLng.lat; - var lng = that.currentClickSearchLatLng.lng; - that.map.closePopup(); - that.map.clickpopup = null; - contactsController.openPlaceContactPopup(lat, lng); - }); - }, - - setSearchAutocomplete: function(field, routingPointIndex=null) { - var fieldElement; - if (field === this.SEARCH_BAR) { - fieldElement = $('#search-term'); - } - else if (field === this.ROUTING_FROM) { - fieldElement = $('.leaflet-routing-geocoder input').first(); - } - else if (field === this.ROUTING_TO) { - fieldElement = $('.leaflet-routing-geocoder input').last(); - } - else if (field === this.ROUTING_POINT) { - fieldElement = $('.leaflet-routing-geocoder input').eq(routingPointIndex); - } - var that = this; - var data = []; - // get favorites - var favData = favoritesController.getAutocompData(); - data.push(...favData); - // get contacts - var contactData = contactsController.getAutocompData(); - data.push(...contactData); - if (field === this.SEARCH_BAR) { - // get tracks - var trackData = tracksController.getAutocompData(); - data.push(...trackData); - } - // get devices - var devData = devicesController.getAutocompData(); - data.push(...devData); - // get photos - var photoData = photosController.getAutocompData(); - data.push(...photoData); - data.push(...this.getExtraAutocompleteData(field)); - that.currentLocalAutocompleteData = data; - fieldElement.autocomplete({ - source: data, - select: function (e, ui) { - var it = ui.item; - if (it.type === 'coordinate') { - mapController.displaySearchResult([it.result]); - } - if (it.type === 'favorite') { - that.map.setView([it.lat, it.lng], 15); - } - else if (it.type === 'contact') { - that.map.setView([it.lat, it.lng], 15); - } - else if (it.type === 'photo') { - that.map.setView([it.lat, it.lng], 15); - } - else if (it.type === 'track') { - if (tracksController.isTrackEnabled(it.id)) { - tracksController.zoomOnTrack(it.id); - tracksController.showTrackElevation(it.id); - } - else { - tracksController.toggleTrack(it.id, true, false, true); - } - } - else if (it.type === 'device') { - devicesController.zoomOnDevice(it.id); - } - else if (it.type === 'address') { - if (field === that.SEARCH_BAR) { - mapController.displaySearchResult([it.result]); - } - } - else if (it.type === 'mylocation') { - navigator.geolocation.getCurrentPosition(function (position) { - var lat = position.coords.latitude; - var lng = position.coords.longitude; - if (field === that.SEARCH_BAR) { - that.map.setView([lat, lng], 15); - } - if (field === that.SEARCH_BAR || field === that.ROUTING_TO) { - routingController.setRouteTo(L.latLng(lat, lng)); - } - else if (field === that.ROUTING_FROM) { - routingController.setRouteFrom(L.latLng(lat, lng)); - $('.leaflet-routing-geocoder input').last().focus(); - } - else if (field === that.ROUTING_POINT) { - routingController.setRoutePoint(routingPointIndex, L.latLng(lat, lng)); - $('.leaflet-routing-geocoder input').last().focus(); - } - }); - return; - } - else if (it.type === 'poi') { - that.submitSearchPOI(it.value, it.label); - return; - } - - // forward to routing controller - if (field === that.SEARCH_BAR || field === that.ROUTING_TO) { - routingController.setRouteTo(L.latLng(it.lat, it.lng)); - } - else if (field === that.ROUTING_FROM) { - routingController.setRouteFrom(L.latLng(it.lat, it.lng)); - $('.leaflet-routing-geocoder input').last().focus(); - } - else if (field === that.ROUTING_POINT) { - routingController.setRoutePoint(routingPointIndex, L.latLng(it.lat, it.lng)); - $('.leaflet-routing-geocoder input').last().focus(); - } - } - }).data('ui-autocomplete')._renderItem = function(ul, item) { - var iconClass = 'icon-link'; - var iconElem = ''; - if (item.type === 'favorite') { - iconClass = 'icon-favorite'; - } - if (item.type === 'photo') { - iconClass = 'icon-picture'; - } - else if (item.type === 'track') { - iconClass = 'icon-category-monitoring'; - } - else if (item.type === 'contact') { - iconClass = 'icon-group'; - } - else if (item.type === 'coordinate') { - iconClass = 'icon-address'; - } - else if (item.type === 'device') { - if (item.subtype === 'computer') { - iconClass = 'icon-desktop'; - } - else { - iconClass = 'icon-phone'; - } - } - else if (item.type === 'mylocation') { - iconClass = 'icon-address'; - } - else if (item.type === 'poi') { - iconClass = ''; - iconElem = ''; - } - // shorten label if needed - var label = item.label; - if (label.length > 35) { - label = label.substring(0, 35) + '…'; - } - var listItem = $('
  • ') - .data('item.autocomplete', item) - .append(' ' + label + '') - .appendTo(ul); - return listItem; - }; - }, - - submitSearchForm: function() { - var str = $('#search-term').val(); - if (str.length < 1) { - return; - } - - this.search(str, this.handleSearchResult, this); - }, - - handleSearchResult: function(results, that, isCoordinateSearch = false, searchString = '') { - if (results.length === 0) { - OC.Notification.showTemporary(t('maps', 'No search result')); - return; - } - else if (results.length === 1) { - var result = results[0]; - mapController.displaySearchResult([result]); - } - else { - var newData = []; - newData.push(...that.currentLocalAutocompleteData); - for (var i=0; i < results.length; i++) { - if (isCoordinateSearch && !results[i].maps_type) { - const label = results[i].display_name + ' (' + searchString + ')' - newData.push({ - type: 'address', - label: label, - value: label, - result: results[i], - lat: results[i].lat, - lng: results[i].lon - }); - } else if (isCoordinateSearch && results[i].maps_type) { - newData.push({ - type: results[i].maps_type, - label: results[i].display_name, - value: 'geo:' + results[i].lat + ',' + results[i].lon, - result: results[i], - lat: results[i].lat, - lng: results[i].lon - }); - } else { - newData.push({ - type: results[i].maps_type ?? 'address', - label: results[i].display_name, - value: results[i].display_name, - result: results[i], - lat: results[i].lat, - lng: results[i].lon - }); - } - } - $('#search-term').autocomplete('option', {source: newData}); - $('#search-term').autocomplete('search'); - } - }, - - submitSearchPOI: function(type, typeName) { - var that = this; - - var mapBounds = this.map.getBounds(); - var latMin = mapBounds.getSouth(); - var latMax = mapBounds.getNorth(); - var lngMin = mapBounds.getWest(); - var lngMax = mapBounds.getEast(); - this.searchPOI(type, latMin, latMax, lngMin, lngMax).then(function(results) { - if (results.length === 0) { - OC.Notification.showTemporary(t('maps', 'No {POItypeName} found', {POItypeName: typeName})); - return; - } - mapController.displaySearchResult(results); - }); - }, - - getExtraAutocompleteData: function(field) { - let data = []; - if (navigator.geolocation && window.isSecureContext) { - data.push({ - type: 'mylocation', - label: t('maps', 'My location'), - value: t('maps', 'My location') - }); - } - if (field === this.SEARCH_BAR) { - data.push({ - type: 'poi', - label: t('maps', 'Restaurant'), - value: 'restaurant' - }); - data.push({ - type: 'poi', - label: t('maps', 'Fast food'), - value: 'fast food' - }); - data.push({ - type: 'poi', - label: t('maps', 'Bar'), - value: 'bar' - }); - data.push({ - type: 'poi', - label: t('maps', 'Supermarket'), - value: 'supermarket' - }); - data.push({ - type: 'poi', - label: t('maps', 'Cafe'), - value: 'cafe' - }); - data.push({ - type: 'poi', - label: t('maps', 'Library'), - value: 'library' - }); - data.push({ - type: 'poi', - label: t('maps', 'School'), - value: 'school' - }); - data.push({ - type: 'poi', - label: t('maps', 'Sports centre'), - value: 'sports centre' - }); - data.push({ - type: 'poi', - label: t('maps', 'Gas station'), - value: 'fuel' - }); - data.push({ - type: 'poi', - label: t('maps', 'Parking'), - value: 'parking' - }); - data.push({ - type: 'poi', - label: t('maps', 'Bicycle parking'), - value: 'bicycle parking' - }); - data.push({ - type: 'poi', - label: t('maps', 'Car rental'), - value: 'car rental' - }); - data.push({ - type: 'poi', - label: t('maps', 'ATM'), - value: 'atm' - }); - data.push({ - type: 'poi', - label: t('maps', 'Pharmacy'), - value: 'pharmacy' - }); - data.push({ - type: 'poi', - label: t('maps', 'Cinema'), - value: 'cinema' - }); - data.push({ - type: 'poi', - label: t('maps', 'Public toilets'), - value: 'toilets' - }); - data.push({ - type: 'poi', - label: t('maps', 'Drinking water'), - value: 'water point' - }); - data.push({ - type: 'poi', - label: t('maps', 'Hospital'), - value: 'hospital' - }); - data.push({ - type: 'poi', - label: t('maps', 'Doctors'), - value: 'doctors' - }); - data.push({ - type: 'poi', - label: t('maps', 'Dentist'), - value: 'dentist' - }); - data.push({ - type: 'poi', - label: t('maps', 'Hotel'), - value: 'hotel' - }); - } - return data; - }, - - isGeocodeable: function(str) { - var pattern = /^\s*-?\d+\.?\d*\,\s*-?\d+\.?\d*\s*$/; - return pattern.test(str); - }, - search: function(str, handleResultsFun, ctx, limit=8) { - let coordinateRegEx = /(geo:)?(\s*|"?lat"?:)"?(?-?\d{1,2}.\d+\s*)"?,"?("?lon"?:)?"?(?-?\d{1,3}.\d+)"?(;.*)?\s*/gmi; - let regResult = coordinateRegEx.exec(str); - const isCoordinateSearch = regResult ? true : false - let coordinateSearchResults; - if (regResult) { - coordinateSearchResults = [{ - maps_type: 'coordinate', - display_name: t('maps', 'Point at {coords}', { coords: str }), - lat: regResult.groups.lat, - lon: regResult.groups.lon, - searchStr: str, - },]; - } else { - coordinateSearchResults = [] - } - var searchTerm = encodeURIComponent(str); - var apiUrl = 'https://nominatim.openstreetmap.org/search/' + searchTerm + '?format=json&addressdetails=1&extratags=1&namedetails=1&limit='+limit; - $.getJSON(apiUrl, {}, function(response) { - return response - }).then(function(results) { - handleResultsFun(coordinateSearchResults.concat(results), ctx, isCoordinateSearch, str); - }); - }, - searchPOI: function(type, latMin, latMax, lngMin, lngMax) { - var query, i; - var amenities = ['restaurant', 'fast food', 'bar', 'parking', 'hospital', 'cafe', 'school', 'bicycle parking', 'cinema', 'supermarket']; - var qs = ['atm', 'pharmacy', 'hotel', 'doctors', 'dentist', 'library', 'car rental', 'fuel', 'toilets', 'water point', 'sports centre']; - if (amenities.indexOf(type) !== -1) { - query = 'amenity='+encodeURIComponent(type); - } - else if (qs.indexOf(type) !== -1) { - query = 'q='+encodeURIComponent(type); - } - var apiUrl = 'https://nominatim.openstreetmap.org/search' + - '?format=json&addressdetails=1&extratags=1&namedetails=1&limit=100&' + - 'viewbox=' + parseFloat(lngMin) + ',' + parseFloat(latMin) + ',' + parseFloat(lngMax) + ',' + parseFloat(latMax) + '&' + - 'bounded=1&' + query; - return $.getJSON(apiUrl, {}, function(response) { - return response; - }); - }, - geocode: function(latlng) { - if (!this.isGeocodeable(latlng)) { - console.log(latlng+' is not geocodable'); - return { - then: function(f) { - f({}); - } - }; - } - var splits = latlng.split(','); - var lat = splits[0].trim(); - var lon = splits[1].trim(); - var apiUrl = 'https://nominatim.openstreetmap.org/reverse?format=json&lat=' + lat + '&lon='+ lon + '&addressdetails=1'; - return $.getJSON(apiUrl, {}, function(response) { - return response; - }); - }, - parseOsmResult: function(result) { - var add = result.address; - var road, postcode, city, state, name; - if (add.road) { - road = add.road; - if (add.house_number) { - road += ' ' + add.house_number; - } - } - if (add.postcode) { - postcode = add.postcode; - } - if (add.city || add.town || add.village) { - if (add.city) { - city = add.city; - } - else if (add.town) { - city = add.town; - } - else if (add.village) { - city = add.village; - } - if (add.state) { - state = add.state; - } - } - var details = result.namedetails; - if (details.name) { - name = details.name; - } - - var unformattedHeader; - if (name) { - unformattedHeader = name; - } - else if (road) { - unformattedHeader = road; - } - else if (city) { - unformattedHeader = city; - } - - var unformattedDesc = ''; - var needSeparator = false; - // add road to desc if it is not heading and exists (isn't heading, if 'name' is set) - if (name && road) { - unformattedDesc = road; - needSeparator = true; - } - if (postcode) { - if (needSeparator) { - unformattedDesc += ', '; - needSeparator = false; - } - unformattedDesc += postcode; - } - if (city) { - if (needSeparator) { - unformattedDesc += ', '; - needSeparator = false; - } - else if (unformattedDesc.length > 0) { - unformattedDesc += ' '; - } - unformattedDesc += city; - } - if (state && add && add.country_code == 'us') { // assume that state is only important for us addresses - if (unformattedDesc.length > 0) { - unformattedDesc += ' '; - } - unformattedDesc += '(' + state + ')'; - } - - var header = '

    ' + unformattedHeader + '

    '; - if (result.icon) { - header = '
    ' + header + '
    '; - } - var desc = '' + unformattedDesc + ''; - desc += ''; - desc += ''; - - // Add extras to parsed desc - var extras = result.extratags; - if (extras.opening_hours) { - desc += '
    '; - var oh = new opening_hours(extras.opening_hours, result); - var isCurrentlyOpen = oh.getState(); - var changeDt = oh.getNextChange(); - var currentDt = new Date(); - if (changeDt) { - var dtDiff = changeDt.getTime() - currentDt.getTime(); - dtDiff = dtDiff / 60000; // get diff in minutes - if (isCurrentlyOpen) { - desc += '' + t('maps', 'Open') + ' '; - if (dtDiff <= 60) { - desc += ', ' + t('maps', 'closes in {nb} minutes', {nb: parseInt(dtDiff)}) + ''; - } - else { - desc += ' ' + t('maps', 'until {date}', {date: changeDt.toLocaleTimeString()}) + ''; - } - } - else { - desc += '' + t('maps', 'Closed') + ' '; - desc += '' + t('maps', 'opens at {date}', {date: changeDt.toLocaleTimeString()}) + ''; - } - } - desc += '
    '; - var todayStart = currentDt; - todayStart.setHours(0); - todayStart.setMinutes(0); - todayStart.setSeconds(0); - var sevDaysEnd = new Date(todayStart); - var sevDaysMs = 7 * 24 * 60 * 60 * 1000; - sevDaysEnd.setTime(sevDaysEnd.getTime()+sevDaysMs); - var intervals = oh.getOpenIntervals(todayStart, sevDaysEnd); - desc += ''; - // intervals should be 7, if 8, then first entry is interval after 00:00:00 from last day - if (intervals.length == 8) { - // set end time of last element to end time of first element and remove it - intervals[7][1] = intervals[0][1]; - intervals.splice(0, 1); - } - for (var i=0; i'; - var startTime = from.toLocaleTimeString(); - var endTime =to.toLocaleTimeString(); - desc += ''; - desc += ''; - } - desc += '
    ' + startTime + ' - ' + endTime + '
    '; - } - if (extras.website) { - desc += ''; - } - if (extras.phone) { - desc += ''; - } - if (extras.email) { - desc += ''; - } - - return header + desc; - }, - - parseCoordinateResult: function(result) { - var header = '

    ' + result.display_name + '

    '; - if (result.icon) { - header = '
    ' + header + '
    '; - } - var desc = '' + t('maps', 'Point encoded in: ')+ escapeHTML(result.searchStr) + ''; - desc += ''; - desc += ''; - - // Add extras to parsed desc - - return header + desc; - }, - - mapLeftClick: function(e) { - var that = this; - var ll = e.latlng; - var strLatLng = ll.lat+','+ll.lng; - this.currentClickSearchLatLng = e.latlng; - - var clickPopupContent = '

    '+t('maps', 'This place')+'

    '; - clickPopupContent += '
    '; - clickPopupContent += ''; - clickPopupContent += ''; - - var popup = L.popup({ - closeOnClick: true - }) - .setLatLng(e.latlng) - .setContent(clickPopupContent) - .openOn(this.map); - $(popup._closeButton).one('click', function (e) { - that.map.clickpopup = null; - }); - - this.geocode(strLatLng).then(function(results) { - $('#click-search-popup-title').removeClass('loading'); - var address = {}; - if (results.address) { - address = results.address; - that.currentClickAddress = address; - var strAddress = formatAddress(address); - $('#clickSearchAddress').text(strAddress); - } - }); - }, - }; - - var photosController = new PhotosController(optionsController, timeFilterController); - var nonLocalizedPhotosController = new NonLocalizedPhotosController(optionsController, timeFilterController, photosController); - var contactsController = new ContactsController(optionsController, searchController); - var favoritesController = new FavoritesController(optionsController, timeFilterController); - var tracksController = new TracksController(optionsController, timeFilterController); - var devicesController = new DevicesController(optionsController, timeFilterController); - - timeFilterController.connect(); - - var helpers = { - beautifyUrl: function(url) { - return url.replace(/^(?:\w+:|)\/\/(?:www\.|)(.*[^\/])\/*$/, '$1'); - } - }; - - // TODO: remove when we have a proper fileinfo standalone library - // original scripts are loaded from - // https://github.com/nextcloud/server/blob/5bf3d1bb384da56adbf205752be8f840aac3b0c5/lib/private/legacy/template.php#L120-L122 - window.addEventListener('DOMContentLoaded', () => { - if (!window.OCA.Files) { - window.OCA.Files = {} - } - // register unused client for the sidebar to have access to its parser methods - Object.assign(window.OCA.Files, { App: { fileList: { filesClient: OC.Files.getClient() } } }, window.OCA.Files) - }) - - $(function() { - // avoid sidebar to appear when grabing map to the right - if (OC.disallowNavigationBarSlideGesture) { - OC.disallowNavigationBarSlideGesture(); - } - if (window.isSecureContext && window.navigator.registerProtocolHandler) { - window.navigator.registerProtocolHandler('geo', generateUrl('/apps/maps/openGeoLink/') + '%s', 'Nextcloud Maps'); - } - mapController.initMap(); - mapController.map.favoritesController = favoritesController; - favoritesController.initFavorites(mapController.map); - photosController.initLayer(mapController.map); - nonLocalizedPhotosController.initLayer(mapController.map); - mapController.map.photosController = photosController; - contactsController.initLayer(mapController.map); - mapController.map.contactsController = contactsController; - tracksController.initController(mapController.map); - tracksController.map.tracksController = tracksController; - devicesController.initController(mapController.map); - mapController.map.devicesController = devicesController; - searchController.initController(mapController.map); - - // once controllers have been set/initialized, we can restore option values from server - optionsController.restoreOptions(); - geoLinkController.showLinkLocation(); - - // Popup - $(document).on('click', '#opening-hours-header', function() { - $('#opening-hours-table').toggle(); - $('#opening-hours-table-toggle-expand').toggle(); - $('#opening-hours-table-toggle-collapse').toggle(); - }); - - document.onkeydown = function (e) { - e = e || window.event; - if (e.key === 'Escape') { - if (favoritesController.addFavoriteMode) { - favoritesController.leaveAddFavoriteMode(); - } - if (favoritesController.movingFavoriteId !== null) { - favoritesController.leaveMoveFavoriteMode(); - } - if (contactsController.movingBookid !== null) { - contactsController.leaveMoveContactMode(); - } - if (photosController.movingPhotoPath !== null) { - photosController.leaveMovePhotoMode(); - } - } - }; - window.onclick = function(event) { - if (event.button === 0) { - $('.leaflet-control-layers').hide(); - $('.easy-button-container').show(); - if (!event.target.matches('.app-navigation-entry-utils-menu-button button')) { - $('.app-navigation-entry-menu.open').removeClass('open'); - } - mapController.map.contextmenu.hide(); - } - }; - - $('#display-slider').click(function(e) { - optionsController.saveOptionValues({displaySlider: $(this).is(':checked')}); - if ($(this).is(':checked')) { - $('#timeRangeSlider').show(); - } - else { - $('#timeRangeSlider').hide(); - } - }); - - // click on menu buttons - $('body').on('click', - '.routingMenuButton, .favoritesMenuButton, .categoryMenuButton, .photosMenuButton, .contactsMenuButton, ' + - '.contactGroupMenuButton, ' + - '.nonLocalizedPhotosMenuButton, .devicesMenuButton, .deviceMenuButton, .tracksMenuButton, .trackMenuButton', - function(e) { - var menu = $(this).parent().parent().parent().find('> .app-navigation-entry-menu'); - var wasOpen = menu.hasClass('open'); - $('.app-navigation-entry-menu.open').removeClass('open'); - if (!wasOpen) { - menu.addClass('open'); - mapController.map.clickpopup = true; - } - }); - // right click on entry line - $('body').on('contextmenu', - '#navigation-routing > .app-navigation-entry-utils, #navigation-routing > a, ' + - '#navigation-favorites > .app-navigation-entry-utils, #navigation-favorites > a, ' + - '.category-line > a, .category-line > .app-navigation-entry-utils, ' + - '#navigation-devices > .app-navigation-entry-utils, #navigation-devices > a, ' + - '.device-line > a, .device-line > .app-navigation-entry-utils, ' + - '#navigation-tracks > .app-navigation-entry-utils, #navigation-tracks > a, ' + - '.track-line > a, .track-line > .app-navigation-entry-utils, ' + - '#navigation-nonLocalizedPhotos > .app-navigation-entry-utils, #navigation-nonLocalizedPhotos > a, ' + - '#navigation-contacts > .app-navigation-entry-utils, #navigation-contacts > a, ' + - '.contact-group-line > a, .contact-group-line > .app-navigation-entry-utils, ' + - '#navigation-photos > .app-navigation-entry-utils, #navigation-photos > a ', - function(e) { - var menu = $(this).parent().find('> .app-navigation-entry-menu'); - var wasOpen = menu.hasClass('open'); - $('.app-navigation-entry-menu.open').removeClass('open'); - if (!wasOpen) { - menu.addClass('open'); - mapController.map.clickpopup = true; - } - return false; - }); - // right click on expand icon - $('body').on('contextmenu', '#navigation-favorites, #navigation-photos, #navigation-devices, #navigation-tracks', function(e) { - var id = $(e.target).attr('id'); - if (e.target.tagName === 'LI' && (id === 'navigation-favorites' || id === 'navigation-photos' || id === 'navigation-devices' || id === 'navigation-tracks')) { - var menu = $(this).find('> .app-navigation-entry-menu'); - var wasOpen = menu.hasClass('open'); - $('.app-navigation-entry-menu.open').removeClass('open'); - if (!wasOpen) { - menu.addClass('open'); - } - return false; - } - }); - }); - -})(jQuery, OC); - diff --git a/src/tracksController.js b/src/tracksController.js deleted file mode 100644 index 3df3a4732..000000000 --- a/src/tracksController.js +++ /dev/null @@ -1,1131 +0,0 @@ -import { generateUrl } from '@nextcloud/router'; - -import { dirname, brify, metersToDistance, metersToElevation, kmphToSpeed, minPerKmToPace, formatTimeSeconds, getUrlParameter } from './utils'; - -import escapeHTML from 'escape-html'; - -function TracksController(optionsController, timeFilterController) { - this.track_MARKER_VIEW_SIZE = 30; - this.optionsController = optionsController; - this.timeFilterController = timeFilterController; - - this.mainLayer = null; - this.elevationControl = null; - this.closeElevationButton = null; - // indexed by track id - // those actually added to map, those which get toggled - this.mapTrackLayers = {}; - // layers which actually contain lines/waypoints, those which get filtered - this.trackLayers = {}; - this.trackColors = {}; - this.trackDivIcon = {}; - this.tracks = {}; - - this.firstDate = null; - this.lastDate = null; - - // used by optionsController to know if tracks loading - // was done before or after option restoration - this.trackListLoaded = false; - - this.changingColorOf = null; - this.lastZIndex = 1000; - this.sortOrder = 'name'; -} - -TracksController.prototype = { - - // set up favorites-related UI stuff - initController : function(map) { - this.map = map; - this.mainLayer = L.featureGroup(); - this.mainLayer.on('click', this.getTrackMarkerOnClickFunction()); - var that = this; - // UI events - // toggle a track - $('body').on('click', '.track-line .track-name', function(e) { - var id = $(this).parent().attr('track'); - that.toggleTrack(id, true); - }); - // zoom on track - $('body').on('click', '.zoomTrackButton', function(e) { - var id = $(this).parent().parent().parent().parent().attr('track'); - that.zoomOnTrack(id); - }); - // sort - $('body').on('click', '#sort-name-tracks', function(e) { - that.sortOrder = 'name'; - that.sortTracks(); - that.optionsController.saveOptionValues({tracksSortOrder: 'name'}); - }); - $('body').on('click', '#sort-date-tracks', function(e) { - that.sortOrder = 'date'; - that.sortTracks(); - that.optionsController.saveOptionValues({tracksSortOrder: 'date'}); - }); - // show/hide all tracks - $('body').on('click', '#select-all-tracks', function(e) { - that.showAllTracks(); - var trackList = Object.keys(that.trackLayers); - var trackStringList = trackList.join('|'); - that.optionsController.saveOptionValues({enabledTracks: trackStringList}); - that.optionsController.enabledTracks = trackList; - that.optionsController.saveOptionValues({tracksEnabled: that.map.hasLayer(that.mainLayer)}); - }); - $('body').on('click', '#select-no-tracks', function(e) { - that.hideAllTracks(); - var trackStringList = ''; - that.optionsController.saveOptionValues({enabledTracks: trackStringList}); - that.optionsController.enabledTracks = []; - that.optionsController.saveOptionValues({tracksEnabled: that.map.hasLayer(that.mainLayer)}); - }); - // toggle tracks - $('body').on('click', '#navigation-tracks > a', function(e) { - that.toggleTracks(); - that.optionsController.saveOptionValues({tracksEnabled: that.map.hasLayer(that.mainLayer)}); - that.updateMyFirstLastDates(true); - if (that.map.hasLayer(that.mainLayer) && !$('#navigation-tracks').hasClass('open')) { - that.toggleTrackList(); - that.optionsController.saveOptionValues({trackListShow: $('#navigation-tracks').hasClass('open')}); - } - }); - // expand track list - $('body').on('click', '#navigation-tracks', function(e) { - if (e.target.tagName === 'LI' && $(e.target).attr('id') === 'navigation-tracks') { - that.toggleTrackList(); - that.optionsController.saveOptionValues({trackListShow: $('#navigation-tracks').hasClass('open')}); - } - }); - $('body').on('click', '.changeTrackColor', function(e) { - var id = $(this).parent().parent().parent().parent().attr('track'); - that.askChangeTrackColor(id); - }); - // context menu event - $('body').on('click', '.contextChangeTrackColor', function(e) { - var id = parseInt($(this).parent().parent().attr('trackid')); - that.askChangeTrackColor(id); - that.map.closePopup(); - }); - $('body').on('change', '#trackcolorinput', function(e) { - that.okColor(); - }); - $('body').on('click', '.drawElevationButton', function(e) { - var id = $(this).attr('track'); - that.showTrackElevation(id); - }); - $('body').on('click', '.contextShowElevation', function(e) { - var id = parseInt($(this).parent().parent().attr('trackid')); - that.showTrackElevation(id); - that.map.closePopup(); - }); - $('body').on('click', '.showTrackElevation', function(e) { - var id = $(this).parent().parent().parent().parent().attr('track'); - that.showTrackElevation(id); - }); - // close elevation char button - this.closeElevationButton = L.easyButton({ - position: 'bottomleft', - states: [{ - stateName: 'no-importa', - icon: 'fa-times', - title: t('maps', 'Close elevation chart'), - onClick: function(btn, map) { - that.clearElevationControl(); - } - }] - }); - }, - - // expand or fold track list in sidebar - toggleTrackList: function() { - $('#navigation-tracks').toggleClass('open'); - }, - - // toggle tracks general layer on map and save state in user options - toggleTracks: function() { - if (this.map.hasLayer(this.mainLayer)) { - this.map.removeLayer(this.mainLayer); - $('#navigation-tracks').removeClass('active'); - $('#map').focus(); - } - else { - if (!this.trackListLoaded) { - this.getTracks(); - } - this.map.addLayer(this.mainLayer); - $('#navigation-tracks').addClass('active'); - } - }, - - // add/remove markers from layers considering current filter values - updateFilterDisplay: function() { - var startFilter = this.timeFilterController.valueBegin; - var endFilter = this.timeFilterController.valueEnd; - - var id, layer, i, date; - for (id in this.trackLayers) { - date = this.trackLayers[id].date; - // if it was not filtered, check if it should be removed - if (this.mapTrackLayers[id].hasLayer(this.trackLayers[id])) { - if (date && (date < startFilter || date > endFilter)) { - this.mapTrackLayers[id].removeLayer(this.trackLayers[id]); - } - } - // if it was filtered, check if it should be added - else { - if (date && (date >= startFilter && date <= endFilter)) { - this.mapTrackLayers[id].addLayer(this.trackLayers[id]); - } - } - } - }, - - updateMyFirstLastDates: function(updateSlider=false) { - if (!this.map.hasLayer(this.mainLayer)) { - this.firstDate = null; - this.lastDate = null; - } - else { - var id; - - // we update dates only if nothing is currently loading - for (id in this.mapTrackLayers) { - if (this.mainLayer.hasLayer(this.mapTrackLayers[id]) && !this.trackLayers[id].loaded) { - return; - } - } - - var initMinDate = Math.floor(Date.now() / 1000) + 1000000 - var initMaxDate = 0; - - var first = initMinDate; - var last = initMaxDate; - for (id in this.mapTrackLayers) { - if (this.mainLayer.hasLayer(this.mapTrackLayers[id]) && this.trackLayers[id].loaded && this.trackLayers[id].date) { - if (this.trackLayers[id].date < first) { - first = this.trackLayers[id].date; - } - if (this.trackLayers[id].date > last) { - last = this.trackLayers[id].date; - } - } - } - if (first !== initMinDate - && last !== initMaxDate) { - this.firstDate = first; - this.lastDate = last; - } - else { - this.firstDate = null; - this.lastDate = null; - } - } - if (updateSlider) { - this.timeFilterController.updateSliderRangeFromController(); - this.timeFilterController.setSliderToMaxInterval(); - } - }, - - saveEnabledTracks: function(additionalIds=[]) { - var trackList = []; - var layer; - for (var id in this.mapTrackLayers) { - layer = this.mapTrackLayers[id]; - if (this.mainLayer.hasLayer(layer)) { - trackList.push(id); - } - } - for (var i=0; i < additionalIds.length; i++) { - trackList.push(additionalIds[i]); - } - var trackStringList = trackList.join('|'); - this.optionsController.saveOptionValues({enabledTracks: trackStringList}); - // this is used when tracks are loaded again - this.optionsController.enabledTracks = trackList; - }, - - showAllTracks: function() { - if (!this.map.hasLayer(this.mainLayer)) { - this.toggleTracks(); - } - for (var id in this.mapTrackLayers) { - if (!this.mainLayer.hasLayer(this.mapTrackLayers[id])) { - this.toggleTrack(id); - } - } - this.updateMyFirstLastDates(true); - }, - - hideAllTracks: function() { - for (var id in this.mapTrackLayers) { - if (this.mainLayer.hasLayer(this.mapTrackLayers[id])) { - this.toggleTrack(id); - } - } - this.updateMyFirstLastDates(true); - }, - - removeTrackMap: function(id) { - this.mainLayer.removeLayer(this.mapTrackLayers[id]); - this.mapTrackLayers[id].removeLayer(this.trackLayers[id]); - delete this.mapTrackLayers[id]; - delete this.trackLayers[id]; - delete this.trackColors[id]; - delete this.trackDivIcon[id]; - delete this.tracks[id]; - - $('style[track='+id+']').remove(); - - $('#track-list > li[track="'+id+'"]').fadeOut('slow', function() { - $(this).remove(); - }); - }, - - addTrackMap: function(track, show=false, pageLoad=false, zoom=false) { - // color - var color = track.color || (OCA.Theming ? OCA.Theming.color : '#0082c9'); - this.trackColors[track.id] = color; - this.trackDivIcon[track.id] = L.divIcon({ - iconAnchor: [12, 25], - className: 'trackWaypoint trackWaypoint-'+track.id, - html: '' - }); - this.tracks[track.id] = track; - this.tracks[track.id].metadata = track.metadata === '' ? {} : $.parseJSON(track.metadata); - this.tracks[track.id].icon = L.divIcon(L.extend({ - html: '
    ​', - className: 'leaflet-marker-track track-marker track-marker-'+track.id - }, null, { - iconSize: [this.track_MARKER_VIEW_SIZE, this.track_MARKER_VIEW_SIZE], - iconAnchor: [this.track_MARKER_VIEW_SIZE / 2, this.track_MARKER_VIEW_SIZE] - })); - - this.mapTrackLayers[track.id] = L.featureGroup(); - this.trackLayers[track.id] = L.featureGroup(); - this.trackLayers[track.id].loaded = false; - this.mapTrackLayers[track.id].addLayer(this.trackLayers[track.id]); - - this.addMenuEntry(track, color); - - // enable if in saved options or if it should be enabled for another reason - if (show || this.optionsController.enabledTracks.indexOf(track.id) !== -1) { - this.toggleTrack(track.id, false, pageLoad, zoom); - } - }, - - addMenuEntry: function(track, color) { - var name = track.file_name; - var path = track.file_path; - - // side menu entry - var imgurl = generateUrl('/svg/core/categories/monitoring?color='+color.replace('#', '')); - var li = '
  • ' + - ' '+name+'' + - '
    ' + - '
      ' + - '
    • ' + - ' ' + - '
    • ' + - '
    ' + - '
    ' + - '
    ' + - ' ' + - '
    ' + - '
  • '; - - var beforeThis = null; - var that = this; - if (this.sortOrder === 'name') { - var nameLower = name.toLowerCase(); - var trackName; - $('#track-list > li').each(function() { - trackName = $(this).attr('name'); - if (nameLower.localeCompare(trackName) < 0) { - beforeThis = $(this); - return false; - } - }); - } - else if (this.sortOrder === 'date') { - var mtime = parseInt(track.mtime); - var tmpMtime; - $('#track-list > li').each(function() { - tmpMtime = parseInt(that.tracks[$(this).attr('track')].mtime); - if (mtime > tmpMtime) { - beforeThis = $(this); - return false; - } - }); - } - if (beforeThis !== null) { - $(li).insertBefore(beforeThis); - } - else { - $('#track-list').append(li); - } - }, - - // wipe track list, then add items again - // take care of enabling selected tracks - sortTracks: function() { - $('#track-list').html(''); - var color; - for (var id in this.tracks) { - color = this.trackColors[id]; - this.addMenuEntry(this.tracks[id], color); - // select if necessary - var mapTrackLayer = this.mapTrackLayers[id]; - var trackLine = $('#track-list > li[track="' + id + '"]'); - var trackName = trackLine.find('.track-name'); - if (this.mainLayer.hasLayer(mapTrackLayer)) { - trackName.addClass('active'); - } - } - }, - - getTracks: function() { - var that = this; - $('#navigation-tracks').addClass('icon-loading-small'); - var req = {}; - var url = generateUrl('/apps/maps/tracks'); - $.ajax({ - type: 'GET', - url: url, - data: req, - async: true - }).done(function (response) { - var i, track, show; - var getFound = false; - for (i=0; i < response.length; i++) { - track = response[i]; - // show'n'zoom track if it was asked with a GET parameter - show = (getUrlParameter('track') === track.file_path); - that.addTrackMap(track, show, true, show); - if (show) { - getFound = true; - } - } - // if the asked track wasn't already in track list, load it and zoom! - if (!getFound && getUrlParameter('track')) { - OC.Notification.showTemporary(t('maps', 'Track {n} was not found', {n: getUrlParameter('track')})); - } - that.trackListLoaded = true; - }).always(function (response) { - $('#navigation-tracks').removeClass('icon-loading-small'); - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to load tracks')); - }); - }, - - isTrackEnabled: function(id) { - var mapTrackLayer = this.mapTrackLayers[id]; - return (this.mainLayer.hasLayer(mapTrackLayer)); - }, - - toggleTrack: function(id, save=false, pageLoad=false, zoom=false) { - var trackLayer = this.trackLayers[id]; - if (!trackLayer.loaded) { - this.loadTrack(id, save, pageLoad, zoom); - } - this.toggleMapTrackLayer(id, zoom); - if (save) { - this.saveEnabledTracks(); - this.updateMyFirstLastDates(true); - } - }, - - toggleMapTrackLayer: function(id, zoom=false) { - var mapTrackLayer = this.mapTrackLayers[id]; - var trackLine = $('#track-list > li[track="'+id+'"]'); - var trackName = trackLine.find('.track-name'); - // hide track - if (this.mainLayer.hasLayer(mapTrackLayer)) { - this.mainLayer.removeLayer(mapTrackLayer); - trackName.removeClass('active'); - $('#map').focus(); - } - // show track - else { - this.mainLayer.addLayer(mapTrackLayer); - // markers are hard to bring to front - var that = this; - this.trackLayers[id].eachLayer(function(l) { - if (l instanceof L.Marker){ - l.setZIndexOffset(that.lastZIndex++); - } - }); - trackName.addClass('active'); - if (zoom) { - this.zoomOnTrack(id); - this.showTrackElevation(id); - } - } - }, - - loadTrack: function(id, save=false, pageLoad=false, zoom=false) { - var that = this; - $('#track-list > li[track="'+id+'"]').addClass('icon-loading-small'); - var req = {}; - var url = generateUrl('/apps/maps/tracks/'+id); - $.ajax({ - type: 'GET', - url: url, - data: req, - async: true - }).done(function (response) { - that.processGpx(id, response.content, response.metadata); - that.trackLayers[id].loaded = true; - that.updateMyFirstLastDates(pageLoad); - if (zoom) { - that.zoomOnTrack(id); - that.showTrackElevation(id); - } - }).always(function (response) { - $('#track-list > li[track="'+id+'"]').removeClass('icon-loading-small'); - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to load track content')); - }); - }, - - processGpx: function(id, gpx, metadata) { - var that = this; - var color; - var coloredTooltipClass; - var rgbc; - - this.tracks[id].metadata = $.parseJSON(metadata); - - var gpxp, gpxx; - try { - gpxp = $.parseXML(gpx.replace(/version="1.1"/, 'version="1.0"')); - gpxx = $(gpxp).find('gpx'); - } - catch (err) { - OC.Notification.showTemporary(t('maps', 'Failed to parse track {fname}', {fname: this.tracks[id].file_name})); - this.removeTrackMap(id); - return; - } - - // count the number of lines and point - var nbPoints = gpxx.find('>wpt').length; - var nbLines = gpxx.find('>trk').length + gpxx.find('>rte').length; - - color = this.trackColors[id]; - this.setTrackCss(id, color); - coloredTooltipClass = 'tooltip' + id; - - var weight = 4; - - var fileDesc = gpxx.find('>metadata>desc').text(); - - var minTrackDate = Math.floor(Date.now() / 1000) + 1000000; - var date; - - var popupText; - - var wpts = gpxx.find('wpt'); - wpts.each(function() { - date = that.addWaypoint(id, $(this), coloredTooltipClass); - minTrackDate = (date < minTrackDate) ? date : minTrackDate; - }); - - var trks = gpxx.find('trk'); - var name, cmt, desc, linkText, linkUrl, popupText, date; - trks.each(function() { - name = $(this).find('>name').text(); - cmt = $(this).find('>cmt').text(); - desc = $(this).find('>desc').text(); - linkText = $(this).find('link text').text(); - linkUrl = $(this).find('link').attr('href'); - popupText = that.getLinePopupText(id, name, cmt, desc, linkText, linkUrl); - $(this).find('trkseg').each(function() { - date = that.addLine(id, $(this).find('trkpt'), weight, color, name, popupText, coloredTooltipClass); - minTrackDate = (date < minTrackDate) ? date : minTrackDate; - }); - }); - - var rtes = gpxx.find('rte'); - rtes.each(function() { - name = $(this).find('>name').text(); - cmt = $(this).find('>cmt').text(); - desc = $(this).find('>desc').text(); - linkText = $(this).find('link text').text(); - linkUrl = $(this).find('link').attr('href'); - popupText = that.getLinePopupText(id, name, cmt, desc, linkText, linkUrl); - date = that.addLine(id, $(this).find('rtept'), weight, color, name, popupText, coloredTooltipClass); - minTrackDate = (date < minTrackDate) ? date : minTrackDate; - }); - - this.trackLayers[id].date = minTrackDate; - - // manage track main icon - // find first point (marker location) - // then bind tooltip and popup - var firstWpt = null; - if (wpts.length > 0) { - var lat = wpts.first().attr('lat'); - var lon = wpts.first().attr('lon'); - firstWpt = L.latLng(lat, lon); - } - var firstLinePoint = null; - if (trks.length > 0) { - var trkpt = trks.first().find('trkpt').first(); - if (trkpt) { - var lat = trkpt.attr('lat'); - var lon = trkpt.attr('lon'); - firstLinePoint = L.latLng(lat, lon); - } - } - if (firstLinePoint === null && rtes.length > 0) { - var rtept = rtes.first().find('rtept').first(); - if (rtept) { - var lat = rtept.attr('lat'); - var lon = rtept.attr('lon'); - firstLinePoint = L.latLng(lat, lon); - } - } - var firstPoint = firstLinePoint || firstWpt; - - if (firstPoint) { - this.tracks[id].marker = L.marker([firstPoint.lat, firstPoint.lng], { - icon: this.tracks[id].icon - }); - this.tracks[id].marker.trackid = id; - - this.tracks[id].marker.on('contextmenu', this.trackMouseRightClick); - - // tooltip - var tooltipText = this.tracks[id].file_name; - this.tracks[id].marker.bindTooltip(tooltipText, { - sticky: false, - className: coloredTooltipClass + ' leaflet-marker-track-tooltip', - direction: 'top', - offset: L.point(0, -16) - }); - // popup - popupText = that.getLinePopupText(id, '', '', '', '', ''); - this.tracks[id].popupText = popupText; - this.trackLayers[id].addLayer(this.tracks[id].marker); - } - }, - - getTrackMarkerOnClickFunction: function() { - var _app = this; - return function(evt) { - var marker = evt.layer; - var popupContent = _app.tracks[marker.trackid].popupText; - marker.unbindPopup(); - _app.map.clickpopup = true; - - var popup = L.popup({ - autoPan: true, - autoClose: true, - closeOnClick: true, - className: 'trackPopup' - }) - .setLatLng(marker.getLatLng()) - .setContent(popupContent) - .openOn(_app.map); - $(popup._closeButton).one('click', function (e) { - _app.map.clickpopup = null; - }); - }; - }, - - addWaypoint: function(id, elem, coloredTooltipClass) { - var lat = elem.attr('lat'); - var lon = elem.attr('lon'); - var name = elem.find('name').text(); - var cmt = elem.find('cmt').text(); - var desc = elem.find('desc').text(); - var sym = elem.find('sym').text(); - var ele = elem.find('ele').text(); - var time = elem.find('time').text(); - var linkText = elem.find('link text').text(); - var linkUrl = elem.find('link').attr('href'); - - var date = null; - if (time) { - date = Date.parse(time)/1000; - } - - var mm = L.marker( - [lat, lon], - { - icon: this.trackDivIcon[id] - } - ); - mm.bindTooltip(brify(name, 20), { - className: coloredTooltipClass + ' leaflet-marker-track-tooltip', - direction: 'top', - offset: L.point(0, -15) - }); - mm.trackid = id; - mm.on('contextmenu', this.trackMouseRightClick); - - var popupText = this.getWaypointPopupText(id, name, lat, lon, cmt, desc, ele, linkText, linkUrl, sym); - mm.bindPopup(popupText); - this.trackLayers[id].addLayer(mm); - return date; - }, - - getWaypointPopupText: function(id, name, lat, lon, cmt, desc, ele, linkText, linkUrl, sym) { - var popupText = '

    ' + escapeHTML(name) + '


    ' + - t('maps', 'File')+ ' : ' + escapeHTML(this.tracks[id].file_name) + '
    '; - if (linkText && linkUrl) { - popupText = popupText + - t('maps', 'Link') + ' : '+ escapeHTML(linkText) + '
    '; - } - if (ele !== '') { - popupText = popupText + t('maps', 'Elevation')+ ' : ' + - escapeHTML(ele) + 'm
    '; - } - popupText = popupText + t('maps', 'Latitude') + ' : '+ parseFloat(lat) + '
    ' + - t('maps', 'Longitude') + ' : '+ parseFloat(lon) + '
    '; - if (cmt !== '') { - popupText = popupText + - t('maps', 'Comment') + ' : '+ escapeHTML(cmt) + '
    '; - } - if (desc !== '') { - popupText = popupText + - t('maps', 'Description') + ' : '+ escapeHTML(desc) + '
    '; - } - if (sym !== '') { - popupText = popupText + - t('maps', 'Symbol name') + ' : '+ sym; - } - return popupText; - }, - - getLinePopupText: function(id, name, cmt, desc, linkText, linkUrl) { - var meta = this.tracks[id].metadata; - var url = generateUrl('/apps/files/ajax/download.php'); - var dir = encodeURIComponent(dirname(this.tracks[id].file_path)) || '/'; - var file = encodeURIComponent(this.tracks[id].file_name); - var dl_url = '"' + url + '?dir=' + dir + '&files=' + file + '"'; - var popupTxt = '

    ' + - t('maps','File') + ' : ' + - ' ' + this.tracks[id].file_name + ' '; - popupTxt = popupTxt + ''; - popupTxt = popupTxt + '

    '; - // link url and text - if (meta.lnktxt) { - var lt = meta.lnktxt; - if (!lt) { - lt = t('maps', 'metadata link'); - } - popupTxt = popupTxt + '' + lt + ''; - } - if (meta.trnl && meta.trnl.length > 0) { - popupTxt = popupTxt + '
      '; - for (var z=0; z < meta.trnl.length; z++) { - var trname = meta.trnl[z]; - if (trname === '') { - trname = t('maps', 'no name'); - } - popupTxt = popupTxt + '
    • ' + escapeHTML(trname) + '
    • '; - } - popupTxt = popupTxt + '
    '; - } - - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - if (meta.distance) { - popupTxt = popupTxt + ''; - } - else{ - popupTxt = popupTxt + ''; - } - popupTxt = popupTxt + ''; - - popupTxt = popupTxt + ''; - popupTxt = popupTxt + ''; - popupTxt = popupTxt + ''; - popupTxt = popupTxt + ''; - popupTxt = popupTxt + ''; - popupTxt = popupTxt + ''; - - var dbs = t('maps', 'no date'); - var dbes = dbs; - try{ - if (meta.begin !== '' && meta.begin !== -1) { - var db = new Date(meta.begin * 1000); - dbs = db.toIsoString(); - } - if (meta.end !== '' && meta.end !== -1) { - var dbe = new Date(meta.end * 1000); - dbes = dbe.toIsoString(); - } - } - catch(err) { - } - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt +''; - popupTxt = popupTxt + ''; - - popupTxt = popupTxt + ''; - popupTxt = popupTxt + ''; - - popupTxt = popupTxt + ''; - - popupTxt = popupTxt + ''; - popupTxt = popupTxt + '
    ' + - t('maps','Distance') + '' + metersToDistance(meta.distance) + '???
    ' + - t('maps','Duration') + ' ' + formatTimeSeconds(meta.duration || 0) + '
    ' + - t('maps','Moving time') + ' ' + formatTimeSeconds(meta.movtime || 0) + '
    ' + - t('maps','Pause time') + ' ' + formatTimeSeconds(meta.stptime || 0) + '
    ' + - t('maps', 'Begin') + ' ' + dbs + '
    ' + - t('maps','End') + ' ' + dbes + '
    ' + - t('maps', 'Cumulative elevation gain') + ' ' + - (meta.posel ? metersToElevation(meta.posel) : 'NA') + '
    ' + - t('maps','Cumulative elevation loss') + ' ' + - (meta.negel ? metersToElevation(meta.negel) : 'NA') + '
    ' + - t('maps','Minimum elevation') + ' ' + - ((meta.minel && meta.minel !== -1000) ? metersToElevation(meta.minel) : 'NA') + '
    ' + - t('maps','Maximum elevation') + ' ' + - ((meta.maxel && meta.maxel !== -1000) ? metersToElevation(meta.maxel) : 'NA') + '
    ' + - t('maps','Maximum speed') + ' '; - if (meta.maxspd) { - popupTxt = popupTxt + kmphToSpeed(meta.maxspd); - } - else{ - popupTxt = popupTxt + 'NA'; - } - popupTxt = popupTxt + '
    ' + - t('maps','Average speed') + ' '; - if (meta.avgspd) { - popupTxt = popupTxt + kmphToSpeed(meta.avgspd); - } - else{ - popupTxt = popupTxt + 'NA'; - } - popupTxt = popupTxt + '
    ' + - t('maps','Moving average speed') + ' '; - if (meta.movavgspd) { - popupTxt = popupTxt + kmphToSpeed(meta.movavgspd); - } - else{ - popupTxt = popupTxt + 'NA'; - } - popupTxt = popupTxt + '
    ' + - t('maps','Moving average pace') + ' '; - if (meta.movpace) { - popupTxt = popupTxt + minPerKmToPace(meta.movpace); - } - else{ - popupTxt = popupTxt + 'NA'; - } - popupTxt = popupTxt + '
    '; - - return popupTxt; - }, - - addLine: function(id, points, weight, color, name, popupText, coloredTooltipClass) { - var lat, lon, ele, time; - var that = this; - var latlngs = []; - // get first date - var date = null; - if (points.length > 0) { - var p = points.first(); - time = p.find('time').text(); - if (time) { - date = Date.parse(time)/1000; - } - } - // build line - points.each(function() { - lat = $(this).attr('lat'); - lon = $(this).attr('lon'); - if (!lat || !lon) { - return; - } - ele = $(this).find('ele').text(); - time = $(this).find('time').text(); - if (ele !== '') { - latlngs.push([lat, lon, ele]); - } - else{ - latlngs.push([lat, lon]); - } - }); - var l = L.polyline(latlngs, { - weight: weight, - opacity : 1, - className: 'poly'+id, - }); - l.line = true; - l.bindPopup( - popupText, - { - autoPan: true, - autoClose: true, - closeOnClick: true, - className: 'trackPopup' - } - ); - var tooltipText = this.tracks[id].file_name; - if (this.tracks[id].file_name !== name) { - tooltipText = tooltipText + '
    ' + escapeHTML(name); - } - l.bindTooltip(tooltipText, { - sticky: true, - className: coloredTooltipClass + ' leaflet-marker-track-tooltip', - direction: 'top' - }); - // border layout - var bl; - bl = L.polyline(latlngs, - {opacity:1, weight: parseInt(weight * 1.6), color: 'black'}); - bl.bindPopup( - popupText, - { - autoPan: true, - autoClose: true, - closeOnClick: true, - className: 'trackPopup' - } - ); - this.trackLayers[id].addLayer(bl); - this.trackLayers[id].addLayer(l); - bl.on('mouseover', function() { - that.trackLayers[id].bringToFront(); - }); - bl.on('mouseout', function() { - }); - bl.bindTooltip(tooltipText, { - sticky: true, - className: coloredTooltipClass + ' leaflet-marker-track-tooltip', - direction: 'top' - }); - - l.on('mouseover', function() { - that.trackLayers[id].bringToFront(); - }); - l.on('mouseout', function() { - }); - l.trackid = id; - l.on('contextmenu', this.trackMouseRightClick); - bl.trackid = id; - bl.on('contextmenu', this.trackMouseRightClick); - - return date; - }, - - trackMouseRightClick: function(e) { - var that = this; - var id = e.target.trackid; - - var yOffset = 5; - if (e.target instanceof L.Marker) { - yOffset = -10; - } - this._map.clickpopup = true; - var popupContent = this._map.tracksController.getTrackContextPopupContent(id); - var popup = L.popup({ - closeOnClick: true, - className: 'popovermenu open popupMarker', - offset: L.point(-5, yOffset) - }) - .setLatLng(e.latlng) - .setContent(popupContent) - .openOn(this._map); - $(popup._closeButton).one('click', function (e) { - that._map.clickpopup = null; - }); - }, - - getTrackContextPopupContent: function(id) { - var colorText = t('maps', 'Change color'); - var elevationText = t('maps', 'Show elevation'); - var res = - '
      ' + - '
    • ' + - ' ' + - '
    • ' + - '
    • ' + - ' ' + - '
    • ' + - '
    '; - return res; - }, - - zoomOnTrack: function(id) { - if (this.mainLayer.hasLayer(this.mapTrackLayers[id])) { - var bounds = this.mapTrackLayers[id].getBounds(); - if (bounds && bounds.constructor === Object && Object.keys(bounds).length !== 0) { - this.map.fitBounds(this.mapTrackLayers[id].getBounds(), {padding: [30, 30], maxZoom: 17}); - this.mapTrackLayers[id].bringToFront(); - // markers are hard to bring to front - var that = this; - this.trackLayers[id].eachLayer(function(l) { - if (l instanceof L.Marker){ - l.setZIndexOffset(that.lastZIndex++); - } - }); - } - } - }, - - askChangeTrackColor: function(id) { - this.changingColorOf = id; - var currentColor = this.trackColors[id]; - $('#trackcolorinput').val(currentColor); - $('#trackcolorinput').click(); - }, - - okColor: function() { - var color = $('#trackcolorinput').val(); - var id = this.changingColorOf; - this.trackColors[id] = color; - this.changeTrackColor(id, color); - }, - - changeTrackColor: function(id, color) { - var that = this; - $('#track-list > li[track="'+id+'"]').addClass('icon-loading-small'); - var req = { - color: color - }; - var url = generateUrl('/apps/maps/tracks/'+id); - $.ajax({ - type: 'PUT', - url: url, - data: req, - async: true - }).done(function (response) { - var imgurl = generateUrl('/svg/core/categories/monitoring?color='+color.replace('#', '')); - $('#track-list > li[track='+id+'] .track-name').attr('style', 'background-image: url('+imgurl+')'); - - that.setTrackCss(id, color); - }).always(function (response) { - $('#track-list > li[track="'+id+'"]').removeClass('icon-loading-small'); - }).fail(function() { - OC.Notification.showTemporary(t('maps', 'Failed to change track color')); - }); - }, - - setTrackCss: function(id, color) { - $('style[track='+id+']').remove(); - - var imgurl = generateUrl('/svg/core/categories/monitoring?color='+color.replace('#', '')); - $('').appendTo('body'); - }, - - showTrackElevation: function(id) { - this.clearElevationControl(); - this.zoomOnTrack(id); - var el = L.control.elevation({ - position: 'bottomleft', - height: 100, - width: 700, - margins: { - top: 10, - right: 40, - bottom: 23, - left: 60 - }, - //collapsed: true, - theme: 'steelblue-theme' - }); - el.addTo(this.map); - - var layers = this.trackLayers[id].getLayers(); - var data; - for (var i=0; i < layers.length; i++) { - if (layers[i].line) { - data = layers[i].toGeoJSON(); - el.addData(data, layers[i]); - } - } - this.closeElevationButton.addTo(this.map); - - this.elevationControl = el; - }, - - clearElevationControl: function() { - if (this.elevationControl !== null) { - this.elevationControl.clear(); - this.elevationControl.remove(); - this.elevationControl = null; - this.closeElevationButton.remove(); - } - }, - - getAutocompData: function() { - var that = this; - var track, trackid; - var data = []; - if (this.map.hasLayer(this.mainLayer)) { - for (trackid in this.tracks) { - // no need for lat/lng here, track will just be enabled or zoomed - track = this.tracks[trackid]; - data.push({ - type: 'track', - id: trackid, - label: track.file_name, - value: track.file_name - }); - } - } - return data; - }, - -} - -export default TracksController; diff --git a/templates/content/index.php b/templates/content/index.php deleted file mode 100644 index bb89243ab..000000000 --- a/templates/content/index.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @author Gary Kim - * - * @license GNU AGPL version 3 or any later version - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -script('viewer', 'viewer'); -style('maps', 'style'); -?> - -
    -
    -
    - - id="geourl"> - diff --git a/templates/index.php b/templates/index.php deleted file mode 100644 index 347202caf..000000000 --- a/templates/index.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * @copyright Copyright (c) 2020, Gary Kim - * - * @license GNU AGPL version 3 or any later version - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ -script('maps', 'script'); -?> - -
    -
    - inc('navigation/index')); ?> - inc('settings/index')); ?> -
    - -
    - inc('content/index')); ?> -
    -
    - diff --git a/templates/navigation/index.php b/templates/navigation/index.php deleted file mode 100644 index 78216045c..000000000 --- a/templates/navigation/index.php +++ /dev/null @@ -1,199 +0,0 @@ - - -