PageSourceSearch

https://visitsavonlinna.fi/wp-content/plugins/visitsaimaa-content/js/visit_saimaa_plugin.js?ver=20240502-1

js visitsavonlinna.fi collected 2026-10-02 04:24:22 UTC 25,781 bytes, 870 lines download raw bytes

1/**
2 * Visit saimaa hakuplugari
3 * [email protected]
4 *  
5 */
6function escapeHtml(str) {
7    var div = document.createElement('div');
8    div.appendChild(document.createTextNode(str));
9    return div.innerHTML;
10};
11console.log("Search script ok");
12// Debounce
13if (typeof debounce == 'undefined') {
14	function debounce(a,b,c){var d;return function(){var e=this,f=arguments;clearTimeout(d),d=setTimeout(function(){d=null,c||a.apply(e,f)},b),c&&!d&&a.apply(e,f)}}
15}
16
17// Hakuboksi.
18// vs.ajaxurl tarvitaan, sekä käsittelijä action vs_search
19(function($) {
20	
21	
22	// Keskeytetään aiemmat ajax haut
23	var xhr = null;
24	var form_selector = '.vs_search_form'; // '.form.search';
25
26	// Datepickeri, kaik hakulomakkeet, ja tää ns. päähakulomake
27	init_datepicker('form.search, '+form_selector);	
28
29	
30	// Lomake lähtee
31    $('body').on('submit', form_selector, function(e) {
32console.log("Search submitting...");
33		e.preventDefault();
34		
35		var form = $(this);
36        var search_filters = [];
37 
38 		var tpl = $('input[name=tpl]', form).val()
39 		  , s_sort = $('select[name=sortby]', form).val()
40          , s_keywords = $('input[name=s]', form).val()
41          , s_date_from = $('input[name=from_date]', form).val()
42          , s_date_to = $('input[name=to_date]', form).val()
43		  , s_date = $('input[name=quick_dates]:checked', form).val()
44          , s_addr = $('input[name=address]', form).val()
45		  , s_resp = $('input[name=responsibility]:checked', form).val()
46          , s_ll = $('input[name=latlong]', form).val()
47          , s_r = $('input[name=range]', form).val()
48          , s_s = $('input[name=site]:checked', form).val()
49		  , s_m_d = $('input[name=maxdistance]:checked', form).val()
50		  , s_m_c = $('input[name=capacity]:checked', form).val()
51		  , s_m_i = []
52          , s_types = []
53          , s_cats = []
54          , s_a = []
55          , s_e = [];
56          
57        $('input[name=types]:checked', form).each(function() {
58        	s_types.push($(this).val());
59        });
60        
61        $('input[name=servicecategory]:checked', form).each(function() {
62        	s_cats.push($(this).val());
63        });	  
64        
65       	$('input[name=actioncategory]:checked', form).each(function() {
66        	s_a.push($(this).val());
67        });
68        
69       	$('input[name=eventcategory]:checked', form).each(function() {
70        	s_e.push($(this).val());
71        });     
72		
73		$('input[name=include]:checked', form).each(function() {
74        	s_m_i.push($(this).val());
75        }); 		
76        
77        
78        // If keywords exist, push to filter
79        if (s_keywords != '') {
80            search_filters.push({s_keywords: s_keywords});
81        }
82 
83        // If date from exists, push to filter
84        if (s_date_from != '') {
85            search_filters.push({s_date_from: s_date_from});
86        }
87 
88        // If date to exists, push to filter
89        if (s_date_to != '') {
90            search_filters.push({s_date_to: s_date_to});
91        }
92        
93        // Quick dates
94        if (s_date != '' && s_date != 'all' && s_date != 'select') {
95        	search_filters.push({s_date: s_date});
96        }
97        
98        // Site - blogi
99        if (s_s  != '') {
100        	search_filters.push({s_s: s_s});
101        }   
102		
103		// Kokouksen kapasiteetti
104        if (s_m_c != '' && s_m_c != 'all') {
105        	search_filters.push({s_m_c: s_m_c});
106        }   
107		// Kokouksen etäisyys
108        if (s_m_d  != '' && s_m_d != 'all') {
109        	search_filters.push({s_m_d: s_m_d});
110        }   				
111        
112        if (s_types.length > 0 && s_types[0] != 'all') {
113        	search_filters.push({s_types: s_types});
114        }
115
116        if (s_cats.length > 0 && s_cats[0] != 'all') {
117        	search_filters.push({s_cats: s_cats});
118        }
119        
120        if (s_a.length > 0 && s_a[0] != 'all') {
121        	search_filters.push({s_a: s_a});
122        }      
123        
124        if (s_e.length > 0 && s_e[0] != 'all') {
125        	search_filters.push({s_e: s_e});
126        }  
127		
128        if (s_m_i.length > 0 && s_m_i[0] != 'all') {
129        	search_filters.push({s_m_i: s_m_i});
130        } 		
131        
132        // Haku käyttäjän sijainnilla.
133    	if ($('input[name=uselocation]', form).is(':checked'))
134    		search_filters.push({uselocation: true});
135       
136        // Tai sitten latlongilla (tekstikentässä osoite ja latlong)
137        if (s_addr != '' && typeof s_addr != 'undefined') {
138            search_filters.push({s_addr: s_addr});
139        }
140        if (s_ll != '' && typeof s_ll != 'undefined') {
141            search_filters.push({s_ll: s_ll});
142        }
143        // Säde paikkahaussa
144		if (s_r != '' && typeof s_r != 'undefined') {
145            search_filters.push({s_r: s_r});
146        } 
147        
148        // Prioriteetillä haku
149        if ($('select[name=priority]', form).length) {
150        	var priority = $('select[name=priority]', form).val();
151        	if (priority != 'all')
152        		search_filters.push({s_p: priority});
153        }
154
155		// SSM Oy jäsenyydellä haku
156        if ($('select[name=ssm-member]', form).length) {
157        	var membership = $('select[name=ssm-member]', form).val();
158        	if (membership != 'all')
159        		search_filters.push({s_mbr: membership});
160        }
161
162        // Vastuullisuus
163        if (typeof s_resp != 'undefined' && s_resp != 'all') {
164        	search_filters.push({s_resp: s_resp});
165        }		
166        
167        // Sorttaus
168        if (typeof s_sort != 'undefined') {
169        	search_filters.push({s_sort: s_sort});
170        }
171       
172		// Näytetään hakutulokset jo ajaxloaderilla.
173		// show()
174		var the_results_container = $('#search_results-'+form.data('formid')).show();
175		var placeholder = $('.list', the_results_container);
176		
177		// Keskeytetään aiemmat pyynnöt
178		if (xhr != null) {
179			xhr.abort();
180			xhr = null;
181			
182			// poistetaan samalla vanahat ajaxloaderit
183			$('.ajaxloader', the_results_container).remove();
184		}		
185		
186		// Loaderi jeahloader.show().addClass('overlay')
187		var ajaxloader = $('<div class="ajaxloader"></div>');
188		if (placeholder.html().length)
189			placeholder.before(ajaxloader.addClass('overlay'));
190		else
191			placeholder.html(ajaxloader);
192
193		var query = {
194            tpl: tpl,
195            action: 'vs_search'
196       	};
197       	
198		// liitetään hakuvariaabelit kans osaksi queryä suoraan..
199		for (var i = 0; i < search_filters.length; i++) {
200			$.extend(query, search_filters[i]);
201		}
202
203		// form saattaa olla tässä formin wrapperi, bakerybuilderi poistaa formin nääs.
204		// tällöin lataukseen liittyvät toiminnot ei skulaa. Ei riko mitään tosin.
205		// @see visit_saimaa.js
206       	form.trigger('search-loading', [query]);
207
208        xhr = $.post( vs.ajaxurl, query, function(res) {
209        	ajaxloader.remove();
210 			placeholder.html(res);
211 			form.trigger('search-done', [query]);
212        });
213    });
214    
215    // Lomake lähtee muutoksista, debounssataa vähä
216    var submitSearchForm = debounce(function(e) {
217    	var $this = $(this);
218    	
219    	// Paitti osoitteen kirjoittamisesta, koska pitää odotella koordinaatit...
220    	if ($this.attr('name') == 'address')
221    		return;
222    		
223   		// Taikka jos muuten disabloitu
224    	else if ($this.data('submit') == 0) {
225  			return;
226  		} 	
227console.log("Triggering search submit");
228    	$this.closest(form_selector).trigger('submit');
229   	}, 300);
230   	
231    $('body').on('change', form_selector+'.fast input, '+form_selector+'.fast select',submitSearchForm);
232
233
234    // Hakutulosten piilotus.
235    // Suljetaan hakutulokset.
236    $('body').on('click', '.vs_search.search_results .close', function(e) {
237           e.preventDefault();
238           
239           // Piilotetaan tulosruutu
240           $(this).closest('.search_results').hide();
241           // Tyhjennetään tulokset
242           $(this).siblings('.list').html('');
243           
244           return false;   
245    });
246
247
248	// 
249	// Hakulomakkeen filtteröintisysteemit
250	// 
251    var formFilterButtons = function(btn) {
252    	var $this = $(btn);
253
254		// Kahotaa onks mitä aktiivisena
255		if ($this.data('toggle')) {
256			var activeFilter = $('.btn.active', $this.data('toggle'));
257			
258			// Kontaineri auki, jos jotain klikattuna
259			if (activeFilter.length && activeFilter.first().find('input:checked').first().val() != 'all') {
260				$this.closest(form_selector).find($this.data('toggle')).show();
261				/*
262				if (!$this.hasClass('.active')) {} // ??
263					$this.button('toggle');
264				*/
265			}		
266		}
267
268		$this.on('click', function() { 
269
270			let theForm = $this.closest(form_selector);
271			// Hakusuotimien toggle
272			// Filtterivalinnat esiin tällä lomakkeella
273			if ($this.data('toggle')) {
274				theForm.find($this.data('toggle')).toggle();    
275			}
276			
277			if ($this.data('show')) {
278				console.log("Show", $this.data('show'));
279				theForm.find($this.data('show')).show();
280					
281				// Tässähän myö hienosti kikataan css luokkaa kovakoodatusti
282				if ($this.data('typeclass')) {
283					var classes = ['product', 'shop', 'offer'];
284					theForm.find($this.data('show')).find('.btn').removeClass(classes.join(' ')).addClass($this.data('typeclass'));
285				}
286				
287			}
288			
289			if ($this.data('hide')) {
290				console.log("Hide", $this.data('hide'));				
291				theForm.find($this.data('hide')).hide();
292			}		
293				
294			// Vielä täytyy bindailla buttonin active > radion checkediin
295			// @see http://getbootstrap.com/javascript/#buttons-checkbox-radio
296			// sivun latautuessa :checked > .active
297			// label.btn :) 
298			if ($this.is('label')) {
299				var btn = $(this),
300					input = $('input',$this);
301
302				// säädetää alkuasetukset, eli checked arvosta napille .active luokka
303				if (input.is( ":checked" )) {
304					$this.addClass('active');
305				} else {
306					$this.removeClass('active');
307				}
308			} 
309		});
310
311    };	
312    
313    var formHook = function(e, form) {
314		console.log("Rigging form ", e, form);
315    	form = $(form);
316
317    	if (!form.data('rigged')) {
318	    	$('button.btn, label.btn', form).each(function() { formFilterButtons(this); });
319	    	
320	    	// Rigataan all -nappulan togletus.
321	    	$('.btn-checkbox input[value=all]', form).each(function() { 
322	    		var name = $(this).attr('name');
323	    		
324	    		$('input[name='+name+']').on('change', function() {
325	    			allButtonToggle( $(this).closest('.btn-checkbox'));
326	    		});
327	    	});
328
329			
330			// erikoistilanne, WPBakery poistaa koko hemeti <form> elementin editorissa, jolloin haun submit lähettää
331			// sen editorin lomakkeen. 
332			if (!$(form_selector + ' form').lenght) {
333				console.log('<form> tägit puuttuu. ' + form_selector);
334				$(form_selector + ' button[type=submit]').on('click', function(e) {
335					console.log("klikkas submittii");
336					e.preventDefault();
337					e.stopPropagation();
338					$(form_selector).trigger('submit');
339					return false;
340				});
341			} else {
342				console.log("<form> tägi löytyy");
343			}
344	    	
345	    	form.data('rigged', true);
346	   	}
347    };
348    
349    var allButtonToggle = function(elem) {
350
351		elem = $(elem);
352
353		// Checkbox ryhmissä togletaan all nappula veke, tai muut veke jos allia klikattu.
354		if (elem.hasClass('btn-checkbox')) {
355			
356			var collection = elem.siblings('.btn-checkbox');
357			
358			var clicked = 0;
359			var allElem = null; // Tämä tai joku sibling
360			
361			collection.each(function() {
362				var $this = $(this);
363				var input = $('input', $this);
364				if (input.is(':checked')) {
365					clicked++;
366					if (input.val() == 'all')
367						all = true;
368				}
369				
370				if (input.val() == 'all')
371					allElem = $this;
372				
373			});
374			
375			// just klikattiin, koska ei löytynyt sisarista
376			if (allElem == null) {
377				allElem = elem;
378				allElem.siblings().each(function() {
379					$(this).removeClass('active').find('input').prop('checked', false);
380				});
381			} else {
382				allElem.removeClass('active').find('input').prop('checked', false);
383			}
384		}
385    };    
386    
387		
388	// Filtteröidään haettuja
389	$('body').on('click', '.search_results .btn-filter', function(e) {
390		
391		var $btn = $(e.target);
392		var container = $btn.closest('.search_results');
393		var groupSelector = '.search-result-item';
394
395		// Ryhmä, jota suodatellaan
396		if ($btn.data('filter') == '') {
397			$(groupSelector, container).parent('div').show();
398		} else {
399			$(groupSelector, container).parent('div').hide();
400			$(groupSelector + $btn.data('filter'), container).parent('div').show();
401		}
402		
403	});
404    
405    // Lomakkeen rendauksen lopussa eventin laukaisu, tai dokument loaded
406    $('body').on('vs_search_form_loaded', formHook);
407    $('document').ready(function(){
408    	
409    	$(form_selector).each(function() {
410    		formHook(null, this);
411
412			// Lauotaan suoraan? 
413			if ($(this).data('submitonload'))
414				$(this).trigger('submit');
415    	});
416    });
417
418
419	// 
420	// Paikannushässäkät
421	// 
422	var reverseGeocode = function(lat,lng, success, fail) {
423		
424		var geocoder = new google.maps.Geocoder();
425		var latlng = new google.maps.LatLng(lat,lng);
426		
427		geocoder.geocode({'latLng': latlng}, function(results, status) {
428	    	if (status == google.maps.GeocoderStatus.OK) {
429	      		if (results[0]) {
430	      			success(results[0]);
431		      	} else {
432		        	fail(null);
433		      	}
434	    	} else {
435		    	fail(status);
436		    }
437	  	});
438	};
439	
440	var geocode = function(address, success, fail) {
441		
442		var geocoder = new google.maps.Geocoder();
443				
444		var locationstring = '-';
445		
446		address = address+',SUOMI';
447		
448		geocoder.geocode({'address': address}, function(results, status) {
449			
450	    	if (status == google.maps.GeocoderStatus.OK) {
451	      		if (results[0]) {
452	      			success(results[0].geometry.location.lat(), results[0].geometry.location.lng());
453		      	} else {
454		        	fail(null);
455		      	}
456	    	} else {
457		    	fail(status);
458		    }
459	  	});
460	};	
461		
462	// Koitetaan etsiä sijainti päätelaitteesta.
463	var getDeviceLocation = function(button, success_callback) {
464		
465		var $button = button && $(button).is('button') ? $(button) : null;
466		
467		// Huom, tarvii modernizerin nääs
468		// @see http://modernizr.com/download/#-fontface-backgroundsize-borderradius-boxshadow-opacity-rgba-textshadow-generatedcontent-csstransforms3d-csstransitions-history-input-inputtypes-geolocation-touch-shiv-mq-cssclasses-teststyles-testprop-testallprops-prefixes-domprefixes-load
469		// jaa https yhteyden... 
470		if (location.protocol == 'https:' && typeof Modernizr != 'undefined' && Modernizr.geolocation) {
471		
472			// Ei saatavilla
473		    if ($button) {
474				$button.button('loading');	
475			}
476			$('#userlocation .glyphicon').addClass('loading');
477			
478		    navigator.geolocation.getCurrentPosition(function(result) {
479		    	
480		    	if ($button) {
481		    		$button.button('reset');
482		    	}
483		    	$('#userlocation .glyphicon').removeClass('loading');
484		    	
485		    	var lat = result.coords.latitude.toFixed(7)
486		    	  , lng = result.coords.longitude.toFixed(7);
487		    	
488				reverseGeocode(lat, lng, function(result) {
489					
490					var address = result.formatted_address;
491					
492					// result.formatted_address antaa kokonaisen osoitteen maineen päivineen.
493					// Näytetään vain katuosoite ja kaupunki
494					address = result.address_components[1].long_name
495							+' '+result.address_components[0].long_name
496							+', '+result.address_components[2].long_name;
497					
498					locationUpdated(lat,lng,address);
499					
500					if (typeof success_callback == 'function')
501						success_callback();
502					
503			    	$.post( vs.ajaxurl, {
504			            lat: lat,
505			            lng: lng,
506			            text: address,
507			            action: 'vs_save_user_location'
508			        }, function(res) {
509			        	//console.log("location saved");
510			        });
511					
512				}, function(status) {
513					var statusText = status || lat+', '+lng;
514
515					locationUpdated(0,0,statusText);
516					
517					$.post( vs.ajaxurl, {
518			            lat: lat,
519			            lng: lng,
520			            text: statusText,
521			            action: 'vs_save_user_location'
522			        }, function(res) {
523			        	//console.log("location saved");
524			        });
525				});
526				
527		    //console.log(coords.latitude, coords.longitude, coords.timestamp);
528		    }, function(err) {
529
530				if ($button) {
531		    		$button.button('reset');
532		    	}	
533		    	$('#userlocation .glyphicon').removeClass('loading');
534
535				// Käyttäjällä on määritelty sijainti! eli ei yliajeta automaattisella refreshillä.
536				if (!$button && vs.user_has_location)
537					return;
538
539		    	if (err.code == 1) { // PERMISSION_DENIED
540		    		statusText = vs.text_PERMISSION_DENIED;
541		    	} else if (err.code == 2) { // POSITION_UNAVAILABLE
542		    		statusText = vs.text_POSITION_UNAVAILABLE;
543		    	} else if (err.code == 3) { // TIMEOUT
544		    		statusText = vs.text_TIMEOUT;
545		    	}
546		    	
547		    	locationUpdated(0,0,statusText);
548		    	
549			    // Ei saatavilla
550			    if ($button) {
551					$button.button('disabled').prop('disabled', true);	
552				}
553		    }, {
554		    	// Sijainti viis minsaa muistissa
555		    	maximumAge: 5 * 60 * 1000,
556		    	
557		    	// pyydetään tarkkaa sijaintia, löyhä sijainti on postinumeron tarkkuudella
558		    	enableHighAccuracy: true
559		   	});
560		} else {
561		    // Ei saatavilla
562		    if ($button) {
563				$button.button('disabled').prop('disabled', true);	
564			}
565		}
566	
567	};
568	
569	var locationByInput = function(button, address, success_callback) {
570		
571		var $button = button && $(button).is('button') ? $(button) : null;
572	    if ($button) {
573			$button.button('loading');	
574		}		
575		$('#userlocation .glyphicon').addClass('loading');
576		
577		var $this = $(this);
578		var address = escapeHtml(address);
579		
580		// Tyhjätään paikka
581		if (address.length < 4) {
582		 	
583			if ($button) {
584	    		$button.button('reset');
585	    	}
586	    	$('#userlocation .glyphicon').removeClass('loading');	
587		    			 	
588		 	$.post( vs.ajaxurl, {
589	            lat: 0,
590	            lng: 0,
591	            text: '',
592	            action: 'vs_save_user_location'
593	        }, function(res) {
594	        	// console.log("location saved");
595	        });
596	        
597			locationUpdated(0,0,'');
598			
599		// Haetaan koordinaatit osoitteella
600		} else {
601
602			geocode(address, function(lat, lng) {
603
604				if ($button) {
605		    		$button.button('reset');
606		    	}				
607		    	$('#userlocation .glyphicon').removeClass('loading');
608				
609				locationUpdated(lat,lng,address);
610		    	
611				if (typeof success_callback == 'function')
612					success_callback();		    	
613		    	
614		    	$.post( vs.ajaxurl, {
615		            lat: lat,
616		            lng: lng,
617		            text: address,
618		            action: 'vs_save_user_location'
619		        }, function(res) {
620		        	// console.log("location saved");
621		        });
622				
623			}, function(status) {
624				var statusText = status || address;
625
626				if ($button) {
627		    		$button.button('reset');
628		    	}	
629		    	$('#userlocation .glyphicon').removeClass('loading');
630		    	
631				if (statusText == 'ZERO_RESULTS') {
632					statusText = vs.text_ZERO_RESULTS;
633				} else {
634					statusText = vs.text_location_error;
635				}
636				
637				locationUpdated(0,0,statusText);
638				
639				$.post( vs.ajaxurl, {
640		            lat: 0,
641		            lng: 0,
642		            text: address,
643		            action: 'vs_save_user_location'
644		        }, function(res) {
645		        	// console.log("location saved");
646		        });
647			});
648		}		
649	};
650	
651	var locationUpdated = function(lat, lng, address) {
652		
653		// Lomake piiloon
654		var the_form = $('form.location').hide();
655		$('#userlocation').show();
656					
657		var uselocationinput = $('input[name=uselocation]');
658		
659		if (address == '') {
660			address = vs.text_location_link;
661		}
662		
663		$('.locationstring').each(function() { $(this).html(address).data('lat', lat).data('lng', lng); });
664
665			
666		$('input[name=location]').val(address);
667		$('input[name=lat]', the_form).val(lat);	
668		$('input[name=lng]', the_form).val(lng);	
669
670		// Hakulomakkeen "hae läheltä"				
671		// nämä on nollat, jos jotain meni mönkään.
672		if (lat && lng) {
673		
674			// Hakulomakkeen paikkarajoitin, ei vaihdeta valintaa, eli 
675			// Tsekataan vain jos ns. uus käyttäjä
676			uselocationinput.prop('disabled', false);
677			if (vs.user_has_location < 30) {
678				uselocationinput.prop('checked', true);
679				uselocationinput.siblings('.locationstring').prepend(vs.text_nearby+' ');
680			}
681			
682			if (typeof(__gaTracker) !== 'undefined') {
683				__gaTracker('send', 'event', 'location', 'set', 'form', address);
684			} 			
685			
686		} else {
687			$('input[name=location]').val('');	
688			uselocationinput.prop('disabled', true).prop('checked', false);
689			
690			uselocationinput.siblings('.locationstring').html(vs.text_uselocation_checkbox);
691		}
692		
693	};
694	
695	var redirectToNearbyPage = function() {
696					
697		// Lähetetään sijaintilomake, pitäis mennä "Lähellä" -sivulle
698		$('form.location').trigger('submit');
699	};
700	
701 
702 	$('body').on('click', 'form.location #geocode', function() {
703 		locationByInput(this, $('form.location input[name=location]').val(), redirectToNearbyPage);
704 		return false;
705 	});
706	$('body').on('click', 'form.location .my-location', function(e) {
707		getDeviceLocation($(this), redirectToNearbyPage);
708		return false;
709	});
710	
711	// Mobiililla kysytään suoraan paikannusta, jos edellinen tieto yli 5min vanha
712	if (Number(vs.autolocate_user) && (!vs.user_has_location || vs.user_has_location > 60 * 5 )) {
713		getDeviceLocation();
714	}
715	
716	
717	// Hakulomakkeelle koordinaatit, jos hateaan tekstikentällä eikä käyttäjän
718	// sijainnilla
719	// TODO tätä ei vielä korjatttu wpbakery. T 19.4.2024 
720	$('body').on('blur', 'form.search input[name=address]', function() {
721		var $this = $(this);
722		var address = $this.val();
723		var $latlong = $this.closest('form').find('input[name=latlong]');
724		
725		$this.closest('.form-group').removeClass('has-success has-error');
726		
727		if (!$latlong.length)
728			return false;
729	
730		$latlong.val('');
731	
732		if (address.length > 4) {
733
734			var placeholder = $latlong.attr('placeholder');
735			$latlong.attr('placeholder', 'Haetaan...');
736			
737			geocode(address, 
738				function(lat, lng) {
739					// 7 desimaalia. Suomen koordinaateissa 2 kokonaisnumeroa nääs
740					$latlong.val(lat.toPrecision(9)+','+lng.toPrecision(9));
741					$latlong.attr('placeholder', placeholder);
742					
743					$this.closest('.form-group').addClass('has-success');
744				}, function (status) {
745					$latlong.attr('placeholder', 'ei löytynyt');
746					$this.closest('.form-group').addClass('has-error');
747				}
748			);
749		} 
750		
751		return false;
752	});
753	var getCoordinates = function(address) {
754		var address = escapeHtml(address);
755		
756		geocode(address, 
757			function(lat, lng) {
758				callback(lat, lng, address);
759			},function(status){
760				callback(null, null, status);
761			});
762	};	
763	
764	
765
766	
767})(jQuery);
768
769/**
770 * Datepickeri käyntiin, from ja to hakukentille etupuolen suodatuslomakkeelle.
771 */
772function init_datepicker(the_form) {
773	
774	var $ = jQuery;
775	
776	the_form = the_form ? $(the_form) : $('form.search');
777	
778	// Pickadate.js.
779	// http://amsul.ca/pickadate.js/date.htm
780	if (typeof $.fn.pickadate == 'function') {
781		
782		
783		// Kieliversiointi. @see functions.php localize script 
784		// Koodit mukana pickadate.js paketissa.
785		if (typeof vs.locale != 'undefined') {
786		
787			if (vs.locale == 'fi_FI' || vs.locale == 'fi') {
788				jQuery.extend( jQuery.fn.pickadate.defaults, {
789				    monthsFull: [ 'tammikuu', 'helmikuu', 'maaliskuu', 'huhtikuu', 'toukokuu', 'kesäkuu', 'heinäkuu', 'elokuu', 'syyskuu', 'lokakuu', 'marraskuu', 'joulukuu' ],
790				    monthsShort: [ 'tammi', 'helmi', 'maalis', 'huhti', 'touko', 'kesä', 'heinä', 'elo', 'syys', 'loka', 'marras', 'joulu' ],
791				    weekdaysFull: [ 'sunnuntai', 'maanantai', 'tiistai', 'keskiviikko', 'torstai', 'perjantai', 'lauantai' ],
792				    weekdaysShort: [ 'su', 'ma', 'ti', 'ke', 'to', 'pe', 'la' ],
793				    today: 'tänään',
794				    clear: 'tyhjennä',
795				    firstDay: 1,
796				});
797			} else if (vs.locale == 'ru_RU' || vs.locale == 'ru') {
798				jQuery.extend( jQuery.fn.pickadate.defaults, {
799				    monthsFull: [ 'Января', 'Февраля', 'Марта', 'Апреля', 'Мая', 'Июня', 'Июля', 'Августа', 'Сентября', 'Октября', 'Ноября', 'Декабря' ],
800				    monthsShort: [ 'Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек' ],
801				    weekdaysFull: [ 'воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота' ],
802				    weekdaysShort: [ 'вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб' ],
803				    today: 'сегодня',
804				    clear: 'удалить',
805				    firstDay: 1,
806				    format: 'd mmmm yyyy г.',
807				    formatSubmit: 'd.m.yyyy'
808				});				
809			}
810		}	
811		
812		the_form.each(function() {
813			
814			let $this = $(this);
815			if (!$('.fromDateInput', $this).length)
816				return;
817			
818			// On jo 
819			if ($this.data('datepicker'))
820				return;
821			else
822				$this.data('datepicker', true);
823			
824			//var formid = $this.data('formid') || 1;
825			var from_picker = $('.fromDateInput', $this).pickadate({
826				    format: 'd.m.yyyy',
827		    		hiddenName: true
828		    	}),
829			    from_picker = from_picker.pickadate('picker');
830			
831			var to_picker = $('.toDateInput', $this).pickadate({
832				    format: 'd.m.yyyy',
833		    		hiddenName: true
834		    	}),
835			    to_picker = to_picker.pickadate('picker');
836			
837			
838			// Check if there’s a “from” or “to” date to start with.
839			if ( from_picker.get('value') ) {
840			  	to_picker.set('min', from_picker.get('select'));
841			}
842			if ( to_picker.get('value') ) {
843			  	from_picker.set('max', to_picker.get('select'));
844			}
845			
846			// When something is selected, update the “from” and “to” limits.
847			from_picker.on('set', function(event) {
848			  if ( event.select ) {
849			  		to_picker.set('min', from_picker.get('select'));  
850			  }
851			  else if ( 'clear' in event ) {
852			  		to_picker.set('min', false);
853			  }
854			});
855			to_picker.on('set', function(event) {
856			  if ( event.select ) {
857			  		from_picker.set('max', to_picker.get('select'));
858			  }
859			  else if ( 'clear' in event ) {
860			  		from_picker.set('max', false);
861			  }
862			});			
863		});
864		
865
866	}
867
868}
869
870

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.