Rev 3881 | Blame | Compare with Previous | Last modification | View Log | RSS feed
import {debounce} from "../lib/debounce.js";export const NOMINATIM_OSM_URL = 'https://nominatim.openstreetmap.org/';const NOMINATIM_OSM_DEFAULT_PARAMS = {'format': 'json','addressdetails': 1,'limit': 10};const ESC_KEY_STRING = /^Esc(ape)?/;export function TbPlaces(clientCallback) {/*** used in this.onSuggestionSelected()** @callback clientCallback* @param {String} locality* @param {{lat: number, lng: number }} coordinates*/this.clientCallback = clientCallback;this.searchResults = [];}TbPlaces.prototype.init = function() {this.initForm();this.initEvts();};TbPlaces.prototype.initForm = function() {this.places = $('#tb-places');this.placeLabel = this.places.siblings('label');this.placesResults = $('.tb-places-results');this.placesResultsContainer = $('.tb-places-results-container');this.placesCloseButton = $('.tb-places-close');};TbPlaces.prototype.initEvts = function() {if (0 < this.places.length) {this.toggleCloseButton(false);this.places.off('input').on('input', debounce(this.launchSearch.bind(this), 500));this.places.off('keydown').on('keydown', debounce(this.handlePlacesKeydown.bind(this), 500));}};TbPlaces.prototype.handlePlacesKeydown = function(evt) {const suggestionEl = $('.tb-places-suggestion'),isEscape = 27 === evt.keyCode || ESC_KEY_STRING.test(evt.key),isArrowDown = 40 === evt.keyCode || 'ArrowDown' === evt.key,isEnter = 13 === evt.keyCode || 'Enter' === evt.key;if (isEscape || isArrowDown || isEnter) {evt.preventDefault();if (isEscape) {this.placesCloseButton.trigger('click');this.places.focus();} else if(isArrowDown || isEnter) {if ( 0 < suggestionEl.length) {suggestionEl.first().focus();} else {this.launchSearch();}}}};TbPlaces.prototype.launchSearch = function () {if (!!this.places.val()) {const url = NOMINATIM_OSM_URL+'search',params = {'q': this.places.val(),'format': 'json','polygon_geojson': 1,'zoom': 17};this.placeLabel.addClass('loading');$.ajax({method: "GET",url: url,data: {...NOMINATIM_OSM_DEFAULT_PARAMS, ...params},success: this.nominatimOsmResponseCallback.bind(this),error: () => {this.placeLabel.removeClass('loading');this.handleSearchError();}});}};TbPlaces.prototype.nominatimOsmResponseCallback = function(data) {this.places.siblings('label').removeClass('loading');if (0 < data.length) {this.searchResults = data;this.setSuggestions();this.toggleCloseButton();this.resetOnClick();this.onSuggestionSelected();} else {this.handleSearchError();}};TbPlaces.prototype.setSuggestions = function() {const lthis = this,acceptedSuggestions = [];this.placesResults.empty();this.searchResults.forEach(suggestion => {if(lthis.validateSuggestionData(suggestion)) {const locality = suggestion['display_name'];if (locality && !acceptedSuggestions.includes(locality)) {acceptedSuggestions.push(locality);lthis.placesResults.append('<li class="tb-places-suggestion" data-place-id="'+suggestion['place_id']+'" tabindex="-1">' +locality +'</li>');}}});if(0 < acceptedSuggestions.length) {this.placesResultsContainer.removeClass('hidden');} else {this.resetPlacesSearch();}};TbPlaces.prototype.validateSuggestionData = function(suggestion) {const validGeometry = undefined !== suggestion.lat && undefined !== suggestion.lon,typeLocalisation = this.places.data('typeLocalisation') || '',validGeometryType = 'rue' === typeLocalisation ? 'LineString' === suggestion?.geojson.type : true,validAddressData = undefined !== suggestion.address,validDisplayName = undefined !== suggestion['display_name'];return (validGeometry && validGeometryType && validAddressData && validDisplayName);};TbPlaces.prototype.onSuggestionSelected = function() {const lthis = this;$('.tb-places-suggestion').off('click').on('click', function (evt) {const $thisSuggestion = $(this),suggestion = lthis.searchResults.find(suggestion => suggestion['place_id'] === $thisSuggestion.data('placeId'));evt.preventDefault();lthis.places.val($thisSuggestion.text());lthis.clientCallback(suggestion);lthis.placesCloseButton.trigger('click');}).off('keydown').on('keydown', function (evt) {evt.preventDefault();const $thisSuggestion = $(this);if (13 === evt.keyCode || 'Enter' === evt.key) {$thisSuggestion.trigger('click');} else if (38 === evt.keyCode || 'ArrowUp'=== evt.key) {if(0 < $thisSuggestion.prev().length) {$thisSuggestion.prev().focus();} else {lthis.places.focus();}} else if((40 === evt.keyCode || 'ArrowDown' === evt.key) && 0 < $thisSuggestion.next().length) {$thisSuggestion.next().focus();} else if (27 === evt.keyCode || ESC_KEY_STRING.test(evt.key)) {lthis.placesCloseButton.trigger('click');lthis.places.focus();}});};TbPlaces.prototype.resetOnClick = function () {const lthis = this;this.placesCloseButton.off('click').on('click', function (event) {event.preventDefault();lthis.resetPlacesSearch();});};TbPlaces.prototype.toggleCloseButton = function(isShow = true) {this.placesCloseButton.toggleClass('hidden', !isShow);$('.tb-places-search-icon').toggleClass('hidden', isShow);};TbPlaces.prototype.handleSearchError = function() {this.resetPlacesSearch();if (0 === $('#tb-places-error').length) {this.places.closest('#tb-places-zone').after(`<span id="tb-places-error" class="error mb-3 mt-3">Votre recherche n’a pas donné de résultat pour le moment.<br>Vous pouvez soit poursuivre ou modifier votre recherche,<br>soit rechercher votre station directement sur la carte.</span>`);setTimeout(function() {$('#tb-places-error').remove();}, 10000);}};TbPlaces.prototype.resetPlacesSearch = function() {this.toggleCloseButton(false);this.placesResultsContainer.addClass('hidden');this.placesResults.empty();};