PageSourceSearch

https://www.auto-trail.co.uk/wp-content/themes/autotrail/resources/js/map.js?v=1791077647

js auto-trail.co.uk collected 2026-10-04 04:24:40 UTC 21,403 bytes, 610 lines download raw bytes

1let map,
2    service,
3    infowindow,
4    usrLocationBtn = document.getElementById('getUserLocation'),
5    locationField = document.getElementById('mapUserLocation'),
6    accordionContainer = document.getElementById('dealershipDetails'),
7    mapUserDistance = document.getElementById('mapUserDistance'),
8    button = document.getElementById('mapUserSubmitButton'),
9    markers = [],
10    usrMarkers = [];
11
12function initMap() {
13    // Don't initialize if no map div exists
14    if (!document.getElementById('map')) {
15        if (typeof initDealerFinderMap === 'function') {
16            initDealerFinderMap();
17        }
18        return;
19    }
20
21    let AT = {lat: 53.8711559431357, lng: -2.5754641874521125};
22
23    infowindow = new google.maps.InfoWindow();
24
25    map = new google.maps.Map(document.getElementById('map'), {
26        zoom: 12,
27        center: AT,
28        disableDefaultUI: true,
29        mapId: 'map_id'
30    });
31}
32
33function updateMap(response) {
34    clearMarkers(markers);
35
36    // Get the user's location from the input fields
37    let locationInput = document.getElementById('mapUserLocation');
38
39    if (locationInput && locationInput.value.trim()) {
40        let location = locationInput.value.trim();
41        let userDistanceInput = document.getElementById('mapUserDistance');
42        let userDistance = userDistanceInput ? userDistanceInput.value : '';
43
44        // Use Geocoding API to get coordinates for the user's entered location
45        var geocoder = new google.maps.Geocoder();
46
47        geocoder.geocode({address: location}, function (results, status) {
48            if (status === 'OK' && results.length > 0) {
49                var location = results[0].geometry.location,
50                    usrLat = location.lat(),
51                    usrLng = location.lng();
52
53                // Add user location marker
54                addUserLocationMarker(usrLat, usrLng);
55
56                // Handle the dealerships with distance filtering
57                if (userDistance && userDistance !== '') {
58                    handleDealerships(response, usrLat, usrLng, parseInt(userDistance));
59                } else {
60                    // No distance filter, show all
61                    addAllMarkers(response);
62                }
63
64            } else {
65                // If geocoding fails, add all markers without distance check
66                addAllMarkers(response);
67            }
68        });
69    } else {
70        // No location entered, show all markers
71        addAllMarkers(response);
72    }
73}
74
75function handleDealerships(dealerships, usrLat, usrLng, userDistance) {
76    // Clear existing markers and accordions
77    clearMarkers(markers);
78    clearAccordions();
79    
80    let usrRange = document.getElementById('usrRange') ? document.getElementById('usrRange').value : null;
81    let filteredDealerships = [];
82
83    for (var i = 0; i < dealerships.length; i++) {
84        let dealership = dealerships[i],
85            lat = parseFloat(dealership.latitude),
86            lng = parseFloat(dealership.longitude);
87
88        // Check if latitude and longitude are valid numbers
89        if (!isNaN(lat) && !isNaN(lng)) {
90            var distanceInMiles = calculateDistance(usrLat, usrLng, lat, lng);
91
92            // Check distance filter
93            let withinDistance = userDistance === 0 || distanceInMiles <= userDistance;
94
95            if (withinDistance) {
96                // Check range filter if applicable
97                if (usrRange && usrRange !== '') {
98                    let campervans = dealership.campervans || [];
99                    let motorhomes = dealership.motorhomes || [];
100                    
101                    let hasRange = campervans.some(campervan => campervan.slug === usrRange) || 
102                                  motorhomes.some(motorhome => motorhome.slug === usrRange);
103                    
104                    if (hasRange) {
105                        filteredDealerships.push(dealership);
106                        addMarkerToMap(lat, lng, dealership);
107                        updateAccordions(dealership);
108                    }
109                } else {
110                    // No range filter, add all within distance
111                    filteredDealerships.push(dealership);
112                    addMarkerToMap(lat, lng, dealership);
113                    updateAccordions(dealership);
114                }
115            }
116        }
117    }
118
119    // Set appropriate zoom level based on results
120    if (filteredDealerships.length > 0) {
121        if (userDistance <= 50) {
122            map.setZoom(8);
123        } else {
124            map.setZoom(6);
125        }
126        
127        // Show results heading
128        let resultsHeading = document.getElementById('searchResultsHeading');
129        if (resultsHeading) {
130            resultsHeading.style.display = 'block';
131        }
132    } else {
133        displayErrorMessage("No results were found.", "mapAccordions");
134    }
135}
136
137function displayErrorMessage(message, wrapperId) {
138    let errorMessage = `<p class="text-center w-full text-2.5xl md:text-3.5xl font-semibold">${message}</p>`;
139    let accordionWrapper = document.getElementById(wrapperId);
140
141    if (accordionWrapper) {
142        accordionWrapper.innerHTML = errorMessage; // Replace content instead of append
143        accordionWrapper.style.display = 'block';
144        
145        // Show results heading even for error
146        let resultsHeading = document.getElementById('searchResultsHeading');
147        if (resultsHeading) {
148            resultsHeading.style.display = 'block';
149        }
150    } else {
151        console.error("Wrapper element not found with the provided ID:", wrapperId);
152    }
153}
154
155function addAllMarkers(dealerships) {
156    clearMarkers(markers);
157    clearAccordions();
158    
159    for (var i = 0; i < dealerships.length; i++) {
160        var dealership = dealerships[i];
161        var lat = parseFloat(dealership.latitude);
162        var lng = parseFloat(dealership.longitude);
163
164        if (dealership && !isNaN(lat) && !isNaN(lng)) {
165            addMarkerToMap(lat, lng, dealership);
166            updateAccordions(dealership);
167        }
168    }
169    
170    map.setZoom(5);
171    
172    // Show results heading
173    let resultsHeading = document.getElementById('searchResultsHeading');
174    if (resultsHeading) {
175        resultsHeading.style.display = 'block';
176    }
177}
178
179function addMarkerToMap(latitude, longitude, dealership) {
180    var marker = new google.maps.marker.AdvancedMarkerElement({
181        position: {lat: latitude, lng: longitude},
182        map: map,
183        title: dealership.title,
184    });
185
186    var content = '<div><h2>' + dealership.title + '</h2><p>' + dealership.address + '</p></div>';
187
188    var infoWindow = new google.maps.InfoWindow({
189        content: content
190    });
191
192    marker.addListener('click', function () {
193        infoWindow.setContent(content);
194        infoWindow.open(map, marker);
195    });
196
197    markers.push(marker);
198}
199
200function geocodeLocation() {
201    let locationInput = document.getElementById('mapUserLocation');
202
203    if (locationInput && locationInput.value.trim()) {
204        let location = locationInput.value.trim();
205
206        // Use Geocoding API to get coordinates for the user's entered location
207        var geocoder = new google.maps.Geocoder();
208
209        geocoder.geocode({address: location}, function (results, status) {
210            if (status === 'OK' && results.length > 0) {
211                var location = results[0].geometry.location;
212                var lat = location.lat();
213                var lng = location.lng();
214
215                // Add a marker for the user's entered location
216                addUserLocationMarker(lat, lng);
217            } else {
218                console.log('Geocoding failed. Status:', status);
219            }
220        });
221    }
222}
223
224function reverseGeocode(usrLat, usrLng) {
225    const geocoder = new google.maps.Geocoder(),
226        latlng = new google.maps.LatLng(usrLat, usrLng);
227
228    geocoder.geocode({'latLng': latlng}, function (results, status) {
229        if (status === google.maps.GeocoderStatus.OK) {
230            if (results[0]) {
231                const addressComponents = results[0].address_components;
232
233                for (let i = 0; i < addressComponents.length; i++) {
234                    const types = addressComponents[i].types;
235
236                    if (types.includes('postal_code')) {
237                        locationField.value = addressComponents[i].long_name;
238                        locationField.setAttribute('value', addressComponents[i].long_name);
239                        break;
240                    }
241                }
242            } else {
243                console.error('No results found');
244            }
245        } else {
246            console.error(`Geocoder failed: ${status}`);
247        }
248    });
249}
250
251function glSuccess(position) {
252    const usrLat = position.coords.latitude,
253        usrLng = position.coords.longitude;
254
255    reverseGeocode(usrLat, usrLng);
256    addUserLocationMarker(usrLat, usrLng);
257}
258
259function glError(error) {
260    console.error(`Error getting geolocation: ${error.message}`);
261}
262
263function moveToLocation(lat, lng) {
264    const center = new google.maps.LatLng(lat, lng);
265    map.panTo(center);
266}
267
268function addUserLocationMarker(lat, lng) {
269    clearMarkers(usrMarkers);
270
271    let iconElement = document.createElement('div');
272    iconElement.innerHTML = '<img src="/wp-content/themes/autotrail/images/usr-location.svg" alt="User Location" style="width: 32px; height: 32px;">';
273
274    var userMarker = new google.maps.marker.AdvancedMarkerElement({
275        position: {lat: lat, lng: lng},
276        title: 'Your location',
277        content: iconElement,
278    });
279
280    userMarker.map = map;
281    moveToLocation(lat, lng);
282    usrMarkers.push(userMarker);
283}
284
285function clearMarkers(markersArray) {
286    for (var i = 0; i < markersArray.length; i++) {
287        markersArray[i].setMap(null);
288    }
289
290    if (markers === markersArray) {
291        markers = [];
292    } else if (usrMarkers === markersArray) {
293        usrMarkers = [];
294    }
295}
296
297function clearAccordions() {
298    let accordionsContainer = document.getElementById('mapAccordions');
299    let resultsHeading = document.getElementById('searchResultsHeading');
300    
301    if (accordionsContainer) {
302        accordionsContainer.innerHTML = '';
303        accordionsContainer.style.display = 'none';
304    }
305    
306    if (resultsHeading) {
307        resultsHeading.style.display = 'none';
308    }
309}
310
311function updateAccordions(dealership) {
312   let accordionsContainer = document.getElementById("mapAccordions"),
313        resultsHeading = document.getElementById("searchResultsHeading");
314
315    if (!accordionsContainer || !resultsHeading) return;
316    let facilitiesList = "",
317        servicesList = "",
318        modelsList = "",
319        rangeList = "";
320    if (dealership.facilities) {
321        facilitiesList = '<p class="font-semibold text-lg">Facilities</p><ul>';
322        for (let i = 0; i < dealership.facilities.length; i++) {
323            facilitiesList += "<li>" + dealership.facilities[i].facility + "</li>"
324        }
325        facilitiesList += "</ul>"
326    }
327    if (dealership.services) {
328        servicesList = '<p class="font-semibold text-lg">Services</p><ul>';
329        for (let i = 0; i < dealership.services.length; i++) {
330            servicesList += "<li>" + dealership.services[i].service + "</li>"
331        }
332        servicesList += "</ul>"
333    }
334    if (dealership.models && dealership.models.length > 0) {
335        modelsList = '<p class="font-semibold text-lg">Models in stock</p><ul>';
336        for (let i = 0; i < dealership.models.length; i++) {
337            modelsList += "<li>" + dealership.models[i].label + "</li>";
338        }
339        modelsList += "</ul>";
340    }
341    
342    if (dealership.campervans || dealership.motorhomes) {
343        rangeList = '<p class="font-semibold text-lg king">Models in stock</p><ul>';
344        for (let i = 0; i < dealership.campervans.length; i++) {
345            rangeList += "<li>" + dealership.campervans[i].name + "</li>"
346        }
347        for (let i = 0; i < dealership.motorhomes.length; i++) {
348            rangeList += "<li>" + dealership.motorhomes[i].name + "</li>"
349        }
350        rangeList += "</ul>"
351    }
352    let accordionHTML = `<div class="accordion-wrapper">
353        <a class="accordion-header" href="#" role="button">
354            <h3 class="text-2xl">` + dealership.title + `</h3>
355        </a>
356        
357        <div class="accordion-content accordion-panel hidden">
358            <div class="content-wrap">`;
359    if (dealership.facilities || dealership.services) {
360        if (dealership.address || dealership.phone) {
361            accordionHTML += '<div class="contact-wrap">';
362            if (dealership.address) {
363                accordionHTML += '<div class="column">';
364                accordionHTML += '<address class="with-location-marker-icon-before">' + dealership.address + "</address>";
365                accordionHTML += "</div>"
366            }
367            if (dealership.phone) {
368                accordionHTML += '<div class="column">';
369                accordionHTML += '<a class="phone relative with-telephone-icon-before" href="tel:' + dealership.phone + '">' + dealership.phone + "</a>";
370                accordionHTML += "</div>"
371            }
372            accordionHTML += "</div>"
373        }
374        if (dealership.facilities) {
375            accordionHTML += '<div class="column content-with-list-style-ticks-small">';
376            accordionHTML += facilitiesList;
377            accordionHTML += "</div>"
378        }
379        if (dealership.services) {
380            accordionHTML += '<div class="column content-with-list-style-ticks-small">';
381            accordionHTML += servicesList;
382            accordionHTML += "</div>"
383        }
384    }
385    if (dealership.models && dealership.models.length > 0) {
386        accordionHTML += '<div class="column content-with-list-style-ticks-small">';
387        accordionHTML += modelsList;
388        accordionHTML += "</div>"
389    }
390    if (dealership.campervans || dealership.motorhomes) {
391        accordionHTML += '<div class="column content-with-list-style-ticks-small">';
392        accordionHTML += rangeList;
393        accordionHTML += "</div>"
394    }
395    if (!dealership.services && !dealership.facilities) {
396        if (dealership.address || dealership.phone) {
397            accordionHTML += '<div class="column">';
398            if (dealership.address) {
399                accordionHTML += '<address class="relative with-location-marker-icon-before">' + dealership.address + "</address>"
400            }
401            if (dealership.phone) {
402                accordionHTML += '<a class="phone relative with-telephone-icon-before" href="tel:' + dealership.phone + '">' + dealership.phone + "</a>"
403            }
404            accordionHTML += "</div>"
405        }
406    }
407    if (dealership.url || dealership.email) {
408        accordionHTML += `<div class="button-wrap">`;
409        if (dealership.url) {
410            let websiteURL = dealership.url.startsWith("http://") || dealership.url.startsWith("https://") ? dealership.url : "//" + dealership.url;
411            accordionHTML += `<a class="button" href="${websiteURL}" target="_blank">
412            <span class="button-text">Visit website</span>
413            <span class="with-chevron bg-brand-2"></span>
414        </a>`
415        }
416        if (dealership.email) {
417            accordionHTML += `<button class="enquire-now-button" data-sender-email="${dealership.email}">
418                <span class="button-text">Enquire now</span>
419                <span class="with-chevron bg-brand-2"></span>
420            </button>`
421        }
422        accordionHTML += `</div>`
423    }
424    accordionHTML += `</div>
425        </div>
426    </div>`;
427    if (dealership === false) {
428        accordionHTML = "no dealerships"
429    }
430   if (!accordionsContainer) return;
431
432accordionsContainer.innerHTML += accordionHTML;
433    accordionsContainer.setAttribute("style", "");
434    resultsHeading.setAttribute("style", "")
435}
436
437// Initialize map
438let mapDiv = document.getElementById('map');
439
440if (mapDiv) {
441    window.initMap = initMap;
442} else {
443    window.initMap = function () {
444        return undefined;
445    };
446}
447
448window.addEventListener('load', function () {
449    if (typeof google !== 'undefined' && google.maps && typeof initMap === 'function') {
450        initMap();
451    }
452});
453
454if (usrLocationBtn) {
455    usrLocationBtn.addEventListener('click', function (e) {
456        e.preventDefault();
457        clearMarkers(usrMarkers);
458        if (navigator.geolocation) {
459            navigator.geolocation.getCurrentPosition(glSuccess, glError);
460        } else {
461            console.error('Geolocation is not supported in this browser.');
462        }
463    });
464}
465
466// jQuery section
467(function ($) {
468    $(document).ready(function () {
469        let $html = $('html');
470        let $body = $('body');
471        let $enquiryFormModal = $('#enquiry-form-modal');
472
473        function loadMapData() {
474            let $form = $('.map-form form');
475            var formData = $form.serialize();
476            
477            let postType,
478                formIDToQuery = $form.attr('id');
479
480            if (formIDToQuery === 'find-a-dealer') {
481                postType = 'dealerships';
482            } else if (formIDToQuery === 'find-a-workshop') {
483                postType = 'workshops';
484            } else if (formIDToQuery === 'find-a-hire-partner') {
485                postType = 'hire';
486            }
487
488            $.ajax({
489                url: ajax_maps_object.ajax_url,
490                type: 'post',
491                data: {
492                    action: 'get_dealerships',
493                    form_data: formData,
494                    post_type: postType
495                },
496                beforeSend: function () {
497                    $('#loading-spinner-modal').show().addClass('fade-in-faster');
498                },
499                success: function (response) {
500                    $('#loading-spinner-modal').hide();
501                    updateMap(response);
502                },
503                error: function(xhr, status, error) {
504                    console.error('AJAX Error:', error);
505                    $('#loading-spinner-modal').hide();
506                }
507            });
508        }
509
510        function submitForm(formId, postType) {
511            $(formId).submit(function (e) {
512                e.preventDefault();
513                loadMapData();
514            });
515        }
516
517        // Load initial data on page load
518        $(window).load(function() {
519            // Small delay to ensure everything is initialized
520            setTimeout(function() {
521                loadMapData();
522            }, 500);
523        });
524
525        submitForm('#find-a-dealer', 'dealerships');
526        submitForm('#find-a-workshop', 'workshops');
527        submitForm('#find-a-hire-partner', 'hire');
528
529        // Modal handlers
530        $body.on("click", ".enquire-now-button", function (e) {
531            let enquiryAddress = $(this).closest('.accordion-content').find('address').text();
532            let enquirySenderEmail = $(this).data('sender-email');
533            e.preventDefault();
534            $('#enquiry-form-dealer-name').text(enquiryAddress);
535            $('.enquiry-form #sender-email').val(enquirySenderEmail);
536            $html.addClass('modal-open');
537            $enquiryFormModal.show();
538            $enquiryFormModal.find('.contact-form-block').removeClass('hidden').addClass('fade-in-fast');
539        });
540        
541        $body.on("click", "#enquiry-form-close-button", function (e) {
542            e.preventDefault();
543            $html.removeClass('modal-open');
544            $enquiryFormModal.find('.contact-form-block').addClass('hidden').removeClass('fade-in-fast');
545            $enquiryFormModal.hide();
546        });
547
548        // Enter key handlers
549        $('#mapUserLocation, #mapUserDistance').on('keydown', function(event) {
550            if (event.key === 'Enter' && !$('#mapUserSubmitButton').parent().hasClass('disabled')) {
551                submitNearestForm($(this));
552            }
553        });
554
555        function submitNearestForm($element) {
556            let $form = $element.closest('form');
557            if ($form.length > 0) {
558                $form.submit();
559            } else {
560                console.error("Form element not found for input:", $element.attr('id'));
561            }
562        }
563    });
564})(jQuery);
565
566// Utility functions
567function calculateDistance(lat1, lon1, lat2, lon2) {
568    var R = 3959; // Radius of the Earth in miles
569    var dLat = toRadians(lat2 - lat1);
570    var dLon = toRadians(lon2 - lon1);
571    var a =
572        Math.sin(dLat / 2) * Math.sin(dLat / 2) +
573        Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
574        Math.sin(dLon / 2) * Math.sin(dLon / 2);
575    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
576    var distance = R * c;
577    return distance;
578}
579
580function toRadians(degrees) {
581    return degrees * Math.PI / 180;
582}
583document.addEventListener('click', function(e) {
584
585    const btn = e.target.closest('.select-dealer-btn');
586    if (!btn) return;
587
588    const card = btn.closest('.dealer-card');
589    if (!card) return;
590
591    const dropdown = card.querySelector('.dealer-dropdown');
592    if (!dropdown) return;
593
594    // 🔴 If dropdown is OPEN → CLOSE it
595    if (dropdown.style.display !== 'none') {
596        dropdown.style.display = 'none';
597        return;
598    }
599
600    // 🟢 Otherwise OPEN it
601
602    // close all first
603    document.querySelectorAll('.dealer-dropdown').forEach(d => {
604        d.style.display = 'none';
605    });
606
607    // open current
608    dropdown.style.display = 'flex';
609
610});

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.