(function($){ // Suppose input name="zip" and name="city" are in form // A div with class="geo_suggestions" has to be available too $.fn.addSearchAutocomplete = function () { var elt = this, prev_key_evt_datetime = null, prev_search_datetime = null, prev_answer_datetime = null, suggest_list = document.querySelector('.geo_suggestions'); const get_element_geom = function(el) { var rect = el.getBoundingClientRect(), scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, scrollTop = window.pageYOffset || document.documentElement.scrollTop; return { top: rect.top + scrollTop, left: rect.left + scrollLeft, height: el.offsetHeight, width: el.offsetWidth} } const clear_suggestion_list = function() { if (suggest_list) suggest_list.innerHTML = ''; } const fill_with_suggestion = function(item) { $('[name="address"]').val(item.getAttribute('data-street')); $('[name="zip"]').val(item.getAttribute('data-zip')); $('[name="city"]').val(item.getAttribute('data-city')); suggest_list.style.display = 'none'; } const display_results = function(features) { let geom = get_element_geom(elt.get(0)), list = document.createElement("ul"); suggest_list.style.position = 'absolute'; suggest_list.style.display = 'block'; suggest_list.style.top = (geom.top + geom.height + 2) + 'px'; suggest_list.style.left = geom.left + 'px'; suggest_list.style.width = geom.width + 'px'; features.forEach(function(f){ let item = document.createElement("li"), cat = street = ''; if (f.properties.type == 'municipality') { cat = 'fa fa-building'; } else if (f.properties.type == 'street') { cat = 'fa fa-road'; } else { cat = 'fa fa-map-marker'; } item.classList.add('geo-suggestion') item.setAttribute('data-zip', f.properties.postcode); item.setAttribute('data-city', f.properties.city); if (f.properties.type == 'housenumber' || f.properties.type == "street") { street = f.properties.name; } item.setAttribute('data-street',street); item.innerHTML = '<i class="' + cat + '"></i>' + f.properties.label list.appendChild(item) }); suggest_list.innerHTML = list.outerHTML; } //fa fa-building fa fa-road fa fa-map-marker const search_address = function(q) { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { try { const results = JSON.parse(this.responseText) prev_answer_datetime = (new Date()).getTime(); if (results.features.length > 0) { display_results(results.features) } } catch (err) { console.log(err) } } }; xhttp.open("GET", "https://api-adresse.data.gouv.fr/search/?q=" + q); xhttp.send(); } const launch_search_if_needed = function(text, now) { // launch search, excepted if one has been launched few time ago if (text.length > 0 && (prev_search_datetime == null || (now - prev_search_datetime >= 500))) { prev_search_datetime = now; clear_suggestion_list(); search_address(text); } } elt.on('keyup touchend', function(){ suggest_list.style.display = 'none'; var text = elt.val().trim(), now = (new Date()).getTime(); if (prev_key_evt_datetime == null) { prev_key_evt_datetime = now; } else { if ((now - prev_key_evt_datetime) > 750 && text.length > 0) { // elapsed time is enough to consider it as a possible end launch_search_if_needed(text, now); } } prev_key_evt_datetime = now setTimeout(function(){ // needed to launch search if no more keyup let now = (new Date()).getTime(); launch_search_if_needed(elt.val().trim(), now); }, 500); }); document.addEventListener('click', function (event) { if (event.target.tagName == "LI" && event.target.matches('.geo-suggestion')) { fill_with_suggestion(event.target); } else { suggest_list.style.display = 'none'; } }); }; }(jQuery));