BR.Search = class extends L.Control.Geocoder { constructor(options) { super( Object.assign( { geocoder: new L.Control.Geocoder.LatLng({ next: new L.Control.Geocoder.Nominatim({ serviceUrl: 'https://nominatim.openstreetmap.org/', }), sizeInMeters: 800, }), position: 'topleft', expand: 'click', shortcut: { search: 70, // char code for 'f' }, placeholder: i18next.t('map.geocoder-placeholder'), }, options ) ); L.DomEvent.addListener(document, 'keydown', this._keydownListener, this); } markGeocode(result) { this._map.fitBounds(result.geocode.bbox, { maxZoom: 17, }); this.clear(); this._geocodeMarker = new L.CircleMarker(result.geocode.center, { interactive: false, color: 'red', opacity: 1, weight: 3, }).addTo(this._map); return this; } clear() { if (this._geocodeMarker) { this._map.removeLayer(this._geocodeMarker); } } _keydownListener(e) { if (BR.Util.keyboardShortcutsAllowed(e) && e.keyCode === this.options.shortcut.search) { $('#map .leaflet-control-geocoder')[0].dispatchEvent(new MouseEvent('click')); e.preventDefault(); } } /* Search favorites handling */ onAdd(map) { if(!BR.Util.localStorageAvailable()) return super.onAdd(map); let container=super.onAdd(map); new SearchFavorites(this,container); return container; } }; class SearchFavorites { constructor(geocoder,container) { //because eslint does not support instance var declaration this.searchInput=undefined; this.autocompleteContainer=undefined; this.autocompleteSelect=undefined; this.autocompleteMenu=undefined; this.geocoderForm=undefined; this.geocoder=undefined; this.favElements=undefined; this.isFiltered=true; this.arFavitems=[]; this.arFavitemsLC=[]; this.geocoder=geocoder; this.searchInput=$(container).find(".leaflet-control-geocoder-form input[type=text]"); this.searchInput.after(` `); //otherwise parent catches event and click is never fired $(container).find(".leaflet-control-geocoder-form .search-fav-ctrls").on("mousedown", (e) => { e.stopPropagation();e.preventDefault(); }); $(container).find(".leaflet-control-geocoder-form .search-fav-ctrls").click((e) => this.onCtrlsClick(e)); $(container).find(".leaflet-control-geocoder-form").append(`
...
`); this.autocompleteContainer=$(container).find("#search-autocomplete-container"); this.autocompleteSelect=this.autocompleteContainer.find("#search-autocomplete-select"); this.autocompleteMenu=this.autocompleteContainer.find("#autocomplete-btngroup"); this.geocoderForm=$(container).find(".leaflet-control-geocoder-form"); this.autocompleteContainer.on("mousedown", (e) => { e.stopPropagation();e.preventDefault(); }); this.autocompleteContainer.find("#search-fav-menu-toggle").on("mousedown touchend", (e) => { e.stopPropagation();e.preventDefault();}); this.autocompleteContainer.find("#search-fav-menu-toggle").on("click touchend", (e) => { e.stopPropagation();e.preventDefault(); this.autocompleteMenu.collapse('toggle'); }); this.autocompleteContainer.find(".autocomplete-select-container").on("wheel", (e) => { e.stopPropagation(); }); this.autocompleteContainer.on("shown.bs.collapse", (e) => this.geocoderForm.addClass("stayvisible")); this.autocompleteContainer.on("hidden.bs.collapse", (e) => { this.geocoderForm.removeClass("stayvisible"); this.autocompleteMenu.collapse('hide'); }); this.autocompleteSelect.click((e) => this.onFavItemClicked(e)); this.autocompleteContainer.find(".autocomplete-menu").click((e) => this.onFavMenuClicked(e)); this.autocompleteContainer.find("#search-fav-file").on("change",(e) => this.onImportFavFile(e)); let strFavitems=localStorage['searchFavItems']; if(strFavitems) { this.arFavitems=JSON.parse(strFavitems); this.arFavitemsLC = this.arFavitems.map(x => x.toLowerCase()); //copy to Lowercase } this.updateFavList(); this.searchInput.on("keyup",(e) => this.onInput(e)); } updateFavList() { if(this.arFavitems.length > 0){ let opts=this.arFavitems.join('`); } else this.autocompleteSelect.empty(); this.favElements=this.autocompleteSelect.find("button"); } appendFavorite(strFav) { this.arFavitems.push(strFav); this.arFavitems=[... new Set(this.arFavitems)]; //remove duplicates this.arFavitems.sort(); this.arFavitemsLC = this.arFavitems.map(x => x.toLowerCase()); //copy to Lowercase localStorage['searchFavItems']=JSON.stringify(this.arFavitems); this.updateFavList(); } deleteFavorite(strFav) { let pos=this.arFavitems.indexOf(strFav); if(pos >= 0) { this.arFavitems.splice(pos, 1); this.arFavitems=[... new Set(this.arFavitems)]; //remove duplicates this.arFavitems.sort(); this.arFavitemsLC = this.arFavitems.map(x => x.toLowerCase()); //copy to Lowercase localStorage['searchFavItems']=JSON.stringify(this.arFavitems); this.updateFavList(); } } onInput(e) { if(e.keyCode == 13) { this.autocompleteContainer.collapse('hide'); return; } if(e.keyCode <=45 && e.keyCode != 8) return; let srch=this.searchInput.val().toLowerCase(); if(!srch || srch.length < 2) { this.autocompleteContainer.collapse('hide'); return; } if(!this.isFiltered) { this.autocompleteContainer.addClass("filtered"); this.isFiltered=true; } let matches=false; this.favElements.removeClass("match"); this.arFavitemsLC.forEach((val,idx) => { if(val.indexOf(srch) != -1) { this.favElements.eq(idx).addClass("match"); matches=true; } }); if(matches) this.autocompleteContainer.collapse('show'); else this.autocompleteContainer.collapse('hide'); } onCtrlsClick(e) { e.stopPropagation();e.preventDefault(); switch(e.target.id) { case "search-fav-add": this.appendFavorite(this.searchInput.val()); break; case "search-fav-expand": if(this.autocompleteContainer.hasClass("show")) { if(this.isFiltered) { this.autocompleteContainer.removeClass("filtered"); this.isFiltered=false; } else { this.autocompleteContainer.collapse('hide') this.autocompleteContainer.addClass("filtered"); this.isFiltered=true; } } else { this.autocompleteContainer.removeClass("filtered"); this.isFiltered=false; this.autocompleteContainer.collapse('show'); } break; default: break; } } onFavItemClicked(e) { e.stopPropagation();e.preventDefault(); if($(e.target).hasClass("favitem")) { this.autocompleteContainer.collapse('hide'); this.geocoder.setQuery(e.target.innerText); this.searchInput.focus(); this.geocoder._keydown({keyCode: 13 }); } else if($(e.target).hasClass("del-favitem")) { this.deleteFavorite($(e.target).closest("button").text()); } } onFavMenuClicked(e) { switch(e.target.id) { case "search-fav-deleteall": if(confirm(i18next.t("searchfav.ask_removeall")) ) { this.arFavitems=[]; this.arFavitemsLC=[]; localStorage['searchFavItems']=JSON.stringify(this.arFavitems); this.updateFavList(); } break; case "search-fav-export": let exp=JSON.stringify(this.arFavitems,null,2); const blob = new Blob([exp], { type: 'application/json;charset=utf-8', }); const objectUrl = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = objectUrl; link.download = 'SearchFavorites.json'; link.click(); break; case "search-fav-import": $(e.target).find("input[type=file]").click(); e.preventDefault(); break; default: break; } } onImportFavFile(e) { if(!e.target.files[0]) return; let r=new FileReader(); r.onload=(f) => { let importFavItems=JSON.parse(f.target.result); this.arFavitems=this.arFavitems.concat(importFavItems); this.arFavitems=[... new Set(this.arFavitems)]; //remove duplicates this.arFavitems.sort(); this.arFavitemsLC = this.arFavitems.map(x => x.toLowerCase()); //copy to Lowercase localStorage['searchFavItems']=JSON.stringify(this.arFavitems); this.updateFavList(); }; r.readAsText(e.target.files[0]); e.target.value=''; } }