1 2class MarketFinder { 3 4 constructor(elem, type, markets = [], radius = 50) { 5 6 const EARTH_RADIUS_KM = 6371; 7 8 const Finder = { 9 10 init: function (elem, type, markets, radius) { 11 12 // cache elements 13 Finder.markets = markets; 14 Finder.filteredMarkets = markets; 15 Finder.container = $(elem); 16 Finder.form = $(elem).find('form.car-repair-form'); 17 Finder.input = $(elem).find('input'); 18 Finder.listing = $(elem).find('.results'); 19 Finder.submit = $(elem).find('button[type="submit"]'); 20 Finder.noResults = $(elem).find('.no-results'); 21 Finder.type = type; 22 Finder.radius = radius; 23 24 // on submit 25 Finder.form.on('submit', function (e) { 26 e.preventDefault(); 27 Finder.filter(); 28 }) 29 }, 30 31 filter: function (ignoreRadius = false) { 32 33 var value = Finder.input.val().toLowerCase().trim(); 34 var places = []; 35 36 if (value.length <= 0) return; 37 38 // If a market matches the searched city name, use the zipcode instead 39 // to ensure that Nominatim identifies the correct city. 40 const matches = Finder.markets.filter(item => 41 item.city?.toLowerCase().includes(value.toLowerCase()) || 42 item.citynames?.toLowerCase().includes(value.toLowerCase()) 43 ); 44 if (matches.length > 0) { 45 value = matches[0].zipcode || value 46 } 47 48 // search place with openstreetmap 49 jQuery.getJSON('https://nominatim.openstreetmap.org/search?format=json&limit=1&countrycodes=de,lu&q=' + value, function (data) { }).then(function (data) { 50 if (typeof data[0] !== 'undefined') { 51 const coords = { lat: data[0].lat, lng: data[0].lon }; 52 Finder.markets.forEach(function (item, index) { 53 var market = item; 54 const distance = getDistanceInKm( 55 { lat: item.lat, lon: item.lng }, 56 { lat: coords.lat, lon: coords.lng } 57 ); 58 // if distance is below radius 59 if ((distance <= radius)) { 60 market.distance = distance; 61 places.push(market); 62 } 63 }) 64 65 } 66 Finder.filteredMarkets = places.sort((a, b) => a.distance - b.distance); 67 Finder.updateListing() 68 }) 69 70 }, 71 72 updateListing: function () { 73 Finder.listing.find('.market').removeClass('filtered').hide(); 74 Finder.noResults.hide(); 75 76 var marketsToShow = Finder.filteredMarkets 77 .slice() 78 .sort(function (a, b) { return a.distance - b.distance; }) 79 .slice(0, 3); 80 81 if (marketsToShow.length > 0) { 82 marketsToShow.forEach(function (item) { 83 var $market = Finder.listing.find('.market#' + item.id) 84 .attr('data-distance', item.distance) 85 .data('distance', item.distance) 86 .addClass('filtered') 87 .show(); 88 Finder.listing.append($market); 89 }); 90 } else { 91 Finder.noResults.show(); 92 } 93 94 }, 95 } 96 97 function toRadians(degrees) { 98 return degrees * (Math.PI / 180); 99 } 100 101 function getDistanceInKm(from, to) { 102 const deltaLat = toRadians(to.lat - from.lat); 103 const deltaLon = toRadians(to.lon - from.lon); 104 105 const fromLat = toRadians(from.lat); 106 const toLat = toRadians(to.lat); 107 108 const a = 109 Math.sin(deltaLat / 2) ** 2 + 110 Math.cos(fromLat) * 111 Math.cos(toLat) * 112 Math.sin(deltaLon / 2) ** 2; 113 114 const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 115 116 return EARTH_RADIUS_KM * c; 117 } 118 119 // init finder 120 Finder.init(elem, type, markets, radius); 121 122 // auto-submit on page load 123 Finder.form.trigger('submit'); 124 } 125 126} 127 128jQuery(document).ready(function ($) { 129 // init finder 130 131 $('.car-repair-finder').each(function () { 132 new MarketFinder(this, 'car-repair', carRepairMarkets, 50); 133 }) 134 135}) 136
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.