/* * Leaflet Location Picker v0.3.4 - 2022-11-18 * * Copyright 2022 Stefano Cudini * stefano.cudini@gmail.com * https://opengeo.tech/ * * Licensed under the MIT license. * * Demo: * https://opengeo.tech/maps/leaflet-locationpicker/ * * Source: * git@github.com:stefanocudini/leaflet-locationpicker.git * */ (function (factory) { if(typeof define === 'function' && define.amd) { //AMD define(['jquery','leaflet'], factory); } else if(typeof module !== 'undefined') { // Node/CommonJS module.exports = factory(require('jquery','leaflet')); } else { // Browser globals if(typeof window.jQuery === 'undefined') throw 'jQuery must be loaded first'; if(typeof window.L === 'undefined') throw 'Leaflet must be loaded first'; factory(window.jQuery, window.L); } })(function(jQuery, L) { var $ = jQuery; $.fn.leafletLocationPicker = function(opts, onChangeLocation) { var http = window.location.protocol; var baseClassName = 'leaflet-locpicker', baseLayers = { 'OSM': http + '//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', // 'SAT': http + '//otile1.mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.png' // AK 2021-04-22: invalid URL!! //TODO add more free base layers }; var optsMap = { zoom: 0, center: L.latLng([40,0]), zoomControl: false, attributionControl: false }; if($.isPlainObject(opts) && $.isPlainObject(opts.map)) optsMap = $.extend(optsMap, opts.map); var defaults = { alwaysOpen: false, className: baseClassName, location: optsMap.center, locationFormat: '{lat}{sep}{lng}', locationMarker: true, locationDigits: 6, locationSep: ',', position: 'topright', layer: 'OSM', height: 140, width: 200, event: 'click', cursorSize: '30px', readOnly: false, map: optsMap, onChangeLocation: $.noop, mapContainer: "" }; if($.isPlainObject(opts)) opts = $.extend(defaults, opts); else if($.isFunction(opts)) opts = $.extend(defaults, { onChangeLocation: opts }); else opts = defaults; if($.isFunction(onChangeLocation)) opts = $.extend(defaults, { onChangeLocation: onChangeLocation }); function roundLocation(loc) { return loc ? L.latLng( parseFloat(loc.lat).toFixed(opts.locationDigits), parseFloat(loc.lng).toFixed(opts.locationDigits) ) : loc; } function parseLocation(loc) { var retLoc = loc; switch($.type(loc)) { case 'string': var ll = loc.split(opts.locationSep); if(ll[0] && ll[1]) retLoc = L.latLng(ll); else retLoc = null; break; case 'array': retLoc = L.latLng(loc); break; case 'object': var lat, lng; if(loc.hasOwnProperty('lat')) lat = loc.lat; else if(loc.hasOwnProperty('latitude')) lat = loc.latitude; if(loc.hasOwnProperty('lng')) lng = loc.lng; else if(loc.hasOwnProperty('lon')) lng = loc.lon; else if(loc.hasOwnProperty('longitude')) lng = loc.longitude; retLoc = L.latLng(parseFloat(lat),parseFloat(lng)); break; default: retLoc = loc; } return roundLocation( retLoc ); } function buildMap(self) { self.divMap = document.createElement('div'); self.$map = $(document.createElement('div')) .addClass(opts.className + '-map') .height(opts.height) .width(opts.width) .append(self.divMap); if (opts.readOnly) self.$map.addClass("read-only"); //adds either as global div or specified container //if added to specified container add some style class if(opts.mapContainer && $(opts.mapContainer)) self.$map.appendTo(opts.mapContainer) .addClass('map-select'); else self.$map.appendTo('body'); if(self.location) opts.map.center = self.location; if(typeof opts.layer === 'string' && baseLayers[opts.layer]) { opts.map.layers = L.tileLayer(baseLayers[opts.layer]); }else if (opts.layer instanceof L.TileLayer || opts.layer instanceof L.GridLayer || opts.layer instanceof L.LayerGroup) { opts.map.layers = opts.layer; }else { opts.map.layers = L.tileLayer(baseLayers.OSM); } //leaflet map self.map = L.map(self.divMap, opts.map) .addControl( L.control.zoom({position: 'bottomright'}) ) .on(opts.event, function(e) { if (!opts.readOnly) self.setLocation(e.latlng); }); if(opts.activeOnMove) { self.map.on('move', function(e) { self.setLocation(e.target.getCenter()); }); } //only adds closeBtn if not alwaysOpen if(opts.alwaysOpen!==true){ var xmap = L.control({position: 'topright'}); xmap.onAdd = function(map) { var btn_holder = L.DomUtil.create('div', 'leaflet-bar'); var btn = L.DomUtil.create('a','leaflet-control '+opts.className+'-close'); btn.innerHTML = '×'; btn_holder.appendChild(btn); L.DomEvent .on(btn, 'click', L.DomEvent.stop, self) .on(btn, 'click', self.closeMap, self); return btn_holder; }; xmap.addTo(self.map); } if(opts.locationMarker) self.marker = buildMarker(self.location).addTo(self.map); return self.$map; } function buildMarker(loc) { return L.marker(parseLocation(loc) || L.latLng(0,0), { icon: L.divIcon({ className: opts.className+'-marker', iconAnchor: L.point(0, 0), // TODO: get rid of inline CSS completely, in order to make it compliant with Content-Security-Policy that doesn't wallows 'unsafe-inline' CSS. // AK: These additional styles can be set up with JavaScript, after creation of the marker icon element. html: '