1/* 2 * ========================================================= 3 * GO Deals Debug Mode 4 * ========================================================= 5 * 6 * false = no GO Deals console output 7 * true = show GO Deals console output 8 * 9 * Enable this temporarily when debugging. 10 */ 11const GO_DEALS_DEBUG = false; 12 13function goDealsLog(...args) { 14 if (GO_DEALS_DEBUG) { 15 console.log(...args); 16 } 17} 18 19function goDealsWarn(...args) { 20 if (GO_DEALS_DEBUG) { 21 console.warn(...args); 22 } 23} 24 25function goDealsError(...args) { 26 if (GO_DEALS_DEBUG) { 27 console.error(...args); 28 } 29} 30 31 32document.addEventListener('DOMContentLoaded', function () { 33 34 /* 35 * ========================================================= 36 * Set current store 37 * ========================================================= 38 * 39 * Makes sure StoreA exists in sessionStorage. 40 * 41 * If user does not exist: 42 * create user with StoreA. 43 * 44 * If user exists but StoreA does not exist: 45 * add StoreA without removing existing values. 46 * 47 * If StoreA already exists: 48 * leave it unchanged. 49 */ 50 51 window.goDealsSetCurrentStore = function (storeNumber) { 52 53 storeNumber = String(storeNumber); 54 55 if (!storeNumber) { 56 return; 57 } 58 59 60 const storeA = 61 Number(storeNumber); 62 63 64 try { 65 66 const storedUser = 67 sessionStorage.getItem('user'); 68 69 70 /* 71 * ------------------------------------------------- 72 * No user session exists 73 * ------------------------------------------------- 74 */ 75 76 if (!storedUser) { 77 78 const user = { 79 StoreA: storeA 80 }; 81 82 83 sessionStorage.setItem( 84 'user', 85 JSON.stringify(user) 86 ); 87 88 89 goDealsLog( 90 'GO Deals: user session created:', 91 user 92 ); 93 94 95 } else { 96 97 /* 98 * ------------------------------------------------- 99 * User session already exists 100 * ------------------------------------------------- 101 */ 102 103 let user; 104 105 106 try { 107 108 user = 109 JSON.parse(storedUser); 110 111 } catch (error) { 112 113 goDealsWarn( 114 'GO Deals: Invalid user session. Recreating it.' 115 ); 116 117 user = {}; 118 } 119 120 121 /* 122 * ------------------------------------------------- 123 * Add StoreA if missing 124 * ------------------------------------------------- 125 */ 126 127 if ( 128 !user.StoreA 129 ) { 130 131 user.StoreA = 132 storeA; 133 134 135 sessionStorage.setItem( 136 'user', 137 JSON.stringify(user) 138 ); 139 140 141 goDealsLog( 142 'GO Deals: Added StoreA to existing user session:', 143 storeA 144 ); 145 146 147 } else { 148 149 goDealsLog( 150 'GO Deals: StoreA already exists:', 151 user.StoreA 152 ); 153 } 154 } 155 156 157 } catch (error) { 158 159 goDealsError( 160 'GO Deals: Unable to synchronize StoreA:', 161 error 162 ); 163 } 164 165 166 /* 167 * --------------------------------------------------------- 168 * selected_store cookie 169 * --------------------------------------------------------- 170 */ 171 172 document.cookie = 173 'selected_store=' + 174 encodeURIComponent(storeNumber) + 175 '; path=/; max-age=86400'; 176 177 178 /* 179 * --------------------------------------------------------- 180 * preferred-store cookie 181 * --------------------------------------------------------- 182 */ 183 184 document.cookie = 185 'preferred-store=' + 186 encodeURIComponent(storeNumber) + 187 '; path=/; max-age=' + 188 (365 * 24 * 60 * 60); 189 190 191 /* 192 * --------------------------------------------------------- 193 * Notify existing store-dependent functionality 194 * --------------------------------------------------------- 195 */ 196 197 if ( 198 window.deps && 199 window.deps.user && 200 typeof window.deps.user.changed === 'function' 201 ) { 202 203 try { 204 205 window.deps.user.changed(); 206 207 } catch (error) { 208 209 goDealsWarn( 210 'GO Deals: deps.user.changed() failed:', 211 error 212 ); 213 } 214 } 215 216 217 goDealsLog( 218 'GO Deals: Current store synchronized:', 219 storeNumber 220 ); 221 }; 222 223 224 /* 225 * ========================================================= 226 * Find deal sections 227 * ========================================================= 228 */ 229 230 const sections = 231 document.querySelectorAll( 232 '.go-deals-section' 233 ); 234 235 236 goDealsLog(
237 'GO Deals: Sections found:', 238 sections.length 239 ); 240 241 242 if (!sections.length) { 243 244 goDealsLog( 245 'GO Deals: No deal sections found.' 246 ); 247 248 return; 249 } 250 251 252 /* 253 * ========================================================= 254 * Identify sections 255 * ========================================================= 256 */ 257 258 const hasWeeklyWin = 259 Array.from( 260 sections 261 ).some( 262 function (sectionElement) { 263 264 return ( 265 sectionElement.getAttribute( 266 'data-go-deals-section' 267 ) === 'weekly_win' 268 ); 269 270 } 271 ); 272 273 274 const hasNormalSections = 275 Array.from( 276 sections 277 ).some( 278 function (sectionElement) { 279 280 const section = 281 sectionElement.getAttribute( 282 'data-go-deals-section' 283 ); 284 285 286 return ( 287 section === 'top_deals' || 288 section === 'coming_soon' 289 ); 290 291 } 292 ); 293 294 295 goDealsLog( 296 'GO Deals: Has Weekly Win:', 297 hasWeeklyWin 298 ); 299 300 301 goDealsLog( 302 'GO Deals: Has normal sections:', 303 hasNormalSections 304 ); 305 306 307 /* 308 * ========================================================= 309 * Initialize store 310 * ========================================================= 311 * 312 * Backend logic: 313 * 314 * 1. preferred-store exists: 315 * - use existing store 316 * - get region from database 317 * 318 * 2. preferred-store does not exist: 319 * - check Cloudflare country 320 * - non-US -> no deals 321 * - US -> find nearby store 322 * 323 * No fallback store is used. 324 */ 325 326 goDealsLog( 327 'GO Deals: Calling initialize:', 328 GODealsConfig.initializeUrl 329 ); 330 331 332 fetch( 333 GODealsConfig.initializeUrl, 334 { 335 method: 'GET', 336 337 credentials: 'same-origin', 338 339 headers: { 340 'Accept': 341 'application/json' 342 } 343 } 344 ) 345 346 347 /* 348 * ========================================================= 349 * Initialize response 350 * ========================================================= 351 */ 352 353 .then( 354 function (response) { 355 356 goDealsLog( 357 'GO Deals: Initialize HTTP status:', 358 response.status 359 ); 360 361 362 if (!response.ok) { 363 364 return response.text() 365 .then( 366 function (text) { 367 368 goDealsError( 369 'GO Deals: Initialize error response:', 370 text 371 ); 372 373 374 throw new Error( 375 'Unable to initialize store.' 376 ); 377 } 378 ); 379 } 380 381 382 return response.json(); 383 } 384 ) 385 386 387 /* 388 * ========================================================= 389 * Determine store / country / region 390 * ========================================================= 391 */ 392 393 .then( 394 function (data) { 395 396 goDealsLog( 397 'GO Deals: Initialize response:', 398 data 399 ); 400 401 402 /* 403 * ------------------------------------------------- 404 * Validate initialize response 405 * ------------------------------------------------- 406 */ 407 408 if ( 409 !data || 410 !data.success 411 ) { 412 413 throw new Error( 414 data && data.message 415 ? data.message 416 : 'Unable to initialize store.' 417 ); 418 } 419 420 421 /* 422 * ------------------------------------------------- 423 * Country 424 * ------------------------------------------------- 425 */ 426 427 const country = 428 data.country 429 ? String( 430 data.country 431 ).trim().toUpperCase() 432 : ''; 433 434 435 goDealsLog( 436 'GO Deals - Country:', 437 country 438 ); 439 440 441 /* 442 * ------------------------------------------------- 443 * Non-US 444 * ------------------------------------------------- 445 * 446 * No fallback anymore. 447 * 448 * Do not show: 449 * 450 * - Top Deals 451 * - Coming Soon 452 * - Weekly Win 453 */ 454 455 if ( 456 !country || 457 country !== 'US' 458 ) { 459 460 goDealsLog( 461 'GO Deals: Visitor is not in the US. No deals will be displayed.' 462 ); 463 464 465 throw new Error( 466 'GO Deals are only available in the US.' 467 ); 468 } 469 470 471 /* 472 * ------------------------------------------------- 473 * Store number 474 * ------------------------------------------------- 475 */ 476 477 const storeNumber = 478 data.store_number 479 ? String( 480 data.store_number 481 ).trim() 482 : ''; 483 484 485 goDealsLog( 486 'GO Deals - Store:', 487 storeNumber 488 ); 489 490 491 /* 492 * ------------------------------------------------- 493 * Store number is required 494 * ------------------------------------------------- 495 */ 496 497 if (!storeNumber) { 498 499 throw new Error( 500 'Store number not found.' 501 ); 502 } 503 504 505 /* 506 * ------------------------------------------------- 507 * Region 508 * ------------------------------------------------- 509 * 510 * Region comes directly from the initialize 511 * REST API. 512 * 513 * No all-stores-4. 514 * No waitForStores(). 515 */ 516 517 const region = 518 data.region 519 ? String( 520 data.region 521 ).trim() 522 : ''; 523 524 525 goDealsLog( 526 'GO Deals - Region:', 527 region 528 ); 529 530 531 /* 532 * ------------------------------------------------- 533 * Region is required 534 * ------------------------------------------------- 535 */ 536 537 if (!region) { 538 539 throw new Error( 540 'Region not found for selected store.' 541 ); 542 } 543 544 545 /* 546 * ------------------------------------------------- 547 * IMPORTANT: 548 * 549 * Whether the store came from: 550 * 551 * source = "cookie" 552 * 553 * OR 554 * 555 * source = "ip" 556 * 557 * make sure StoreA exists in sessionStorage. 558 * 559 * We do NOT overwrite StoreA if it already exists. 560 * ------------------------------------------------- 561 */ 562 563 window.goDealsSetCurrentStore( 564 storeNumber 565 ); 566 567 568 /* 569 * =================================================
570 * Render all 3 sections 571 * ================================================= 572 */ 573 574 goDealsLog( 575 'GO Deals: Calling render:', 576 GODealsConfig.renderUrl 577 ); 578 579 580 goDealsLog( 581 'GO Deals: Render request:', 582 { 583 store_number: 584 Number( 585 storeNumber 586 ), 587 588 region: 589 region, 590 591 country: 592 country 593 } 594 ); 595 596 597 return fetch( 598 GODealsConfig.renderUrl, 599 { 600 method: 'POST', 601 602 credentials: 603 'same-origin', 604 605 headers: { 606 'Content-Type': 607 'application/json', 608 609 'Accept': 610 'application/json' 611 }, 612 613 body: 614 JSON.stringify({ 615 store_number: 616 Number( 617 storeNumber 618 ), 619 620 region: 621 region, 622 623 country: 624 country 625 }) 626 } 627 ); 628 } 629 ) 630 631 632 /* 633 * ========================================================= 634 * Render response 635 * ========================================================= 636 */ 637 638 .then( 639 function (response) { 640 641 goDealsLog( 642 'GO Deals: Render HTTP status:', 643 response.status 644 ); 645 646 647 if (!response.ok) { 648 649 return response.text() 650 .then( 651 function (text) { 652 653 goDealsError( 654 'GO Deals: Render error response:', 655 text 656 ); 657 658 659 throw new Error( 660 'Unable to load deals.' 661 ); 662 } 663 ); 664 } 665 666 667 return response.json(); 668 } 669 ) 670 671 672 /* 673 * ========================================================= 674 * Render sections 675 * ========================================================= 676 */ 677 678 .then( 679 function (data) { 680 681 goDealsLog( 682 'GO Deals: Render response:', 683 data 684 ); 685 686 687 if ( 688 !data || 689 !data.success 690 ) { 691 692 throw new Error( 693 data && data.message 694 ? data.message 695 : 'Unable to load deals.' 696 ); 697 } 698 699 700 if ( 701 !data.sections || 702 typeof data.sections !== 'object' 703 ) { 704 705 throw new Error( 706 'Invalid render response.' 707 ); 708 } 709 710 711 /* 712 * ------------------------------------------------- 713 * Render each section 714 * ------------------------------------------------- 715 */ 716 717 sections.forEach( 718 function (sectionElement) { 719 720 /* 721 * The element may have been removed or 722 * cleared because of an error. 723 */ 724 725 if ( 726 !document.body.contains( 727 sectionElement 728 ) 729 ) { 730 731 return; 732 } 733 734 735 const section = 736 sectionElement.getAttribute( 737 'data-go-deals-section' 738 ); 739 740 741 const sectionHtml = 742 data.sections[ 743 section 744 ]; 745 746 747 goDealsLog( 748 'GO Deals: Section result:', 749 { 750 section: 751 section, 752 753 hasHtml: 754 typeof sectionHtml === 'string' && 755 sectionHtml.trim() !== '' 756 } 757 ); 758 759 760 if ( 761 typeof sectionHtml === 'string' && 762 sectionHtml.trim() !== '' 763 ) { 764 765 sectionElement.innerHTML = 766 sectionHtml; 767 768 769 goDealsLog( 770 'GO Deals: Rendered:', 771 section 772 ); 773 774 775 /* 776 * ------------------------------------------------- 777 * Weekly Win More button 778 * ------------------------------------------------- 779 * 780 * Hide the Elementor button when Weekly Win 781 * has data. 782 */ 783 784 if (section === 'weekly_win') { 785 786 const winMoreBtn = 787 document.querySelector('.win-more-btn'); 788 789 790 if (winMoreBtn) { 791 792 winMoreBtn.style.display = 'none'; 793 794 795 goDealsLog( 796 'GO Deals: Weekly Win has data - hiding win-more-btn' 797 ); 798 } 799 } 800 801 802 /* 803 * Initialize Upcoming Deals slider
804 * AFTER the HTML has been inserted. 805 */ 806 807 if ( 808 section === 'coming_soon' && 809 typeof window.initGoDealsSlider === 'function' 810 ) { 811 812 setTimeout( 813 function () { 814 815 window.initGoDealsSlider( 816 sectionElement 817 ); 818 819 }, 820 100 821 ); 822 } 823 824 825 } else { 826 827 sectionElement.innerHTML = 828 ''; 829 830 831 goDealsLog( 832 'GO Deals: No content for:', 833 section 834 ); 835 } 836 } 837 ); 838 } 839 ) 840 841 842 /* 843 * ========================================================= 844 * Error handling 845 * ========================================================= 846 * 847 * Any failure means: 848 * 849 * - Top Deals -> nothing 850 * - Coming Soon -> nothing 851 * - Weekly Win -> nothing 852 */ 853 854 .catch( 855 function (error) { 856 857 goDealsError( 858 'GO Deals ERROR:', 859 error 860 ); 861 862 863 /* 864 * Clear ALL deal sections. 865 */ 866 867 document 868 .querySelectorAll( 869 '.go-deals-section' 870 ) 871 .forEach( 872 function (sectionElement) { 873 874 const section = 875 sectionElement.getAttribute( 876 'data-go-deals-section' 877 ); 878 879 880 sectionElement.innerHTML = 881 ''; 882 883 884 goDealsLog( 885 'GO Deals: Cleared section after error:', 886 section 887 ); 888 } 889 ); 890 } 891 ); 892 893 894 /* 895 * ========================================================= 896 * GO Deals Swiper 897 * ========================================================= 898 */ 899 900 (function () { 901 902 goDealsLog( 903 'GO Deals: Slider script loaded' 904 ); 905 906 907 window.initGoDealsSlider = function (container) { 908 909 goDealsLog( 910 'GO Deals: Slider function' 911 ); 912 913 914 /* 915 * Mobile only 916 */ 917 918 if (window.innerWidth > 768) { 919 return; 920 } 921 922 923 /* 924 * Check Swiper 925 */ 926 927 if (typeof Swiper === 'undefined') { 928 929 goDealsError( 930 'GO Deals: Swiper is not loaded.' 931 ); 932 933 return; 934 } 935 936 937 /* 938 * Find slider inside the rendered section 939 */ 940 941 const sliderElement = container 942 ? container.querySelector('.go-deals-slider') 943 : document.querySelector('.go-deals-slider'); 944 945 946 if (!sliderElement) { 947 948 goDealsLog( 949 'GO Deals: Slider element not found.' 950 ); 951 952 return; 953 } 954 955 956 /* 957 * Already initialized 958 */ 959 960 if (sliderElement.swiper) { 961 962 goDealsLog( 963 'GO Deals: Slider already initialized.' 964 ); 965 966 return; 967 } 968 969 970 /* 971 * Check slides 972 */ 973 974 const slides = 975 sliderElement.querySelectorAll( 976 '.swiper-slide' 977 ); 978 979 980 goDealsLog( 981 'GO Deals: Upcoming Deals slides:', 982 slides.length 983 ); 984 985 986 if (!slides.length) { 987 988 goDealsLog( 989 'GO Deals: No slides found.' 990 ); 991 992 return; 993 } 994 995 996 /* 997 * Initialize Swiper 998 */ 999 1000 new Swiper( 1001 sliderElement, 1002 { 1003 loop: slides.length > 1, 1004 1005 slidesPerView: 'auto', 1006 1007 spaceBetween: 0, 1008 1009 centeredSlides: false, 1010 1011 grabCursor: true, 1012 1013 speed: 600,
1014 1015 autoplay: slides.length > 1 1016 ? { 1017 delay: 2500, 1018 disableOnInteraction: false, 1019 pauseOnMouseEnter: true 1020 } 1021 : false 1022 } 1023 ); 1024 1025 1026 goDealsLog( 1027 'GO Deals: Upcoming Deals slider initialized.' 1028 ); 1029 }; 1030 1031 })(); 1032 1033});
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.