diff --git a/css/style.css b/css/style.css
index de47a03..461e975 100644
--- a/css/style.css
+++ b/css/style.css
@@ -854,6 +854,68 @@ table.dataTable.display tbody tr:hover.selected {
border-radius: 0;
}
+
+/**
+ * Autocompleter styles
+ */
+.leaflet-control-geocoder-form.stayvisible { display: inline-block; }
+.leaflet-control-geocoder-alternatives{
+ /* display: block; */
+ position: absolute;
+ background-color: white;
+ left: 2rem;
+}
+
+.leaflet-control-geocoder-alternatives{
+ background-color: rgb(255, 255, 255);
+}
+
+.autocomplete-container {
+ position:absolute;
+ left: 2rem;
+ width: calc( 100% - 3rem );
+ z-index: 100;
+}
+
+.autocomplete-select-container {
+ max-height: 15vh;
+ overflow-y: auto;
+}
+
+.autocomplete-container .autocomplete-select button{
+ text-align: left;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ width: 100%;
+}
+
+#search-fav-menu-toggle {
+ text-align: right;
+ padding-right: 2rem;
+ line-height: 100%;
+ cursor: pointer;
+}
+
+#search-fav-menu-toggle > span {
+ font-weight: bold;
+ line-height: 0;
+ font-size: 1.2rem;
+}
+
+.autocomplete-container.filtered .autocomplete-select button{ display: none; }
+.autocomplete-container.filtered .autocomplete-select button.match{ display: inherit; }
+
+@media (max-width: 320.98px) {
+ .leaflet-control-geocoder-form > input[type=text] {
+ max-width: 50vw;
+ }
+
+ .leaflet-control-geocoder-alternatives {
+ max-width: 65vw;
+ }
+}
+
+
@media (max-width: 575.98px) {
.modal-fullscreen-sm-down {
width: 100vw;
diff --git a/js/plugin/Search.js b/js/plugin/Search.js
index e810867..7af0987 100644
--- a/js/plugin/Search.js
+++ b/js/plugin/Search.js
@@ -22,7 +22,8 @@ BR.Search = class extends L.Control.Geocoder {
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
}
-
+
+
markGeocode(result) {
this._map.fitBounds(result.geocode.bbox, {
maxZoom: 17,
@@ -51,4 +52,305 @@ BR.Search = class extends L.Control.Geocoder {
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('