PageSourceSearch

https://uossm.org/wp-content/plugins/open-user-map/src/js/frontend-block-map.js?ver=1.3.54

js uossm.org collected 2026-10-02 04:30:22 UTC 39,322 bytes, 1,069 lines download raw bytes

1window.addEventListener('load', function(e) {
2
3  // Restore the extended L object (OUMLeaflet.L) to the global scope (prevents conflicts with other Leaflet instances)
4  window.L = window.OUMLeaflet.L;
5
6  // VARIABLES
7  const { __ } = wp.i18n;
8
9  // FUNCTIONS
10
11  function getParameterByName(name) {
12    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
13    const regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
14        results = regex.exec(location.search);
15    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
16  }
17
18  function latLngToBounds(lat, lng, zoom, width, height){
19    const EARTH_CIR_METERS = 40075016.686;
20    const degreesPerMeter = 360 / EARTH_CIR_METERS;
21    const metersPerPixelEW = EARTH_CIR_METERS / Math.pow(2, zoom + 8);
22    const metersPerPixelNS = EARTH_CIR_METERS / Math.pow(2, zoom + 8) * Math.cos(lat * Math.PI / 180);
23
24    const shiftMetersEW = width/2 * metersPerPixelEW;
25    const shiftMetersNS = height/2 * metersPerPixelNS;
26
27    const shiftDegreesEW = shiftMetersEW * degreesPerMeter;
28    const shiftDegreesNS = shiftMetersNS * degreesPerMeter;
29
30    // [[south, west], [north, east]]
31    return [[lat-shiftDegreesNS, lng-shiftDegreesEW], [lat+shiftDegreesNS, lng+shiftDegreesEW]];
32  }
33
34  function customAutoSuggestText(text,val) {
35    return '<div><img src="' + val.layer.options.icon.options.iconUrl + '" />' + val.layer.options.title + '</div>';
36  }
37
38  function updatePreview() {
39    this.nextElementSibling.classList.add('active');
40    this.nextElementSibling.querySelector('span').textContent = this.files[0].name;
41  }
42
43  function editLocation(post_id) {
44    // Trigger the Add Location button to open the form
45    document.getElementById('open-add-location-overlay').click();
46
47    document.getElementById('add-location-overlay').classList.add('edit-location');
48
49    // Wait for the form to be visible (use a small timeout if necessary)
50    setTimeout(function() {
51        // Retrieve the location data (this assumes the data is available in JavaScript, possibly as a global variable or via an AJAX call)
52        let locationData = oum_all_locations.find(location => location.post_id == post_id);
53
54        if (locationData) {
55            // Prefill the form fields with the location data
56            const titleField = document.querySelector('input[name="oum_location_title"]');
57            if (titleField) titleField.value = locationData.title;
58
59            const textField = document.querySelector('textarea[name="oum_location_text"]');
60            if (textField) textField.value = locationData.text;
61
62            const addressField = document.querySelector('input[name="oum_location_address"]');
63            if (addressField) addressField.value = locationData.address;
64
65            const latField = document.querySelector('input[name="oum_location_lat"]');
66            if (latField) latField.value = locationData.lat;
67
68            const lngField = document.querySelector('input[name="oum_location_lng"]');
69            if (lngField) lngField.value = locationData.lng;
70
71            // Add the location marker to the map
72            const coords = L.latLng(locationData.lat, locationData.lng);
73            oumMap2.fire('click', {
74                latlng: coords
75            });
76
77            // Set the map view to the location
78            oumMap2.setView(coords, oumMap2.getZoom());
79
80            // Marker categories
81            if (locationData.types) {
82                locationData.types.forEach(type => {
83                    const selectBox = document.querySelector(`select[name="oum_marker_icon[]"]`);
84                    if (selectBox) {
85                        selectBox.value = type;
86                    } else {
87                        const checkbox = document.querySelector(`input[name="oum_marker_icon[]"][value="${type}"]`);
88                        if (checkbox) {
89                            checkbox.checked = true;
90                        }
91                    }
92                });
93            }
94
95            // Custom fields
96            if (locationData.custom_fields) {
97                locationData.custom_fields.forEach(custom_field => {
98                    if(custom_field.val.length > 0) {
99                        if(custom_field.fieldtype == 'checkbox') {
100                            if(Array.isArray(custom_field.val)) {
101                              custom_field.val.forEach(val => {
102                                  const checkbox = document.querySelector(`input[name="oum_location_custom_fields[${custom_field.index}][]"][value="${val}"]`);
103                                  if (checkbox) checkbox.checked = true;
104                              });
105                            }
106                        } else if(custom_field.fieldtype == 'radio') {
107                            const radio = document.querySelector(`input[name="oum_location_custom_fields[${custom_field.index}]"][value="${custom_field.val}"]`);
108                            if (radio) radio.checked = true;
109                        } else if(custom_field.fieldtype == 'select') {
110                            const select = document.querySelector(`select[name="oum_location_custom_fields[${custom_field.index}]"]`);
111                            if (select) select.value = custom_field.val;
112                        } else {
113                            const input = document.querySelector(`input[name="oum_location_custom_fields[${custom_field.index}]"]`);
114                            if (input) input.value = custom_field.val;
115                        }
116                    }
117                });
118            }
119
120            // Image
121            if (locationData.image) {
122                const imageField = document.querySelector('input[name="oum_location_image"]');
123                if (imageField) {
124                    // Remove the required attribute (in case it was set)
125                    imageField.required = false;
126
127                    // Update the image preview
128                    const label = imageField.nextElementSibling;
129                    if (label) {
130                        label.classList.add('active');
131                        label.querySelector('span').textContent = locationData.image.split('/').pop();
132                    }
133                }
134
135                const oum_remove_existing_image = document.getElementById('oum_remove_existing_image');
136                if (oum_remove_existing_image) oum_remove_existing_image.value = '0';
137            }
138
139            // Audio
140            if (locationData.audio) {
141                const audioField = document.querySelector('input[name="oum_location_audio"]');
142                if (audioField) {
143                    // Remove the required attribute (in case it was set)
144                    audioField.required = false;
145
146                    // Update the audio preview
147                    const label = audioField.nextElementSibling;
148                    if (label) {
149                        label.classList.add('active');
150                        label.querySelector('span').textContent = locationData.audio.split('/').pop();
151                    }
152                }
153
154                const oum_remove_existing_audio = document.getElementById('oum_remove_existing_audio');
155                if (oum_remove_existing_audio) oum_remove_existing_audio.value = '0';
156            }
157
158            // Video
159            const videoField = document.querySelector('input[name="oum_location_video"]');
160            if (videoField) videoField.value = decodeURIComponent(locationData.video.replace(/&#038;/g, '&'));
161
162            // Set the form action or hidden input to indicate this is an edit and not a new submission
163            const postIdField = document.querySelector('input[name="oum_post_id"]');
164            if (postIdField) postIdField.value = locationData.post_id;
165        }
166    }, 500); // Adjust timeout as needed
167  }
168
169  // Dynamic Filtering Function with Text and Category Filters
170  function filterMarkers() {
171    // Check if the text search input exists and get its value
172    const markerFilterInput = document.getElementById('oum_filter_markers');
173    const filter = markerFilterInput ? markerFilterInput.value.toLowerCase() : '';
174
175    // Check if category filters exist and get selected categories
176    const categoryInputs = document.querySelectorAll('.open-user-map .oum-filter-controls [name="type"]');
177    const checkedCategories = categoryInputs.length > 0
178        ? Array.from(categoryInputs).filter(input => input.checked).map(input => input.value)
179        : [];
180
181    // Clear existing markers from the map
182    oumMarkersLayer.clearLayers();
183
184    // Filter and re-add markers based on both text filter and selected categories
185    oumAllMarkers.forEach(marker => {
186        const contentText = marker.options.content.toLowerCase();
187        const markerTypes = marker.options.types || [];
188
189        // Check if marker matches the text filter
190        const matchesTextFilter = !filter || contentText.includes(filter);
191
192        // Check if marker should be shown based on selected categories
193        const matchesCategoryFilter = markerTypes.length === 0 // Always show markers without categories
194            || (checkedCategories.length === 0 && markerTypes.length === 0) // Show uncategorized markers when no categories are selected
195            || markerTypes.some(type => checkedCategories.includes(type)); // Show markers matching any selected category
196
197        // Only add marker if it matches both filters
198        if (matchesTextFilter && matchesCategoryFilter) {
199            oumMarkersLayer.addLayer(marker); // Add the marker back to the map if it matches both filters
200        }
201    });
202  }
203
204  // Create leaflet markers based on "oum_all_locations" json
205  function addMarkers() {
206      oum_all_locations.forEach(location => {
207          const contentText = (location.title + ' | ' + location.content.replace(/(<([^>]+)>)/gi, " ").replace(/\s\s+/g, " ")).toLowerCase();
208
209          let marker = L.marker([location.lat, location.lng], {
210              title: location.title,
211              post_id: location.post_id,
212              content: contentText,
213              icon: L.icon({
214                  iconUrl: location.icon,
215                  iconSize: [26, 41],
216                  iconAnchor: [13, 41],
217                  popupAnchor: [0, -25],
218                  shadowUrl: marker_shadow_url,
219                  shadowSize: [41, 41],
220                  shadowAnchor: [13, 41]
221              }),
222              types: location.types || []
223          });
224          let popup = L.responsivePopup().setContent(location.content);
225          marker.bindPopup(popup);
226          oumAllMarkers.push(marker); // Add to the array for future filtering
227      });
228  }
229
230
231  // Use this to initialize markers and add them to the map initially
232  function initializeMarkers() {
233    addMarkers();  // Fill the oumAllMarkers array
234    oumAllMarkers.forEach(marker => {
235      oumMarkersLayer.addLayer(marker);  // Add all markers to the markers LayerGroup or ClusterGroup
236    });
237  }
238
239
240  // VARIABLES
241
242  const POPUP_MARKER_ID = getParameterByName('markerid');
243  const REGION_ID = getParameterByName('region');
244  const enableFullscreen = oum_enable_fullscreen ? true : false;
245  const enableGestureHandlingMap = oum_enable_scrollwheel_zoom_map ? false : true;
246
247  // Handle "Add Location" popup DOM placement on fullscreen mode
248  const addLocationPopup = document.querySelector('#add-location-overlay');
249  const originalContainer = addLocationPopup.parentElement;
250  const fullscreenContainer = document.querySelector('.open-user-map .map-wrap');
251
252  // Handle Location Bubble on small screens (show in fullscreen)
253  const locationFullscreenContainer = document.querySelector('.open-user-map #location-fullscreen-container');
254
255  // Handle "Locate My Position" service (should not run in parallel)
256  var map_locate_process = false;
257  var map2_locate_process = false;
258
259  // SETUP MAIN MAP
260
261  // Init Map
262  const map = L.map(map_el, {
263    gestureHandling: enableGestureHandlingMap,
264    zoomSnap: 0.5,
265    zoomDelta: 0.5,
266    attributionControl: true,
267    fullscreenControl: enableFullscreen,
268    fullscreenControlOptions: {
269      position: 'topleft',
270      fullscreenElement: fullscreenContainer,
271    }
272  });
273
274  map.attributionControl.setPrefix(false);
275
276  // prevent moving/zoom outside main world bounds
277  let world_bounds = L.latLngBounds(L.latLng(-60, -190), L.latLng(80, 190));
278  let world_min_zoom = (map.getBoundsZoom(world_bounds) > 0) ? map.getBoundsZoom(world_bounds) : 1;
279  map.setMaxBounds(world_bounds);
280  map.setMinZoom(Math.ceil(world_min_zoom));
281  map.on('drag', function() {
282    map.panInsideBounds(world_bounds, { animate: false });
283  });
284
285  // make map reloadable (oumMap.invalidateSize()) after some preloader is ready
286  oumMap = map;
287
288  // Get Initial Map Bounds & Zoom
289  let start_bounds = latLngToBounds(parseFloat(start_lat), parseFloat(start_lng), parseFloat(start_zoom), 570, 372);
290  let start_bounds_zoom = map.getBoundsZoom(start_bounds);
291
292  oum_minimum_zoom_level = oum_minimum_zoom_level ? oum_minimum_zoom_level : 1;
293
294  if(oum_use_settings_start_location && !oum_has_regions) {
295
296    // START POSITION FROM SETTINGS AND REGIONS ARE DISABLED
297
298    // Make sure "Minimum zoom level" is lower than start zoom
299    if(oum_minimum_zoom_level > parseFloat(start_zoom)) {
300      oum_minimum_zoom_level = Math.floor(start_bounds_zoom);
301    }
302
303    // Set min zoom
304    map.setMinZoom(oum_minimum_zoom_level);
305
306  }else{
307
308    // CUSTOM START POSITION 
309
310    // Disable "Fixed Map Bounds" from Settings
311    oum_enable_fixed_map_bounds = false;
312  }
313
314  // Render Map
315  map.setView([start_lat, start_lng], start_bounds_zoom);
316
317  // Bound map to fixed position
318  if(oum_enable_fixed_map_bounds) { 
319    map.setMaxBounds(map.getBounds().pad(0.1));
320  }
321
322  // Create Bounds Object needed for Marker Search
323  let start_bounds_object = map.getBounds();
324
325  // Set map style
326  if (mapStyle == 'Custom1') {
327
328    L.tileLayer('https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png').addTo(map);
329    L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}{r}.png', {
330      tileSize: 512,
331      zoomOffset: -1
332    }).addTo(map);
333
334  } else if (mapStyle == 'Custom2') {
335
336    L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png').addTo(map);
337    L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}{r}.png', {
338      tileSize: 512,
339      zoomOffset: -1
340    }).addTo(map);
341
342  } else if (mapStyle == 'Custom3') {
343
344    L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png').addTo(map);
345    L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}{r}.png', {
346      tileSize: 512,
347      zoomOffset: -1
348    }).addTo(map);
349
350  } else if (mapStyle == 'MapBox.streets') {
351
352    L.tileLayer.provider('MapBox', {
353      id: 'mapbox/streets-v12',
354      accessToken: oum_tile_provider_mapbox_key
355    }).addTo(map);
356
357  } else if (mapStyle == 'MapBox.outdoors') {
358
359    L.tileLayer.provider('MapBox', {
360      id: 'mapbox/outdoors-v12',
361      accessToken: oum_tile_provider_mapbox_key
362    }).addTo(map);
363
364  } else if (mapStyle == 'MapBox.light') {
365
366    L.tileLayer.provider('MapBox', {
367      id: 'mapbox/light-v11',
368      accessToken: oum_tile_provider_mapbox_key
369    }).addTo(map);
370
371  } else if (mapStyle == 'MapBox.dark') {
372
373    L.tileLayer.provider('MapBox', {
374      id: 'mapbox/dark-v11',
375      accessToken: oum_tile_provider_mapbox_key
376    }).addTo(map);
377
378  } else if (mapStyle == 'MapBox.satellite') {
379
380    L.tileLayer.provider('MapBox', {
381      id: 'mapbox/satellite-v9',
382      accessToken: oum_tile_provider_mapbox_key
383    }).addTo(map);
384
385  } else if (mapStyle == 'MapBox.satellite-streets') {
386
387    L.tileLayer.provider('MapBox', {
388      id: 'mapbox/satellite-streets-v12',
389      accessToken: oum_tile_provider_mapbox_key
390    }).addTo(map);
391
392  } else {
393    // Default
394    L.tileLayer.provider(mapStyle).addTo(map);
395  }
396
397
398  // ADD LOCATIONS
399
400  let oumAllMarkers = []; // holds all markers
401  let oumMarkersLayer; // Marker parent layer
402
403  if (!oum_enable_cluster) {
404    // clustering disabled
405    oumMarkersLayer = L.layerGroup({
406      chunkedLoading: true
407    });
408  } else {
409    // clustering enabled
410    oumMarkersLayer = L.markerClusterGroup({
411      showCoverageOnHover: false,
412      removeOutsideVisibleBounds: false,
413      maxClusterRadius: 40,
414      chunkedLoading: true
415    });
416  }
417
418  // Add markers layer to map
419  oumMarkersLayer.addTo(map);
420
421  // Call this function initially to set up markers
422  initializeMarkers();
423
424
425
426
427  // ADD MAP CONTROLS
428
429  // Control: search markers
430  if (oum_enable_searchmarkers_button && (!oum_enable_searchbar || oum_searchbar_type !== 'markers')) {
431    L.control.search({
432      textPlaceholder: oum_searchmarkers_label,
433      layer: oumMarkersLayer,
434      propertyName: 'content',
435      initial: false,
436      buildTip: customAutoSuggestText,
437      firstTipSubmit: true,
438      autoCollapse: true, // resets search field
439      zoom: oum_searchmarkers_zoom,
440    }).addTo(map);
441  }
442
443  // Searchbar: search markers
444  if (oum_enable_searchbar && oum_searchbar_type == 'markers') {
445    L.control.search({
446      container: 'oum_search_marker',
447      collapsed: false,
448      textPlaceholder: oum_searchmarkers_label,
449      layer: oumMarkersLayer,
450      propertyName: 'content',
451      initial: false,
452      buildTip: customAutoSuggestText,
453      firstTipSubmit: true,
454      autoCollapse: true, // resets search field
455      zoom: oum_searchmarkers_zoom,
456    }).addTo(map);
457  }
458
459  // Geosearch Provider
460  switch (oum_geosearch_provider) {
461    case 'osm':
462      oum_geosearch_selected_provider = new GeoSearch.OpenStreetMapProvider();
463      break;
464    case 'geoapify':
465      oum_geosearch_selected_provider = new GeoSearch.GeoapifyProvider({
466        params: {
467          apiKey: oum_geosearch_provider_geoapify_key
468        }
469      });
470      break;
471    case 'here':
472      oum_geosearch_selected_provider = new GeoSearch.HereProvider({
473        params: {
474          apiKey: oum_geosearch_provider_here_key
475        }
476      });
477      break;
478    case 'mapbox':
479      oum_geosearch_selected_provider = new GeoSearch.MapBoxProvider({
480        params: {
481          access_token: oum_geosearch_provider_mapbox_key
482        }
483      });
484      break;
485    default:
486      oum_geosearch_selected_provider = new GeoSearch.OpenStreetMapProvider();
487      break;
488  }
489
490  // Control: search address
491  if (oum_enable_searchaddress_button && (!oum_enable_searchbar || oum_searchbar_type !== 'address')) {
492    const searchControl = new GeoSearch.GeoSearchControl({
493      style: 'button', //bar, button
494      showMarker: false,
495      provider: oum_geosearch_selected_provider,
496      notFoundMessage: 'Sorry, that address could not be found.',
497      searchLabel: oum_searchaddress_label,
498      updateMap: false,
499      autoComplete: true
500    });
501    map.addControl(searchControl);
502  }
503
504  // Searchbar: search address
505  if (oum_enable_searchbar && oum_searchbar_type == 'address') {
506    const searchControl = new GeoSearch.GeoSearchControl({
507      style: 'bar', //bar, button
508      showMarker: false,
509      provider: oum_geosearch_selected_provider,
510      searchLabel: oum_searchaddress_label,
511      updateMap: false,
512    });
513    map.addControl(searchControl);
514  }
515
516  // Control: get current location
517  if (oum_enable_currentlocation) {
518    map_locate_process = L.control.locate({
519      flyTo: true,
520      showPopup: false
521    }).addTo(map);
522  }
523
524
525  // EVENTS
526
527  // Event: Enter Fullscreen
528  map.on('enterFullscreen', function () {
529    fullscreenContainer.appendChild(addLocationPopup);
530  });
531
532  // Event: Exit Fullscreen
533  map.on('exitFullscreen', function () {
534    originalContainer.appendChild(addLocationPopup);
535  });
536
537  // Event: Open Location Bubble
538  map.on('popupopen', function(locationBubble){
539    var el = locationFullscreenContainer;
540    el.querySelector('.location-content-wrap').innerHTML = locationBubble.popup.getContent();
541    locationFullscreenContainer.classList.add('visible');
542    document.querySelector('body').classList.add('oum-location-opened');
543  });
544
545  // Event: Close Location Bubble
546  map.on('popupclose', function(locationBubble){
547    var el = locationFullscreenContainer;
548    el.classList.remove('visible');
549    document.querySelector('body').classList.remove('oum-location-opened');
550    //map.setView(locationBubble.popup.getLatLng());
551  });
552
553  // Event: pan or zoom Map
554  map.on('moveend', function(ev) {
555    start_lat = map.getCenter().lat;
556    start_lng = map.getCenter().lng;
557    start_zoom = map.getZoom();
558  });
559
560  // Event: click on geosearch result
561  map.on('geosearch/showlocation', function(e) {
562    let coords = e.marker._latlng;
563    let isInBounds = start_bounds_object.contains(coords);
564    const searchBar = document.querySelector(`#${map_el} .leaflet-geosearch-bar form, #${map_el} .leaflet-geosearch-button form`);
565
566    if(!isInBounds && oum_enable_fixed_map_bounds) {
567      console.log('This search result is out of reach.');
568      searchBar.style.boxShadow = "0 0 10px rgb(255, 111, 105)";
569      setTimeout(function() {
570        searchBar.style.boxShadow = "0 1px 5px rgba(255, 255, 255, 0.65)";
571      }, 2000);
572    }else{
573      if(e.location.bounds !== null) {
574        // Bounds exist for this search result
575        map.flyToBounds(e.location.bounds);
576      }else{
577        if(e.location.raw.mapView) {
578          // Here
579          map.flyToBounds([
580            [e.location.raw.mapView.south,e.location.raw.mapView.west],
581            [e.location.raw.mapView.north,e.location.raw.mapView.east]
582          ]);
583        }else{
584          // No Bounds available for this search result
585          map.flyTo([e.location.y, e.location.x], 17);
586        }
587      }
588    }
589  });
590
591  // Event: automatically open popup on ?markerid=123
592  oumMarkersLayer.eachLayer(function(layer) {
593
594    if(layer.options.post_id && layer.options.post_id === POPUP_MARKER_ID){
595
596      map.setView(layer.getLatLng(), oum_searchmarkers_zoom);
597      layer.openPopup();
598
599    }
600  });
601
602  // Event: Change Region
603  document.querySelectorAll('.open-user-map .change_region').forEach(function(btn) {
604    btn.onclick = function(event) {
605      let el = event.currentTarget;
606      let region_lat = el.getAttribute('data-lat');
607      let region_lng = el.getAttribute('data-lng');
608      let region_zoom = el.getAttribute('data-zoom');
609
610      let region_bounds = latLngToBounds(parseFloat(region_lat), parseFloat(region_lng), parseFloat(region_zoom), 570, 372);
611      let region_bounds_zoom = map.getBoundsZoom(region_bounds);
612
613      // Center Map
614      map.flyTo([region_lat, region_lng], region_bounds_zoom);
615
616      document.querySelectorAll('.open-user-map .change_region').forEach(function(el) {
617        el.classList.remove('active');
618      });
619      el.classList.add('active');
620    };
621
622    // Event: Change Region on ?region=Europe
623    if(btn.textContent == REGION_ID) {
624      btn.click();
625    }
626  });
627
628  // Event: Filter markers on text input change (only if it exists)
629  const markerFilterInput = document.getElementById('oum_filter_markers');
630  if (markerFilterInput) {
631      markerFilterInput.addEventListener('input', filterMarkers);
632  }
633
634  // Event: Filter markers on category change (only if categories exist)
635  const categoryInputs = document.querySelectorAll('.open-user-map .oum-filter-controls [name="type"]');
636  if (categoryInputs.length > 0) {
637      categoryInputs.forEach(input => {
638          input.addEventListener('change', filterMarkers);
639      });
640  }
641
642  // Event: Toggle Filter List
643  (function() {
644    // Cache the filter controls element
645    let filterControls = document.querySelector('.open-user-map .oum-filter-controls');
646  
647    if (!filterControls) return; // Exit if element is not found
648  
649    // Function to show the filter list
650    function showFilterList() {
651      filterControls.classList.add('active');
652    }
653  
654    // Function to hide the filter list
655    function hideFilterList() {
656      filterControls.classList.remove('active');
657    }
658  
659    // Event: Open Filter List (mouseover for collapsed design)
660    if (filterControls.classList.contains('use-collapse')) {
661      filterControls.querySelector('.oum-filter-toggle').addEventListener('mouseover', showFilterList);
662  
663      // Close on mouseleave
664      filterControls.querySelector('.oum-filter-list').addEventListener('mouseleave', hideFilterList);
665    }
666  
667    // Event: Open Filter List (click)
668    filterControls.querySelector('.oum-filter-toggle').addEventListener('click', showFilterList);
669  
670    // Event: Close Filter List (click on close button)
671    filterControls.querySelector('.oum-filter-list .close-filter-list').addEventListener('click', hideFilterList);
672  })();
673
674  
675  // ADD LOCATION
676
677  if (document.getElementById('open-add-location-overlay') != null) {
678    //init form map
679    const map2 = L.map('mapGetLocation', {
680      attributionControl: false,
681      gestureHandling: true,
682      zoomSnap: 1,
683      zoomDelta: 1,
684      fullscreenControl: enableFullscreen,
685      fullscreenControlOptions: {
686        position: 'topleft'
687      }
688    });
689
690    // Activate Map inside overlay
691    (function() {
692
693      let markerIsVisible = false;
694
695      // Set map style
696      if (mapStyle == 'Custom1') {
697
698        L.tileLayer('https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png').addTo(map2);
699        L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}{r}.png', {
700          tileSize: 512,
701          zoomOffset: -1
702        }).addTo(map2);
703
704      } else if (mapStyle == 'Custom2') {
705
706        L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png').addTo(map2);
707        L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}{r}.png', {
708          tileSize: 512,
709          zoomOffset: -1
710        }).addTo(map2);
711
712      } else if (mapStyle == 'Custom3') {
713
714        L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png').addTo(map2);
715        L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}{r}.png', {
716          tileSize: 512,
717          zoomOffset: -1
718        }).addTo(map2);
719
720      } else if (mapStyle == 'MapBox.streets') {
721
722        L.tileLayer.provider('MapBox', {
723          id: 'mapbox/streets-v12',
724          accessToken: oum_tile_provider_mapbox_key
725        }).addTo(map2);
726
727      } else if (mapStyle == 'MapBox.outdoors') {
728
729        L.tileLayer.provider('MapBox', {
730          id: 'mapbox/outdoors-v12',
731          accessToken: oum_tile_provider_mapbox_key
732        }).addTo(map2);
733
734      } else if (mapStyle == 'MapBox.light') {
735
736        L.tileLayer.provider('MapBox', {
737          id: 'mapbox/light-v11',
738          accessToken: oum_tile_provider_mapbox_key
739        }).addTo(map2);
740
741      } else if (mapStyle == 'MapBox.dark') {
742
743        L.tileLayer.provider('MapBox', {
744          id: 'mapbox/dark-v11',
745          accessToken: oum_tile_provider_mapbox_key
746        }).addTo(map2);
747
748      } else if (mapStyle == 'MapBox.satellite') {
749
750        L.tileLayer.provider('MapBox', {
751          id: 'mapbox/satellite-v9',
752          accessToken: oum_tile_provider_mapbox_key
753        }).addTo(map2);
754
755      } else if (mapStyle == 'MapBox.satellite-streets') {
756
757        L.tileLayer.provider('MapBox', {
758          id: 'mapbox/satellite-streets-v12',
759          accessToken: oum_tile_provider_mapbox_key
760        }).addTo(map2);
761
762      } else {
763        // Default
764        L.tileLayer.provider(mapStyle).addTo(map2);
765      }
766
767      // Add searchbar: address
768      const search = new GeoSearch.GeoSearchControl({
769        style: 'bar',
770        showMarker: false,
771        provider: oum_geosearch_selected_provider,
772        searchLabel: oum_searchaddress_label,
773        updateMap: false,
774      });
775      map2.addControl(search);
776
777      // Add control: get current location
778      if (oum_enable_currentlocation) {
779        map2_locate_process = L.control.locate({
780          flyTo: true,
781          showPopup: false
782        }).addTo(map2);
783      }
784
785      //define marker
786
787      // Marker Icon
788      let markerIcon = L.icon({
789        iconUrl: marker_icon_url,
790        iconSize: [26, 41],
791        iconAnchor: [13, 41],
792        popupAnchor: [0, -25],
793        shadowUrl: marker_shadow_url,
794        shadowSize: [41, 41],
795        shadowAnchor: [13, 41]
796      });
797
798      let locationMarker = L.marker([0, 0], {
799        icon: markerIcon
800      }, {
801        'draggable': true
802      });
803
804      // move "Add Location"-Map to current Main map position
805      start_lat = map.getCenter().lat;
806      start_lng = map.getCenter().lng;
807      start_zoom = map.getZoom();
808
809      let main_map_width = document.querySelector(`#${map_el}`).offsetWidth;
810      let main_map_height = document.querySelector(`#${map_el}`).offsetHeight;
811      let start_bounds = latLngToBounds(parseFloat(start_lat), parseFloat(start_lng), parseFloat(start_zoom), main_map_width, main_map_height);
812      let start_bounds_zoom = map2.getBoundsZoom(start_bounds);
813
814      map2.setView([start_lat, start_lng], start_bounds_zoom);
815
816      // prevent moving/zoom outside main world bounds
817      map2.setMaxBounds(world_bounds);
818      map2.setMinZoom(Math.ceil(world_min_zoom));
819      map2.on('drag', function() {
820        map2.panInsideBounds(world_bounds, { animate: false });
821      });
822
823      // Bound map to fixed position
824      if(oum_enable_fixed_map_bounds) {  
825        map2.setMaxBounds(map.getBounds());
826      }
827
828      //Event: click on map to set marker OR location found
829      map2.on('click locationfound', function(e) {
830        let coords = e.latlng;
831
832        locationMarker.setLatLng(coords);
833
834        if (!markerIsVisible) {
835          locationMarker.addTo(map2);
836          markerIsVisible = true;
837        }
838
839        setLocationLatLng(coords);
840      });
841
842      //Event: geosearch success
843      map2.on('geosearch/showlocation', function(e) {
844        let coords = e.marker._latlng;
845        let label = e.location.label;
846        let isInBounds = start_bounds_object.contains(coords);
847        const searchBar = document.querySelector(`#mapGetLocation .leaflet-geosearch-bar form`);
848
849        if(!isInBounds && oum_enable_fixed_map_bounds) {
850          console.log('This search result is out of reach.');
851          searchBar.style.boxShadow = "0 0 10px rgb(255, 111, 105)";
852          setTimeout(function() {
853            searchBar.style.boxShadow = "0 1px 5px rgba(255, 255, 255, 0.65)";
854          }, 2000);
855        }else{
856          if(e.location.bounds !== null) {
857            // Bounds exist for this search result
858            map2.flyToBounds(e.location.bounds);
859          }else{
860            if(e.location.raw.mapView) {
861              // Here
862              map2.flyToBounds([
863                [e.location.raw.mapView.south,e.location.raw.mapView.west],
864                [e.location.raw.mapView.north,e.location.raw.mapView.east]
865              ]);
866            }else{
867              // No Bounds available for this search result
868              map2.flyTo([e.location.y, e.location.x], 17);
869            }
870          }
871          
872          locationMarker.setLatLng(coords);
873
874          if (!markerIsVisible) {
875            locationMarker.addTo(map2);
876            markerIsVisible = true;
877          }
878
879          setLocationLatLng(coords);
880          
881          //setAddress(label);
882        }
883      });
884
885      oumMap2 = map2;
886
887      //Event: drag marker
888      locationMarker.on('dragend', function(e) {
889        setLocationLatLng(e.target.getLatLng());
890      });
891
892      //Validation for required checkbox groups
893      jQuery('#oum_add_location input[type="submit"]').on('click', function() {
894        let required_fieldsets = jQuery('#oum_add_location fieldset.is-required');
895
896        required_fieldsets.each(function() {
897          $cbx_group = jQuery(this).find('input:checkbox');
898          $cbx_group.prop('required', true);
899          if($cbx_group.is(":checked")){
900            $cbx_group.prop('required', false);
901          }
902        });
903      });
904
905      //set lat & lng input fields
906      function setLocationLatLng(markerLatLng) {
907        console.log(markerLatLng);
908
909        jQuery('#oum_location_lat').val(markerLatLng.lat);
910        jQuery('#oum_location_lng').val(markerLatLng.lng);
911      }
912
913      //set address field
914      function setAddress(label) {
915        jQuery('#oum_location_address').val(label);
916      }
917
918    })();
919
920    // Event: click on "+ Add Location" button
921    document.getElementById('open-add-location-overlay').addEventListener('click', function(event) {
922
923      // show overlay
924      document.getElementById('add-location-overlay').classList.add('active');
925
926      // reset overlay
927      document.getElementById('oum_add_location_thankyou').style.display = 'none'; // hide thank you message
928      document.getElementById('oum_add_location').style.display = 'block';
929      document.getElementById('oum_add_location').reset(); // clear form (except marker lat/lng)
930      document.getElementById('add-location-overlay').classList.remove('edit-location'); // remove edit class
931      if (document.querySelector('input[name="oum_post_id"]') != null) document.querySelector('input[name="oum_post_id"]').value = ''; // clear post_id
932      if (document.querySelector('input[name="oum_delete_location"]') != null) document.querySelector('input[name="oum_delete_location"]').value = ''; // clear delete_location
933      if (document.getElementById('oum_remove_image') != null) document.getElementById('oum_remove_image').click(); // remove image
934      if (document.getElementById('oum_remove_audio') != null) document.getElementById('oum_remove_audio').click(); 
935
936      // prevent body scrolling
937      document.querySelector('body').classList.add('oum-add-location-opened');
938
939      // scroll to top of overlay
940      window.scrollTo(0, document.getElementById('add-location-overlay').getBoundingClientRect().top + scrollY);
941
942      //recalculate map size (due to overlay opening)
943      map2.invalidateSize({animate: false});
944
945      // stop locate process (main map)
946      if(map_locate_process) {
947        map_locate_process.stop();
948      }
949
950      // move "Add Location"-Map to current Main map position
951      let main_map_width = document.querySelector(`#${map_el}`).offsetWidth;
952      let main_map_height = document.querySelector(`#${map_el}`).offsetHeight;
953      let start_bounds = latLngToBounds(parseFloat(start_lat), parseFloat(start_lng), parseFloat(start_zoom), main_map_width, main_map_height);
954
955      // reposition map (wait for invalidateSize() to be ready)
956      setTimeout(function() {
957        map2.fitBounds(start_bounds);
958      }, 300);
959
960    });
961
962    // Event: click on "notify on publish"
963    if (document.getElementById('oum_location_notification') != null) {
964      document.getElementById('oum_location_notification').addEventListener('change', function(event) {
965        if (this.checked) {
966          document.getElementById('oum_author').classList.add('active');
967          document.getElementById('oum_location_author_name').required = true;
968          document.getElementById('oum_location_author_email').required = true;
969        } else {
970          document.getElementById('oum_author').classList.remove('active');
971          document.getElementById('oum_location_author_name').required = false;
972          document.getElementById('oum_location_author_email').required = false;
973        }
974      });
975    }
976
977    // Events: close "Add location" overlay
978    if (document.getElementById('close-add-location-overlay') != null) {
979      
980      // Event: Close "Add location" popup on X
981      document.getElementById('close-add-location-overlay').addEventListener('click', function(event) {
982        document.getElementById('add-location-overlay').classList.remove('active');
983
984        // stop locate process (map2)
985        if(map2_locate_process) {
986          map2_locate_process.stop();
987        }
988
989        // allow body scrolling
990        document.querySelector('body').classList.remove('oum-add-location-opened');
991      });
992
993      // Event: Close "Add location" popup on ESC key
994      document.onkeydown = function(evt) {
995        evt = evt || window.event;
996        if(evt.key === "Escape") {
997            document.getElementById('close-add-location-overlay').click();
998        }
999      };
1000
1001      // Event: Close "Add location" popup on click on backdrop
1002      document.getElementById('add-location-overlay').addEventListener('click', function(event) {
1003        if (event.target !== this) return;
1004        document.getElementById('close-add-location-overlay').click();
1005      });
1006    }
1007
1008    // Event: Remove uploaded image
1009    if (document.getElementById('oum_remove_image') != null) {
1010      document.getElementById('oum_remove_image').addEventListener('click', function() {        
1011        document.getElementById('oum_location_image').value = '';
1012        document.getElementById('oum_remove_existing_image').value = '1';
1013        document.getElementById('oum_location_image').nextElementSibling.classList.remove('active');
1014        document.getElementById('oum_location_image').nextElementSibling.querySelector('span').textContent = '';
1015      });
1016    }
1017
1018    // Event: Remove uploaded audio
1019    if (document.getElementById('oum_remove_audio') != null) {
1020      document.getElementById('oum_remove_audio').addEventListener('click', function() {
1021        document.getElementById('oum_location_audio').value = '';
1022        document.getElementById('oum_remove_existing_audio').value = '1';
1023        document.getElementById('oum_location_audio').nextElementSibling.classList.remove('active');
1024        document.getElementById('oum_location_audio').nextElementSibling.querySelector('span').textContent = '';
1025      });
1026    }
1027
1028    // Event: add another location
1029    if (document.getElementById('oum_add_another_location') != null) {
1030      document.getElementById('oum_add_another_location').addEventListener('click', function() {
1031        document.getElementById('close-add-location-overlay').click(); // close current overlay
1032        document.getElementById('open-add-location-overlay').click(); // open new overlay
1033      });
1034    }
1035
1036    if(document.getElementById('oum_location_image') != null) {
1037      document.getElementById('oum_location_image').addEventListener('change', updatePreview);
1038    }
1039
1040    if(document.getElementById('oum_location_audio') != null) {
1041      document.getElementById('oum_location_audio').addEventListener('change', updatePreview)
1042    }
1043
1044    // Event delegation for Edit and Delete Location buttons
1045    document.addEventListener('click', function(event) {
1046      // Edit Location button clicked
1047      if (event.target.classList.contains('edit-location-button')) {
1048          let post_id = event.target.getAttribute('data-post-id');
1049          editLocation(post_id); // Call edit function
1050      }
1051
1052      // Delete Location button clicked
1053      if (event.target.matches('#oum_delete_location_btn span')) {
1054          const userConfirmed = confirm(__('Are you sure you want to delete this location?', 'open-u
1054ser-map'));
1055
1056          if (userConfirmed) {
1057              // Set delete flag to true and submit the form
1058              document.querySelector('input[name="oum_delete_location"]').value = 'true';
1059              document.getElementById('oum_submit_btn').click();
1060          }
1061      }
1062    });
1063
1064  }
1065
1066  //execute custom JS from the settings here
1067  let oum_custom_js = Function(custom_js.snippet)();
1068
1069}, false);

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.