PageSourceSearch

https://www.hagemeister.de/_assets/4b28e31d35198cbe19595c46761126a9/JavaScript/list.js?1781168489

js hagemeister.de collected 2026-10-04 18:59:23 UTC 16,150 bytes, 536 lines download raw bytes

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.