1(function ($, Drupal) { 2 Drupal.behaviors.asd2eq = { 3 attach: function (context) { 4 if (typeof (initialized) == 'undefined') { 5 initialized = true; 6 // Ðод напиÑаннÑй здеÑÑ Ð±ÑÐ´ÐµÑ Ð²Ñполнен ÑолÑко один Ñаз пÑи загÑÑзке ÑÑÑаниÑи 7 8 $(document).ajaxStart(function () { 9 $(".preloader--spin").addClass("js--active"); 10 // disableScroll() 11 }); 12 $(document).ajaxStop(function () { 13 $(".preloader--spin").removeClass("js--active"); 14 // enableScroll() 15 }); 16 17 window.addEventListener( 18 "scroll", 19 () => { 20 if (document.querySelector(".js--lazyload")) { 21 document.querySelectorAll(".js--lazyload").forEach((el) => { 22 el.classList.remove("js--lazyload"); 23 }); 24 } 25 }, 26 { once: true } 27 ); 28 29 30 $("#faq-accordion") 31 .on("show.bs.collapse", function (e) { 32 $(e.target).parent(".questions-item").addClass("js--active"); 33 }) 34 .on("hide.bs.collapse", function (e) { 35 $(e.target).parent(".questions-item").removeClass("js--active"); 36 }); 37 38 const heroBannerSwiper = new Swiper(".hero-banner__left .swiper-container", { 39 navigation: { 40 nextEl: ".swiper-button-next", 41 prevEl: ".swiper-button-prev", 42 }, 43 pagination: { 44 el: ".hero-banner__pagination", 45 }, 46 watchSlidesVisibility: true, 47 autoplay: { 48 delay: 3000, 49 disableOnInteraction: false, 50 }, 51 loop: true, 52 }); 53 54 const galleryLeft = document.querySelector(".photo-gallery__left .swiper-container") 55 const galleryRightDescription = document.querySelector('.photo-gallery__right-description .swiper-container') 56 57 let galleryImages, galleryDescriptions 58 59 if (galleryLeft) { 60 galleryImages = new Swiper(".photo-gallery__left .swiper-container", { 61 navigation: { 62 nextEl: ".swiper-button-next", 63 prevEl: ".swiper-button-prev", 64 }, 65 watchSlidesVisibility: true, 66 }); 67 } 68 69 if (galleryRightDescription) { 70 galleryDescriptions = new Swiper( 71 ".photo-gallery__right-description .swiper-container", 72 {} 73 ); 74 } 75 76 const isPhotoGalleryInitialized = galleryImages 77 && galleryImages instanceof Swiper 78 && galleryDescriptions 79 && galleryDescriptions instanceof Swiper 80 81 if (isPhotoGalleryInitialized) { 82 galleryDescriptions.controller.control = galleryImages; 83 galleryImages.controller.control = galleryDescriptions; 84 } 85 86 const costCalcButton = document.querySelector('.cost-calculation-banner__button') 87 const gboInstallForm = document.querySelector('#gbo-install-form') 88 89 if (costCalcButton && gboInstallForm) { 90 costCalcButton.addEventListener('click', (el) => { 91 el.preventDefault() 92 gboInstallForm.scrollIntoView({ 93 behavior: 'auto' 94 }) 95 }) 96 } 97 98 const thumbItem = $(".photo-gallery__right-nav .nav__item"); 99 100 if (isPhotoGalleryInitialized) { 101 galleryImages.on("slideChange", function () { 102 thumbItem.removeClass("js--active"); 103 $( 104 `.photo-gallery__right-nav .nav__item[data-thumb=${galleryImages.activeIndex}]` 105 ).addClass("js--active"); 106 }); 107 108 thumbItem.click(function () { 109 thumbItem.removeClass("js--active"); 110 $(this).addClass("js--active"); 111 galleryImages.slideTo($(this).data("thumb"), 1000, false); 112 }); 113 } 114 115 if (document.querySelector(".photo-gallery__right-nav .swiper-container")) { 116 const thumbsToSwiper = () => { 117 const breakpoint = window.matchMedia("(min-width:768px)"); 118 119 let mySwiper; 120 const breakpointChecker = function () { 121 if (breakpoint.matches) {
122 if (mySwiper !== undefined) mySwiper.destroy(true, true); 123 } else { 124 return enableSwiper(); 125 } 126 }; 127 const enableSwiper = () => { 128 mySwiper = new Swiper(".photo-gallery__right-nav .swiper-container", { 129 slidesPerView: 5.1, 130 paginationClickable: true, 131 }); 132 }; 133 breakpoint.addListener(breakpointChecker); 134 breakpointChecker(); 135 }; 136 thumbsToSwiper(); 137 } 138 139 var cliensSwiper = new Swiper(".clients__content-slider .swiper-container", { 140 grabCursor: true, 141 slidesPerView: "auto", 142 scrollbar: { 143 el: ".swiper-scrollbar", 144 hide: false, 145 }, 146 }); 147 148 var certificatesSwiper = new Swiper( 149 ".certificates__content-slider .swiper-container", 150 { 151 grabCursor: true, 152 spaceBetween: 12, 153 slidesPerView: "auto", 154 scrollbar: { 155 el: ".swiper-scrollbar", 156 hide: false, 157 }, 158 } 159 ); 160 161 var blogTeaserSwiper = new Swiper(".blog__teaser-items .swiper-container", { 162 grabCursor: true, 163 slidesPerView: "auto", 164 breakpoints: { 165 320: { 166 spaceBetween: 20, 167 }, 168 1200: { 169 spaceBetween: 48, 170 }, 171 }, 172 }); 173 174 var reviewsSwiper = new Swiper(".paragraph__reviews-body .swiper-container", { 175 grabCursor: true, 176 slidesPerView: "auto", 177 freeMode: true, 178 breakpoints: { 179 320: { 180 spaceBetween: 20, 181 }, 182 1200: { 183 spaceBetween: 36, 184 }, 185 }, 186 }); 187 188 var portfolioSwiper = new Swiper( 189 ".paragraph--portfolio .brands .swiper-container", 190 { 191 // grabCursor: true, 192 slidesPerView: "auto", 193 breakpoints: { 194 320: { 195 spaceBetween: 10, 196 }, 197 1200: { 198 spaceBetween: 12, 199 }, 200 }, 201 scrollbar: { 202 el: ".swiper-scrollbar", 203 hide: false, 204 }, 205 } 206 ); 207 portfolioSwiper.on("slideChange", function () { 208 const target = this.slides[this.activeIndex].dataset.prop; 209 $(".paragraph--portfolio .letters__item").removeClass("js--active"); 210 $( 211 `.paragraph--portfolio .letters__item[data-target-letter=${target}]` 212 ).addClass("js--active"); 213 }); 214 $(".paragraph--portfolio .letters__item").click(function () { 215 $(".paragraph--portfolio .letters__item").removeClass("js--active"); 216 $(this).addClass("js--active"); 217 const target = $(this).data("target-letter"); 218 const slides = portfolioSwiper.slides; 219 portfolioSwiper.slideTo( 220 slides.findIndex((p) => p.dataset.letter === target), 221 1000, 222 false 223 ); 224 }); 225 226 var portfolioLettersSwiper = new Swiper( 227 ".paragraph--portfolio .letters .swiper-container", 228 { 229 // grabCursor: true, 230 slidesPerView: "auto", 231 } 232 ); 233 234 new Tippy("#review-index", { 235 position: window.innerWidth <= 576 ? "top" : "top", 236 animation: "shift", 237 allowHTML: true, 238 arrow: "true", 239 }); 240 241 const bankTooltips = document.querySelectorAll(".banks__trigger"); 242 if (bankTooltips) { 243 bankTooltips.forEach((p) => { 244 new Tippy(p, { 245 position: window.innerWidth <= 576 ? "top" : "top", 246 animation: "shift", 247 allowHTML: true, 248 arrow: "true", 249 }); 250 }); 251 } 252 if (document.querySelector(".paragraph--multiple-block")) { 253 const ps = new PerfectScrollbar(".paragraph--multiple-block", { 254 wheelSpeed: 1, 255 wheelPropagation: true, 256 swipeEasing: true, 257 minScrollbarLength: 20, 258 suppressScrollX: true, 259 }); 260 } 261 262 $(".paragraph--minor-text .showMore").click(function () { 263 $(this).parent(".text").toggleClass("collapsed"); 264 $(this).toggleClass("js--active"); 265 const target = $(this).parent(".text"); 266 const top = $(target).offset().top; 267 $("body,html").animate({ scrollTop: top }, 1000); 268 }); 269 270 var gboPriceSwiper = new Swiper( 271 ".paragraph--gbo .paragraph__gbo-slider .swiper-container", 272 { 273 // grabCursor: true, 274 freeMode: true, 275 slidesPerView: "auto", 276 breakpoints: { 277 320: { 278 spaceBetween: 0, 279 }, 280 768: { 281 spaceBetween: 48, 282 }, 283 }, 284 } 285 ); 286 287 var gboPriceSwiper = new Swiper( 288 ".paragraph--bank .paragraph__gbo-slider .swiper-container", 289 { 290 // grabCursor: true, 291 freeMode: true, 292 slidesPerView: "auto", 293 breakpoints: { 294 320: { 295 spaceBetween: 0, 296 }, 297 768: { 298 spaceBetween: 48, 299 }, 300 }, 301 } 302 ); 303 304 $(".paragraph__gbo .paragraph__gbo-description .showMore").click(function () { 305 $(this).siblings(".description__content").toggleClass("collapsed"); 306 $(this).toggleClass("js--active"); 307 }); 308 // gboPriceSwiper.on('transitionStart', function () { 309 // const titles = $('.slider-head__titles .item') 310 // titles.each(function () { 311 // $(this).mouseout(); 312 // }) 313 // }); 314 // gboPriceSwiper.on('reachBeginning', function () { 315 // console.log('show') 316 // }); 317 // const gboSliderHead = document.querySelector('.slider-head__titles') 318 // gboPriceSwiper.on('transitionStart', function () { 319 // gboPriceSwiper.isBeginning ? gboSliderHead.classList.remove('js--hidden') : gboSliderHead.classList.add('js--hidden') 320 // }); 321 322 const gboKits = document.querySelectorAll( 323 ".paragraph__gbo-slider .swiper-slide .slide-top .trigger" 324 ); 325 if (gboKits.length) {
326 gboKits.forEach((p) => { 327 new Tippy(p, { 328 position: "bottom-end", 329 animation: "shift", 330 allowHTML: true, 331 arrow: "true", 332 }); 333 }); 334 } 335 336 const gboPrices = document.querySelectorAll( 337 ".paragraph__gbo-footer .left .price__trigger" 338 ); 339 if (gboPrices.length) { 340 gboPrices.forEach((p) => { 341 new Tippy(p, { 342 position: "top", 343 animation: "shift", 344 allowHTML: true, 345 arrow: "true", 346 }); 347 }); 348 } 349 350 // custom 351 352 353 354 const customLeft = document.querySelector('.paragraph--custom .double-column__content-left') 355 const customRight = document.querySelector('.paragraph--custom .double-column__content-right') 356 const customContent = document.querySelector('.paragraph--custom .double-column__content') 357 358 if(!!customLeft){ 359 customLeft.classList.add('js--active') 360 361 customLeft.addEventListener('mouseover', ()=>{ 362 customLeft.classList.add('js--active') 363 customContent.classList.add('left-hover') 364 customContent.classList.remove('right-hover') 365 customRight.classList.remove('js--active') 366 }) 367 368 customRight.addEventListener('mouseover', ()=>{ 369 customRight.classList.add('js--active') 370 customContent.classList.add('right-hover') 371 customContent.classList.remove('left-hover') 372 customLeft.classList.remove('js--active') 373 }) 374 } 375 376 377 const stationBannerSlider = new Swiper(".station-banner__slider", 378 { 379 slidesPerView: "auto", 380 pagination: { 381 el: '.swiper-pagination', 382 clickable: true, 383 }, 384 navigation: { 385 nextEl: '.station-banner__slider .swiper-button-next', 386 prevEl: '.station-banner__slider .swiper-button-prev', 387 }, 388 autoplay: { 389 delay: 6000, 390 disableOnInteraction: true, 391 }, 392 loop: true, 393 breakpoints: { 394 320: { 395 spaceBetween: 0, 396 }, 397 768: { 398 spaceBetween: 48, 399 }, 400 }, 401 } 402 ); 403 404 405 406 407 408 409 410 411 412 413 414 415 416 const videos = document.querySelectorAll("video.video"); 417 if (videos) { 418 videos.forEach(p => { 419 let playState = null; 420 let playPromise = p.play(); 421 if (playPromise !== undefined) { 422 playPromise.then(_ => { 423 const observer = new IntersectionObserver((entries) => { 424 entries.forEach((entry) => { 425 if (!entry.isIntersecting) { 426 p.pause(); 427 playState = false; 428 } else { 429 p.play(); 430 playState = true; 431 } 432 }); 433 }, {}); 434 435 observer.observe(p); 436 }) 437 } 438 439 }) 440 } 441 442 443 $('.header__city-selection .current').click(function () { 444 445 $(this).parent('.header__city-selection').toggleClass('js--active') 446 447 hideSubMenus() 448 449 }); 450 451 452 453 $('.header__city-selection .item').click(function () { 454 455 saveData($(this)) 456 457 $('.header__city-selection').toggleClass('js--active') 458 459 }); 460 461 462 463 $('.header__city-selection .item[data-city="lviv"]').click(redirectToGBOPage) 464 465 466 467 $('.city-popup .list__item').click(function () { 468 469 saveData($(this)); 470 471 toggleCityPopup() 472 473 }); 474 475 476 477 $('.numbers_header').click(function () { 478 479 $('.header__phones').toggleClass('js--active') 480 481 }); 482 483 484 485 const certificateLinkLviv = $('.menu__item--certificate .lviv') 486 487 const certificateLinkOthers = $('.menu__item--certificate .others') 488 489 const repairLvivLink = $('.submenu__items .list-main .list__item--repair-lviv') 490 491 const repairDefaultLink = $('.submenu__items .list-main .list__item--repair-default') 492 493 494 495 function redirectToGBOPage() { 496 497 const isUkrainianLang = drupalSettings.path.currentLanguage === 'uk' 498 499 500 501 window.location.href = isUkrainianLang ? "/uk/node/3555" : "/stanciya-lviv" 502 503 } 504 505 506 507 const saveData = selector => { 508 509 const name = selector.children('span').text(); 510 511 const prop = selector.data('city'); 512 513 const item = $(`.header__city-selection .item[data-city=${prop}]`) 514
515 setActiveInList(item) 516 517 handleSelectedLocation(prop) 518 519 setCityToCurrent(name, prop); 520 521 const savedData = JSON.stringify({ prop: prop }); 522 523 localStorage.setItem('city', savedData); 524 525 }; 526 527 528 529 const setCityToCurrent = (name, prop) => { 530 531 const currentItem = $('.header__city-selection .current'); 532 533 const currentText = $('.header__city-selection .current .current__text'); 534 535 currentText.text(name); 536 537 currentItem.attr('data-city', prop); 538 539 }; 540 541 542 543 const setActiveInList = selector => { 544 545 $('.header__city-selection .item').removeClass('active'); 546 547 $(selector).addClass('active'); 548 549 }; 550 551 552 553 const toggleCityPopup = () => { 554 555 $('.city-popup').toggleClass('js--active') 556 557 }; 558 559 const savedData = localStorage.getItem('city'); 560 561 if (savedData) { 562 563 const { prop } = JSON.parse(savedData) 564 565 566 567 const selector = $(`.header__city-selection .item[data-city=${prop}]`) 568 569 const name = selector.children('span').text() 570 571 572 573 handleSelectedLocation(prop) 574 575 setCityToCurrent(name, prop) 576
577 setActiveInList(selector) 578 579 $('.header__city-selection .skeleton').removeClass('js--active') 580 581 } else { 582 583 $('.header__city-selection .skeleton').removeClass('js--active') 584 585 toggleCityPopup() 586 587 handleSelectedLocation('') 588 589 } 590 591 592 593 function handleSelectedLocation(prop) { 594 595 const lvivGBO = $('.list-main .list__item--gbo-lviv') 596 597 const othersGBO = $('.list-main .list__item--gbo-others') 598 599 600 601 if (prop === 'lviv') { 602 603 handleSelectedLviv(lvivGBO, othersGBO) 604 605 } 606 607 else { 608 609 handleSelectedOtherCity(lvivGBO, othersGBO) 610 611 } 612 613 } 614 615 616 617 function handleSelectedLviv(lvivGBO, othersGBO) { 618 619 lvivGBO.removeClass('hidden') 620 621 622 623 if (!othersGBO.hasClass('hidden')) { 624 625 othersGBO.addClass('hidden') 626 627 } 628 629 630 631 replaceGenerationLinks('urlLviv') 632 633 toggleLocationLinks(true, { 634 635 linkForLviv: repairLvivLink, 636 637 defaultLink: repairDefaultLink 638 639 }) 640 641 toggleLocationLinks(true, { 642 643 linkForLviv: certificateLinkLviv, 644 645 defaultLink: certificateLinkOthers 646 647 }) 648 649 } 650 651 652 653 function handleSelectedOtherCity(lvivGBO, othersGBO) { 654 655 othersGBO.removeClass('hidden') 656 657 658 659 if (!lvivGBO.hasClass('hidden')) { 660 661 lvivGBO.addClass('hidden') 662 663 } 664 665 666 667 replaceGenerationLinks('urlDefault') 668 669 toggleLocationLinks(false, { 670 671 linkForLviv: repairLvivLink, 672 673 defaultLink: repairDefaultLink 674 675 }) 676 677 678 679 toggleLocationLinks(false, { 680 681 linkForLviv: certificateLinkLviv, 682 683 defaultLink: certificateLinkOthers 684 685 }) 686 687 } 688 689 690 691 function replaceGenerationLinks(dataAttribute) { 692 693 const generationLinks = $('.submenu__items .generation .list__item--dynamic a') 694 695 696 697 generationLinks.each(function() { 698 699 const url = $(this).data(dataAttribute) 700 701 702 703 if (url) { 704 705 $(this).attr('href', url) 706 707 } 708 709 }) 710 711 } 712 713 714 715 function toggleLocationLinks(isLvivSelected, { linkForLviv, defaultLink }) { 716 717 if (isLvivSelected) { 718 719 linkForLviv.removeClass('hidden') 720 721 722 723 if (!defaultLink.hasClass('hidden')) { 724 725 defaultLink.addClass('hidden') 726 727 } 728 729 730 731 } else { 732 733 defaultLink.removeClass('hidden') 734 735 736 737 if (!linkForLviv.hasClass('hidden')) { 738 739 linkForLviv.addClass('hidden') 740 741 } 742 743 } 744 745 } 746 747 748 749 $('.city-popup__btn').click(function () { 750 751 toggleCityPopup() 752 753 saveData($('.header__city-selection .item.active')) 754 755 }) 756 757 758 759 $(document).on('click',function (e) { 760 761 const el = '.menu__item.menu__item--parent'; 762 763 if ($(e.target).closest(el).length) return; 764 765 hideSubMenus() 766 767 }); 768 769 770 771 772 773 774 775 $('.menu__item.menu__item--parent').click(function (e) { 776 777 const gboInstallPageData = e.currentTarget.dataset.isGboInstallPage 778 779 const gboInstallUrl = e.currentTarget.dataset.gboInstallUrl 780 781 const isAllowToNavigate = gboInstallPageData && gboInstallPageData === '0' 782 783 784 785 if (isAllowToNavigate) { 786 787 window.location.href = gboInstallUrl 788 789 } else { 790 791 $('.header__city-selection.js--active').removeClass('js--active') 792 793 794 795 if (e.target === this || e.target === this.querySelector('.menu__item-text')) { 796 797 const currentSubmenu = $(this).children('.submenu') 798 799 // -------------- UNCOMMENT WHEN VIDEOS WILL RETURN TO ME NU 800 801 pauseMenuVideos() 802 803 const currentVideo = currentSubmenu[0].querySelector('.menu-video') 804 805 if (currentVideo) { 806 807 currentVideo.play() 808 809 } 810 811 // -------------- UNCOMMENT WHEN VIDEOS WILL RETURN TO MENU 812 813 $('.menu__item.menu__item--parent .submenu').not(currentSubmenu).removeClass('js--active') 814 815 $('.menu__item.menu__item--parent').not($(this)).removeClass('js--active') 816 817 $(this).toggleClass('js--active') 818 819 820 821 822 823 currentSubmenu.toggleClass('js--active') 824
825 const btnBack = $('.header__menu-controls .btn__back') 826 827 checkAllSubMenus() ? btnBack.addClass('js--active') : btnBack.removeClass('js--active') 828 829 // -------------- UNCOMMENT WHEN VIDEOS WILL RETURN TO MENU 830 831 if (!checkAllSubMenus()) { 832 833 pauseMenuVideos() 834 835 } 836 837 // -------------- UNCOMMENT WHEN VIDEOS WILL RETURN TO MENU 838 839 } 840 841 } 842 843 844 845 if(document.querySelector('.menu__item.menu__item--parent .js--active')){ 846 847 $('.header__menu-overlay').addClass('js--active') 848 849 }else{ 850 851 $('.header__menu-overlay').removeClass('js--active') 852 853 } 854 855 }) 856 857 858 859 const pauseMenuVideos = () => { 860 861 const menuVideos = document.querySelectorAll('.menu-video') 862 863 menuVideos.forEach(p => p.pause()) 864 865 } 866 867 868 869 const hideSubMenus = () => { 870 871 $('.menu__item.menu__item--parent .submenu').removeClass('js--active') 872 873 $('.menu__item.menu__item--parent').removeClass('js--active') 874 875 $('.header__menu-overlay').removeClass('js--active') 876 877 pauseMenuVideos() 878 879 } 880 881 882 883 884 885 886 887 const checkAllSubMenus = function() { 888 889 const subMenus = document.querySelectorAll('.menu__item--parent .submenu'); 890 891 let states = []; 892 893 subMenus.forEach(p => { 894 895 states.push(p.classList.contains('js--active')) 896 897 }) 898 899 // states.some(state => state === true) ? disableScroll() : enableScroll() 900 901 return states.some(state => state === true) 902 903 } 904 905 906 907 908 909 $('.header-toggler').click(function () { 910 911 toggleMainMenu() 912 913 disableScroll() 914 915 916 917 }) 918 919 920 921 $('.header__menu-controls .btn__close').click(function () { 922 923 toggleMainMenu() 924 925 enableScroll() 926 927 }) 928 929 930 931 $('.header__menu .anchor__link').click(function () { 932 933 $('.header__menu-controls .btn__close').trigger('click') 934 935 }) 936 937 938 939 $('.header__menu-controls .btn__back').click(function () { 940 941 $(this).removeClass('js--active') 942 943 hideSubMenus() 944 945 }) 946 947 948 949 $('.header__menu-overlay').click(function () { 950 951 toggleMainMenu() 952 953 enableScroll() 954 955 }) 956 957 958 959 const toggleMainMenu = () => { 960 961 $('.header__menu').toggleClass('js--active--mobile') 962 963 $('.header__menu-overlay').toggleClass('js--active') 964 965 $('.header__menu-controls .btn__back').removeClass('js--active') 966 967 } 968 969 970 971 972 973 974 975 const subMenus = document.querySelectorAll('.menu__item .submenu') 976 977 subMenus.forEach(p => { 978 979 const subMenuPs = new PerfectScrollbar(p, { 980 981 wheelSpeed: 1, 982 983 wheelPropagation: true, 984 985 swipeEasing: true, 986 987 minScrollbarLength: 20, 988 989 suppressScrollX: true 990 991 992 993 }); 994 995 }) 996 997 998 999 const appHeight = () => { 1000 1001 const doc = document.documentElement 1002 1003 doc.style.setProperty('--app-height', `${window.innerHeight}px`) 1004 1005 } 1006 1007 window.addEventListener('resize', appHeight) 1008 1009 appHeight() 1010 1011 1012 1013 $(window).resize(function() { 1014 1015 if (window.innerWidth >= 1024) { 1016 1017 enableScroll(false) 1018 1019 } 1020 1021 }) 1022 1023 1024 1025 function clickOutside(element, callback) { 1026 1027 1028 1029 document.addEventListener("click", function(event) { 1030 1031 1032 1033 let isClickInsideElement = element.contains(event.target); 1034 1035 1036 1037 1038 1039 if (!isClickInsideElement) { 1040 1041 callback(); 1042 1043 } 1044 1045 }); 1046 1047 } 1048 1049 1050 1051 const headerPhone = document.querySelector('.header__phones') 1052 1053 const headerCity = document.querySelector('.header__city-selection') 1054 1055 1056 1057 clickOutside(headerPhone, function() { 1058 1059 headerPhone.classList.remove('js--active') 1060 1061 }); 1062 1063 1064 1065 clickOutside(headerCity, function() { 1066 1067 headerCity.classList.remove('js--active') 1068 1069 }); 1070 1071 1072 1073 1074 1075 1076 const $body = document.querySelector('body'); 1077 const getScrollbarWidth = () => { 1078 return window.innerWidth - document.documentElement.clientWidth; 1079 } 1080 1081 let scrollPosition = 0; 1082 1083 const disableScroll = function () { 1084 scrollPosition = window.pageYOffset; 1085 //$body.style.paddingRight = `${getScrollbarWidth()}px`; 1086 $body.style.setProperty('--pr', `${getScrollbarWidth()}px`) 1087 $body.style.overflow = 'hidden'; 1088 $body.style.position = 'fixed'; 1089 $body.style.top = `-${scrollPosition}px`; 1090 $body.style.width = '100%'; 1091 }; 1092 const enableScroll = function (isScrollTop) { 1093 // $body.style.removeProperty('padding-right'); 1094 // $body.style.setProperty('--pr', `${0}px`) 1095 $body.style.removeProperty('overflow'); 1096 $body.style.removeProperty('position'); 1097 $body.style.removeProperty('top'); 1098 $body.style.removeProperty('width'); 1099 if (isScrollTop !== false) { 1100 window.scrollTo(0, scrollPosition); 1101 } 1102 1103 }; 1104 1105 /*let currentLetter = ''; 1106 1107 $('.page-portfolio .filter input').change(function () { 1108 currentLetter = $(this).val(); 1109 makeSearch(currentLetter); 1110 }); 1111 1112 $('.page-portfolio .filter input[type=radio]').click(function () { 1113 if (currentLetter === $(this).val()) { 1114 $(this).prop('checked', false); 1115 makeSearch('', 'byWord'); 1116 currentLetter = '' 1117 } 1118 }); 1119 1120 1121 const makeSearch = function (keyword) { 1122 let filter = keyword.toUpperCase(); 1123 const list = document.querySelector('.page-portfolio .brands, .page-portfolio .autos'); 1124 let items = list.querySelectorAll('.brands__item, .autos__items'); 1125 for (let i = 0; i < items.length; i += 1) { 1126 let txtValue = items[i].getAttribute('data-search') 1127 if (txtValue.toUpperCase().indexOf(filter) > -1) { 1128 items[i].style.display = ""; 1129 } else { 1130 items[i].style.display = "none"; 1131 } 1132 } 1133 };*/ 1134 1135 $('.page-portfolio .filter .letter').click(function () { 1136 $(`.page-portfolio .brands__item, .page-portfolio .autos__item`).removeClass('js--active') 1137 const target = $(`.page-portfolio .brands__item[data-search=${this.dataset.prop}], .page-portfolio .autos__item[data-search=${this.dataset.prop}]`) 1138 target.addClass('js--active') 1139 const top = $(target).offset().top; 1140 $('body,html').animate({scrollTop: top}, 1000); 1141 }); 1142 1143 1144 const state = (key) => sessionStorage.getItem(key) 1145 1146 const announcesWrapper = document.querySelector('.header-announces') 1147 1148 const messagesWrapper = document.querySelector('.header-messages') 1149 1150 const types = { 1151 messages: { 1152 key: 'messages', 1153 selector: messagesWrapper.querySelectorAll('.header-messages__item'), 1154 }, 1155 announces: { 1156 key: 'announces', 1157 selector: announcesWrapper.querySelectorAll('.header-announces__item'), 1158 } 1159 } 1160 1161 const setActiveNotify = (index, selector, key) => { 1162 selector[index].classList.add('js--active') 1163 let store = getState(key) 1164 const closeBtn = selector[index].querySelector('.close') 1165 closeBtn.addEventListener('click', (e) => { 1166 e.preventDefault() 1167 selector[index].classList.remove('js--active') 1168 store.closed.push(index) 1169 setDataToState(key, store) 1170 }) 1171 } 1172 1173 const getState = (key) => JSON.parse(state(key)) 1174 1175 const setDataToState = (key, data) => { 1176 const storeItem = { ...data } 1177 sessionStorage.setItem(`${key}`, JSON.stringify(storeItem)) 1178 } 1179 1180 const checkIsAllClosed = (arrayOfClosed, selector) => { 1181 const indices = Array.from(Array(selector.length).keys()) 1182 return indices.every(p => arrayOfClosed.includes(p)) 1183 } 1184 1185 const detectActive = (stateIndex, arrayOfClosed, selector) => { 1186 let tempIndex = stateIndex += 1 1187 tempIndex = tempIndex === selector.length ? 0 : tempIndex 1188 if (arrayOfClosed.includes(tempIndex)) { 1189 return detectActive(tempIndex, arrayOfClosed, selector) 1190 } else { 1191 return tempIndex 1192 } 1193 } 1194 1195 const getInitialState = () => { 1196 return { closed: [], active: 0 } 1197 } 1198 1199 const setDataAndActivate = (key, data, index, selector) => { 1200 setDataToState(key, data)
1201 setActiveNotify(index, selector, key) 1202 } 1203 1204 const notifyAction = type => { 1205 const key = type.key 1206 const selector = type.selector 1207 if (state(key)) { 1208 let store = getState(key) 1209 if (!checkIsAllClosed(store.closed, selector)) { 1210 store.active = detectActive(store.active, store.closed, selector) 1211 setDataAndActivate(key, store, store.active, selector) 1212 // setDataToState(key, store); 1213 // setActiveNotify(store.active, selector, key); 1214 } 1215 } else { 1216 const initialState = getInitialState() 1217 setDataAndActivate(key, initialState, initialState.active, selector) 1218 // setDataToState(key, initialState); 1219 // setActiveNotify(initialState.active, selector, key); 1220 } 1221 }; 1222 1223 if (types.announces.selector.length > 0) { 1224 notifyAction(types.announces) 1225 } 1226 1227 if (types.messages.selector.length > 0) { 1228 notifyAction(types.messages) 1229 } 1230 1231 1232 1233 var autosSliderrSwiper = new Swiper('.autos-slider .swiper-container', { 1234 grabCursor: true, 1235 slidesPerView: 'auto', 1236 breakpoints: { 1237 320: { 1238 spaceBetween: 20 1239 }, 1240 1200: { 1241 spaceBetween: 24 1242 } 1243 } 1244 }); 1245 1246 1247 // Nov 30, 2020 00:00:00 1248 const timers = document.querySelectorAll('.timer__clock'); 1249 if (timers.length > 0) { 1250 timers.forEach(timer => { 1251 const deadline = timer.dataset.deadline; 1252 const countDownDate = new Date(deadline).getTime(); 1253 const interval = setInterval(function() { 1254 const now = new Date().getTime(); 1255 const distance = countDownDate - now; 1256 const days = Math.floor(distance / (1000 * 60 * 60 * 24)); 1257 const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); 1258 const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); 1259 const seconds = Math.floor((distance % (1000 * 60)) / 1000); 1260 setCount(timer, { days, hours, minutes, seconds }); 1261 // setCount(timer, { days: 27, hours: 9, minutes: 46, seconds: 58 }); 1262 if (distance < 0) { 1263 clearInterval(interval); 1264 setCount(timer, { days: 0, hours: 0, minutes: 0, seconds: 0 }); 1265 } 1266 }, 1000); 1267 }) 1268 }
1269 const setCount = (timer, counts) => { 1270 const { days, hours, minutes, seconds } = counts; 1271 timer.querySelector('.days .days__count .number').textContent = days; 1272 timer.querySelector('.hours .hours__count .number').textContent = hours; 1273 timer.querySelector('.minutes .minutes__count .number').textContent = minutes; 1274 timer.querySelector('.seconds .seconds__count .number').textContent = seconds; 1275 }; 1276 1277 1278 // const timers = document.querySelectorAll('.timer__clock'); 1279 // if (timers.length > 0) { 1280 // timers.forEach(p => { 1281 // function CountdownTracker(label, value){ 1282 // var el = document.createElement('span'); 1283 // el.className = 'flip-clock__piece'; 1284 // el.innerHTML = '<span class="flip-clock__card card"><span class="card__top"></span><span class="card__bottom"></span><span class="card__back"><span class="card__bottom"></span></span></span>' + 1285 // '<span class="flip-clock__slot">' + label + '</span>'; 1286 // this.el = el; 1287 // var top = el.querySelector('.card__top'), 1288 // bottom = el.querySelector('.card__bottom'), 1289 // back = el.querySelector('.card__back'), 1290 // backBottom = el.querySelector('.card__back .card__bottom'); 1291 // this.update = function(val){ 1292 // val = ( '0' + val ).slice(-2); 1293 // if ( val !== this.currentValue ) { 1294 // if ( this.currentValue >= 0 ) { 1295 // back.setAttribute('data-value', this.currentValue); 1296 // bottom.setAttribute('data-value', this.currentValue); 1297 // } 1298 // this.currentValue = val; 1299 // top.innerText = this.currentValue; 1300 // backBottom.setAttribute('data-value', this.currentValue); 1301 // this.el.classList.remove('flip'); 1302 // void this.el.offsetWidth; 1303 // this.el.classList.add('flip'); 1304 // } 1305 // } 1306 // this.update(value); 1307 // } 1308 // function getTimeRemaining(endtime) { 1309 // var t = Date.parse(endtime) - Date.parse(new Date()); 1310 // return { 1311 // 'Total': t, 1312 // 'Days': Math.floor(t / (1000 * 60 * 60 * 24)), 1313 // 'Hours': Math.floor((t / (1000 * 60 * 60)) % 24), 1314 // 'Minutes': Math.floor((t / 1000 / 60) % 60), 1315 // 'Seconds': Math.floor((t / 1000) % 60) 1316 // }; 1317 // } 1318 // function getTime() { 1319 // var t = new Date(); 1320 // return { 1321 // 'Total': t, 1322 // 'Hours': t.getHours() % 12, 1323 // 'Minutes': t.getMinutes(), 1324 // 'Seconds': t.getSeconds() 1325 // }; 1326 // } 1327 // function Clock(countdown,callback) { 1328 // countdown = countdown ? new Date(Date.parse(countdown)) : false; 1329 // callback = callback || function(){}; 1330 // var updateFn = countdown ? getTimeRemaining : getTime; 1331 // this.el = document.createElement('div'); 1332 // this.el.className = 'flip-clock'; 1333 // var trackers = {}, 1334 // t = updateFn(countdown), 1335 // key, timeinterval; 1336 // for ( key in t ){ 1337 // if ( key === 'Total' ) { continue; } 1338 // trackers[key] = new CountdownTracker(key, t[key]); 1339 // this.el.appendChild(trackers[key].el); 1340 // } 1341 // var i = 0; 1342 // function updateClock() { 1343 // timeinterval = requestAnimationFrame(updateClock); 1344 // // throttle so it's not constantly updating the time. 1345 // if ( i++ % 10 ) { return; } 1346 // var t = updateFn(countdown); 1347 // if ( t.Total < 0 ) { 1348 // cancelAnimationFrame(timeinterval); 1349 // for ( key in trackers ){ 1350 // trackers[key].update( 0 ); 1351 // } 1352 // callback(); 1353 // return; 1354 // } 1355 // for ( key in trackers ){ 1356 // trackers[key].update( t[key] ); 1357 // } 1358 // } 1359 // setTimeout(updateClock,500); 1360 // } 1361 // const deadline = p.dataset.deadline 1362 // var c = new Clock(deadline); 1363 // p.appendChild(c.el); 1364 // }) 1365 // } 1366 1367 1368 1369 1370 1371 1372 1373 1374 const totalSum = 480; 1375 const stepsCount = 6; 1376 1377 const progress = document.querySelector(".calculator-progress__bar"); 1378 if (progress) { 1379 const getCurrentStep = () => 1380 document.querySelector(".paragraph--calculator").dataset.step - 1; 1381 let currentStep = getCurrentStep(); 1382 const radius = progress.r.baseVal.value; 1383 const circumference = 2 * Math.PI * radius; 1384 1385 progress.style.setProperty( 1386 "--dasharray", 1387 `${circumference} ${circumference}` 1388 ); 1389 progress.style.setProperty("--dashoffset", circumference); 1390 1391 const setProgress = () => { 1392 const percent = (currentStep * 100) / stepsCount; 1393 const offset = circumference - (percent / 100) * circumference; 1394 progress.style.setProperty("--dashoffset", offset); 1395 }; 1396 1397 setProgress(); 1398 1399 const animateValue = (el, start, end, duration) => { 1400 if (start === end) return; 1401 const range = end - start; 1402 let current = start; 1403 const increment = end > start ? 1 : -1; 1404 const stepTime = Math.abs(Math.floor(duration / range)); 1405 const timer = setInterval(() => { 1406 current += increment; 1407 el.innerHTML = current; 1408 if (current === end) { 1409 clearInterval(timer); 1410 } 1411 }, stepTime); 1412 }; 1413 const btnBack = document.querySelector(".calculator-left__btn"); 1414 btnBack.addEventListener("click", () => { 1415 document.querySelector(".calculator-right input.button-prev").click(); 1416 }); 1417 1418 $(document).ajaxStop(function () { 1419 currentStep = getCurrentStep(); 1420 const currentSum = parseInt( 1421 document.querySelector(".calculator-progress__info .count").textContent 1422 ); 1423 const target = document.querySelector(".calculator-progress__info .count"); 1424 const end = (totalSum / stepsCount) * getCurrentStep(); 1425 animateValue(target, currentSum, end, 800); 1426 setProgress(); 1427 }); 1428 } 1429 var calculatorSwiper = new Swiper(".paragraph__calculator .swiper-container", { 1430 slidesPerView: 1, 1431 pagination: { 1432 el: ".swiper-pagination", 1433 clickable: true, 1434 }, 1435 }); 1436 1437 1438 const mapEl = document.getElementById("map-desktop"); 1439 const mobileMapEl = document.getElementById("map-mobile"); 1440 1441 window.initGmap = () => { 1442 const currentLang = drupalSettings.path.currentLanguage || 'ru' 1443 const isPolishVersion = currentLang === 'pl' 1444 const isUkrainian = currentLang === 'uk' 1445 const icon = "/themes/mytheme/build/img/map/pin--mini.svg" 1446 const isDesktop = window?.innerWidth > 992 1447 1448 if (mapEl) { 1449 const myLatLng = { lat: 50.454784, lng: 30.603934877317855 }; // {lat: 50.454784, lng: 30.457707} 1450 const plLatLng = { lat: 52.23649162256689, lng: 21.141722957670297 } 1451 const initialCoordinates = isPolishVersion ? plLatLng : myLatLng 1452 const mapHeader = document.querySelector(".stations-map__map-header"); 1453 const mapFooter = document.querySelector(".stations-map__map-footer"); 1454 const mobileHideStations = document.querySelector( 1455 ".stations-map__map .hide" 1456 ); 1457 const mobileStationsToggler = document.querySelector( 1458 ".stations-map__toggler" 1459 ); 1460 const stationsList = document.querySelector(".stations-map__list"); 1461 const mobileBackBtn = document.querySelector(".stations-map__nav-back"); 1462 const citiesFilter = document.querySelector(".stations-map__nav-nav"); 1463 let isMobileStationsListOpen = false;
1464 let isSomeStationActive = false; 1465 let currentFilter = "All"; 1466 const cities = { 1467 All: { 1468 prop: false, 1469 coords: isPolishVersion ? plLatLng : myLatLng, 1470 }, 1471 Kyiv: { 1472 prop: "Kyiv", 1473 coords: myLatLng, 1474 }, 1475 Irpen: { 1476 prop: "Irpen", 1477 coords: { lat: 50.529903833371336, lng: 30.244301860118266 }, 1478 }, 1479 Borispol: { 1480 prop: "Borispol", 1481 coords: { lat: 50.36515915615754, lng: 30.919675492643083 }, 1482 }, 1483 Warszawa: { 1484 prop: "Warszawa", 1485 coords: { lat: 52.23649162256689, lng: 21.141722957670297 }, 1486 }, 1487 Lviv: { 1488 prop: "Lviv", 1489 coords: { lat: 49.83607773238876, lng: 23.977604557329887 }, 1490 }, 1491 }; 1492 1493 const translations = { 1494 uk: { 1495 tooltipTitle: { 1496 obolon: "ÐболонÑ", 1497 slavutich: "СлавÑÑиÑ", 1498 podil: "ÐодÑл", 1499 okr: "ÐÑлÑÑева доÑога", 1500 svn: "СвÑÑоÑино / Ðивки", 1501 warszawa: 'Warszawa', 1502 irpin: 'ÐÑпÑнÑ', 1503 borispil: 'ÐоÑиÑпÑлÑ', 1504 lviv: 'ÐÑвÑв', 1505 }, 1506 street: { 1507 obolon: "вÑл. ÐвÑозаводÑÑка, 18", 1508 slavutich: "вÑл. ЦенÑÑалÑна Ñа вÑл. 139-Ñа Садова", 1509 podil: "вÑл. ÐабеÑежно-ÐÑгова, 8", 1510 okr: 'Ñ. СоÑÑÑвÑÑка ÐоÑÑагÑвка, вÑл. Садова, 48а', 1511 svn: "вÑл. ÐкадемÑка ТÑполÑва, 19 (ÐÐ ÐÐ)", 1512 warszawa: 'st. Åysakowska 29', 1513 irpin: 'вÑл. ЦенÑÑалÑна, 30', 1514 borispil: 'вÑл. ÐиÑвÑÑкий ÑлÑÑ , 2/15 (оÑÑÑнÑÐ¸Ñ â ТРЦ «ÐеÑомолл»)', 1515 lviv: 'вÑл.СÑйво 2/4' 1516 }, 1517 }, 1518 ru: { 1519 tooltipTitle: { 1520 obolon: "ÐболонÑ", 1521 slavutich: "СлавÑÑиÑ", 1522 podil: "Ðодол", 1523 okr: "ÐкÑÑÐ¶Ð½Ð°Ñ Ð´Ð¾Ñога", 1524 warszawa: 'Warszawa', 1525 irpin: 'ÐÑпенÑ', 1526 svn: "СвÑÑоÑино / Ðивки", 1527 borispil: 'ÐоÑиÑполÑ', 1528 lviv: 'ÐÑвов' 1529 }, 1530 street: { 1531 obolon: "Ñл. ÐвÑозаводÑкаÑ, 18", 1532 slavutich: "Ñл. ЦенÑÑалÑÐ½Ð°Ñ Ð¸ 139-Ñ Ð¡Ð°Ð´Ð¾Ð²Ð°Ñ", 1533 podil: "Ñл. ÐабеÑежно-ÐÑговаÑ, 8", 1534 okr: 'ÐкÑÑÐ¶Ð½Ð°Ñ Ð´Ð¾Ñога', 1535 warszawa: 'st. Åysakowska 29', 1536 irpin: 'Ñл. ЦенÑÑалÑнаÑ, 30', 1537 svn: "Ñл. Ðкадемика ТÑполева, 19 (ÐÐ ÐÐ)", 1538 borispil: 'Ñл. ÐиевÑкий ÑлÑÑ 2/15 (оÑиенÑÐ¸Ñ ÐÑÑомолл ТРЦ)', 1539 lviv: 'Ñл.СÑйво 2/4' 1540 }, 1541 }, 1542 pl: { 1543 tooltipTitle: { 1544 obolon: "Obolon", 1545 slavutich: "Slavutich", 1546 podil: "Podol", 1547 okr: "Ring road", 1548 warszawa: 'Warszawa', 1549 irpin: 'Irpen', 1550 svn: "Svyatoshino / Nyvky", 1551 borispil: 'Borispol', 1552 lviv: 'Lviv' 1553 }, 1554 street: { 1555 obolon: "st. Avtozavodskaya, 18", 1556 slavutich: "corner of st. Central and 139th Sadovaya", 1557 podil: "st. Naberezhno-Lugovaya, 8", 1558 okr: 'Sofievskaya Borschagovka, st. Sadovaya, 48a', 1559 warszawa: 'st. Åysakowska 29', 1560 irpin: 'st. Centralnaya, 30', 1561 svn: "st. Academician Tupolev, 19 (MREO)", 1562 borispil: 'st. Kievskiy shlyakh 2/15 (landmark Aeromall mall)', 1563 lviv: 'st. Syaivo 2/4' 1564 }, 1565 }, 1566 }; 1567 1568 function getTranslation(key, value) { 1569 const currentLang = drupalSettings.path.currentLanguage || "ru"; 1570 return translations[currentLang]?.[key]?.[value] || value; 1571 }; 1572 1573 function getGeneralTranslations() { 1574 const translations = { 1575 uk: { 1576 city: "ÐÑÑÑо", 1577 phone: "Тел:", 1578 routeName: 'ÐÐРШРУТ', 1579 schedule: 'Ðн.-Ðд.', 1580 short_schedule: 'Ðн.-Сб.', 1581 sunday_off: 'Ðд - <span class="google-maps-content__value">Ð²Ð¸Ñ Ñдний</span>', 1582 }, 1583 ru: { 1584 city: "ÐоÑод", 1585 phone: "Тел:", 1586 routeName: 'ÐÐРШРУТ', 1587 schedule: 'Ðн.-ÐÑ.', 1588 short_schedule: 'Ðн.-Сб.', 1589 sunday_off: 'ÐÑ - <span class="google-maps-content__value">вÑÑ Ð¾Ð´Ð½Ð¾Ð¹</span>', 1590 }, 1591 pl: { 1592 city: "Miasto", 1593 phone: "Tel:", 1594 routeName: 'TRASA', 1595 schedule: 'Pn - Pt', 1596 short_schedule: 'Pn - Sb', 1597 sunday_off: 'Niedziela - <span class="google-maps-content__value">dzieÅ wolny</span>', 1598 }, 1599 }; 1600 1601 return translations[drupalSettings.path.currentLanguage || "ru"]; 1602 }; 1603 1604 function getVideoLabel() { 1605 return { 1606 uk: 'ÐÐÐÐÐ', 1607 ru: 'ÐÐÐÐÐ', 1608 pl: 'WIDEO' 1609 }?.[currentLang] || 'ÐÐÐÐÐ' 1610 } 1611 1612 let markers = []; 1613 const allStations = [ 1614 { 1615 position: new google.maps.LatLng(50.50325247173102, 30.460030329447736), 1616 name: "obolon", 1617 city: cities.Kyiv.prop, 1618 tooltipTitle: getTranslation('tooltipTitle', 'obolon'),
1619 street: getTranslation('street', 'obolon'), 1620 schedule: "9:00-19:00", 1621 weekend: "9:00-20:00", // day off 1622 phone: "067 415 05 00", 1623 isUkraineLocation: true, 1624 video: { 1625 url: "https://youtube.com/shorts/I3A_XCBPT04", 1626 label: getVideoLabel(), 1627 }, 1628 route: 1629 "https://www.google.com/maps/dir//%D0%A1%D0%A2%D0%9E+%22%D0%92%D1%80%D0%B5%D0%BC%D1%8F+%D0%B3%D0%B0%D0%B7%D0%B0%22,+%D0%B2%D1%83%D0%BB%D0%B8%D1%86%D1%8F+%D0%90%D0%B2%D1%82%D0%BE%D0%B7%D0%B0%D0%B2%D0%BE%D0%B4%D1%81%D1%8C%D0%BA%D0%B0,+18,+%D0%9A%D0%B8%D1%97%D0%B2,+%D0%A3%D0%BA%D1%80%D0%B0%D0%B8%D0%BD%D0%B0,+04074/@50.503252,30.46003,18z/data=!4m16!1m6!3m5!1s0x0:0xfd04a06b153a3f7b!2z0KHQotCeICLQktGA0LXQvNGPINCz0LDQt9CwIg!8m2!3d50.5032513!4d30.4600303!4m8!1m0!1m5!1m1!1s0x40d4cd87ace34a99:0xfd04a06b153a3f7b!2m2!1d30.4600303!2d50.5032513!3e3?hl=ru-RU", 1630 }, 1631 { 1632 position: new google.maps.LatLng(50.38756527514124, 30.603934877317855), 1633 name: "slavutich", 1634 city: cities.Kyiv.prop, 1635 tooltipTitle: getTranslation('tooltipTitle', 'slavutich'), 1636 street: getTranslation('street', 'slavutich'), 1637 schedule: "9:00-19:00", 1638 weekend: "9:00-19:00", 1639 phone: "067 415 05 00", 1640 isUkraineLocation: true, 1641 video: { 1642 url: 'https://youtube.com/shorts/o6ffqAMN6wE', 1643 label: getVideoLabel(), 1644 }, 1645 route: 1646 "https://www.google.com/maps/dir//Vremya+Haza,+%D0%9A%D0%B8%D0%B5%D0%B2,+%D0%BF%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5+%D1%83%D0%BB.+%D0%A6%D0%B5%D0%BD%D1%82%D1%80%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F+%D0%B8,+139-%D0%B0+%D0%A1%D0%B0%D0%B4%D0%BE%D0%B2%D0%B0+%D0%B2%D1%83%D0%BB%D0%B8%D1%86%D1%8F,+%D0%9A%D0%B8%D1%97%D0%B2,+%D0%A3%D0%BA%D1%80%D0%B0%D0%B8%D0%BD%D0%B0,+02132/@50.387565,30.603935,18z/data=!4m16!1m6!3m5!1s0x0:0xd1e7dfa2d9c3f0d8!2sVremya+Haza!8m2!3d50.3875638!4d30.6039362!4m8!1m0!1m5!1m1!1s0x40d4c5cf0af22b15:0xd1e7dfa2d9c3f0d8!2m2!1d30.6039362!2d50.3875638!3e3?hl=ru-RU", 1647 }, 1648 // { 1649 // position: new google.maps.LatLng(50.49894576900998, 30.435807259506863), 1650 // name: 'vino', 1651 // city: cities.Kyiv.prop, 1652 // schedule: '9:00-19:00', 1653 // weekend: '9:00-19:00', 1654 // phone: '067 415 05 00', 1655 // isUkraineLocation: true, 1656 // route: 'https://www.google.com/maps/dir//Vremya+Haza,+%D0%B2%D1%83%D0%BB%D0%B8%D1%86%D1%8F+%D0%9D%D0%BE%D0%B2%D0%BE%D0%BC%D0%BE%D1%81%D1%82%D0%B8%D1%86%D1%8C%D0%BA%D0%B0,+25,+%D0%9A%D0%B8%D1%97%D0%B2,+%D0%A3%D0%BA%D1%80%D0%B0%D0%B8%D0%BD%D0%B0,+04074/@50.498946,30.435807,18z/data=!4m16!1m6!3m5!1s0x0:0x51075f4a5f685ca1!2sVremya+Haza!8m2!3d50.4989458!4d30.4358065!4m8!1m0!1m5!1m1!1s0x40d4cd77b3d888d5:0x51075f4a5f685ca1!2m2!1d30.4358065!2d50.4989458!3e3?hl=ru-RU' 1657 // }, 1658 { 1659 position: new google.maps.LatLng(50.42007855116396, 30.37027661226821), 1660 name: "okr", 1661 city: cities.Kyiv.prop, 1662 tooltipTitle: getTranslation('tooltipTitle', 'okr'), 1663 street: getTranslation('street', 'okr'), 1664 schedule: "9:00-19:00", 1665 weekend: "9:00-20:00", 1666 phone: "067 415 05 00", 1667 isUkraineLocation: true, 1668 video: { 1669 url: 'https://youtube.com/shorts/ab4PNuJmh0s', 1670 label: getVideoLabel(), 1671 }, 1672 route: 1673 "https://www.google.com/maps/dir//%D0%92%D1%80%D0%B5%D0%BC%D1%8F+%D0%93%D0%B0%D0%B7%D0%B0,+%D0%B2%D1%83%D0%BB%D0%B8%D1%86%D1%8F+%D0%A1%D0%B0%D0%B4%D0%BE%D0%B2%D0%B0,+48%D0%B0,+%D0%9A%D0%B8%D1%97%D0%B2,+%D0%9A%D0%B8%D1%97%D0%B2%D1%81%D1%8C%D0%BA%D0%B0+%D0%BE%D0%B1%D0%BB.,+%D0%A3%D0%BA%D1%80%D0%B0%D0%B8%D0%BD%D0%B0,+08131/@50.420079,30.370277,18z/data=!4m16!1m6!3m5!1s0x0:0x17a83725ca9cfa3d!2z0JLRgNC10LzRjyDQk9Cw0LfQsA!8m2!3d50.4200794!4d30.3702768!4m8!1m0!1m5!1m1!1s0x40d4cb9918d69bcd:0x17a83725ca9cfa3d!2m2!1d30.3702768!2d50.4200794!3e3?hl=ru-RU", 1674 }, 1675 { 1676 position: new google.maps.LatLng(50.47597828976137, 30.507431046627243), 1677 name: "podol", 1678 city: cities.Kyiv.prop, 1679 tooltipTitle: getTranslation('tooltipTitle', 'podil'), 1680 street: getTranslation('street', 'podil'), 1681 schedule: "9:00-19:00", 1682 weekend: "9:00-19:00", 1683 phone: "067 415 05 00", 1684 isUkraineLocation: true, 1685 video: { 1686 url: 'https://youtube.com/shorts/-fxfKW-AeBA', 1687 label: getVideoLabel(), 1688 }, 1689 route: 1690 "https://www.google.com/maps/dir//%D0%92%D1%80%D0%B5%D0%BC%D1%8F+%D0%93%D0%B0%D0%B7%D0%B0,+%D0%B2%D1%83%D0%BB%D0%B8%D1%86%D1%8F+%D0%9D%D0%B0%D0%B1%D0%B5%D1%80%D0%B5%D0%B6%D0%BD%D0%BE-%D0%9B%D1%83%D0%B3%D0%BE%D0%B2%D0%B0,+8,+%D0%9A%D0%B8%D1%97%D0%B2,+%D0%A3%D0%BA%D1%80%D0%B0%D0%B8%D0%BD%D0%B0,+04071/@50.475978,30.507431,18z/data=!4m16!1m6!3m5!1s0x0:0x263c33b20756c4f7!2z0JLRgNC10LzRjyDQk9Cw0LfQsA!8m2!3d50.47598!4d30.5074301!4m8!1m0!1m5!1m1!1s0x40d4ce0ef6ce0f69:0x263c33b20756c4f7!2m2!1d30.5074301!2d50.47598!3e3?hl=ru-RU", 1691 }, 1692 { 1693 position: new google.maps.LatLng(50.48693400379458, 30.394202915345303), 1694 name: "svn", 1695 city: cities.Kyiv.prop, 1696 tooltipTitle: getTranslation('tooltipTitle', 'svn'), 1697 street: getTranslation('street', 'svn'), 1698 schedule: "9:00-19:00", 1699 weekend: "9:00-19:00", 1700 phone: "067 415 05 00", 1701 isUkraineLocation: true, 1702 video: { 1703 url: 'https://youtube.com/shorts/_pYEiuNc4Ds', 1704 label: getVideoLabel(), 1705 }, 1706 route: 1707 "https://www.google.com/maps/dir//Vremya+Haza,+%D0%B2%D1%83%D0%BB%D0%B8%D1%86%D1%8F+%D0%90%D0%BA%D0%B0%D0%B4%D0%B5%D0%BC%D1%96%D0%BA%D0%B0+%D0%A2%D1%83%D0%BF%D0%BE%D0%BB%D1%94%D0%B2%D0%B0,+19,+%D0%9A%D0%B8%D1%97%D0%B2,+%D0%A3%D0%BA%D1%80%D0%B0%D0%B8%D0%BD%D0%B0,+04128/@50.486934,30.394203,18z/data=!4m16!1m6!3m5!1s0x0:0xf6dd2c0be1597cb2!2sVremya+Haza!8m2!3d50.4869331!4d30.3942027!4m8!1m0!1m5!1m1!1s0x40d4cd89f16a7b41:0xf6dd2c0be1597cb2!2m2!1d30.3942027!2d50.4869331!3e3?hl=ru-RU", 1708 }, 1709 { 1710 position: new google.maps.LatLng( 1711 50.529903833371336, 1712 30.244301860118266 1713 ), 1714 name: "irpen", 1715 city: cities.Irpen.prop, 1716 tooltipTitle: getTranslation('tooltipTitle', 'irpin'), 1717 street: getTranslation('street', 'irpin'), 1718 schedule: "9:00-18:00", 1719 weekend: "9:00-18:00", 1720 phone: "067 415 05 00", 1721 isUkraineLocation: true, 1722 video: { 1723 url: 'https://youtube.com/shorts/VatznfrPUfc', 1724 label: getVideoLabel(), 1725 }, 1726 route: 1727 "https://www.google.com/maps/dir//%D0%A1%D0%A2%D0%9E+%D0%92%D1%80%D0%B5%D0%BC%D1%8F+%D0%B3%D0%B0%D0%B7%D0%B0+-+%D1%81%D0%B5%D1%80%D0%B2%D0%B8%D1%81+%D0%93%D0%91%D0%9E,+%D0%B2%D1%83%D0%BB%D0%B8%D1%86%D1%8F+%D0%A6%D0%B5%D0%BD%D1%82%D1%80%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0,+30,+%D0%86%D1%80%D0%BF%D1%96%D0%BD%D1%8C,+%D0%9A%D0%B8%D1%97%D0%B2%D1%81%D1%8C%D0%BA%D0%B0+%D0%BE%D0%B1%D0%BB.,+%D0%A3%D0%BA%D1%80%D0%B0%D0%B8%D0%BD%D0%B0,+08200/@50.529904,30.244302,18z/data=!4m16!1m6!3m5!1s0x0:0xd39cc8b9cbeaab3d!2z0KHQotCeINCS0YDQtdC80Y8g0LPQsNC30LAgLSDRgdC10YDQstC40YEg0JPQkdCe!8m2!3d50.529903!4d30.2443019!4m8!1m0!1m5!1m1!1s0x472b33b7404ae23d:0xd39cc8b9cbeaab3d!2m2!1d30.2443019!2d50.529903!3e3?hl=ru-RU", 1728 }, 1729 { 1730 position: new google.maps.LatLng(50.36515915615754, 30.919675492643083), 1731 name: "borispol", 1732 city: cities.Borispol.prop, 1733 tooltipTitle: getTranslation('tooltipTitle', 'borispil'), 1734 street: getTranslation('street', 'borispil'), 1735 schedule: "9:00-18:00", 1736 weekend: "9:00-18:00", // 'day off', 1737 isUkraineLocation: true, 1738 phone: "067 415 05 00", 1739 video: { 1740 url: 'https://youtube.com/shorts/eKhXujwCC6c', 1741 label: getVideoLabel(), 1742 }, 1743 route: 1744 "https://www.google.com/maps/dir//%D0%92%D1%80%D0%B5%D0%BC%D1%8F+%D0%93%D0%B0%D0%B7%D0%B0,+%D0%B2%D1%83%D0%BB%D0%B8%D1%86%D1%8F+%D0%9A%D0%B8%D1%97%D0%B2%D1%81%D1%8C%D0%BA%D0%B8%D0%B9+%D1%88%D0%BB%D1%8F%D1%85,+2%2F15,+%D0%91%D0%BE%D1%80%D0%B8%D1%81%D0%BF%D1%96%D0%BB%D1%8C,+%D0%9A%D0%B8%D1%97%D0%B2%D1%81%D1%8C%D0%BA%D0%B0+%D0%BE%D0%B1%D0%BB.,+%D0%A3%D0%BA%D1%80%D0%B0%D0%B8%D0%BD%D0%B0,+08301/@50.365174,30.919806,20z/data=!4m16!1m6!3m5!1s0x0:0x17c86378317ebd0f!2z0JLRgNC10LzRjyDQk9Cw0LfQsA!8m2!3d50.365159!4d30.9196762!4m8!1m0!1m5!1m1!1s0x40d4e90ba151e99b:0x17c86378317ebd0f!2m2!1d30.9196762!2d50.365159!3e3?hl=ru-RU", 1745 }, 1746 { 1747 position: new google.maps.LatLng(52.23649162256689, 21.141722957670297),
1748 name: "warszawa", 1749 city: cities.Warszawa.prop, 1750 tooltipTitle: getTranslation('tooltipTitle', 'warszawa'), 1751 street: getTranslation('street', 'warszawa'), 1752 schedule: "09:00 - 18:00", 1753 weekend: "09:00 - 16:00", // 'day off', 1754 phone: "+48 222 57 1717", 1755 isUkraineLocation: false, 1756 route: "https://maps.app.goo.gl/7p9CKuB894fUxviz9", 1757 video: { 1758 url: '', 1759 label: getVideoLabel(), 1760 }, 1761 }, 1762 { 1763 position: new google.maps.LatLng(49.83607773238876, 23.977604557329887), 1764 name: "lviv", 1765 city: cities.Lviv.prop, 1766 tooltipTitle: getTranslation('tooltipTitle', 'lviv'), 1767 street: getTranslation('street', 'lviv'), 1768 schedule: "9:00-19:00", 1769 weekend: "9:00-19:00", // 'day off', 1770 phone: "+380671899325", 1771 isUkraineLocation: true, 1772 video: { 1773 url: 'https://www.youtube.com/shorts/xDsWpNIASXA', 1774 label: getVideoLabel(), 1775 }, 1776 route: 1777 "https://www.google.com/maps/dir//%D0%B2%D1%83%D0%BB%D0%B8%D1%86%D1%8F+%D0%A1%D1%8F%D0%B9%D0%B2%D0%BE,+2,+%D0%9B%D1%8C%D0%B2%D1%96%D0%B2,+%D0%9B%D1%8C%D0%B2%D0%BE%D0%B2%D1%81%D0%BA%D0%B0%D1%8F+%D0%BE%D0%B1%D0%BB%D0%B0%D1%81%D1%82%D1%8C/@49.8361283,23.9364041,13z/data=!3m1!4b1!4m9!4m8!1m0!1m5!1m1!1s0x473add8a132bb41b:0x3b8ecfdc4901b5b0!2m2!1d23.9776033!2d49.8360802!3e3?hl=ru-RU&entry=ttu", 1778 }, 1779 ]; 1780 1781 const stations = isPolishVersion 1782 ? allStations.filter((station) => !station.isUkraineLocation) 1783 : allStations 1784 1785 // desktop map instance 1786 const mapDesktop = new google.maps.Map(mapEl, { 1787 zoom: 10, 1788 // disableDefaultUI: true, 1789 // styles: styles, 1790 }); 1791 1792 // Mobile tab map instance 1793 const activeMobileMapInstance = new google.maps.Map(mobileMapEl, { 1794 zoom: 10, 1795 }) 1796 1797 const map = isDesktop ? mapDesktop : activeMobileMapInstance 1798 1799 const generalTranslations = getGeneralTranslations() 1800 1801 const infoWindow = new google.maps.InfoWindow(); 1802 1803 function generateInfoModalContent(station) { 1804 return station ? ` 1805 <div class="google-maps-content"> 1806 <p class="google-maps-content__city">${station.tooltipTitle}</p> 1807 <p class="google-maps-content__description">${station.street}</p> 1808 <p class="google-maps-content__schedule">${(station.name === 'lviv' ? generalTranslations.short_schedule : generalTranslations.schedule)} <span class="google-maps-content__value">${station.schedule}</span></p> 1809 ${station.name === 'lviv' ? ` 1810 <p class="google-maps-content__schedule"> 1811 ${generalTranslations.sunday_off} 1812 </p> 1813 ` : ''} 1814 ${isPolishVersion ? ` 1815 <p class="google-maps-content__schedule"> 1816 Sobota <span class="google-maps-content__value">09:00 - 16:00</span> <br> 1817 </p> 1818 <p class="google-maps-content__schedule"> 1819 Niedziela - <span class="google-maps-content__value">dzieÅ wolny</span> 1820 </p> 1821 ` : ''} 1822 <p class="google-maps-content__phone"> 1823 ${generalTranslations.phone} 1824 <a href="tel:${station.phone}" class="google-maps-content__value">${station.phone}</a> 1825 </p> 1826 <div class="google-maps-content__row"> 1827 <a href="${station.route}" class="google-maps-content__route" target="_blank">${generalTranslations.routeName}</a> 1828 ${station?.video?.url 1829 ? `<a 1830 href="${station?.video?.url}" 1831 class="google-maps-content__route" 1832 target="_blank" 1833 >${station.video.label}</a>` 1834 : '' 1835 } 1836 </div> 1837 </div> 1838 ` : '' 1839 } 1840 1841 const setMarkers = (mapInstance, stations, coords, isFromCLoseButton) => { 1842 if (stations.length === 1 && !isFromCLoseButton) { 1843 // selection of first sidebar station 1844 const station = stations[0]; 1845 const prop = station.name; 1846 const selectors = { 1847 desktop: `.stations-map-desktop .stations-map__list-item[data-prop=${prop}]`, 1848 mobile: `.stations-mobile .stations-map__list-item[data-prop=${prop}]` 1849 } 1850 const dynamicLinkSelector = isDesktop 1851 ? selectors.desktop 1852 : selectors.mobile 1853 const currentLink = stationsList.querySelector(dynamicLinkSelector); 1854 // currentLink.click() 1855 setTimeout(() => {
1856 setActiveClass(stationLinks, currentLink); 1857 const name = currentLink.querySelector(".content__title").textContent; 1858 setMobileContent(currentLink, station); 1859 isSomeStationActive = true; 1860 showMapControls(name, station); 1861 toggleMobileBackBtn(); 1862 // currentLink.classList.add('js--active') 1863 }, 0); 1864 } 1865 stations.forEach((station) => { 1866 const marker = new google.maps.Marker({ 1867 position: station.position, 1868 icon: icon, 1869 map: mapInstance, 1870 title: station.tooltipTitle 1871 // animation: google.maps.Animation.DROP, 1872 }); 1873 1874 markers.push(marker); 1875 marker.addListener("click", () => { 1876 mapInstance.setZoom(18); 1877 infoWindow.setContent(generateInfoModalContent(station)) 1878 infoWindow.open(mapInstance, marker) 1879 mapInstance.panTo(marker.getPosition()); 1880 1881 const selectors = { 1882 desktop: `.stations-map-desktop .stations-map__list-item[data-prop=${station.name}]`, 1883 mobile: `.stations-mobile .stations-map__list-item[data-prop=${station.name}]` 1884 } 1885 const dynamicSelector = isDesktop 1886 ? selectors.desktop 1887 : selectors.mobile 1888 1889 const target = document.querySelector(dynamicSelector);
1890 setActiveClass(stationLinks, target); 1891 scrollToStation(target); 1892 const name = target.querySelector(".content__title").textContent; 1893 const obj = stations.find((p) => p.name === station.name); 1894 setMobileContent(target, obj); 1895 isSomeStationActive = true; 1896 showMapControls(name, obj); 1897 toggleMobileBackBtn(); 1898 }); 1899 }); 1900 mapInstance.panTo(coords); 1901 }; 1902 1903 const reloadMarkers = (mapInstance) => { 1904 markers.forEach((marker) => { 1905 mapInstance.setZoom(10); 1906 marker.setMap(null); 1907 }); 1908 }; 1909 1910 // Desktop Top filters above the map 1911 const mapDesktopNavLinks = document.querySelectorAll(".stations-map-desktop .stations-map__nav .link"); 1912 initMapNavLinks(map, mapDesktopNavLinks) 1913 1914 function initMapNavLinks(map, links) { 1915 links.forEach((link) => { 1916 link.addEventListener("click", () => { 1917 const newStations = cities[link.dataset.prop].prop 1918 ? stations.filter((p) => p.city === link.dataset.prop) 1919 : stations; 1920 reloadMarkers(map); 1921 setMarkers(map, newStations, cities[link.dataset.prop].coords);
1922 setActiveClass(links, link); 1923 // TODO: HERE 1924 setActiveClass(stationLinks); 1925 hideStations(link.dataset.prop); 1926 currentFilter = link.dataset.prop; 1927 hideMapControls(map); 1928 scrollToStation(); 1929 }); 1930 }); 1931 } 1932 1933 // left sidebar buttons 1934 const dynamicSelector = isDesktop 1935 ? ".stations-map-desktop .stations-map__list .stations-map__list-item" 1936 : ".stations-mobile .stations-map__list .stations-map__list-item" 1937 const stationLinks = document.querySelectorAll( 1938 dynamicSelector 1939 ); 1940 stationLinks.forEach((link) => { 1941 link.addEventListener("click", () => { 1942 const selectedStation = stations.find((p) => p.name === link.dataset.prop) 1943 const selectedMarker = markers.find((marker) => marker.position?.lat() === selectedStation.position?.lat()) 1944 1945 if (selectedMarker) { 1946 infoWindow.setContent(generateInfoModalContent(selectedStation)) 1947 infoWindow.open(map, selectedMarker) 1948 }; 1949 map.setZoom(15); 1950 map.panTo(selectedStation.position);
1951 setActiveClass(stationLinks, link); 1952 const name = link.querySelector(".content__title").textContent; 1953 const obj = stations.find((p) => p.name === link.dataset.prop); 1954 setMobileContent(link, obj); 1955 isSomeStationActive = true; 1956 showMapControls(name, obj); 1957 toggleMobileBackBtn(); 1958 }); 1959 }); 1960 1961 const setActiveClass = (items, target) => { 1962 items.forEach((p) => { 1963 p.classList.remove("js--active"); 1964 }); 1965 if (target) { 1966 target.classList.add("js--active"); 1967 if (window.innerWidth < 1024) { 1968 scrollToStation(); 1969 } 1970 } 1971 }; 1972 1973 const hideStations = (prop) => { 1974 if (cities[prop].prop) { 1975 stationLinks.forEach((p) => p.classList.add("d-none")); 1976 const currentStationLinks = document.querySelectorAll( 1977 `.stations-map__list-item[data-city=${prop}]` 1978 ); 1979 currentStationLinks.forEach((p) => { 1980 p.classList.remove("d-none"); 1981 p.classList.remove("js--hidden--mobile"); 1982 }); 1983 } else { 1984 stationLinks.forEach((p) => { 1985 p.classList.remove("d-none"); 1986 p.classList.remove("js--hidden--mobile"); 1987 }); 1988 } 1989 }; 1990 1991 const showMapControls = (name, { schedule, weekend, route, phone }) => { 1992 const obj = { 1993 name: name, 1994 route: route, 1995 schedule: schedule, 1996 weekend: Drupal.t(weekend), 1997 phone: phone, 1998 }; 1999 setDesktopContent(obj, false); 2000 mapHeader.classList.add("js--active"); 2001 mapFooter.classList.add("js--active"); 2002 // mapEl.classList.add('js--active') 2003 }; 2004 const hideMapControls = (mapInstance, isFromCloseButton) => { 2005 isFromCloseButton = !!isFromCloseButton; 2006 setDesktopContent({}, true); 2007 mapHeader.classList.remove("js--active"); 2008 mapFooter.classList.remove("js--active"); 2009 // mapEl.classList.remove('js--active') 2010 const newStations = cities[currentFilter].prop 2011 ? stations.filter((p) => p.city === currentFilter) 2012 : stations; 2013 reloadMarkers(mapInstance); 2014 setMarkers(mapInstance, newStations, cities[currentFilter].coords, isFromCloseButton);
2015 setActiveClass(stationLinks); 2016 hideStations(currentFilter); 2017 isSomeStationActive = false; 2018 toggleMobileBackBtn(); 2019 }; 2020 2021 mapHeader.querySelector(".close").addEventListener("click", () => { 2022 const mapInstance = isDesktop ? map : activeMobileMapInstance 2023 hideMapControls(mapInstance, true); 2024 }); 2025 2026 const setDesktopContent = ( 2027 { name, schedule, weekend, phone, route }, 2028 isClear 2029 ) => { 2030 mapHeader.querySelector(".name").textContent = isClear ? "" : name; 2031 mapFooter.querySelector( 2032 ".bottom__schedule-item--total .text" 2033 ).textContent = isClear ? "" : schedule; 2034 mapFooter.querySelector( 2035 ".bottom__schedule-item--weekend .text" 2036 ).textContent = isClear ? "" : weekend; 2037 mapFooter.querySelector(".phone").textContent = isClear ? "" : phone; 2038 mapFooter.querySelector(".phone").href = isClear ? "" : `tel:${phone}`; 2039 mapFooter.querySelector(".buttons__route").href = isClear ? "" : route; 2040 if (typeof window.BinotelCallTracking !== 'undefined' && window.BinotelCallTracking[502069]) { 2041 window.BinotelCallTracking[502069].replacePhoneNumbersOnDynamicContent(); 2042 } 2043 }; 2044 2045 const setMobileContent = ( 2046 selector, 2047 { schedule, weekend, route, phone } 2048 ) => { 2049 if (!selector) { 2050 console.log('setMobileContent no selector', selector) 2051 return 2052 } 2053 selector.querySelector(".schedule-item--total .text").textContent = 2054 schedule; 2055 selector.querySelector(".schedule-item--weekend .text").textContent = 2056 Drupal.t(weekend); 2057 selector.querySelector(".link--route").href = route; 2058 selector.querySelector(".phone").href = `tel:${phone}`; 2059 selector.querySelector(".phone").textContent = phone; 2060 if (typeof window.BinotelCallTracking !== 'undefined' && window.BinotelCallTracking[502069]) { 2061 window.BinotelCallTracking[502069].replacePhoneNumbersOnDynamicContent(); 2062 } 2063 }; 2064 2065 const initDesktopMap = () => { 2066 const availableStations = isPolishVersion 2067 ? stations.filter((station) => !station.isUkraineLocation) 2068 : stations 2069 2070 setMarkers(map, availableStations, initialCoordinates) 2071 }; 2072 initDesktopMap(); 2073 2074 // Don't know why add scrollbar for list, maybe for cross browser styles, 2075 // just leave this shit for now 2076 const stationsListPs = new PerfectScrollbar(".stations-map-desktop .stations-map__list", { 2077 wheelSpeed: 1, 2078 wheelPropagation: false, 2079 swipeEasing: true, 2080 minScrollbarLength: 20, 2081 suppressScrollX: true, 2082 }); 2083 const stationsListPsMobile = new PerfectScrollbar(".stations-mobile .stations-map__list", { 2084 wheelSpeed: 1, 2085 wheelPropagation: false, 2086 swipeEasing: true, 2087 minScrollbarLength: 20, 2088 suppressScrollX: true, 2089 }); 2090 const scrollToStation = (target) => { 2091 document.querySelector(".stations-map__list").scrollTo({ 2092 top: target ? target.offsetTop : 0, 2093 behavior: "smooth", 2094 }); 2095 stationsListPs.update(); 2096 stationsListPsMobile.update(); 2097 // $('.stations-map__list').animate({scrollTop: target.offsetTop}, 1000); 2098 }; 2099 2100 mobileStationsToggler.addEventListener("click", function () { 2101 isMobileStationsListOpen = true; 2102 this.classList.add("js--hidden"); 2103 stationsList.classList.add("js--active"); 2104 mobileHideStations.classList.add("js--active"); 2105 // mapEl.classList.add("js--collapsed"); 2106 toggleMobileBackBtn(); 2107 }); 2108 2109 mobileHideStations.addEventListener("click", function () { 2110 isMobileStationsListOpen = false;
2111 this.classList.remove("js--active"); 2112 stationsList.classList.remove("js--active"); 2113 mobileStationsToggler.classList.remove("js--hidden"); 2114 // mapEl.classList.remove("js--collapsed"); 2115 toggleMobileBackBtn(); 2116 // hideMapControls() 2117 }); 2118 2119 mobileBackBtn.addEventListener("click", () => { 2120 const mapInstance = isDesktop ? map : activeMobileMapInstance 2121 hideMapControls(mapInstance, true); 2122 }); 2123 2124 const toggleMobileBackBtn = () => { 2125 if (isMobileStationsListOpen && isSomeStationActive) { 2126 mobileBackBtn.classList.add("js--active"); 2127 citiesFilter.classList.add("js--hidden"); 2128 } else { 2129 mobileBackBtn.classList.remove("js--active"); 2130 citiesFilter.classList.remove("js--hidden"); 2131 } 2132 }; 2133 2134 function initMobileStationActive() { 2135 const tabSelectors = { 2136 listed: { 2137 tab: document.querySelector('.stations-mobile__tab--listed'), 2138 body: document.querySelector('.stations-mobile__tab-body--listed'), 2139 }, 2140 map: { 2141 tab: document.querySelector('.stations-mobile__tab--map'), 2142 body: document.querySelector('.stations-mobile__tab-body--map'), 2143 } 2144 } 2145 2146 const { listed, map } = tabSelectors 2147 2148 // Check if all elements present 2149 if (!listed.tab || !map.tab || !listed.body || !map.body) return 2150 2151 // Set listed to be default active tab
2152 setActiveTab('listed') 2153 2154 // Event listeners 2155 listed.tab.addEventListener('click', () => setActiveTab('listed')) 2156 map.tab.addEventListener('click', () => setActiveTab('map')) 2157 2158 function setActiveTab(activeKey) { 2159 Object.entries(tabSelectors).forEach(([key, { tab, body }]) => { 2160 const isActive = key === activeKey 2161 tab.classList.toggle('active', isActive) 2162 body.classList.toggle('active', isActive) 2163 }) 2164 } 2165 } 2166 2167 initMobileStationActive() 2168 2169 function initStationAccordions() { 2170 const stationElements = document.querySelectorAll('.stations-mobile__city-station') 2171 if (!stationElements.length) return 2172 2173 let activeStationEl = null 2174 let activeMapInstance = null 2175 2176 function closeOpenedStation() { 2177 if (!activeStationEl) return 2178 2179 activeStationEl.classList.remove('active') 2180 const prevMap = activeStationEl.querySelector('.map') 2181 if (prevMap) prevMap.style.display = 'none' 2182 } 2183 2184 stationElements.forEach(stationEl => { 2185 const headingEl = stationEl.querySelector('.stations-mobile__city-station-heading') 2186 const stationMapEl = stationEl.querySelector('.map') 2187 const cityId = stationEl.dataset.id 2188 const foundStation = allStations.find((item) => item.name === cityId) 2189 2190 if (!foundStation) return 2191 2192 const lat = parseFloat(foundStation.position?.lat()) 2193 const lng = parseFloat(foundStation?.position?.lng()) 2194 2195 headingEl.addEventListener('click', (e) => { 2196 const isArrow = e.target.classList.contains('stations-mobile__station-arrow') 2197 2198 if (stationEl === activeStationEl && !isArrow) { 2199 return 2200 } 2201 2202 // if station is active and click on arrow â close this and clear 2203 if (stationEl === activeStationEl && isArrow) { 2204 closeOpenedStation() 2205 activeStationEl = null 2206 return 2207 } 2208 2209 // deactivate previous station and hide map 2210 if (activeStationEl) { 2211 closeOpenedStation() 2212 } 2213 2214 // make a new station active 2215 activeStationEl = stationEl 2216 activeStationEl.classList.add('active') 2217 stationMapEl.style.display = 'block' 2218 2219 // init map 2220 activeMapInstance = new google.maps.Map(stationMapEl, { 2221 center: { lat, lng }, 2222 zoom: 15, 2223 }) 2224 2225 const marker = new google.maps.Marker({ 2226 position: { lat, lng }, 2227 icon: icon, 2228 map: activeMapInstance, 2229 title: cityId, 2230 }) 2231 2232 function openMarkerInfo() { 2233 activeMapInstance.setZoom(15) 2234 infoWindow.setContent(generateInfoModalContent(foundStation)) 2235 infoWindow.open(activeMapInstance, marker) 2236 activeMapInstance.panTo(marker.getPosition()) 2237 } 2238 2239 openMarkerInfo() 2240 2241 marker.addListener("click", openMarkerInfo) 2242 }) 2243 }) 2244 } 2245 2246 initStationAccordions() 2247 2248 function initMobileMap() { 2249 if (!mobileMapEl) return 2250 2251 const availableStations = isPolishVersion 2252 ? stations.filter((station) => !station.isUkraineLocation) 2253 : stations 2254 2255 setMarkers(activeMobileMapInstance, availableStations, initialCoordinates) 2256 2257 const mapMobileNavLinks = document.querySelectorAll(".stations-mobile .stations-map__nav .link"); 2258 initMapNavLinks(activeMobileMapInstance, mapMobileNavLinks) 2259 } 2260 2261 initMobileMap() 2262 2263 function setActiveStationByPage() { 2264 const path = window.location.pathname; 2265 2266 // 1. ÐонÑÑгÑÑаÑÑÑ Ð²ÑдповÑдноÑÑей ÑлÑÑ Ñв Ñ ID ÑÑанÑÑй 2267 const stationRoutes = [ 2268 { 2269 id: 'borispol', 2270 paths: ['/uk/kontakty/borispol', '/kontakty/borispol'], 2271 }, 2272 {
2273 id: 'irpen', 2274 paths: ['/uk/stantsiya-irpin', '/stanciya-irpen', '/stacja-irpen'], 2275 }, 2276 { 2277 id: 'warszawa', 2278 paths: ['/mi-u-polschi', '/uk/my-u-polshchi'], 2279 }, 2280 { 2281 id: 'lviv', 2282 paths: ['/uk/stantsiya-lviv', '/stanciya-lvov'], 2283 }, 2284 ] 2285 2286 // 2. ÐоÑÑк вÑдповÑÐ´Ð½Ð¾Ñ ÑÑанÑÑÑ Ð·Ð° URL 2287 const matchedStation = stationRoutes.find(route => route.paths.includes(path)) 2288 if (!matchedStation) return 2289 2290 const stationId = matchedStation.id 2291 const selectedStation = stations.find(p => p.name === stationId) 2292 const selectedMarker = markers.find(marker => marker.position?.lat() === selectedStation?.position?.lat()) 2293 2294 if (!selectedMarker) return 2295 2296 // 3. ÐÑдобÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð¼Ð°ÑкеÑа Ñа ÑнÑоÑмаÑÑйного вÑкна
2297 setActiveMarkerInfo(selectedStation, selectedMarker) 2298 2299 // 4. ÐкÑивÑÑмо вÑдповÑдний DOM-ÐµÐ»ÐµÐ¼ÐµÐ½Ñ 2300 const selectors = { 2301 desktop: `.stations-map-desktop .stations-map__list-item[data-prop=${stationId}]`, 2302 mobile: `.stations-mobile .stations-map__list-item[data-prop=${stationId}]`, 2303 }; 2304 const dynamicLinkSelector = isDesktop ? selectors.desktop : selectors.mobile 2305 const link = document.querySelector(dynamicLinkSelector) 2306 if (!link) return 2307 2308 setActiveClass(stationLinks, link); 2309 2310 const name = link.querySelector(".content__title")?.textContent; 2311 const obj = stations.find(p => p.name === link.dataset.prop); 2312 2313 setMobileContent(link, obj); 2314 isSomeStationActive = true; 2315 showMapControls(name, obj); 2316 toggleMobileBackBtn(); 2317 } 2318 2319 setActiveStationByPage() 2320 2321 function setActiveMarkerInfo(selectedStation, selectedMarker) { 2322 if (isDesktop) { 2323 infoWindow.setContent(generateInfoModalContent(selectedStation)) 2324 infoWindow.open(map, selectedMarker) 2325 map.setZoom(15) 2326 map.panTo(selectedStation.position) 2327 } else { 2328 const listedMobileStationHeading = document.querySelector( 2329 `.stations-mobile__city-station[data-id="${selectedStation.name}"] .stations-mobile__city-station-heading` 2330 ) 2331 if (listedMobileStationHeading) { 2332 setTimeout(() => { 2333 listedMobileStationHeading.click() 2334 }, 100) 2335 } 2336 } 2337 } 2338 2339 // the smooth zoom function 2340 // function smoothZoom (map, max, cnt) { 2341 // if (cnt >= max) { 2342 // return; 2343 // } 2344 // else { 2345 // const z = google.maps.event.addListener(map, 'zoom_changed', function(event){ 2346 // google.maps.event.removeListener(z); 2347 // smoothZoom(map, max, cnt + 1); 2348 // }); 2349 // setTimeout(function(){map.setZoom(cnt)}, 80); // 80ms is what I found to work well on my system -- it might not work well on all systems 2350 // } 2351 // } 2352 } 2353 }; 2354 2355 2356 const sideAnnouncesWrapper = document.querySelector('.side-announces') 2357 const sideAnnouncesKey = 'sideAnnounces' 2358 if (sideAnnouncesWrapper) { 2359 const observeAnnounces = () => { 2360 const observer = new IntersectionObserver((entries) => { 2361 entries.forEach((entry) => { 2362 // console.log(entry) 2363 if (entry.isIntersecting) { 2364 entry.target.classList.add('js--active') 2365 } 2366 }) 2367 }, {}) 2368 observer.observe(sideAnnouncesWrapper) 2369 } 2370 const sessionStorageData = (key) => sessionStorage.getItem(key) 2371 const getSessionStorageData = (key) => JSON.parse(sessionStorageData(key)) 2372 const sideAnnounces = sideAnnouncesWrapper.querySelectorAll( 2373 '.side-announces__item', 2374 ) 2375 const getState = () => getSessionStorageData(sideAnnouncesKey) 2376 const getLastIndex = (arr) => arr.slice(-1)[0] 2377 const setDataToSessionStorage = (data) => { 2378 sessionStorage.setItem(sideAnnouncesKey, JSON.stringify(data)) 2379 } 2380 const createInitialState = () => [0] 2381 2382 const activateAnnounce = () => { 2383 const index = getLastIndex(getState()) 2384 sideAnnounces[index].classList.add('js--active') 2385 const closeBtn = sideAnnounces[index].querySelector('.close') 2386 2387 if(!!closeBtn) { 2388 closeBtn.addEventListener('click', () => { 2389 sideAnnounces[index].classList.remove('js--active')
2390 sideAnnouncesWrapper.classList.add('js--hidden') 2391 }) 2392 } 2393 } 2394 if (sessionStorageData(sideAnnouncesKey)) { 2395 const state = getState() 2396 const newIndex = getLastIndex(state) + 1 2397 if (newIndex < sideAnnounces.length) { 2398 observeAnnounces() 2399 state.push(newIndex) 2400 setDataToSessionStorage(state) 2401 activateAnnounce() 2402 } 2403 } else { 2404 const initialState = createInitialState() 2405 observeAnnounces() 2406 setDataToSessionStorage(initialState) 2407 activateAnnounce() 2408 } 2409 // sideAnnounces.forEach((p, index) => { console.log(index) }) 2410 } 2411 2412 2413 } 2414 2415 const numReg = new RegExp('^\\d*[.|,]?\\d*$') 2416 const replaceVal = val => val.replace(/\D/g, ''); 2417 2418 //Ðод напиÑаннÑй здеÑÑ Ð±ÑÐ´ÐµÑ Ð²Ñполнен пÑи каждом AJAX запÑоÑе 2419 2420 $(".paragraph--cta-hr .form-item-field-years-0-value input").on('propertychange input', function () 2421 2422 { 2423 // const submit = $(this).parent().siblings('.button') 2424 if (!numReg.test(this.value) || (this.value === '')) { 2425 this.value = replaceVal(this.value) 2426 } 2427 }); 2428 $(".paragraph__calculator .form-item-form-text:not(.form-item-email) input").on('propertychange input', function () 2429 { 2430 if (!numReg.test(this.value)) { 2431 this.value = replaceVal(this.value) 2432 } 2433 }); 2434 2435 $(".form-item-form-select select").change(function () { 2436 setTimeout(() => { 2437 $('.chosen-search-input').blur() 2438 }, 100) 2439 }) 2440 2441 // $(".paragraph__calculator .form-item-form-text input").mask("+38 (099) 999 99 99"); 2442 const detailsList = document.querySelector('.details__set-modal .list-wrapper') 2443 if (detailsList) { 2444 const detailsListPs = new PerfectScrollbar(detailsList, { 2445 wheelSpeed: 1, 2446 wheelPropagation: false, 2447 swipeEasing: true, 2448 minScrollbarLength: 20, 2449 suppressScrollX: true 2450 2451 }); 2452 } 2453 2454 const toTopButton = $('.to-top-button'); 2455 $(window).scroll(function() { 2456 if ($(this).scrollTop() > 1000) { 2457 toTopButton.addClass('visible'); 2458 } else { 2459 toTopButton.removeClass('visible'); 2460 } 2461 }); 2462 2463 toTopButton.click(function() { 2464 $('html, body').animate({ scrollTop: 0 }, 300); 2465 }); 2466 } 2467 }; 2468}(jQuery, Drupal)); 2469 2470 2471(function ($, Drupal) { 2472 Drupal.behaviors.validation = { 2473 attach: function (context) { 2474 2475 function standartMusk (event){ 2476 let x = event.target.value 2477 .replace(/\D/g, "") 2478 .match(/(\d{0,3})(\d{0,9})/); 2479 2480 if (event.target.value.length > 13){ 2481 event.target.value = event.target.value.slice(0, 13); 2482 } 2483 2484 if (!x[2]) { 2485 event.target.value = "+380"; 2486 return 2487 } 2488 2489 event.target.value = `+${x[1]}${x[2]}`; 2490 } 2491 2492 function languagePlMusk (event){ 2493 let x = event.target.value 2494 .replace(/\D/g, "") 2495 .match(/(\d{0,11})/); 2496 2497 if (event.target.value.length > 12){ 2498 event.target.value = event.target.value.slice(0, 12); 2499 } 2500 2501 2502 event.target.value = `+${x[1]}`; 2503 } 2504 2505 function inputClickPosition (event){ 2506 event.target.selectionStart = event.target.selectionStart < 4 ? 4 : event.target.selectionStart 2507 } 2508 2509 function handlePLInputClickPosition(event) { 2510 const input = event.target; 2511 const value = input.value; 2512 2513 // Ensure that the cursor remains after +380 or after the entered numbers 2514 const prefixLength = 3; // length of "+380" 2515 const digitsOnly = value.slice(prefixLength).replace(/\D/g, ''); // all digits after "+380" 2516 2517 const newCursorPosition = digitsOnly.length + prefixLength; // Position after the last digit or +380 2518 2519 // Place the cursor after +380 or the last entered digit 2520 setTimeout(() => { 2521 input.selectionStart = input.selectionEnd = Math.max(newCursorPosition, prefixLength); 2522 }, 0); 2523 } 2524 2525 function handleInputClickPosition(event, prefixLength = 4) { 2526 const input = event.target; 2527 2528 // Ensure that the cursor remains after +380 or after the entered numbers 2529 const digitsOnly = input.value.slice(prefixLength).replace(/\D/g, ''); // all digits after prefixLength 2530 2531 const newCursorPosition = digitsOnly.length + prefixLength; // Position after the last digit or +380 2532 2533 // Place the cursor after +380 or the last entered digit 2534 setTimeout(() => { 2535 input.selectionStart = input.selectionEnd = Math.max(newCursorPosition, prefixLength); 2536 }, 0); 2537 } 2538 2539 function setPhoneError (input, error){ 2540 input.addClass('input-error') 2541 input.next('.input-error__text').remove(); 2542 input.after(`<p class='input-error__text'>${error}</p>`); 2543 } 2544 2545 function removePhoneError (input) { 2546 input.removeClass('input-error'); 2547 input.next('.input-error__text').remove(); 2548 } 2549 2550 // click position 2551 $('input[name="contact_info[phone]"]').on('click', (event)=> inputClickPosition(event)); 2552 2553 const domenIsPL = drupalSettings.path.currentLanguage === 'pl' 2554 2555 if (domenIsPL){ 2556 $(".form-item-form-tel input").attr('placeholder', '+48').mask("+99999999999"); 2557 $('input[name="contact_info[phone]"]').attr('placeholder', '+48') 2558 $(".form-item-form-tel input").on('click focus', (event)=> handleInputClickPosition(event, 1)); 2559 2560 $('input[name="contact_info[phone]"]').on('focus', (event)=> languagePlMusk(event)); 2561 $('input[name="contact_info[phone]"]').on('input',(event)=> languagePlMusk(event)); 2562 $('#edit-payment-type-answer-2').siblings('label').hide(); 2563 2564 // form validation 2565 $("form").on( "submit", function( event ) { 2566 event.preventDefault(); 2567 2568 const phoneInput = $(this).find('input[name="contact_info[phone]"]'); 2569 let errorText = '' 2570 let isError = false 2571 2572 removePhoneError(phoneInput) 2573 2574 // phone validation 2575 2576 $(this).find(phoneInput).each(function() { 2577 2578 if(phoneInput.val().length === 0){ 2579 errorText = "Pole jest obowiÄ zkowe" 2580 setPhoneError(phoneInput,errorText) 2581 isError = true 2582 } 2583 2584 if(phoneInput.val().length !== 12) { 2585 errorText = 'Sprawdź prawidÅowe wejÅcie' 2586 setPhoneError(phoneInput,errorText) 2587 isError = true 2588 } 2589 2590 }) 2591 2592 // ... 2593 2594 if (isError) return 2595 2596 this.submit(); 2597 }); 2598 2599 }else{ 2600 $(".form-item-form-tel input").attr('placeholder', '+380').mask("+380999999999"); 2601 $('input[name="contact_info[phone]"]').attr('placeholder', '+380') 2602 $('input[name="contact_info[phone]"]').on('focus',(event)=> standartMusk(event)); 2603 $('input[name="contact_info[phone]"]').on('input',(event)=> standartMusk(event)); 2604 $(".form-item-form-tel input").on('click focus', (event)=> handleInputClickPosition(event, 4)); 2605 2606 // form validation 2607 2608 $("form").on( "submit", function( event ) { 2609 event.preventDefault(); 2610 2611 const phoneInput = $(this).find('input[name="contact_info[phone]"]'); 2612 const operatorArr = ['+38039','+38067','+38068','+38096','+38097','+38098','+38050','+38066','+38095',"+38099","+38063","+38073","+38093","+38091","+38092","+38089","+38094"] 2613 let errorText = '' 2614 let isError = false 2615 2616 removePhoneError(phoneInput) 2617 2618 // phone validation 2619 2620 $(this).find(phoneInput).each(function() { 2621 2622 const checkOperatorInVal = operatorArr.some((operator) => 2623 phoneInput.val().slice(0, 6).startsWith(operator) 2624 ); 2625 2626 if(phoneInput.val().length === 0){ 2627 2628 if (window.location.href.indexOf('/uk') !== -1) { 2629 errorText = "Ðоле обв'Ñзкове до заповенннÑ" 2630 }else{ 2631 errorText = 'Ðоле обезаÑелÑное к заполнениÑ' 2632 } 2633 2634 setPhoneError(phoneInput,errorText) 2635 isError = true 2636 } 2637 2638 if(phoneInput.val().length !== 13) { 2639 2640 if (window.location.href.indexOf('/uk') !== -1) { 2641 errorText = 'ÐеÑевÑÑÑе пÑавилÑнÑÑÑÑ Ð²Ð²ÐµÐ´ÐµÐ½Ð½Ñ' 2642 }else{ 2643 errorText = 'ÐÑовеÑÑÑе пÑавилÑноÑÑÑ Ð²Ð²Ð¾Ð´Ð°' 2644 } 2645 2646 setPhoneError(phoneInput,errorText) 2647 isError = true 2648 } 2649 2650 if(!checkOperatorInVal){ 2651 2652 if (window.location.href.indexOf('/uk') !== -1) { 2653 errorText = 'ÐеÑевÑÑÑе пÑавилÑнÑÑÑÑ Ð²Ð²ÐµÐ´ÐµÐ½Ð½Ñ' 2654 }else{ 2655 errorText = 'ÐÑовеÑÑÑе пÑавилÑноÑÑÑ Ð²Ð²Ð¾Ð´Ð°' 2656 } 2657 2658 setPhoneError(phoneInput,errorText) 2659 isError = true 2660 } 2661 }) 2662 2663 // ... 2664 2665 if (isError) return 2666 2667 $(".preloader--spin").addClass("js--active"); 2668 this.submit(); 2669 }); 2670 2671 } 2672 } 2673 }; 2674}(jQuery, Drupal)); 2675
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.