1(function () { 2 const iconCache = {}; 3 const instances = (window.__EVOLUTE_MAPS_INSTANCES = window.__EVOLUTE_MAPS_INSTANCES || {}); 4 5 function pick(cfg, camelKey, snakeKey, fallback) { 6 if (cfg && cfg[camelKey] !== undefined && cfg[camelKey] !== null && cfg[camelKey] !== '') return cfg[camelKey]; 7 if (cfg && cfg[snakeKey] !== undefined && cfg[snakeKey] !== null && cfg[snakeKey] !== '') return cfg[snakeKey]; 8 return fallback; 9 } 10 11 function markerIcon(color) { 12 if (iconCache[color]) return iconCache[color]; 13 14 iconCache[color] = L.divIcon({ 15 className: '', 16 html: ` 17 <svg width="26" height="36" viewBox="0 0 34 48" xmlns="http://www.w3.org/2000/svg"> 18 <path d="M17 0C7.6 0 0 7.6 0 17c0 12.8 17 31 17 31s17-18.2 17-31C34 7.6 26.4 0 17 0z" 19 fill="${color}"/> 20 <circle cx="17" cy="17" r="6" fill="#ffffff"/> 21 </svg> 22 `, 23 iconSize: [26, 36], 24 iconAnchor: [13, 36] 25 }); 26 27 return iconCache[color]; 28 } 29 30 function destroyInstance(id) { 31 const inst = instances[id]; 32 const el = document.getElementById(id); 33 if (el) { 34 if (el._evoluteTouchHandler) { 35 el.removeEventListener('touchstart', el._evoluteTouchHandler); 36 el._evoluteTouchHandler = null; 37 } 38 if (el._evolutePopupPaneRef && el._evolutePopupPaneHandler) { 39 el._evolutePopupPaneRef.removeEventListener('touchstart', el._evolutePopupPaneHandler); 40 el._evolutePopupPaneRef = null; 41 el._evolutePopupPaneHandler = null; 42 } 43 } 44 if (inst && inst.map) { 45 try { inst.map.remove(); } catch (e) {} 46 } 47 delete instances[id]; 48 if (el) { 49 if (el._evoluteResizeObs) { 50 el._evoluteResizeObs.disconnect(); 51 el._evoluteResizeObs = null; 52 } 53 if (el._leaflet_id) { 54 try { delete el._leaflet_id; } catch (e) { el._leaflet_id = null; } 55 } 56 el.innerHTML = ''; 57 } 58 } 59 60 function initOne(cfg) { 61 if (!cfg || !cfg.id) return; 62 const id = cfg.id; 63 const el = document.getElementById(id); 64 if (!el) return; 65 66 destroyInstance(id); 67 68 ensureMapWidth(el); 69 70 const height = parseInt(pick(cfg, 'height', 'height', 600), 10) || 600; 71 el.style.height = height + 'px'; 72 73 const globalColor = pick(cfg, 'primaryColor', 'primary_color', '#d6393b') || '#d6393b'; 74 75 const isMobile = window.matchMedia('(max-width:767px)').matches; 76 77 const legacyPopupClosed = !!pick(cfg, 'popupClosed', 'popup_closed', false); 78 79 const popupClosed = isMobile 80 ? !!pick(cfg, 'popupClosedMobile', 'popup_closed_mobile', legacyPopupClosed) 81 : !!pick(cfg, 'popupClosedDesktop', 'popup_closed_desktop', legacyPopupClosed); 82 const useGlobalColor = !!pick(cfg, 'useGlobalColor', 'use_global_color', true); 83 const globalPopupBg = pick(cfg, 'popupBodyBg', 'popup_body_bg', '#ffffff') || '#ffffff'; 84 const useGlobalPopupBg = !!pick(cfg, 'useGlobalPopupBg', 'use_global_popup_bg', true); 85 const globalHeaderColor = pick(cfg, 'popupHeaderColor', 'popup_header_color', '#ffffff') || '#ffffff'; 86 const useGlobalHeaderColor = !!pick(cfg, 'useGlobalPopupHeaderColor', 'use_global_popup_header_color', true); 87 const globalBodyColor = pick(cfg, 'popupBodyColor', 'popup_body_color', '#333333') || '#333333'; 88 const useGlobalBodyColor = !!pick(cfg, 'useGlobalPopupBodyColor', 'use_global_popup_body_color', true); 89 const popupOffset = Math.max(0, parseInt(pick(cfg, 'popupOffset', 'popup_offset', 20), 10) || 20); 90 const popupBorderRadiusRaw = parseInt(pick(cfg, 'popupBorderRadius', 'popup_border_radius', 10), 10); 91 const popupBorderRadius = (!isNaN(popupBorderRadiusRaw) && popupBorderRadiusRaw >= 0) ? popupBorderRadiusRaw : 10; 92 93 const mapOpts = { scrollWheelZoom: false }; 94 if (isMobile) { 95 mapOpts.dragging = false; 96 mapOpts.touchZoom = false;
97 mapOpts.doubleClickZoom = false; 98 } 99 const map = L.map(id, mapOpts); 100 const tileUrl = pick(cfg, 'mapTileUrl', 'map_tile_url', '') || 101 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; 102 const tileOpts = {}; 103 const subdomains = pick(cfg, 'mapTileSubdomains', 'map_tile_subdomains', ''); 104 if (subdomains) tileOpts.subdomains = subdomains; 105 L.tileLayer(tileUrl, tileOpts).addTo(map); 106 const overlayUrl = pick(cfg, 'mapTileOverlayUrl', 'map_tile_overlay_url', ''); 107 if (overlayUrl) { 108 L.tileLayer(overlayUrl, tileOpts).addTo(map); 109 } 110 111 const bounds = L.latLngBounds(); 112 113 (cfg.locations || []).forEach(loc => { 114 const lat = parseFloat(loc.lat); 115 const lng = parseFloat(loc.lng); 116 if (!isFinite(lat) || !isFinite(lng)) return; 117 118 bounds.extend([lat, lng]); 119 120 const perColor = loc.color || globalColor; 121 const c = useGlobalColor ? globalColor : perColor; 122 const perPopupBg = loc.popup_body_bg || globalPopupBg; 123 const popupBg = useGlobalPopupBg ? globalPopupBg : perPopupBg; 124 const perHeaderColor = loc.popup_header_color || globalHeaderColor; 125 const headerColor = useGlobalHeaderColor ? globalHeaderColor : perHeaderColor; 126 const perBodyColor = loc.popup_body_color || globalBodyColor; 127 const bodyColor = useGlobalBodyColor ? globalBodyColor : perBodyColor; 128 129 const marker = L.marker([lat, lng], { icon: markerIcon(c) }).addTo(map); 130 131 const imgHtml = (loc.popup_image && loc.popup_image.trim()) ? `<div class="custom-popup-image"><img src="${loc.popup_image.replace(/"/g, '"')}" alt=""></div>` : ''; 132 const popup = L.popup({ 133 autoPan: false, 134 closeButton: false, 135 offset: [0, -popupOffset] 136 }) 137 .setLatLng([lat, lng]) 138 .setContent( 139 `<div class="custom-popup" style="--evolute-color:${c};--evolute-popup-bg:${popupBg};--evolute-popup-header-color:${headerColor};--evolute-popup-body-color:${bodyColor};--evolute-popup-radius:${popupBorderRadius}px">` + 140 `<div class="custom-popup-header">${loc.title || ''}</div>` + 141 imgHtml + 142 `<div class="custom-popup-body">${loc.popup_html || ''}</div>` + 143 `</div>` 144 ); 145 146 if (!popupClosed) popup.addTo(map); 147 marker.on('click', () => (map.hasLayer(popup) ? map.removeLayer(popup) : popup.addTo(map))); 148 }); 149 150 function fitAll() { 151 if (!bounds.isValid()) return; 152 map.fitBounds(bounds, { 153 paddingTopLeft: [160, 180], 154 paddingBottomRight: [160, 180], 155 animate: false 156 }); 157 } 158 159 const manualLat = pick(cfg, 'mapCenterLat', 'map_center_lat', ''); 160 const manualLng = pick(cfg, 'mapCenterLng', 'map_center_lng', ''); 161 const manualZoom = pick(cfg, 'mapCenterZoom', 'map_center_zoom', ''); 162 const hasManualView = manualLat !== '' && manualLng !== '' && isFinite(parseFloat(manualLat)) && isFinite(parseFloat(manualLng)); 163 164 if (hasManualView) { 165 const center = [parseFloat(manualLat), parseFloat(manualLng)]; 166 const z = (manualZoom !== '' && manualZoom !== null && isFinite(parseInt(manualZoom, 10))) 167 ? parseInt(manualZoom, 10) 168 : (parseInt(pick(cfg, 'desktopZoom', 'desktop_zoom', '15'), 10) || 15);
169 map.setView(center, Math.max(1, Math.min(18, z)), { animate: false }); 170 } else if (bounds.isValid()) { 171 const isMobile = window.matchMedia('(max-width:767px)').matches; 172 const z = isMobile ? pick(cfg, 'mobileZoom', 'mobile_zoom', '') : pick(cfg, 'desktopZoom', 'desktop_zoom', ''); 173 174 if (z !== '' && z !== null && z !== undefined && isFinite(parseInt(z, 10))) { 175 map.setView(bounds.getCenter(), parseInt(z, 10), { animate: false }); 176 } else { 177 fitAll(); 178 } 179 } 180 181 if (isMobile) { 182 let lastTouchStart = 0; 183 let lastTouchX = 0; 184 let lastTouchY = 0; 185 let mapInteractionEnabled = false; 186 let lastToggleTime = 0; 187 let lastTouchId = -1; 188 const DOUBLE_TAP_DELAY = 700; 189 const MOVE_THRESHOLD = 35; 190 const TOGGLE_COOLDOWN = 450; 191 const SAME_TOUCH_IGNORE_MS = 100; 192 193 function handleMobileDoubleTap(e) { 194 if (!e.changedTouches || !e.changedTouches[0]) return; 195 const t = e.changedTouches[0]; 196 const now = Date.now(); 197 if (now - lastToggleTime < TOGGLE_COOLDOWN) return; 198 if (t.identifier === lastTouchId && now - lastTouchStart < SAME_TOUCH_IGNORE_MS) return; 199 200 const x = t.clientX; 201 const y = t.clientY; 202 const isQuickTap = lastTouchStart > 0 && (now - lastTouchStart) < DOUBLE_TAP_DELAY; 203 const isSameArea = Math.abs(x - lastTouchX) < MOVE_THRESHOLD && Math.abs(y - lastTouchY) < MOVE_THRESHOLD; 204 205 if (isQuickTap && isSameArea) { 206 e.preventDefault(); 207 e.stopPropagation(); 208 lastToggleTime = now; 209 210 if (mapInteractionEnabled) { 211 map.dragging.disable(); 212 map.touchZoom.disable(); 213 el.style.touchAction = 'pan-y'; 214 mapInteractionEnabled = false; 215 } else { 216 map.dragging.enable(); 217 map.touchZoom.enable(); 218 el.style.touchAction = ''; 219 mapInteractionEnabled = true; 220 } 221 lastTouchStart = 0; 222 lastTouchX = 0; 223 lastTouchY = 0; 224 lastTouchId = -1; 225 return; 226 } 227 lastTouchStart = now; 228 lastTouchX = x; 229 lastTouchY = y; 230 lastTouchId = t.identifier; 231 } 232 233 el._evoluteTouchHandler = handleMobileDoubleTap; 234 el.addEventListener('touchstart', handleMobileDoubleTap, { capture: true, passive: false }); 235 el.style.touchAction = 'pan-y'; 236 237 const popupPane = map.getPane('popupPane'); 238 if (popupPane) { 239 el._evolutePopupPaneRef = popupPane; 240 el._evolutePopupPaneHandler = handleMobileDoubleTap; 241 popupPane.addEventListener('touchstart', handleMobileDoubleTap, { capture: true, passive: false }); 242 } 243 } 244 245 instances[id] = { map, bounds, fitAll }; 246 247 scheduleInstanceSizing(map); 248 attachResizeObserver(el, id); 249 } 250 251 function attachResizeObserver(el, id) { 252 if (!el || !window.ResizeObserver || el._evoluteResizeObs) return; 253 254 var ro = new ResizeObserver(function () { 255 var inst = instances[id]; 256 if (inst && inst.map) { 257 try { inst.map.invalidateSize(); } catch (e) {} 258 } 259 }); 260 ro.observe(el); 261 el._evoluteResizeObs = ro; 262 } 263 264 function ensureMapWidth(el) { 265 if (!el) return; 266 el.style.width = '100%'; 267 el.style.maxWidth = '100%'; 268 269 var widget = el.closest('.elementor-widget-shortcode'); 270 if (widget) { 271 widget.style.width = '100%'; 272 widget.style.alignSelf = 'stretch'; 273 widget.style.maxWidth = '100%'; 274 } 275 276 var wrap = el.closest('.elementor-shortcode'); 277 if (wrap) { 278 wrap.style.width = '100%'; 279 wrap.style.maxWidth = '100%'; 280 } 281 282 if (el.offsetWidth === 0) { 283 var parent = el.parentElement; 284 while (parent && parent !== document.body) { 285 var w = parent.clientWidth; 286 if (w > 0) { 287 el.style.width = w + 'px'; 288 break; 289 } 290 parent = parent.parentElement; 291 } 292 } 293 } 294 295 function initWhenSized(cfg) { 296 if (!cfg || !cfg.id) return; 297 var el = document.getElementById(cfg.id); 298 if (!el) return; 299 300 function go() { 301 ensureMapWidth(el); 302 initOne(cfg); 303 } 304 305 function tryGo() { 306 ensureMapWidth(el); 307 if (el.offsetWidth > 0 && el.offsetHeight > 0) { 308 go(); 309 return true; 310 } 311 return false;
312 } 313 314 if (tryGo()) return; 315 316 if (window.IntersectionObserver && !el._evoluteIo) { 317 el._evoluteIo = new IntersectionObserver(function (entries) { 318 entries.forEach(function (entry) { 319 if (!entry.isIntersecting) return; 320 if (tryGo()) { 321 el._evoluteIo.disconnect(); 322 el._evoluteIo = null; 323 } 324 }); 325 }, { rootMargin: '100px' }); 326 el._evoluteIo.observe(el); 327 } 328 329 var attempts = 0; 330 var timer = setInterval(function () { 331 attempts++; 332 if (tryGo() || attempts >= 60) { 333 clearInterval(timer); 334 if (attempts >= 60 && !instances[cfg.id]) go(); 335 } 336 }, 100); 337 } 338 339 function initMapsInRoot(root) { 340 (root || document).querySelectorAll('.evolute-map[data-evolute-maps-config]').forEach(function (el) { 341 try { 342 var cfg = JSON.parse(el.getAttribute('data-evolute-maps-config') || '{}'); 343 if (cfg && cfg.id) initWhenSized(cfg); 344 } catch (e) {} 345 }); 346 } 347 348 function scheduleInstanceSizing(map) { 349 [0, 100, 300, 600].forEach(function (ms) { 350 setTimeout(function () { 351 try { map.invalidateSize(); } catch (e) {} 352 }, ms); 353 }); 354 } 355
356 function invalidateAllMaps() { 357 Object.keys(instances).forEach(function (id) { 358 const inst = instances[id]; 359 if (inst && inst.map) { 360 try { inst.map.invalidateSize(); } catch (e) {} 361 } 362 }); 363 } 364 365 function elementorOnPage() { 366 return !!(window.elementorFrontendConfig || document.getElementById('elementor-frontend-js')); 367 } 368 369 function getConfigs() { 370 const fromData = []; 371 document.querySelectorAll('.evolute-map[data-evolute-maps-config]').forEach(function (el) { 372 try { 373 const cfg = JSON.parse(el.getAttribute('data-evolute-maps-config') || '{}'); 374 if (cfg && cfg.id) fromData.push(cfg); 375 } catch (e) {} 376 }); 377 const fromArray = window.EVOLUTE_MAPS || []; 378 return fromData.length ? fromData : fromArray; 379 } 380 381 window.EvoluteMapsInit = function (onlyId) { 382 const list = getConfigs(); 383 if (onlyId) { 384 const cfg = list.find(function (x) { return x && x.id === onlyId; }); 385 if (cfg) initWhenSized(cfg); 386 return; 387 } 388 list.forEach(initWhenSized); 389 }; 390 391 window.EvoluteMapsCenter = function (id) { 392 const inst = instances[id]; 393 if (inst && inst.fitAll) { 394 inst.fitAll(); 395 setTimeout(() => inst.map.invalidateSize(), 50); 396 return; 397 } 398 // fallback: re-init only this map 399 window.EvoluteMapsInit(id); 400 }; 401 402 function runInit() { 403 try { 404 window.EvoluteMapsInit(); 405 } catch (e) { 406 console.warn('Evolute Maps init:', e); 407 } 408 invalidateAllMaps(); 409 } 410 411 function scheduleStart() { 412 requestAnimationFrame(function () { 413 requestAnimationFrame(function () { 414 runInit(); 415 }); 416 }); 417 } 418 419 function registerElementorHooks() { 420 if (!window.elementorFrontend || !window.elementorFrontend.hooks) return; 421 if (window.__EVOLUTE_MAPS_ELEMENTOR_HOOKS) return; 422 window.__EVOLUTE_MAPS_ELEMENTOR_HOOKS = true; 423 424 elementorFrontend.hooks.addAction('frontend/element_ready/shortcode.default', function ($scope) { 425 var root = $scope && $scope[0] ? $scope[0] : document; 426 initMapsInRoot(root); 427 }); 428 429 elementorFrontend.hooks.addAction('frontend/element_ready/global', function ($scope) { 430 var root = $scope && $scope[0] ? $scope[0] : null; 431 if (root && root.querySelector && root.querySelector('.evolute-map')) { 432 initMapsInRoot(root); 433 } 434 }); 435 } 436 437 function bootWithElementor() { 438 registerElementorHooks(); 439 scheduleStart(); 440 441 if (document.readyState === 'complete') { 442 setTimeout(runInit, 150); 443 } else { 444 window.addEventListener('load', function () { 445 setTimeout(runInit, 150); 446 }); 447 } 448 449 if (window.jQuery) { 450 window.jQuery(window).on('elementor/frontend/init', function () { 451 registerElementorHooks(); 452 scheduleStart(); 453 }); 454 } 455 } 456 457 function boot() { 458 if (typeof window.L === 'undefined') { 459 setTimeout(boot, 50); 460 return; 461 } 462 463 if (elementorOnPage()) { 464 bootWithElementor(); 465 return; 466 } 467 468 runInit(); 469 } 470 471 if (document.readyState === 'loading') { 472 document.addEventListener('DOMContentLoaded', boot); 473 } else { 474 boot(); 475 } 476})();
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.