1jQuery(document).ready(function ($) { 2 var locationPopupEnabled = wlf_front_vars.showLocationPopup === 'yes'; 3 var locationPopupClosed = getCookie('wlf_location_popup_closed') === 'true'; 4 var locationCookieSet = !!getCookie('wlf_location_cookies'); 5 6 const allLocationsInTitle = wlf_front_vars.allLocationsInTitle || 'All Locations in'; 7 const parentContainer = $('.wlf-parent-locations-container'); 8 const childContainer = $('.wlf-child-locations-container'); 9 10 var wlfChildViewStack = []; 11 12 function wlfGetChildList() { 13 return $('.wlf-child-locations-container').find('ul.wlf-child-location-list'); 14 } 15 16 function wlfUpdatePopupBackButton() { 17 var isChildView = wlfChildViewStack.length > 0; 18 19 $('.wlf-location-popup-back-btn').toggle(isChildView); 20 $('.wlf-location-popup-header-icon').toggle(!isChildView); 21 $('.wlf-location-popup-header-mobile-icon').toggle(!isChildView); 22 } 23 24 function wlfShowMainLocationView() { 25 wlfChildViewStack = []; 26 $('.wlf-location-search-results').remove(); 27 $('#wlf-no-results').hide(); 28 wlfGetChildList().empty(); 29 childContainer.hide(); 30 parentContainer.show(); 31 wlfUpdatePopupBackButton(); 32 } 33 34 function wlfEnterChildLocationView(childContent) { 35 var $childList = wlfGetChildList(); 36 37 if (childContainer.is(':visible')) { 38 wlfChildViewStack.push($childList.html()); 39 } else { 40 wlfChildViewStack.push(null); 41 } 42 43 parentContainer.hide(); 44 $('.wlf-location-search-results').remove(); 45 $('#wlf-no-results').hide(); 46 $childList.html(childContent); 47 childContainer.show(); 48 wlfUpdatePopupBackButton(); 49 } 50 51 $(document).on('click', '.wlf-location-popup-back-btn', function (event) { 52 event.preventDefault(); 53 54 if (!wlfChildViewStack.length) { 55 wlfShowMainLocationView(); 56 return; 57 } 58 59 var previousView = wlfChildViewStack.pop(); 60 61 if (previousView === null || typeof previousView === 'undefined') { 62 wlfShowMainLocationView(); 63 return; 64 } 65 66 parentContainer.hide(); 67 wlfGetChildList().html(previousView); 68 childContainer.show(); 69 wlfUpdatePopupBackButton(); 70 }); 71 72 73 // ========================================== 74 // URL Routing & Cookie Sync Logic 75 // Moved from PHP to JS for stability 76 // ========================================== 77 var LOCATION_SLUGS = wlf_front_vars.locationSlugs || []; 78 var LOCATION_LABELS = { 'all': 'All' }; 79 80 function wlfRememberLocationLabel(slug, name) { 81 slug = (slug || '').toString().trim().toLowerCase(); 82 name = (name || '').toString().trim(); 83 84 if (slug && name) { 85 LOCATION_LABELS[slug] = name; 86 } 87 } 88 89 function wlfGetDefaultLocationLabel() { 90 return $('.wlf-selected-location-name').first().data('default-location-label') || 'Select your location'; 91 } 92 93 function wlfHydrateLocationLabelsFromDom() { 94 $('.wlf-featured-location-list li, .wlf-non-featured-location-list li, .wlf-child-locations-container li, .wlf-location-search-results li').each(function() { 95 var slug = $(this).data('location'); 96 var name = $(this).find('.wlf-featured-location-name, .wlf-non-featured-location-name, .wlf-child-location-name, .wlf-search-result-location-name').first().text().trim(); 97 98 wlfRememberLocationLabel(slug, name); 99 }); 100 101 wlfRememberLocationLabel($('#wlf-location-popup').data('selected-location-slug'), $('#wlf-location-popup').data('selected-location-name')); 102 } 103 104 // Dynamically populate labels from DOM payload. 105 wlfHydrateLocationLabelsFromDom(); 106 107 // Ensure SITE_BASE is correctly fetched 108 var SITE_BASE = ''; 109 try { 110 var siteUrl = new URL(wlf_front_vars.siteurl); 111 SITE_BASE = siteUrl.pathname.replace(/\/+$/, ''); 112 } catch(e) { 113 SITE_BASE = ''; 114 } 115 116 var switchingLocationUntil = 0; 117 118 function lc(s) { 119 return (s || '').toString().trim().toLowerCase(); 120 } 121 122 function getLocationCookieDomain() { 123 var host = window.location.hostname.toLowerCase(); 124 125 if (!host || host === 'localhost' || /^[0-9.]+$/.test(host)) { 126 return ''; 127 } 128 129 if (host.indexOf('www.') === 0) { 130 host = host.substring(4); 131 } 132 133 return '.' + host; 134 } 135 136 function setCookie(name, valLC, days) { 137 days = days || 7; 138 const date = new Date(); 139 date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000); 140 141 var value = name + '=' + encodeURIComponent(lc(valLC)) + 142 ';expires=' + date.toUTCString() + 143 ';path=/' + 144 ';samesite=Lax' + 145 (window.location.protocol === 'https:' ? ';secure' : ''); 146 147 // Host-only cookie for current host. 148 document.cookie = value; 149 150 // Parent-domain cookie so both www and non-www can read it. 151 var cookieDomain = getLocationCookieDomain(); 152 if (cookieDomain) { 153 document.cookie = value + ';domain=' + cookieDomain; 154 } 155 } 156 157 function getCookie(name) { 158 const cookies = document.cookie.split('; '); 159 var found = null; 160 161 for (let i = 0; i < cookies.length; i++) { 162 const parts = cookies[i].split('='); 163 if (parts[0] === name) { 164 found = decodeURIComponent(parts.slice(1).join('=') || ''); 165 } 166 } 167 168 return found; 169 } 170 171 function deleteCookie(name) { 172 var expired = name + '=;path=/;expires=Thu, 01 Jan 1970 00:00:00 UTC;' + 173 (window.location.protocol === 'https:' ? ';secure' : ''); 174 175 // Delete current host cookie. 176 document.cookie = expired; 177 178 // Delete parent-domain cookie. 179 var cookieDomain = getLocationCookieDomain(); 180 if (cookieDomain) { 181 document.cookie = expired + ';domain=' + cookieDomain; 182 } 183 184 // Delete explicit current hostname domain cookie, if any. 185 if (window.location.hostname) { 186 document.cookie = expired + ';domain=' + window.location.hostname; 187 } 188 } 189 190 function looksLikeFile(pathname) { 191 return /\.[a-z0-9]{1,5}(?:$|\?)/i.test(pathname); 192 } 193 194 function isLocationSlug(segLC) { 195 segLC = lc(segLC); 196 for (var i = 0;
196 i < LOCATION_SLUGS.length; i++) { 197 if (lc(LOCATION_SLUGS[i]) === segLC) return true; 198 } 199 return false; 200 } 201 202 function getCurrentUrlParts() { 203 var url = new URL(window.location.href); 204 var rawPath = url.pathname; 205 var rel = ''; 206 207 if (SITE_BASE && rawPath.indexOf(SITE_BASE + '/') === 0) { 208 rel = rawPath.substring((SITE_BASE + '/').length); 209 } else if (SITE_BASE && rawPath === SITE_BASE) { 210 rel = ''; 211 } else { 212 rel = rawPath.replace(/^\/+/, ''); 213 } 214 215 var relParts = rel ? rel.split('/') : []; 216 var firstSegLC = lc(relParts[0] || ''); 217 218 return { 219 url: url, 220 rawPath: rawPath, 221 rel: rel, 222 relParts: relParts, 223 firstSegLC: firstSegLC 224 }; 225 } 226 227 function updateSelectedUIFromSlug(slugLC) { 228 slugLC = lc(slugLC); 229 wlfHydrateLocationLabelsFromDom(); 230 231 var labelNode = $('.wlf-selected-location-name'); 232 if (labelNode.length) { 233 if (slugLC && slugLC !== 'all') { 234 var label = LOCATION_LABELS[slugLC]; 235 labelNode.text(label || wlfGetDefaultLocationLabel()); 236 } else { 237 labelNode.text(wlfGetDefaultLocationLabel()); 238 } 239 } 240 241 var lists = ['.wlf-featured-location-list li', '.wlf-non-featured-location-list li', '.wlf-child-locations-container li']; 242 $(lists.join(', ')).each(function() { 243 $(this).find('.wlf-selected-location-indicator').html(''); 244 var s = lc($(this).data('location') || ''); 245 if ((slugLC && s === slugLC) || (!slugLC && s === 'all')) { 246 $(this).find('.wlf-selected-location-indicator').html('<i class="fas fa-circle"></i>'); 247 } 248 }); 249 250 checkLocationType(slugLC); 251 } 252 253 function getRelWithoutLocationPrefix(rel) { 254 rel = (rel || '').replace(/^\/+|\/+$/g, ''); 255 if (!rel) return ''; 256 257 var parts = rel.split('/'); 258 var first = lc(parts[0] || ''); 259 260 if (isLocationSlug(first)) { 261 parts.shift(); 262 } 263 264 return parts.join('/'); 265 } 266 267 function buildPrefixedPath(slugLC, relWithoutPrefix) { 268 slugLC = lc(slugLC); 269 relWithoutPrefix = (relWithoutPrefix || '').replace(/^\/+|\/+$/g, ''); 270 271 var base = SITE_BASE ? SITE_BASE.replace(/\/+$/, '') : ''; 272 273 if (!slugLC || slugLC === 'all') { 274 var plainPath = base + (relWithoutPrefix ? '/' + relWithoutPrefix : '/'); 275 return plainPath.replace(/([^:])\/{2,}/g, '$1/'); 276 } 277 278 var newRel = slugLC + (relWithoutPrefix ? '/' + relWithoutPrefix : ''); 279 var newPath = base + '/' + newRel; 280 return newPath.replace(/([^:])\/{2,}/g, '$1/'); 281 } 282 283 function replaceUrlKeepingQueryHash(newPath) { 284 var url = new URL(window.location.href); 285 var finalUrl = newPath + url.search + url.hash; 286 var currentUrl = url.pathname + url.search + url.hash; 287 288 if (finalUrl !== currentUrl) { 289 history.replaceState(history.state, '', finalUrl); 290 } 291 } 292 293 function navigateToPath(newPath) { 294 var url = new URL(window.location.href); 295 var finalUrl = newPath + url.search + url.hash; 296 var currentUrl = url.pathname + url.search + url.hash; 297 298 if (finalUrl !== currentUrl) { 299 window.location.href = finalUrl; 300 } else { 301 window.location.reload(); 302 } 303 } 304 305 function ensureLocationSlugInUrl() { 306 var parts = getCurrentUrlParts(); 307 var url = parts.url; 308 var firstSegLC = parts.firstSegLC; 309 var rel = parts.rel; 310 var cookieLC = lc(getCookie('wlf_location_cookies') || ''); 311 312 var assetPrefixes = ['wp-admin', 'wp-includes', 'wp-content', 'wp-json']; 313 if (assetPrefixes.indexOf(firstSegLC) !== -1) return; 314 if (looksLikeFile(url.pathname)) return; 315 316 // During active switching: cookie should win 317 if (Date.now() < switchingLocationUntil) { 318 if (cookieLC && isLocationSlug(cookieLC)) { 319 var relWithoutPrefixDuringSwitch = getRelWithoutLocationPrefix(rel);
320 var pathDuringSwitch = buildPrefixedPath(cookieLC, relWithoutPrefixDuringSwitch); 321 replaceUrlKeepingQueryHash(pathDuringSwitch); 322 updateSelectedUIFromSlug(cookieLC); 323 } 324 return; 325 } 326 327 // Normal browsing: URL wins when it already has valid slug (i.e. Opening an external link) 328 if (isLocationSlug(firstSegLC)) { 329 if (cookieLC !== firstSegLC) { 330 setCookie('wlf_location_cookies', firstSegLC, 7); 331 } 332 updateSelectedUIFromSlug(firstSegLC); 333 return; 334 } 335 336 // If URL has no slug but cookie has one, restore it to URL 337 if (cookieLC && cookieLC !== 'all' && isLocationSlug(cookieLC)) { 338 var relWithoutPrefix = getRelWithoutLocationPrefix(rel); 339 var newPath = buildPrefixedPath(cookieLC, relWithoutPrefix); 340 replaceUrlKeepingQueryHash(newPath); 341 updateSelectedUIFromSlug(cookieLC); 342 return; 343 } 344 345 updateSelectedUIFromSlug('all'); 346 } 347 348 function debounce(fn, delay) { 349 var t; 350 return function() { 351 clearTimeout(t); 352 t = setTimeout(fn, delay); 353 }; 354 } 355 356 var ensureDebounced = debounce(function() { 357 ensureLocationSlugInUrl(); 358 }, 80); 359 360 window.WLF_setSelectedLocation = function(slug, options) { 361 var slugLC = lc(slug); 362 options = options || {}; 363 364 if (!slugLC) slugLC = 'all'; 365 if (!isLocationSlug(slugLC)) return false; 366 367 switchingLocationUntil = Date.now() + 2000; 368 369 var parts = getCurrentUrlParts(); 370 var relWithoutPrefix = getRelWithoutLocationPrefix(parts.rel); 371 372 setCookie('wlf_location_cookies', slugLC, 7); 373 updateSelectedUIFromSlug(slugLC); 374 375 var newPath = buildPrefixedPath(slugLC, relWithoutPrefix); 376 377 if (options.reload === true) { 378 navigateToPath(newPath); 379 } else { 380 replaceUrlKeepingQueryHash(newPath); 381 } 382 return true; 383 }; 384 385 if (String(wlf_front_vars.locationInUrl || 'no').toLowerCase() === 'yes') { 386 ensureLocationSlugInUrl(); 387 388 window.addEventListener('popstate', ensureDebounced); 389 390 var originalPushState = history.pushState; 391 var originalReplaceState = history.replaceState; 392 393 history.pushState = function() { 394 var result = originalPushState.apply(this, arguments); 395 ensureDebounced(); 396 return result; 397 }; 398 399 history.replaceState = function() { 400 var result = originalReplaceState.apply(this, arguments); 401 ensureDebounced(); 402 return result; 403 }; 404 405 $(document).ajaxComplete(ensureDebounced); 406 $(document.body).on('updated_wc_div wc_fragments_loaded wc_fragments_refreshed updated_checkout', ensureDebounced); 407 408 if (window.fetch) { 409 var originalFetch = window.fetch; 410 window.fetch = function() { 411 return originalFetch.apply(this, arguments).then(function(response) { 412 ensureDebounced(); 413 return response; 414 }); 415 }; 416 } 417 } 418 419 // ========================================== 420 // Existing Popup Logic 421 // ========================================== 422 423 if (locationPopupEnabled && !locationPopupClosed && !locationCookieSet) { 424 $('.wlf-location-popup').fadeIn(); 425 } 426 427 $(document).on('click', '#wlf-selected-location, .wlf-location-single-page-container', function () { 428 wlfShowMainLocationView(); 429 $('.wlf-location-popup').fadeIn(); 430 }); 431 432 // Handle clicking on a parent location 433 $(document).on('click', '.wlf-featured-location-list li, .wlf-non-featured-location-list li', function (event) { 434 event.preventDefault(); 435 436 const $clickedElement = $(this); 437 const selectedLocationId = $clickedElement.data('location-id'); 438 const selectedLocationSlug = $clickedElement.data('location'); 439 const selectedLocationName = $clickedElement.find('.wlf-featured-location-name, .wlf-non-featured-location-name').text().trim(); 440 const hasChildren = $clickedElement.data('has-children'); 441 442 if (!selectedLocationId) { 443 return; 444 } 445 446 if (hasChildren) { 447 // Fetch child locations via AJAX 448 $.ajax({ 449 url: wlf_front_vars.ajaxurl, 450 type: 'POST', 451 data: { 452 action: 'get_child_locations', 453 parent_id: selectedLocationId, 454 }, 455 success: function (response) { 456 if (response.success && Array.isArray(response.data) && response.data.length > 0) { 457 $('.wlf-parent-locations-container').hide(); 458 const childContainer = $('.wlf-child-locations-container'); 459 const childList = childContainer.find('ul.wlf-child-location-list'); 460 let childContent = ''; 461 wlfRememberLocationLabel(selectedLocationSlug, selectedLocationName); 462 463 // Add "All Locations" option 464 const isParentSelected = selectedLocationSlug === getCookie('wlf_location_cookies'); 465 childContent += ` 466 <li data-location="${selectedLocationSlug}" data-location-id="${selectedLocationId}" class="all-locations-option"> 467 <div class="wlf-child-top-parent-location-content"> 468 <div class="wlf-child-top-parent-location-indicator-name"> 469 <div class="wlf-selected-location-indicator"> 470 ${isParentSelected ? '<i class="fas fa-circle"></i>' : ''} 471 </div> 472 <div class="wlf-child-location-name">${allLocationsInTitle} ${selectedLocationName}</div> 473 </div> 474 <button type="button" class="button wlf-default-clear-location-btn" style="display: none;">Clear</button> 475 </div> 476 </li>`; 477 478 // --------- SORT FEATURED FIRST --------- 479 const sortedChildren = response.data.slice().sort(function(a, b) { 480 if (a.is_featured === b.is_featured) return 0; 481 return a.is_featured ? -1 : 1; 482 }); 483
484 sortedChildren.forEach(function (child) { 485 wlfRememberLocationLabel(child.slug, child.name); 486 const isChildSelected = child.slug === getCookie('wlf_location_cookies'); 487 childContent += ` 488 <li data-location="${child.slug}" data-location-id="${child.term_id}" data-has-children="${child.has_children}"> 489 <div class="wlf-child-location-content"> 490 <div class="wlf-child-location-image-name-container"> 491 ${child.image ? `<div class="wlf-child-location-image-container"><img src="${child.image}" alt="${child.name}"></div>` : ''} 492 <div class="wlf-child-location-name">${child.name}</div> 493 </div> 494 <div class="wlf-location-indicators"> 495 <div class="wlf-selected-location-indicator"> 496 ${isChildSelected ? '<i class="fas fa-circle"></i>' : ''} 497 </div> 498 ${child.has_children ? '<div class="wlf-has-children-indicator"><i class="fas fa-angle-right"></i></div>' : ''} 499 </div> 500 </div> 501 </li>`; 502 }); 503 504 wlfEnterChildLocationView(childContent); 505 } 506 }, 507 error: function (error) { } 508 }); 509 } else { 510 setSelectedLocation(selectedLocationSlug); 511 } 512 }); 513 514 // Handle clicking on a child location or "All Locations" 515 $(document).on('click', '.wlf-child-locations-container li', function () { 516 const $clickedElement = $(this); 517 const selectedLocationId = $clickedElement.data('location-id'); 518 const selectedLocationSlug = $clickedElement.data('location'); 519 const selectedLocationName = $clickedElement.find('.wlf-child-location-name').text().trim(); 520 const hasChildren = $clickedElement.data('has-children'); 521 522 if (hasChildren) { 523 $.ajax({ 524 url: wlf_front_vars.ajaxurl, 525 type: 'POST', 526 data: { 527 action: 'get_child_locations', 528 parent_id: selectedLocationId, 529 }, 530 success: function (response) { 531 if (response.success && Array.isArray(response.data) && response.data.length > 0) { 532 const childContainer = $('.wlf-child-locations-container'); 533 const childList = childContainer.find('ul.wlf-child-location-list'); 534 let childContent = ''; 535 wlfRememberLocationLabel(selectedLocationSlug, selectedLocationName); 536 537 // Add "All Locations" option 538 const isChildSelected = selectedLocationSlug === getCookie('wlf_location_cookies'); 539 childContent += ` 540 <li data-location="${selectedLocationSlug}" data-location-id="${selectedLocationId}" class="all-locations-option"> 541 <div class="wlf-child-top-parent-location-content"> 542 <div class="wlf-child-top-parent-location-indicator-name"> 543 <div class="wlf-selected-location-indicator"> 544 ${isChildSelected ? '<i class="fas fa-circle"></i>' : ''} 545 </div> 546 <div class="wlf-child-location-name">${allLocationsInTitle} ${selectedLocationName}</div> 547 </div> 548 <button type="button" class="button wlf-default-clear-location-btn" style="display: none;">Clear</button> 549 </div> 550 </li>`; 551 552 // --------- SORT FEATURED FIRST --------- 553 const sortedChildren = response.data.slice().sort(function(a, b) { 554 if (a.is_featured === b.is_featured) return 0; 555 return a.is_featured ? -1 : 1; 556 }); 557
558 sortedChildren.forEach(function (child) { 559 wlfRememberLocationLabel(child.slug, child.name); 560 const isChildSelected = child.slug === getCookie('wlf_location_cookies'); 561 childContent += ` 562 <li data-location="${child.slug}" data-location-id="${child.term_id}" data-has-children="${child.has_children}"> 563 <div class="wlf-child-location-content"> 564 <div class="wlf-child-location-image-name-container"> 565 ${child.image ? `<div class="wlf-child-location-image-container"><img src="${child.image}" alt="${child.name}"></div>` : ''} 566 <div class="wlf-child-location-name">${child.name}</div> 567 </div> 568 <div class="wlf-location-indicators"> 569 <div class="wlf-selected-location-indicator"> 570 ${isChildSelected ? '<i class="fas fa-circle"></i>' : ''} 571 </div> 572 ${child.has_children ? '<div class="wlf-has-children-indicator"><i class="fas fa-angle-right"></i></div>' : ''} 573 </div> 574 </div> 575 </li>`; 576 }); 577 578 wlfEnterChildLocationView(childContent); 579 } 580 }, 581 error: function (error) { } 582 }); 583 } else { 584 setSelectedLocation(selectedLocationSlug); 585 } 586 }); 587 588 // Handle location search 589 $('#wlf-location-search').on('input', function () { 590 const searchTerm = $(this).val().trim(); 591 $('.wlf-location-search-results').remove(); 592 $('#wlf-no-results').hide(); 593 wlfShowMainLocationView(); 594 595 if (searchTerm.length < 2) return; 596 597 parentContainer.hide(); 598 childContainer.hide(); 599 600 $.ajax({ 601 url: wlf_front_vars.ajaxurl, 602 type: 'POST', 603 data: { 604 action: 'search_locations', 605 search: searchTerm, 606 }, 607 success: function (response) { 608 $('.wlf-location-search-results').remove(); 609 610 if (response.success && Array.isArray(response.data)) { 611 const resultsContainer = $('<ul class="wlf-location-search-results"></ul>'); 612 if (response.data.length > 0) { 613 response.data.forEach(function (location) { 614 wlfRememberLocationLabel(location.slug, location.name); 615 const listItem = ` 616 <li data-location="${location.slug}" data-location-id="${location.term_id}"> 617 <div class="wlf-search-result-location-name-image-container"> 618 ${location.image ? `<div class="wlf-search-result-location-image-container"><img src="${location.image}" alt="${location.name}" /></div>` : ''} 619 <div class="wlf-search-result-location-name">${location.name}</div> 620 </div> 621 </li> 622 `; 623 resultsContainer.append(listItem); 624 }); 625 $('#wlf-location-popup').find('.wlf-search-container').after(resultsContainer); 626 } else { 627 $('#wlf-no-results').show(); 628 } 629 } 630 }, 631 error: function () { 632 console.error('Error fetching search results'); 633 }, 634 }); 635 }); 636 637 // Check whether the selected location is featured or non-featured 638 function checkLocationType(selectedLocation) { 639 var isFeatured = false; 640 var isNonFeatured = false;
641 642 $('.wlf-featured-location-list li').each(function () { 643 if ($(this).data('location') === selectedLocation) { 644 isFeatured = true; 645 } 646 }); 647 648 $('.wlf-non-featured-location-list li').each(function () { 649 if ($(this).data('location') === selectedLocation) { 650 isNonFeatured = true; 651 } 652 }); 653 654 if (isFeatured) { 655 $('.wlf-clear-featured-selected-location-button').show(); 656 $('.wlf-clear-non-featured-selected-location-button').hide(); 657 } else if (isNonFeatured) { 658 $('.wlf-clear-featured-selected-location-button').hide(); 659 $('.wlf-clear-non-featured-selected-location-button').show(); 660 } else { 661 $('.wlf-clear-featured-selected-location-button, .wlf-clear-non-featured-selected-location-button').hide(); 662 } 663 } 664 665 var selectedLocation = getCookie('wlf_location_cookies'); 666 if (selectedLocation) { 667 checkLocationType(selectedLocation); 668 } 669 670 $(document).on('click', '.wlf-clear-featured-selected-location-button, .wlf-clear-non-featured-selected-location-button', function () { 671 var locationInUrlEnabled = 672 String((wlf_front_vars && wlf_front_vars.locationInUrl) || 'no').toLowerCase() === 'yes'; 673 674 if (locationInUrlEnabled && typeof window.WLF_setSelectedLocation === 'function') { 675 window.WLF_setSelectedLocation('all', { reload: true }); 676 return; 677 } 678 679 deleteCookie('wlf_location_cookies'); 680 location.reload(); 681 }); 682 683 $(document).on('click', '.wlf-location-search-results li', function () { 684 const selectedLocationSlug = $(this).data('location'); 685 if (!selectedLocationSlug) return; 686 setSelectedLocation(selectedLocationSlug); 687 }); 688 689 function setSelectedLocation(slug) { 690 slug = (slug || '').toString().trim().toLowerCase(); 691 692 var locationInUrlEnabled = 693 String((wlf_front_vars && wlf_front_vars.locationInUrl) || 'no').toLowerCase() === 'yes'; 694 695 // close popup immediately for better UX 696 $('.wlf-location-popup').fadeOut(); 697 698 // when URL mode is enabled, delegate everything to the central helper 699 if (locationInUrlEnabled && typeof window.WLF_setSelectedLocation === 'function') { 700 window.WLF_setSelectedLocation(slug, { reload: true }); 701 return; 702 } 703 704 // fallback when location in URL is disabled 705 setCookie('wlf_location_cookies', slug, 7); 706 707 window.location.reload(); 708 } 709 710 $(document).on('click', '.wlf-location-popup-close-btn', function () { 711 $('.wlf-location-popup').fadeOut(); 712 wlfShowMainLocationView(); 713 setCookie('wlf_location_popup_closed', 'true', 7); 714 }); 715}); 716 717/* Woo Location Filter - Frontend auto location detect */ 718jQuery(function ($) { 719 if (typeof wlf_front_vars === 'undefined' || String(wlf_front_vars.autoLocationDetect || 'no').toLowerCase() !== 'yes') { 720 return; 721 } 722 723 var $detectWrapper = $('.wlf-detect-my-location-btn-wrapper'); 724 if ($detectWrapper.length && !$detectWrapper.find('.wlf-detect-my-location-btn').length) { 725 $detectWrapper.html('<button type="button" class="button wlf-detect-my-location-btn"><i class="fas fa-location-arrow"></i><span>Detect my location</span></button>'); 726 } 727 728 function wlfSetDetectButtonState(isLoading, text) { 729 var $btn = $('.wlf-detect-my-location-btn'); 730 if (!$btn.length) { 731 return; 732 } 733 734 if (!$btn.data('default-text')) { 735 $btn.data('default-text', $.trim($btn.text()) || 'Detect my location'); 736 } 737 738 $btn.prop('disabled', !!isLoading).toggleClass('is-loading', !!isLoading); 739 $btn.find('span').text(text || $btn.data('default-text')); 740 } 741 742 function wlfShowNoServicePopup(message) { 743 message = message || 'Sorry, we do not currently provide service at this location. Please choose a nearby location manually.'; 744 745 $('.wlf-location-popup').fadeOut(150); 746 $('.wlf-no-service-message').text(message); 747 $('#wlf-no-service-popup').fadeIn(180).css('display', 'flex'); 748 } 749 750 function wlfApplyDetectedLocation(locationSlug) { 751 if (!locationSlug) { 752 wlfShowNoServicePopup(); 753 return; 754 } 755 756 $('.wlf-location-popup, #wlf-no-service-popup').fadeOut(120); 757 758 if (typeof window.WLF_setSelectedLocation === 'function') { 759 window.WLF_setSelectedLocation(locationSlug, { reload: true }); 760 return; 761 } 762 763 // Fallback if the central helper is unavailable. 764 var date = new Date(); 765 date.setTime(date.getTime() + (7 * 24 * 60 * 60 * 1000)); 766 document.cookie = 'wlf_location_cookies=' + encodeURIComponent(locationSlug) + ';expires=' + date.toUTCString() + ';path=/;samesite=Lax' + (window.location.protocol === 'https:' ? ';secure' : ''); 767 window.location.reload(); 768 } 769 770 function wlfCheckCoordinatesAgainstZones(lat, lng, source) { 771 wlfSetDetectButtonState(true, source === 'search' ? 'Checking location...' : 'Detecting...'); 772 773 $.ajax({ 774 url: wlf_front_vars.ajaxurl, 775 type: 'POST', 776 dataType: 'json', 777 data: {
778 action: 'wlf_detect_location_by_coordinates', 779 nonce: wlf_front_vars.nonce, 780 lat: lat, 781 lng: lng, 782 source: source || 'browser' 783 }, 784 success: function (response) { 785 if (response && response.success && response.data && response.data.location_slug) { 786 wlfApplyDetectedLocation(response.data.location_slug); 787 return; 788 } 789 790 var message = response && response.data && response.data.message ? response.data.message : ''; 791 wlfShowNoServicePopup(message); 792 }, 793 error: function () { 794 wlfShowNoServicePopup('Unable to check service availability right now. Please choose your location manually.'); 795 }, 796 complete: function () { 797 wlfSetDetectButtonState(false); 798 } 799 }); 800 } 801 802 $(document).on('click', '.wlf-detect-my-location-btn', function (e) { 803 e.preventDefault(); 804 805 if (!navigator.geolocation) { 806 wlfShowNoServicePopup('Your browser does not support location detection. Please choose your location manually.'); 807 return; 808 } 809 810 wlfSetDetectButtonState(true, 'Detecting...'); 811 812 navigator.geolocation.getCurrentPosition( 813 function (position) { 814 wlfCheckCoordinatesAgainstZones(position.coords.latitude, position.coords.longitude, 'browser'); 815 }, 816 function () { 817 wlfSetDetectButtonState(false); 818 wlfShowNoServicePopup('Location permission was denied or unavailable. Please choose your location manually.'); 819 }, 820 { 821 enableHighAccuracy: true, 822 timeout: 15000, 823 maximumAge: 300000 824 } 825 ); 826 }); 827 828 $(document).on('click', '.wlf-no-service-popup-close', function () { 829 $('#wlf-no-service-popup').fadeOut(150); 830 }); 831 832 function wlfOpenManualLocationPopupFromNoService() { 833 $('.wlf-location-search-results').remove(); 834 $('#wlf-no-results').hide(); 835 $('#wlf-location-search').val(''); 836 837 $('.wlf-child-location-list').empty(); 838 $('.wlf-child-locations-container').hide(); 839 $('.wlf-parent-locations-container').show(); 840 $('.wlf-location-popup-back-btn').hide(); 841 $('.wlf-location-popup-header-icon').show(); 842 $('.wlf-location-popup-header-mobile-icon').show(); 843 844 $('#wlf-no-service-popup').fadeOut(150, function () { 845 $('#wlf-location-popup').fadeIn(180).css('display', 'flex'); 846 847 setTimeout(function () { 848 $('#wlf-location-search').trigger('focus'); 849 }, 220); 850 }); 851 } 852 853 $(document).on('click', '.wlf-no-service-choose-location', function (e) { 854 e.preventDefault(); 855 wlfOpenManualLocationPopupFromNoService(); 856 }); 857 858 async function wlfInitGooglePlacesSearch() { 859 if (!$('#wlf-location-search').length) { 860 return; 861 } 862 863 if (typeof google === 'undefined' || !google.maps || !google.maps.importLibrary) { 864 return; 865 } 866 867 try { 868 await google.maps.importLibrary('places'); 869 var input = document.getElementById('wlf-location-search'); 870 var autocomplete = new google.maps.places.Autocomplete(input, { 871 fields: ['geometry', 'name', 'formatted_address'], 872 types: ['geocode'] 873 }); 874 875 autocomplete.addListener('place_changed', function () { 876 var place = autocomplete.getPlace(); 877 if (!place || !place.geometry || !place.geometry.location) { 878 return; 879 } 880 881 // Remove manual AJAX suggestions when a Google place is selected. 882 $('.wlf-location-search-results').remove(); 883 $('#wlf-no-results').hide(); 884 885 wlfCheckCoordinatesAgainstZones( 886 place.geometry.location.lat(), 887 place.geometry.location.lng(), 888 'search' 889 ); 890 }); 891 } catch (error) { 892 if (window.console && console.warn) { 893 console.warn('WLF Google Places search could not be initialized:', error); 894 } 895 } 896 } 897 898 wlfInitGooglePlacesSearch(); 899});
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.