PageSourceSearch

https://adoddle.org/app/js/autocomplete.js?v245

js adoddle.org collected 2026-10-04 02:16:43 UTC 9,547 bytes, 326 lines download raw bytes

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.