1const activeColorClass = 'active'; 2 3if (typeof hideClass !== 'undefined') { 4 const hideClass = 'd-none'; 5} else { 6 hideClass = 'd-none'; 7} 8 9const openedClass = 'opened'; 10const searchInput = document.querySelector('form input[name$="[filterSearch]"]'); 11const groupSelect = document.querySelector('.fulltitle-text-button-input select.group-select'); 12const formatSelect = document.querySelector('.fulltitle-text-button-input select.format-select'); 13const typeSelect = document.querySelector('.reference-select select.type-select'); 14const productTypeSelect = document.querySelector('.reference-select select.product-type-select'); 15const citySelect = document.querySelector('.reference-select select.city-select'); 16const sortSelect = document.querySelector('.reference-select select.sort-select'); 17const colorElements = document.querySelectorAll('.color-select .farb-kachel[data-id]'); 18const objectAssortmentElement = document.querySelector('.produkt-filter .object-sorting input[type="checkbox"]'); 19const displayModeButtonElements = document.querySelectorAll('.choose-button button'); 20const formElement = document.querySelectorAll('form[name="filter"]')[0]; 21const hiddenColorInput = document.querySelector('form input[name$="[filterColor]"]'); 22const hiddenObjectAssortmentInput = document.querySelector('form input[name="tx_hagemeisterproducts_list[filterShowObjectAssortment]"]'); 23const hiddenDisplayModeInput = document.querySelector('form input[name$="[displayMode]"]'); 24const loadMoreElements = document.querySelectorAll('.load-more'); 25const mapContainerElement = document.querySelector('.map'); 26const mapElement = document.getElementById('map'); 27const mapLoadingElement = document.querySelector('.map-loading'); 28const autocompleteElement = document.querySelector('.search-filters input[name="city"]'); 29const countrySelectElement = document.querySelector('.search-filters select[name="country"]'); 30const radiusSelectElement = document.querySelector('.search-filters select[name="radius"]'); 31const searchSubmitElement = document.querySelector('.search-filters .location-search-submit'); 32const mapOverlayElement = document.querySelector('.map-overlay'); 33const mapOverlayCloseElement = document.querySelector('.map-overlay .close'); 34const locationTitleElement = document.querySelector('.map-overlay .location-title'); 35const locationAddressElement = document.querySelector('.map-overlay .location-address'); 36const locationUrlElement = document.querySelector('.map-overlay .location-url'); 37const locationDirectionsElement = document.querySelector('.map-overlay .location-directions'); 38const locationImageElement = document.querySelector('.map-overlay .location-image'); 39 40let locationXhr = null; 41let displayMode = 'grid'; 42let mapInitialized = false; 43let markerUrl = null; 44let markerHoverUrl = null; 45let map = null; 46let markers = []; 47let markerClustererInstance = null; 48let autocomplete = null; 49let geocoder = null; 50let componentRestrictions = null; 51let latLng = null; 52let radius = null; 53let country = null; 54 55// Check for product-type GET parameter and pre-select the filter 56const urlParams = new URLSearchParams(window.location.search); 57const productTypeParam = urlParams.get('product-type'); 58if (productTypeParam && productTypeSelect) { 59 productTypeSelect.value = productTypeParam; 60 // Auto-submit the form 61 setTimeout(() => search(), 100); 62} 63 64for (let i = 0; i < colorElements.length; i++) { 65 colorElements[i].addEventListener('click', toggleActive); 66} 67 68for (let i = 0; i < displayModeButtonElements.length; i++) { 69 displayModeButtonElements[i].addEventListener('click', updateDisplayMode); 70 71 if (displayModeButtonElements[i].classList.contains(activeColorClass)) { 72 displayMode = i; 73 } 74} 75 76for (let i = 0; i < loadMoreElements.length; i++) { 77 loadMoreElements[i].addEventListener('click', loadMore); 78} 79 80if (objectAssortmentElement) objectAssortmentElement.addEventListener('click', toggleObjectAssortment); 81if (groupSelect) groupSelect.addEventListener('change', search); 82if (formatSelect) formatSelect.addEventListener('change', search); 83if (typeSelect) typeSelect.addEventListener('change', search); 84if (productTypeSelect) productTypeSelect.addEventListener('change', search); 85if (citySelect) citySelect.addEventListener('change', search); 86if (sortSelect) sortSelect.addEventListener('change', search); 87if (countrySelectElement) countrySelectElement.addEventListener('change', updateCountry); 88if (radiusSelectElement) radiusSelectElement.addEventListener('change', updateRadius); 89if (mapOverlayCloseElement) mapOverlayCloseElement.addEventListener('click', hideMapOverlay); 90 91if (mapElement !== null) { 92 window.addEventListener('CookiebotOnAccept', function (e) { 93 if (Cookiebot.consent.marketing && Cookiebot.consent.statistics) 94 { 95 initializeMapLoading(); 96 } 97 }, false); 98 } 99 100 101function toggleActive(e) { 102 e.preventDefault(); 103 104 let target = e.target.classList.contains('farb-kachel') ? e.target : e.target.closest('.farb-kachel'); 105 const activeColorElement = document.querySelector('.color-select .farb-kachel.' + activeColorClass + '[data-id]'); 106 107 if (activeColorElement !== null && activeColorElement !== target) { 108 activeColorElement.classList.remove(activeColorClass); 109 } 110 111 if (target.classList.contains(activeColorClass)) { 112 target.classList.remove(activeColorClass); 113 hiddenColorInput.value = ''; // Reset value when deselecting 114 } else { 115 target.classList.add(activeColorClass); 116 hiddenColorInput.value = target.dataset.id; 117 } 118 119 search(); 120 121 return false;
122} 123 124function updateDisplayMode() { 125 if (this.classList.contains('liste') || this.classList.contains('karte')) { 126 displayMode = 1; 127 128 if (this.classList.contains('karte')) { 129 initializeMapLoading(); 130 mapContainerElement.classList.remove(hideClass); 131 } else if (mapContainerElement !== null) { 132 mapContainerElement.classList.add(hideClass); 133 } 134 } else { 135 displayMode = 0; 136 137 if (mapContainerElement !== null) { 138 mapContainerElement.classList.add(hideClass); 139 } 140 } 141 142 hiddenDisplayModeInput.value = displayMode; 143} 144 145function updateCountry(e) { 146 const $checkedOption = this.querySelector(':checked'); 147 const selectedCountry = $checkedOption.value; 148 const mapLat = parseFloat($checkedOption.dataset.lat); 149 const mapLng = parseFloat($checkedOption.dataset.lng); 150 const mapZoom = parseInt($checkedOption.dataset.zoom); 151 152 if (selectedCountry) { 153 country = selectedCountry; 154 componentRestrictions = {country: selectedCountry}; 155 156 if (autocomplete !== null) { 157 autocomplete.setComponentRestrictions(componentRestrictions); 158 } 159 } 160 161 if (map && !isNaN(mapLat) && !isNaN(mapLng) && !isNaN(mapZoom)) { 162 const position = { 163 lat: mapLat, 164 lng: mapLng 165 }; 166 167 map.setCenter(position); 168 map.setZoom(mapZoom); 169 } 170} 171 172function updateRadius(e) { 173 radius = parseInt(this.querySelector(':checked').value); 174 175 if (!isNaN(radius)) { 176 getLocations(); 177 } 178} 179 180function toggleObjectAssortment(e) { 181 hiddenObjectAssortmentInput.value = e.target.checked ? 1 : 0; 182 183 search(); 184} 185 186function search() { 187 formElement.submit(); 188 189 // @TODO: use proper typeNum and evaluate response, AJAX 190 // xhr.open('POST', window.location.pathname + '?type=321'); 191 // xhr.setRequestHeader('Content-Type', 'application/json'); 192 // xhr.send(JSON.stringify(data)); 193} 194 195function loadMore() { 196 this.classList.add('loading'); 197 let typeNum, prefix; 198 199 if (this.dataset.type === 'product') { 200 typeNum = 1651492839; 201 prefix = 'tx_hagemeisterproducts_list'; 202 } else { 203 typeNum = 1651751731; 204 prefix = 'tx_hagemeisterproducts_referenceslist'; 205 } 206 207 let formData = new FormData(formElement);
208 const loadMoreWrapper = this.parentElement; 209 const container = loadMoreWrapper.parentElement; 210 211 formData.append(prefix + '[offset]', this.dataset.offset); 212 formData.append(prefix + '[ajax]', '1'); 213 214 let xhr = new XMLHttpRequest(); 215 xhr.open('POST', window.location.pathname + '?type=' + typeNum); 216 217 xhr.onreadystatechange = function () { 218 if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { 219 const template = document.createElement('template'); 220 template.innerHTML = this.response.replace(/(\r\n|\n|\r|\t|\s\s)/gm, '').trim(); // remove line breaks, tabs and multiple whitespaces 221 222 for (let i = template.content.children.length - 1; i >= 0; i--) { 223 loadMoreWrapper.after(template.content.children[i]); 224 const loadMoreElements = container.querySelectorAll('.load-more'); 225 226 if (loadMoreElements.length > 1) { 227 loadMoreElements[loadMoreElements.length - 1].addEventListener('click', loadMore); 228 } 229 } 230 231 loadMoreWrapper.remove(); 232 233 if (typeof window.registerSpecialRequestHandler === 'function') { 234 window.registerSpecialRequestHandler(); 235 } 236 } 237 } 238 239 xhr.send(formData); 240} 241 242function initializeMapLoading() { 243 if (mapElement === null || mapInitialized || displayMode !== 1) { 244 return; 245 } 246 247 markerUrl = mapElement.dataset.marker; 248 markerHoverUrl = mapElement.dataset.markerHover; 249 if (!Cookiebot.consent.marketing || !Cookiebot.consent.statistics) { 250 console.log('Cookies must be accepted before loading maps.'); 251 return; 252 } 253 254 mapInitialized = true; 255 256 const apiKey = mapElement.dataset.key; 257 const script = document.createElement('script'); 258 script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places&callback=initMap`; 259 script.async = true; 260 261 window.initMap = function () { 262 map = new google.maps.Map(mapElement, { 263 center: { 264 lat: parseFloat(mapElement.dataset.latitude), 265 lng: parseFloat(mapElement.dataset.longitude) 266 }, 267 zoom: parseInt(mapElement.dataset.zoom) 268 }); 269 270 const options = { 271 fields: ['geometry'], 272 types: ['(regions)'] 273 }; 274 275 autocomplete = new google.maps.places.Autocomplete(autocompleteElement, options); 276 geocoder = new google.maps.Geocoder(); 277 278 autocomplete.addListener('place_changed', () => { 279 const place = autocomplete.getPlace(); 280 281 if (!place.geometry || !place.geometry.location) { 282 console.log(`No details available for input: ${place.name}`); 283 return; 284 } 285 286 latLng = place.geometry.location; 287 getLocations(); 288 }); 289 290 autocompleteElement.addEventListener('keyup', function (e) { 291 if (e.keyCode === 13) { 292 e.stopPropagation(); 293 geocodeSearch(); 294 295 return false; 296 } 297 }); 298 299 searchSubmitElement.addEventListener('click', function (e) { 300 e.preventDefault(); 301 geocodeSearch(); 302 303 return false; 304 }); 305 306 latLng = map.getCenter(); 307 getLocations(true); 308 }; 309 310 document.head.appendChild(script); 311} 312 313function geocodeSearch() { 314 const value = autocompleteElement.value; 315 316 if (value != '') { 317 geocoder.geocode({address: value, componentRestrictions: componentRestrictions}, function (data, status) { 318 if (status === google.maps.GeocoderStatus.OK) { 319 latLng = data[0].geometry.location; 320 getLocations(); 321 } else { 322 console.log('geocoding failed'); // @TODO: give user feedback 323 } 324 }); 325 } 326} 327 328function getLocations(initial) { 329 hideMapOverlay(); 330 startLoadingAnimation(); 331 332 if (latLng === null) { 333 stopLoadingAnimation(); 334 return; 335 } 336 337 if (radius === null && !initial) { 338 map.setCenter(latLng); 339 map.setZoom(parseInt(mapElement.dataset.zoom) + 2); 340 stopLoadingAnimation(); 341 return; 342 } 343 344 clearMarkers(); 345 346 const typeNum = 1668701302; 347 const prefix = 'tx_hagemeisterproducts_api'; 348 const searchFormData = new FormData(formElement); 349 350 let formData = new FormData(); 351 352 searchFormData.forEach(function (value, key) { 353 if (key.indexOf('__') === -1) { 354 const newKey = key.replace('referenceslist', 'api'); 355 formData.append(newKey, value); 356 } 357 }); 358 359 formData.append(prefix + '[latitude]', latLng.lat()); 360 formData.append(prefix + '[longitude]', latLng.lng()); 361 362 if (!initial) { 363 if (!isNaN(radius)) { 364 formData.append(prefix + '[radius]', radius); 365 } 366 367 if (country !== null) { 368 formData.append(prefix + '[country]', country); 369 } 370 } 371 372 let xhr = new XMLHttpRequest(); 373 xhr.open('POST', window.location.pathname + '?type=' + typeNum); 374 375 xhr.onreadystatechange = function () { 376 if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { 377 const references = JSON.parse(this.response); 378 379 let key; 380 let centerSet = false;
381 const markerSize = new google.maps.Size(32, 32); 382 383 for (key in references) { 384 if (references[key].hasOwnProperty('latitude') && references[key].hasOwnProperty('longitude')) { 385 const position = { 386 lat: references[key].latitude, 387 lng: references[key].longitude 388 }; 389 390 const marker = new google.maps.Marker({ 391 id: references[key].uid, 392 map: map, 393 position: position, 394 icon: { 395 url: markerUrl, 396 scaledSize: markerSize 397 }, 398 animation: google.maps.Animation.DROP 399 }); 400 401 marker.addListener('mouseover', markerMouseOver); 402 marker.addListener('mouseout', markerMouseOut); 403 marker.addListener('click', markerClicked); 404 405 markers.push(marker); 406 407 if (!centerSet && !initial) { 408 map.setCenter(position); 409 map.setZoom(getZoomLevelByRadius(radius)); 410 centerSet = true; 411 } 412 } 413 } 414 415 if (!centerSet) { 416 map.setCenter(latLng); 417 centerSet = true; 418 } 419 420 markerClustererInstance = new markerClusterer.MarkerClusterer({markers, map}); 421 } 422 423 stopLoadingAnimation(); 424 } 425 426 xhr.send(formData); 427} 428 429function markerClicked() { 430 hideMapOverlay(); 431 const locationId = this.id; 432 const typeNum = 1668701302; 433 const prefix = 'tx_hagemeisterproducts_api'; 434 435 let formData = new FormData(); 436 437 formData.append(prefix + '[action]', 'reference'); 438 formData.append(prefix + '[reference]', locationId); 439 440 if (locationXhr !== null) { 441 locationXhr.abort(); 442 } 443 444 locationXhr = new XMLHttpRequest(); 445 locationXhr.open('POST', window.location.pathname + '?type=' + typeNum); 446 447 locationXhr.onreadystatechange = function () { 448 if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { 449 const data = JSON.parse(this.response); 450 451 locationTitleElement.textContent = data.reference.name; 452 locationAddressElement.textContent = data.reference.city + ', ' + data.reference.country; 453 locationUrlElement.href = data.url; 454 locationDirectionsElement.href = data.directions; 455 456 if (data.reference.image) { 457 let set = false; 458 for (let key in data.reference.image) { 459 if (!set) { 460 locationImageElement.src = data.reference.image[key]; 461 set = true; 462 } 463 } 464 } 465 466 showMapOverlay(); 467 } 468 }; 469 470 locationXhr.send(formData); 471} 472 473function markerMouseOver() { 474 this.setIcon({ 475 url: markerHoverUrl, 476 scaledSize: new google.maps.Size(32, 32) 477 }); 478} 479 480function markerMouseOut() { 481 this.setIcon({ 482 url: markerUrl, 483 scaledSize: new google.maps.Size(32, 32) 484 }); 485} 486 487function clearMarkers() { 488 let key; 489 for (key in markers) { 490 markers[key].setMap(null); 491 } 492 493 markers = []; 494 495 if (markerClustererInstance !== null) { 496 markerClustererInstance.setMap(null); 497 } 498} 499 500function showMapOverlay() { 501 if (!mapOverlayElement.classList.contains(openedClass)) { 502 mapOverlayElement.classList.add(openedClass); 503 } 504} 505 506function hideMapOverlay() { 507 if (mapOverlayElement.classList.contains(openedClass)) { 508 mapOverlayElement.classList.remove(openedClass); 509 } 510} 511 512function startLoadingAnimation() { 513 mapLoadingElement.classList.remove(hideClass); 514} 515 516function stopLoadingAnimation() { 517 mapLoadingElement.classList.add(hideClass); 518} 519 520function getZoomLevelByRadius(radius) { 521 let zoomLevel = 8; 522 523 if (radius <= 10) { 524 zoomLevel = 13; 525 } else if (radius <= 25) { 526 zoomLevel = 10; 527 } else if (radius <= 50) { 528 zoomLevel = 9; 529 } else if (radius <= 100) { 530 zoomLevel = 8; 531 } else if (radius <= 200) { 532 zoomLevel = 7; 533 } 534 535 return zoomLevel; 536}
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.