1$(document).ready(function() { 2 initAutocomplete(); 3}); 4 5function initAutocomplete() 6{ 7 $('.autocomplete-init').each(function() { 8 var input = $(this); 9 var searchViaAdoddle = ($(this).attr('data-search-via-adoddle')); 10 var button = input.parent().find('.input-group-btn').find('button'); 11 var timeout; 12 13 // Wrap input in container 14 input.wrap('<div class="autocomplete-container"></div>'); 15 16 input.click(function(event) { 17 event.stopPropagation(); 18 if(input.val() != '') { 19 if(input.hasClass('retry')) { 20 retry = true; 21 input.removeClass('retry'); 22 } else { 23 retry = false; 24 } 25 waitForFinalEvent(function() { 26 autocomplete(input, retry, searchViaAdoddle); 27 }, 500, 'autocompleteInputClick'); 28 29 } 30 }); 31 32 button.click(function(event) { 33 event.stopPropagation(); 34 35 if(input.val() != '') { 36 waitForFinalEvent(function() { 37 autocomplete(input, false, searchViaAdoddle); 38 }, 500, 'autocompleteButtonClick'); 39 } 40 }); 41 42 input.on('keydown', function(event) { 43 44 if(event.keyCode == 13) { 45 // Press enter to choose an address from the list 46 var list = $(this).parent().find('.autocomplete-addresses'); 47 if(list.length == 1) { 48 list.find('li:first-child').click(); 49 } 50 51 event.preventDefault(); 52 } 53 }); 54 55 input.on('keyup', function(event) { 56 waitForFinalEvent(function() { 57 autocomplete(input, false, searchViaAdoddle); 58 }, 500, 'autocompleteKeyup'); 59 }); 60 }) 61} 62 63function autocomplete(input, retry=false, searchViaAdoddle=false) 64{ 65 if($('body').hasClass('finding-addresses')) { 66 return false; 67 } 68 69 $('body').addClass('finding-addresses'); 70 71 var button = input.parent().find('.input-group-btn').find('button'); 72 var query = input.val(); 73 var type = input.attr('data-type'); 74 75 if(input.val() == input.attr('data-value') && input.parent().find('.autocomplete').length == 1) { 76 displayAutocomplete(input.parent().find('.autocomplete'), input); 77 $('body').removeClass('finding-addresses'); 78 return false; 79 } 80 81 // Remove illegal characters 82 query = query.replaceAll('#', ''); 83 query = query.replaceAll('?', ''); 84 query = query.replaceAll('/', ''); 85 86 // Add query to attribute to check if the value has changed, avoids searching for the same query multiple times 87 input.attr('data-value', input.val()); 88 89 if (searchViaAdoddle) { 90 var autocomplete = $.ajax({ 91 url: appUrl + `/api/autocomplete?query=${query}`, 92 type: 'GET', 93 }); 94 } else { 95 var autocomplete = $.ajax({ 96 url: 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + query + '.json?access_token=pk.eyJ1IjoiamFraWIiLCJhIjoiY2xha3RmbXBuMHE2czNxbjNiaThlMzE3eCJ9.OPqokjncM4xpF2OgMW6XMA&autocomplete=true&country=gb', 97 type: 'GET', 98 }); 99 } 100 101 autocomplete.always(function(response) { 102 data = response; 103 console.log(data); 104 105 $('body').removeClass('finding-addresses'); 106 107 var addresses = data.features; 108 109 if(data.message !== undefined && data.message.includes('Not Authorized')) { 110 if(retry) { 111 alert('Oops! Error occurred with the address autocomplete. Either try typing the address again for refresh the page.'); 112 return false; 113 } 114 115 setTimeout(function() { 116 input.addClass('retry').click(); 117 }, 1000); 118 119 // Bug with mapbox? 120 // Sometimes the autocomplete stops working by returning a 'no token' message 121 return false; 122 } 123 124 // Create autocomplete element if it doesn't exist 125 if(input.parent().find('.autocomplete').length == 0) { 126 // Create autocomplete element 127 input.after('<div class="autocomplete" style="display: block !important;"><div class="autocomplete-addresses" style="display: block !important;"><h3>Addresses <span class="badge badge-secondary" style="font-size: .7rem; margin-top: -5px;">' + addresses.length + '</span></h3><ul></ul></div></div>'); 128 var elem = input.parent().find('.autocomplete'); 129 130 // Set top position of autocomplete element to height of input 131 var inputHeight = input.parent().outerHeight(true); 132 elem.css('top', inputHeight + 'px'); 133 134 displayAutocomplete(elem, input); 135 } else { 136 var elem = input.parent().find('.autocomplete'); 137 } 138 139 var addressesElem = elem.find('.autocomplete-addresses ul'); 140 141 // Clear existing data 142 addressesElem.empty(); 143 144 // Append address 145 if(addresses.length == 0) { 146 addressesElem.append('<li class="no-locations>
146No locations found.</li>'); 147 } else { 148 for (var a = 0; a < addresses.length; a++) { 149 addressesElem.append('<li class="autocomplete-address" data-lat="' + addresses[a].center[1] + '" data-lng="' + addresses[a].center[0]+ '" data-name="' + addresses[a].place_name +'"><a href="#">' + addresses[a].place_name +'</a></li>'); 150 } 151 } 152 153 if ('projects' in data) { 154 var projects = data.projects; 155 156 $('.autocomplete-projects').remove() 157 158 let projectsAutocompleteHTML = '<div class="autocomplete-projects" style="display: block !important;"><h3>Projects <span class="badge badge-secondary" style="font-size: .7rem; margin-top: -5px;">' + projects.length + '</span></h3><ul>' 159 160 projects.forEach(project => { 161 projectsAutocompleteHTML += `<li><a href="${project.url}">${project.name}</a></li>` 162 }); 163 164 projectsAutocompleteHTML += '</ul></div>' 165 166 $('.autocomplete').append(` 167 ${projectsAutocompleteHTML} 168 `) 169 } 170 171 // Hide autocomplete when user clicks elsewhere on page 172 $('body').click(function(event) { 173 // if the target of the click isn't the container nor a descendant of the container 174 if (!elem.is(event.target) && elem.has(event.target).length === 0) { 175 hideAutocomplete(elem, input); 176 } 177 }); 178 179 // Display autocomplete on click 180 input.click(function(event) { 181 event.stopImmediatePropagation(); 182 displayAutocomplete(elem, input); 183 }); 184 185 // Display autocomplete on click 186 button.click(function(event) { 187 event.stopImmediatePropagation(); 188 console.log('test'); 189 190 if($('.autocomplete').length == 1 && $('.autocomplete').is(':visible')) { 191 $('.autocomplete-address:nth-of-type(1)').click(); 192 } else { 193 displayAutocomplete(elem, input); 194 } 195 196 197 }); 198 199 // Move map to chosen address 200 $('body').on('click', '.autocomplete-address', function(event) { 201 event.preventDefault(); 202 var address = $(this); 203 var input = $(this).parents('.autocomplete-container').find('input[id="location"]'); 204 205 if(address.hasClass('clicked')) { 206 return false; 207 } 208 209 address.addClass('clicked'); 210 211 var lat = address.attr('data-lat'); 212 var lng = address.attr('data-lng'); 213 var name = address.attr('data-name'); 214 var latLng = JSON.stringify([ lng, lat ]); 215 216 input.val(name); 217 218 // Only search for new projects when the search form does not exist 219 if(type == 'map') {
220 map.setView([lat, lng], 15); 221 searchForProjects(); 222 } 223 224 if(type == 'url') { 225 var u = url + '/app/search/map?location=' + name + '&lat= ' + lat + '&lng=' + lng; 226 227 // ?location=Yate%2C+Bristol%2C+South+Gloucestershire%2C+England%2C+United+Kingdom&lat=51.5403&lng=-2.4133 228 229 if(u.includes('/app/app')) { 230 u = u.replace('/app/app', '/app'); 231 } 232 233 window.location.href = u; 234 } 235 236 237 if(type == 'search') { 238 $('input[name="lat"]').remove(); 239 $('input[name="lng"]').remove(); 240 241 input.after('<input type="hidden" name="lat" value="' + lat + '">'); 242 input.after('<input type="hidden" name="lng" value="' + lng + '">'); 243 244 var data = { location: name, lat: lat, 'lng': lng }; 245 246 // Call searchForProjects function only if it exists 247 if(typeof searchForProjects == 'function' && $('#search-form').length == 0) { 248 var filters = searchFilters(); 249 250 // if there is no radius in the filters, add default radius of 10 251 if(!filters.get('radius') && type == 'list') { 252 filters = searchFilters({ radius: 10 }); 253 $('select[name="radius"]').val(10); 254 $('.orderby-field').fadeIn(); 255 } 256 257 if(filters.get('radius') > 0) { 258 // Delete bounds data 259 searchFilters({ ne_bounds: '', sw_bounds: ''}, true); 260 261 searchFilters(data); 262 263 if(searchView == 'map') { 264 updateMapLocation(); 265 } 266 267 searchForProjects(); 268 } else { 269 270 // Delete bounds data 271 searchFilters({ ne_bounds: '', sw_bounds: ''}, true); 272 273 // Add location data 274 searchFilters(data); 275 276 if(searchView == 'map') { 277 // Update map location 278 updateMapLocation(); 279 280 showSearchForProjectsButton(); 281 } 282 } 283 } 284 285 $(window).trigger('addressChosen', data); 286 } 287 288 hideAutocomplete(); 289 }); 290 }); 291} 292 293function displayAutocomplete(elem, input) 294{ 295 if(typeof elem === 'undefined') { 296 var elem = $('.autocomplete'); 297 } 298 299 if(typeof input === 'undefined') { 300 input = $('.autocomplete-init'); 301 } 302 303 if(!elem.is(':visible')) { 304 elem.fadeIn('slow'); 305 306 // Dim background 307 //elem.add(input).add(input.parent().find('button')).dimBackground({ darkness: .4 }); 308 } 309} 310 311function hideAutocomplete(elem, input) 312{ 313 if(typeof elem === 'undefined') { 314 var elem = $('.autocomplete'); 315 } 316 317 if(typeof input === 'undefined') { 318 input = $('.autocomplete-init'); 319 } 320 321 elem.fadeOut('slow'); 322 323 // Remove dim 324 $.undim(); 325 326}
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.