1"use strict"; 2 3document.addEventListener("DOMContentLoaded", function () { 4 if (typeof Fancybox !== "undefined" && typeof Fancybox.bind === "function") { 5 Fancybox.bind("[data-fancybox]", { 6 }); 7 } 8}); 9 10Notiflix.Loading.init({ 11 svgColor: "#294634", 12 fontFamily: "CoFo", 13 backgroundColor: 'rgba(0,0,0,0.3)', 14 messageColor: "#000", 15}); 16 17Notiflix.Report.init({ 18 fontFamily: 'CoFo', 19 backOverlayClickToClose: true, 20 titleMaxLength: 200, 21 messageMaxLength: 200, 22 buttonMaxLength: 200, 23 borderRadius: 0, 24 success: { 25 svgColor: '#294634', 26 buttonBackground: '#294634', 27 backOverlayColor: 'rgba(0, 0, 0, 0.3)', 28 }, 29 failure: { 30 backOverlayColor: 'rgba(0, 0, 0, 0.3)', 31 } 32}); 33 34const maskElements = document.querySelectorAll("[data-phone-mask]"); 35if (maskElements.length > 0) { 36 maskElements.forEach((item) => { 37 let mask = IMask(item, { 38 mask: "+{7} (000) 000-00-00", 39 lazy: true, 40 }); 41 item.addEventListener("focus", function () { 42 mask.updateOptions({ lazy: false }); 43 mask.alignCursor(); 44 }); 45 item.addEventListener("blur", function () { 46 mask.updateOptions({ lazy: true }); 47 }); 48 }); 49} 50 51 52let buttons = document.querySelectorAll('.menu__link'); 53 54buttons.forEach((elem)=>{ 55 elem.addEventListener('click',()=>{ 56 menuBody.classList.remove('_active'); 57 burgerMenu.classList.remove('_active'); 58 }) 59}) 60 61const menuLinks = document.querySelectorAll('.menu__link[data-goto]'); 62 63if (menuLinks.length > 0) { 64 menuLinks.forEach(menuLink => { 65 menuLink.addEventListener("click", onMenuLinkClick); 66 }); 67 function onMenuLinkClick(e) { 68 const menuLink = e.target; 69 if(menuLink.dataset.goto && document.querySelector(menuLink.dataset.goto)) { 70 const gotoBlock = document.querySelector(menuLink.dataset.goto); 71 const gotoBlockValue = gotoBlock.getBoundingClientRect().top + scrollY - document.querySelector('header').offsetHeight; 72 73 window.scrollTo({ 74 top:gotoBlockValue, 75 behavior: "smooth" 76 }); 77 e.preventDefault(); 78 } 79 } 80} 81 82window.addEventListener('scroll', () => { 83 if(pageYOffset > 50) { 84 document.querySelector('.header').classList.add('header__bg'); 85 } else { 86 document.querySelector('.header').classList.remove('header__bg'); 87 } 88}); 89 90const input = document.getElementById('formNumPopup'); 91const btnPlus = document.querySelector('.form__plus'); 92const btnMinus = document.querySelector('.form__minus'); 93 94if (input && btnPlus && btnMinus) { 95 96 let value = 1; 97 input.value = value; 98 99 btnPlus.addEventListener('click', () => { 100 if (value < 100) { 101 value++; 102 input.value = value; 103 } 104 }); 105 106 btnMinus.addEventListener('click', () => { 107 if (value > 1) { 108 value--; 109 input.value = value; 110 } 111 }); 112 113 input.addEventListener('input', () => { 114 let num = parseInt(input.value); 115 116 if (isNaN(num) || num < 1) num = 1; 117 if (num > 100) num = 100; 118 119 value = num; 120 input.value = value; 121 }); 122} 123 124document.addEventListener('DOMContentLoaded', () => { 125 126 document.querySelectorAll('form').forEach((form) => { 127 128 form.addEventListener("submit", e => { 129 e.preventDefault(); 130 form.dispatchEvent(new CustomEvent("smartCaptchaSuccess")); 131 }); 132 133 form.addEventListener('smartCaptchaSuccess', async (e) => { 134 e.preventDefault(); 135 136 const errorCount = validateForm(form); 137 if (errorCount !== 0) { 138 Notiflix.Loading.remove(); 139 return; 140 } 141 142 Notiflix.Loading.hourglass("ÐÑпÑавлÑем даннÑе..."); 143 144 form.classList.add('_sending'); 145 146 const formData = new FormData(form); 147 148 const dateInput = form.querySelector('#formDatePopup'); 149 if (dateInput) { 150 const raw = formData.get(dateInput.name); 151 if (raw) { 152 const [y,m,d] = String(raw).split('-'); 153 formData.set(dateInput.name, `${d}.${m}.${y}`); 154 } 155 } 156 157 try { 158 const response = await fetch(form.action, { 159 method: form.method || 'POST', 160 body: formData,
161 credentials: 'same-origin', // ÑÑÐ¾Ð±Ñ ÑеÑÑиÑ/кÑки бÑли ок 162 headers: { 'X-Requested-With': 'XMLHttpRequest' }, 163 }); 164 165 if (!response.ok) { 166 Notiflix.Loading.remove(); 167 Notiflix.Report.failure("ÐÑибка оÑпÑавки", "", "ÐакÑÑÑÑ"); 168 } 169 170 const html = await response.text(); 171 172 const doc = new DOMParser().parseFromString(html, 'text/html'); 173 174 const success = doc.querySelector('.form__success, .success-message, .form-note, .form__note'); 175 176 if (success) { 177 form.reset(); 178 YandexSmartCaptcha.reset(); 179 Notiflix.Loading.remove(); 180 let message = form.dataset.success ? form.dataset.success : "ÐаÑе ÑообÑение оÑпÑавлено"; 181 Notiflix.Report.success(message, "", "ÐакÑÑÑÑ"); 182 return; 183 } 184 185 // инаÑе â оÑибка: доÑÑанем ÑекÑÑ Ð¾Ñибок из оÑвеÑа 186 const errorBlock = doc.querySelector('.form__error-global, .errortext, .form-error'); 187 if (errorBlock) { 188 Notiflix.Loading.remove(); 189 Notiflix.Report.failure("ÐÑибка оÑпÑавки", errorBlock.textContent.trim(), "ÐакÑÑÑÑ"); 190 YandexSmartCaptcha.reset(); 191 return; 192 } 193 194 alert('Ðе ÑдалоÑÑ Ð¾ÑпÑавиÑÑ ÑоÑмÑ: неизвеÑÑнÑй оÑÐ²ÐµÑ ÑеÑвеÑа'); 195 } catch (err) { 196 console.error(err); 197 Notiflix.Loading.remove(); 198 Notiflix.Report.failure("ÐÑибка пÑи оÑпÑавке ÑоÑмÑ", "", "ÐакÑÑÑÑ"); 199 YandexSmartCaptcha.reset(); 200 } finally { 201 form.classList.remove('_sending'); 202 } 203 }); 204 }); 205 206 function validateForm(form) { 207 let error = 0; 208 209 form.querySelectorAll('._req').forEach((input) => { 210 removeError(input); 211 212 const val = input.value.trim(); 213 214 if (input.classList.contains('_email') && !emailTest(val)) { 215 addError(input); 216 error++; 217 } else if (input.classList.contains('_number') && !phoneTest(val)) { 218 addError(input); 219 error++; 220 } else if (input.type === 'checkbox' && !input.checked) { 221 addError(input); 222 error++; 223 } else if (!val) { 224 addError(input); 225 error++; 226 } 227 }); 228 229 return error; 230 } 231 232 function addError(input) { 233 let parent = input.closest('.form__item'); 234 parent = parent ? parent : input.closest('.checkbox'); 235 parent.classList.add('_error'); 236 input.classList.add('_error'); 237 238 const errMsg = parent.querySelector('.form__error'); 239 if (errMsg) { 240 errMsg.classList.add('view'); 241 } 242 } 243 244 function removeError(input) { 245 let parent = input.closest('.form__item'); 246 parent = parent ? parent : input.closest('.checkbox'); 247 parent.classList.remove('_error'); 248 input.classList.remove('_error'); 249 250 const errMsg = parent.querySelector('.form__error'); 251 if (errMsg) errMsg.classList.remove('view'); 252 } 253 254 const emailTest = (val) => 255 /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/.test(val); 256 257 const phoneTest = (val) => 258 /^\+7\s\(\d{3}\)\s\d{3}-\d{2}-\d{2}$/.test(val); 259 260}); 261 262document.addEventListener('DOMContentLoaded', function() { 263 if (!document.getElementById('map') || typeof ymaps === 'undefined') return; 264 265 ymaps.ready(function() { 266 var map = new ymaps.Map('map', { 267 center: [55.761457, 37.614159], 268 zoom: 16, 269 behaviors: ['drag', 'multiTouch'] 270 }); 271 272 const balloonData = window.balloonData; 273 274 var balloonContent = ` 275 <div class="contacts__balloon"> 276 <img class="contacts__balloon_img" 277 src="${balloonData.logo}" 278 alt="Savras" 279 width="200" 280 height="145"> 281 282 <div class="contacts__balloon_address"> 283 ${balloonData.address} 284 </div> 285 286 <a class="contacts__balloon_phone" 287 href="tel:${balloonData.phone_raw}"> 288 ${balloonData.phone_pretty} 289 </a> 290 </div> 291 `; 292 293 var placemark = new ymaps.Placemark( 294 [55.761457, 37.614159], 295 { 296 hintContent: 'ÐÐ°Ñ Ð¾ÑÐ¸Ñ Ð² ÐоÑкве', 297 balloonContent: balloonContent 298 }, 299 { 300 iconLayout: 'default#image', 301 iconImageHref: 'images/icons/map-icon.svg', 302 iconImageSize: [45, 50], 303 iconImageOffset: [-25, -50], 304 balloonCloseButton: true, 305 balloonPanelMaxMapArea: 0, 306 balloonOffset: [50, -20], 307 } 308 ); 309 310 map.geoObjects.add(placemark); 311 312 setTimeout(function() { 313 placemark.balloon.open(); 314 }, 1000); 315 }); 316}); 317 318const burgerMenu = document.querySelector('.burger'); 319const menuBody = document.querySelector('.menu'); 320const menuArrow = document.querySelector('.menu__top_arrow'); 321 322if (burgerMenu) { 323 burgerMenu.addEventListener("click", function () { 324 325 const isOpen = burgerMenu.classList.toggle('_active'); 326 menuBody.classList.toggle('_active'); 327 328 document.body.classList.toggle('body-lock', isOpen); 329 }); 330 331 if (menuArrow) { 332 menuArrow.addEventListener("click", function () { 333 burgerMenu.classList.remove('_active'); 334 menuBody.classList.remove('_active'); 335 document.body.classList.remove('body-lock'); 336 }); 337 } 338} 339 340const popupLinks = document.querySelectorAll('.popup-link'); 341const body = document.body; 342const lockPadding = document.querySelectorAll(".lock-padding"); 343 344let unlock = true; 345 346 347function lockBody() { 348 const scrollBarWidth = window.innerWidth - document.documentElement.clientWidth; 349 350 body.style.paddingRight = scrollBarWidth + "px"; 351 352 lockPadding.forEach(el => { 353 el.style.paddingRight = scrollBarWidth + "px"; 354 }); 355 356 body.classList.add('body-lock'); 357} 358 359function unlockBody() { 360 body.classList.remove('body-lock'); 361 362 body.style.paddingRight = "0px"; 363 364 lockPadding.forEach(el => { 365 el.style.paddingRight = "0px"; 366 }); 367} 368 369 370function popupOpen(currentPopup) { 371 if (currentPopup && unlock) { 372 const popupActive = document.querySelector('.popup.open'); 373 374 if (popupActive) { 375 popupClose(popupActive, false); 376 } 377 378 currentPopup.removeAttribute('inert'); 379 currentPopup.classList.add('open'); 380 381 lockBody(); 382 383 currentPopup.addEventListener("click", e => { 384 if (!e.target.closest('.popup__content')) { 385 popupClose(currentPopup); 386 } 387 }); 388 } 389} 390 391 392function popupClose(popupActive, doUnlock = true) { 393 if (popupActive && unlock) { 394 popupActive.classList.remove('open'); 395 popupActive.setAttribute('inert', ''); 396 397 unlockBody(); 398 } 399} 400 401 402popupLinks.forEach(link => { 403 link.addEventListener("click", e => { 404 e.preventDefault(); 405 const popupName = link.getAttribute('href').replace('#', ''); 406 const currentPopup = document.getElementById(popupName); 407 popupOpen(currentPopup); 408 }); 409}); 410 411document.querySelectorAll('.close-popup').forEach(btn => { 412 btn.addEventListener("click", e => { 413 e.preventDefault(); 414 popupClose(btn.closest('.popup')); 415 }); 416}); 417 418document.addEventListener("keydown", e => { 419 if (e.key === "Escape") { 420 const popupActive = document.querySelector('.popup.open'); 421 if (popupActive) popupClose(popupActive); 422 } 423}); 424 425 426 427document.addEventListener('DOMContentLoaded', () => { 428 const dropdowns = document.querySelectorAll('.dropdown'); 429 430 dropdowns.forEach(dropdown => { 431 const btn = dropdown.querySelector('.dropdown__button'); 432 const list = dropdown.querySelector('.dropdown__list'); 433 const items = dropdown.querySelectorAll('.dropdown__item'); 434 const input = dropdown.querySelector('.dropdown__input-hidden'); 435 436 const closeDropdown = () => { 437 list.classList.remove('dropdown__list--active'); 438 btn.setAttribute('aria-expanded', 'false'); 439 }; 440 441 const openDropdown = () => { 442 document.querySelectorAll('.dropdown__list--active').forEach(l => l.classList.remove('dropdown__list--active')); 443 document.querySelectorAll('.dropdown__button--active').forEach(b => b.classList.remove('dropdown__button--active')); 444 445 list.classList.add('dropdown__list--active'); 446 btn.setAttribute('aria-expanded', 'true'); 447 btn.classList.add('dropdown__button--active'); 448 }; 449 450 btn.addEventListener('click', (e) => { 451 e.stopPropagation(); 452 list.classList.contains('dropdown__list--active') ? closeDropdown() : openDropdown(); 453 }); 454
455 items.forEach(item => { 456 item.addEventListener('click', (e) => { 457 e.stopPropagation(); 458 btn.textContent = item.textContent; 459 input.value = item.dataset.value; 460 closeDropdown(); 461 btn.focus(); 462 }); 463 }); 464 465 document.addEventListener('click', (e) => { 466 if (!dropdown.contains(e.target)) { 467 closeDropdown(); 468 } 469 }); 470 471 document.addEventListener('keydown', (e) => { 472 if (e.key === 'Escape') closeDropdown(); 473 }); 474 }); 475}); 476 477 478 479const sliders = document.querySelectorAll('.slider'); 480 481if (sliders.length > 0) { 482 sliders.forEach(slider => { 483 new Swiper(slider, { 484 loop: true, 485 slidesPerView: 1, 486 speed: 1000, 487 autoHeight: false, 488 navigation: { 489 nextEl: slider.querySelector('.swiper-button-next'), 490 prevEl: slider.querySelector('.swiper-button-prev'), 491 }, 492 pagination: { 493 el: slider.querySelector('.swiper-pagination'), 494 clickable: true, 495 }, 496 }); 497 }); 498} 499 500 501let slidersRestaurant = []; 502 503function initRestaurantSliders() { 504 const sliderElems = document.querySelectorAll('.restaurant__slider'); 505
506 sliderElems.forEach((sliderElem, index) => { 507 if (window.innerWidth <= 768 && !slidersRestaurant[index]) { 508 slidersRestaurant[index] = new Swiper(sliderElem, { 509 slidesPerView: 1.2, 510 spaceBetween: 10, 511 scrollbar: { 512 el: sliderElem.querySelector('.swiper-scrollbar'), 513 draggable: true, 514 hide: false, 515 }, 516 }); 517 } 518 519 if (window.innerWidth > 768 && slidersRestaurant[index]) { 520 slidersRestaurant[index].destroy(true, true); 521 slidersRestaurant[index] = null; 522 } 523 }); 524} 525 526initRestaurantSliders(); 527 528window.addEventListener('resize', initRestaurantSliders); 529 530const eventSlider = document.querySelectorAll('.event__slider'); 531if (eventSlider.length > 0) { 532 eventSlider.forEach(slider => { 533 new Swiper(slider, { 534 loop: true, 535 direction: 'horizontal', 536 loop: true, 537 spaceBetween: 20, 538 speed: 1000, 539 autoHeight: false, 540 scrollbar: { 541 el: slider.querySelector('.swiper-scrollbar'), 542 draggable: true, 543 hide: false, 544 }, 545 breakpoints: { 546 320: { 547 slidesPerView: 1.2, 548 }, 549 640: { 550 slidesPerView: 3, 551 }, 552 1440: { 553 slidesPerView: 5, 554 } 555 } 556 }); 557 }); 558} 559 560/* ========================================================= 561 YANDEX METRIKA GOALS 562 Counter: 108598200 563 ========================================================= */ 564 565(function () { 566 567 const METRIKA_COUNTER_ID = 108598200; 568 569 function sendMetrikaGoal(goalName) { 570 if (typeof window.ym !== 'function') { 571 console.warn('[Metrika] ym is not available:', goalName); 572 return; 573 } 574 575 window.ym(METRIKA_COUNTER_ID, 'reachGoal', goalName); 576 577 if ( 578 window.location.search.includes('_ym_debug=1') || 579 window.location.search.includes('_ym_debug=2') 580 ) { 581 console.log('[Metrika goal]', goalName); 582 } 583 } 584 585 586 function isSocialLink(link) { 587 if (!link || !link.href) { 588 return false; 589 } 590 591 let url; 592 593 try { 594 url = new URL(link.href, window.location.href); 595 } catch (e) { 596 return false; 597 } 598 599 const host = url.hostname 600 .replace(/^www\./, '') 601 .toLowerCase(); 602 603 const socialHosts = [ 604 't.me', 605 'telegram.me', 606 'telegram.org', 607 608 'wa.me', 609 'whatsapp.com', 610 'api.whatsapp.com', 611 612 'vk.com', 613 'vk.ru', 614 615 'instagram.com', 616 'facebook.com', 617 618 'max.ru', 619 'web.max.ru', 620 621 'youtube.com', 622 'youtu.be' 623 ]; 624 625 return socialHosts.some(function (socialHost) { 626 return ( 627 host === socialHost || 628 host.endsWith('.' + socialHost) 629 ); 630 }); 631 } 632 633 634 document.addEventListener('click', function (event) { 635 636 const target = event.target; 637 638 /* 639 * reserve-send 640 * Ðлик по кнопке "ÐабÑониÑоваÑÑ" 641 * внÑÑÑи ÑоÑÐ¼Ñ ReMarked 642 */ 643 const reserveSendButton = target.closest( 644 '.remarked-primary-widget__submit' 645 ); 646 647 if (reserveSendButton) { 648 sendMetrikaGoal('reserve-send'); 649 return; 650 } 651 652 653 /* 654 * phone-click 655 * Ðлик по лÑÐ±Ð¾Ð¼Ñ Ð½Ð¾Ð¼ÐµÑÑ ÑелеÑона 656 */ 657 const phoneLink = target.closest( 658 'a[href^="tel:"]' 659 ); 660 661 if (phoneLink) { 662 sendMetrikaGoal('phone-click'); 663 return; 664 } 665 666 667 /* 668 * reserve-click 669 * Ðлик по лÑбой кнопке, 670 * оÑкÑÑваÑÑей бÑониÑование ReMarked 671 * 672 * УÑиÑÑваем и новÑÑ, 673 * и ÑÑаÑÑÑ ÑÑ ÐµÐ¼Ñ ÐºÐ½Ð¾Ð¿Ð¾Ðº 674 */ 675 const reserveButton = target.closest( 676 'a[href="#openReMarkedWidget"], .open__primary__widget' 677 ); 678 679 if (reserveButton) { 680 sendMetrikaGoal('reserve-click'); 681 return; 682 } 683 684 685 /* 686 * menu-click 687 * Ðлик по каÑÑоÑкам ÑеÑÑоÑанного Ð¼ÐµÐ½Ñ 688 */ 689 const link = target.closest('a'); 690 691 if ( 692 link && 693 link.closest('.gallery--menu') 694 ) { 695 sendMetrikaGoal('menu-click'); 696 return; 697 } 698 699 700 /* 701 * social-click 702 * СоÑÑеÑи и меÑÑенджеÑÑ 703 */ 704 if ( 705 link && 706 isSocialLink(link) 707 ) { 708 sendMetrikaGoal('social-click'); 709 } 710 711 }, true); 712 713})();
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.