1var myMap, firstGeoObject; // ÐеÑеменнÑе Ð´Ð»Ñ ÐºÐ°ÑÑÑ 2var mouseClick, hashChanged = "", tmp_timer; // ÐеÑеменнÑе Ð´Ð»Ñ Ð¿ÐµÑÐµÑ Ð²Ð°Ñа AJAX пеÑÐµÑ Ð¾Ð´Ð° 3var memMenu, page, flag, u_promo = ""; 4let lazyScriptsLoaded = false; 5 6document.addEventListener("DOMContentLoaded", e => { 7 8 bindEvents(); 9 10 OPTIONS.reload = false; 11 12 document.addEventListener('click', e => { 13 14 const link = e.target.closest('a[href^="#"]'); 15 if(!link) return; 16 17 const id = link.getAttribute('href'); 18 19 // пÑопÑÑкаем пÑÑÑÑе ÑкоÑÑ 20 if(id === '#' || id.length < 2) return; 21 22 const el = document.querySelector(id); 23 if(!el) return; 24 25 e.preventDefault(); 26 27 el.scrollIntoView({ 28 behavior: 'smooth', 29 block: 'start' 30 }); 31 32 }); 33 34 if (window.matchMedia("(hover: none)").matches) { 35 36 document.addEventListener('click', function(e){ 37 38 const el = e.target.closest('[data-tooltip]'); 39 const opened = document.querySelector('.tooltip-open'); 40 41 if(opened && !el){
42 opened.classList.remove('tooltip-open'); 43 return; 44 } 45 46 if(el){ 47 el.classList.toggle('tooltip-open'); 48 } 49 50 }); 51 } 52 53 const mobileSearch = document.querySelector("#mobile-search"); 54 mobileSearch.addEventListener("click", e => { 55 e.stopPropagation(); 56 let data = `<div id="dialog-search"><input type="search" name="search_input" placeholder="ÐайÑи ÑкÑкÑÑÑиÑ"><button id="search">ÐоиÑк</button></div>`; 57 createFlyWindow(data); 58 setTimeout(() => { 59 const button_search = document.querySelector("#dialog-search #search"); 60 if (button_search) { 61 button_search.addEventListener("click", e => { 62 const str = e.target.closest("#dialog-search").querySelector("input").value; 63 const bytes = new TextEncoder().encode(str); 64 const binary = Array.from(bytes, byte => String.fromCharCode(byte)).join(''); 65 const hash = btoa(binary) 66 .replace(/\+/g, '-') 67 .replace(/\//g, '_') 68 .replace(/=+$/, ''); 69 70 window.location.href = "/tours/search?title=" + hash; 71 }); 72 } 73 }, 500); 74 }); 75 76 const search = document.querySelector("#pc input[type=search]"); 77 if (search) { 78 search.addEventListener("keydown", e => { 79 if (e.key === 'Enter') { 80 e.preventDefault(); // ÑÑÐ¾Ð±Ñ ÑоÑма не оÑпÑавилаÑÑ ÑÑандаÑÑно 81 82 const str = e.target.value; 83 const bytes = new TextEncoder().encode(str); 84 85 const binary = Array.from(bytes, byte => String.fromCharCode(byte)).join(''); 86 const hash = btoa(binary) 87 .replace(/\+/g, '-') 88 .replace(/\//g, '_') 89 .replace(/=+$/, ''); 90 91 window.location.href = "/tours/search?title=" + hash; 92 } 93 }); 94 } 95 96 if (window.location.pathname != "/") { 97 if (window.innerWidth > 640) { 98 document.querySelector("section#article_page").style.paddingTop = "60px"; 99 } else { 100 document.querySelector("section#article_page").style.paddingTop = "130px"; 101 } 102 } 103 104 document.querySelector('.openDate')?.addEventListener('click', function() { 105 const input = document.querySelector('input[name="tdate"]'); 106 input.focus(); 107 108 // ÐопÑÑка ÑмÑлиÑоваÑÑ ÐºÐ»Ð¸Ðº Ð´Ð»Ñ Ð¾ÑкÑÑÑÐ¸Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°ÑÑ 109 const event = new MouseEvent('click', { 110 bubbles: true, 111 cancelable: true, 112 view: window 113 }); 114 input.dispatchEvent(event); 115 }); 116 117 if (window.matchMedia("(max-width: 640px)").matches) { 118 119 const mobile = document.getElementById("mobile-menu"); 120 const mobile_buton = document.getElementById("mobile"); 121 122 mobile_buton.addEventListener("click", (e) => { 123 // не даÑм summary закÑÑваÑÑ Ð¼ÐµÐ½Ñ 124 if (e.target.closest("summary")) return; 125 mobile.classList.toggle("open"); 126 mobile_buton.classList.toggle("open"); 127 128 const header = mobile.closest("header"); 129 130 if (mobile.classList.contains("open")) { 131 if (window.scrollY == 0) { 132 OPTIONS.header["invert"] = true; 133 header.style.backgroundColor = "#f9f8f8"; 134 header.style.marginTop = "24px"; 135 header.style.padding = "0 12px"; 136 header.querySelectorAll('#header-section .header-logo path').forEach(p => p.setAttribute('fill', '#e95275')); 137 mobile.style.margin = "8px 0px 0px -12px"; 138 header.querySelector("#pc").style.padding = "6px 0"; 139 header.style.height = "auto"; 140 } else { 141 OPTIONS.header["invert"] = false; 142 mobile.style.margin = "8px 0 0 0"; 143 header.style.padding = "0"; 144 header.style.height = "110px"; 145 } 146 147 header.querySelector("a.menu-button").style.color = "white"; 148 } else { 149 if (window.location.pathname == "/" && window.scrollY == 0) { 150 header.style.backgroundColor = "transparent"; 151 header.style.marginTop = "24px"; 152 header.style.padding = "8px 16px"; 153 header.querySelectorAll('#header-section .header-logo path').forEach(p => p.setAttribute('fill', '#FFF')); 154 header.querySelector("#pc").style.padding = "6px 12px"; 155 document.querySelector("#mobile-search").style.filter = "brightness(2)"; 156 } else { 157 header.style.background = "#f9f8f8"; 158 header.style.marginTop = "28px"; 159 header.style.padding = "0"; 160 header.querySelector("#pc").style.padding = "6px 12px"; 161 header.querySelector("#header-section .header-logo").style.height = "48px"; 162 header.querySelectorAll('#header-section .header-logo path').forEach(p => p.setAttribute('fill', '#e95275')); 163 header.style.height = "70px"; 164 document.querySelector("#mobile-search").style.filter = "brightness(0)"; 165 } 166 167 } 168 });
169 } 170 171 const dreit = document.querySelector("#dreit"); 172 if (dreit) { 173 dreit.addEventListener("click", e => { 174 if (e.target.classList.contains("star")) { 175 let reit = parseInt(e.target.dataset.value); 176 for (let i = 1; i <= reit + 1; i++) { 177 dreit.querySelector(`[data-value="${i}"]`)?.setAttribute("class", "star"); 178 } 179 for (let j = reit + 1; j <= 6; j++) { 180 dreit.querySelector(`[data-value="${j}"]`)?.setAttribute("class", "star half_star"); 181 } 182 document.querySelector("input[name=reit]").value = reit; 183 dreit.previousElementSibling.querySelector("span").textContent = reit; 184 } 185 }); 186 } 187 188 document.querySelector("#site_buy")?.addEventListener("click", e => { 189 e.preventDefault(); 190 e.currentTarget.style.display = "none"; 191 document.querySelector("div#office_buy").style.display = "block"; 192 }); 193 194 let sw = document.body.clientWidth; 195 196 const details = document.querySelectorAll("footer details, header details"); 197 if (details) { 198 if (sw < 760) { 199 details.forEach(el => { 200 el.removeAttribute("open"); 201 }); 202 } 203 else { 204 details.forEach(el => { 205 el.setAttribute("open", true); 206 }); 207 } 208 } 209 210 let feeds = document.querySelectorAll("a[data-feed]"); 211 if (feeds) { 212 feeds.forEach(feed => { 213 feed.addEventListener("click", e => { 214 e.preventDefault(); 215 let id = e.target.getAttribute("data-feed"); 216 217 fd = new FormData(); 218 fd.append("data_type", "feedback"); 219 fd.append("id", id); 220 221 tmp = postData("../user/getAjaxData.php", fd, false, "GET").then(response => { 222 try { 223 let resp = JSON.parse(response); 224 if (/^ok/.test(resp[0])) { 225 createFlyWindow(resp.html); 226 } 227 else { 228 console.log(response); 229 alert("ЧÑо Ñо поÑло не Ñак!"); 230 } 231 } 232 catch (err) { 233 console.error("ÐÑибка загÑÑзки ÑÑÑаниÑÑ, ÑидÑ", err); 234 } 235 }); 236 }); 237 }); 238 } 239 240 // обÑабоÑка ESC 241 document.addEventListener("keyup", e => { 242 if (e.key === "Escape") { 243 // ÑкÑÑваем блоки Ñ Ð¿Ð»Ð°Ð²Ð½Ð¾ÑÑÑÑ 244 document.querySelectorAll(".flyTimeWindow_menu, .flyTimeWindow_article, .flyOrderWindow") 245 .forEach(el => el.classList.add("hidden")); 246 247 // ÑкÑÑваем и ÑдалÑем оÑновнÑе окна 248 document.querySelectorAll("div#view_road, div#bg-big-img, div.win-bg, .flyTimeWindow") 249 .forEach(el => { 250 el.classList.add("hidden"); 251 el.classList.remove("visible"); 252 el.remove(); 253 }); 254 255 } 256 }); 257 258 // пÑовеÑка payResponse 259 if (/payResponse\//.test(window.location.href)) { 260 const checkLink = document.querySelector("a#check_link"); 261 if (checkLink && checkLink.getAttribute("href")) { 262 const check = checkLink.getAttribute("href"); 263 264 const params = new URLSearchParams(window.location.search); 265 const orderId = params.get('orderId'); 266 267 // ÑоздаÑм Ð±Ð¸Ð»ÐµÑ 268 const fd1 = new FormData(); 269 fd1.append("data", "create_check"); 270 fd1.append("link", check); 271 fd1.append("orderId", orderId); 272 273 postData("../user/saveData.php", fd1).then(response => { 274 if (!response.ok) { 275 console.log(response); 276 const html = ` 277 <div class="win-close" onclick="closeFlyWindow();"></div> 278 <img src="../images/site-errror.jpg" /> 279 <h2 style="text-align: center">Создание билеÑа</h2> 280 <p>Ðе ÑдалоÑÑ ÑоздаÑÑ Ð±Ð¸Ð»ÐµÑ, пожалÑйÑÑа ÑвÑжиÑеÑÑ Ñ Ð½Ð°Ñим оÑиÑом:</p>
281 <span style="display: block; text-align: center; font-size: 1.5em; color: #fd736c; margin: 0.5em;">+7 (812) 441-33-23</span> 282 <button onclick="closeFlyWindow();">ХоÑоÑо</button>`; 283 createFlyWindow(html); 284 } else { 285 const menu = document.querySelector("input#tour_sale_id").value; 286 287 // оÑпÑавлÑем пиÑÑмо 288 const fd2 = new FormData(); 289 fd2.append("data", "send_mail"); 290 fd2.append("id_tour", menu); 291 292 postData("../user/saveData.php", fd2).then(response2 => { 293 if (!response2.ok) { 294 const html = ` 295 <div class="win-close" onclick="closeFlyWindow();"></div> 296 <img src="../images/site-errror.jpg" /> 297 <h2 style="text-align: center">ÐÑпÑавка ÑведомлениÑ</h2> 298 <p>ÐÑибка: ${response2}</p> 299 <p>Ðе ÑдалоÑÑ Ð¾ÑпÑавиÑÑ ÑообÑение Ñ Ð±Ð¸Ð»ÐµÑом на ÑказаннÑй Ðами email, пожалÑйÑÑа ÑкаÑайÑе Ð±Ð¸Ð»ÐµÑ Ñо ÑÑÑлки на данной ÑÑÑаниÑе.<br>ТелеÑон наÑего оÑиÑа:</p> 300 <span style="display: block; text-align: center; font-size: 1.5em; color: #fd736c; margin: 0.5em;">+7 (812) 441-33-23</span> 301 <button onclick="closeFlyWindow();">ХоÑоÑо</button>`; 302 createFlyWindow(html); 303 } 304 }); 305 306 checkLink.textContent = "СкаÑаÑÑ Ð±Ð¸Ð»ÐµÑ"; 307 } 308 }); 309 } 310 } 311 312 if (/tour\//.test(window.location.href)) { 313 314 // ==== ÐалеÑÐµÑ 315 new HeroGallery(".box-hero__body"); 316 FeedBackSlider(); 317 renderExcursionDate(); 318 319 // ==== полÑÑаем пÑомокод по заÑоÑÑ 320 const u_promo_cmd = document.querySelector("#u_promo_cmd"); 321 u_promo_cmd?.addEventListener("click", e => { 322 323 const urlObj = new URL(window.location.href); 324 const tour = urlObj.pathname.split('/').pop(); // ÐолÑÑаем Ð¸Ð¼Ñ ÑÑÑа 325 const promo = document.querySelector("input[name=u_promo]"); 326 327 const fd = new FormData(); 328 fd.append("data_type", "u_promo"); 329 fd.append("tour", tour); 330 fd.append("promo", promo.value); 331 332 postData("../user/getAjaxData.php", fd, false, "GET").then(data => { 333 document.querySelector("input[name=promo_sum]").value = data; 334 recalcSum(); 335 336 let pm = document.querySelector("#promo_message"); 337 if (parseInt(data) != 0) { 338 pm.style.color = "#006605ff"; 339 promo.style.backgroundColor = "#b5fcb8ff"; 340 pm.textContent = "ÐÑомокод пÑименÑн"; 341 } else { 342 pm.style.color = "#db0000ff"; 343 promo.style.backgroundColor = "#fcb5b5ff"; 344 pm.textContent = "Ðе наÑли Ñакой пÑомокод"; 345 } 346 }); 347 }); 348 349 // пеÑеклÑÑение пÑедоплаÑÑ 350 const prepay_radio = document.querySelectorAll(".options input[type=radio]"); 351 if (prepay_radio) { 352 prepay_radio.forEach(radio => { 353 radio.addEventListener("click", e => recalcSum()); 354 }); 355 } 356 357 // показаÑÑ ÐºÐ°ÑÑÑ 358 const cmdRoad = document.querySelector("#roadMap"); 359 cmdRoad?.addEventListener("click", e => { 360 e.preventDefault(); 361 362 const tour_id = e.target.closest("a").dataset.tour; 363 showRoadMap(tour_id); 364 }); 365 366 const points = document.querySelectorAll(".spollers__item"); 367 if (points.length) { 368 points.forEach(point => { 369 point.addEventListener("click", e => { 370 const clicked = e.currentTarget; // ÑлеменÑ, на коÑоÑом виÑÐ¸Ñ ÑлÑÑаÑÐµÐ»Ñ 371 372 // 1. УбиÑаем show Ñ ÐСÐÐ¥ ÑлеменÑов коллекÑии 373 points.forEach(p => { 374 if (p !== clicked) p.classList.remove("show"); 375 }); 376 377 // 2. ÐобавлÑем show ÑолÑко к кликнÑÑÐ¾Ð¼Ñ 378 if (!clicked.classList.contains("show")) { 379 clicked.classList.add("show"); 380 } else { 381 clicked.classList.remove("show"); 382 } 383 }); 384 }); 385 } 386 } 387 388 // изменение даÑÑ 389 const input = document.querySelector("input[name=d_start]"); 390 input?.addEventListener("input", e => { 391 if (!input.value) return; 392 393 const [year, month, day] = input.value.split('-').map(Number); 394 395 // ÐÑовеÑка года 396 if (year < 1900 || year > 2100) return; 397 398 // ÐÑовеÑка наÑивной валидноÑÑи 399 if (!input.validity.valid) return; 400 401 // ÐеболÑÑÐ°Ñ Ð·Ð°Ð´ÐµÑжка â UX 402 setTimeout(() => { 403 window.location.href= `/tours/all?date=${input.value}`; 404 }, 300); 405 }); 406 407 if (getCookie("userCookie")) { 408 let cBlock = document.querySelector("div#cookieBlock"); 409 cBlock.style.display = "none"; 410 } 411 412 // bindGalery(); 413 load_lazy_scripts(); 414 window.onscroll(); 415 416}); 417 418document.addEventListener("click", event => { 419 420 if (OPTIONS.justOpenedWindow) return; 421 422 // еÑли клик внÑÑÑи ÑказаннÑÑ ÑлеменÑов â ниÑего не делаем 423 if (event.target.closest("#bg-big-img, .flyTimeWindow, .flyTimeWindow_menu, .flyOrderWindow, .window")) { 424 return; 425 } 426 427 // ÑкÑÑваем и ÑдалÑем оÑновнÑе окна 428 document.querySelectorAll("div#bg-big-img, .flyTimeWindow, div.win-bg, #view_road") 429 .forEach(el => { 430 el.classList.add("hidden"); // плавноÑÑÑ Ð¾Ð±ÐµÑпеÑиваеÑÑÑ CSS 431 el.classList.remove("visible"); 432 el.remove(); 433 });
434 435 // ÑкÑÑваем вÑпомогаÑелÑнÑе блоки 436 document.querySelectorAll(".flyTimeWindow_menu, .flyTimeWindow_article, #view_road, .window") 437 .forEach(el => { 438 el.classList.add("hidden"); 439 el.classList.remove("visible"); 440 }); 441 442 if (!event.target.closest('[data-run-script="true"]')) { 443 event.stopPropagation(); 444 } 445}); 446 447/** 448 * ÐеÑедаÑа паÑамеÑÑов Ð¼ÐµÐ´Ð¶Ñ ÑÑнкÑиÑми 449 */ 450const handler = { 451 get(target, prop) { 452 return target[prop]; 453 }, 454 set(target, prop, value) { 455 target[prop] = value; 456 return true; 457 } 458}; 459 460const OPTIONS = new Proxy({ 461 header: { "invert" : false } 462}, handler); 463 464window.OPTIONS = OPTIONS; 465 466window.onscroll = e => { 467 468 if (window.innerWidth <= 640) { 469 if (booking_block) { 470 const goto_booking = document.querySelector("#goto_booking").closest(".mobile-fixed"); 471 if (OPTIONS.booking_block_visible) { 472 if (!isVisible(goto_booking)) { 473 goto_booking.style.display = "none"; 474 } else { 475 goto_booking.style.display = "flex"; 476 } 477 } else { 478 if (!isVisible(goto_booking)) { 479 goto_booking.style.display = "flex"; 480 } else { 481 goto_booking.style.display = "none"; 482 } 483 } 484 } 485 } 486 487 let header = document.querySelector("header"); 488 489 if (!window.matchMedia("(max-width: 640px)").matches) { 490 if ((window.location.pathname == "/" && !/payRequest/.test(window.location.href)) && window.scrollY == 0) { 491 OPTIONS.header["invert"] = false; 492 document.getElementById("pc").classList.remove("gray"); 493 header.style.background = "transparent"; 494 header.style.marginTop = "56px auto"; 495 header.style.borderBottom = "none"; 496 header.querySelector("#header-section").style.margin = "0 auto"; 497 header.style.padding = "8px 16px"; 498 header.querySelector("#header-section .header-logo").style.height = "62px"; 499 header.querySelectorAll('#header-section .header-logo path').forEach(p => p.setAttribute('fill', "#FFF")); 500 header.querySelector("#mobile").classList.remove("gray"); 501 header.querySelectorAll("#pc > li > a").forEach(el => { 502 if (!el.classList.contains("menu-button")) { 503 el.style.color = "white"; 504 } 505 }); 506 document.querySelector("#mobile-search").style.filter = "brightness(0)"; 507 } else { 508 if (!OPTIONS.header["invert"]) { 509 OPTIONS.header["invert"] = true; 510 document.getElementById("pc").classList.add("gray"); 511 header.style.background = "#f9f8f8"; 512 header.style.marginTop = "34px"; 513 header.style.padding = "6px 12px"; 514 header.style.borderBottom = "solid 2px #E75375"; 515 header.querySelector("#header-section .header-logo").style.height = "48px"; 516 header.querySelector("#header-section").style.margin = "0 auto"; 517 header.querySelectorAll('#header-section .header-logo path').forEach(p => p.setAttribute('fill', '#e95275')); 518 header.querySelector("#mobile").classList.add("gray"); 519 header.querySelectorAll("#pc > li > a").forEach(el => { 520 if (!el.classList.contains("menu-button")) { 521 el.style.color = "black"; 522 } 523 }); 524 document.querySelector("#mobile-search").style.filter = "brightness(2)"; 525 } 526 } 527 } else { 528 if (window.location.pathname == "/" && window.scrollY == 0) { 529 header.querySelector('#mobile-menu').classList.remove("open"); 530 header.querySelector('#mobile').classList.remove("open"); 531 header.querySelectorAll("#pc > li > a").forEach(el => { 532 if (!el.classList.contains("menu-button")) { 533 el.parentElement.style.display = "none"; 534 } 535 }); 536 537 OPTIONS.header["invert"] = false; 538 header.style.backgroundColor = "transparent"; 539 header.querySelectorAll('#header-section .header-logo path').forEach(p => p.setAttribute('fill', "#FFF")); 540 header.querySelector('#header-section .header-logo').style.height = "62px"; 541 header.querySelector('#mobile-menu').style.margin = "108px 0 0 -32px"; 542 header.style.marginTop = "32px"; 543 header.style.padding = "0 16px"; 544 header.style.height = "110px"; 545 document.querySelector("#mobile-search").style.filter = "brightness(2)"; 546 } else { 547 if (!OPTIONS.header["invert"]) { 548 header.querySelector('#mobile-menu').classList.remove("open"); 549 header.querySelector('#mobile').classList.remove("open"); 550 header.querySelectorAll("#pc > li > a").forEach(el => { 551 if (!el.classList.contains("menu-button")) { 552 el.parentElement.style.display = "none"; 553 } 554 }); 555 556 OPTIONS.header["invert"] = true; 557 header.style.backgroundColor = "white"; 558 header.querySelectorAll('#header-section .header-logo path').forEach(p => p.setAttribute('fill', '#e95275')); 559 header.querySelector('#header-section .header-logo').style.height = "48px"; 560 header.querySelector('#mobile-menu').style.margin = "8px 0 0 12px"; 561 header.style.marginTop = "28px"; 562 header.style.padding = "0 12px"; 563 header.style.height = "68px"; 564 document.querySelector("#mobile-search").style.filter = "brightness(0)"; 565 } 566 } 567 } 568} 569 570function initYMap() 571{ 572 if (document.querySelector("div#ymap")) { 573 574 myMap = new ymaps.Map("ymap", { 575 center: [59.937296, 30.317305], 576 zoom: 16, 577 controls: ['zoomControl'] 578 }); 579 580 document.querySelector('ymaps[class*="ground-pane"]').style.filter = "grayscale(90%)"; 581 582 const myPlacemark = new ymaps.Placemark([59.937296, 30.317305], 583 { 584 iconContent: 'Ñл. ÐолÑÑÐ°Ñ ÐоÑÑкаÑ, дом 3-5', 585 balloonContent: "<div class='bcontent'><p style='font-weight: bold; color: #dc117a; font-size: 16px;'>ÐÑÐ¸Ñ ÑÑÑиÑÑиÑеÑкой<br />ÑиÑÐ¼Ñ «ÐикÑоÑиѻ</p><p>СанкÑ-ÐеÑеÑбÑÑг<br />Ñл. ÐолÑÑÐ°Ñ ÐоÑÑкаÑ, дом 3-5, оÑÐ¸Ñ 427<br />ÐЦ «ÐидвалÑ»<br />Ñел. 8 800 234 12 16</p></div>" 586 }, {
587 preset: 'islands#violetStretchyIcon' 588 }); 589 590 myMap.geoObjects.add(myPlacemark); 591 } 592 else if (document.querySelector("div.map_place")) { 593 594 try { 595 console.log("map_place JSON:", document.querySelector("div.map_place").getAttribute("data_addr")); 596 let data = JSON.parse(document.querySelector("div.map_place").getAttribute("data_addr")); 597 598 myMap = new ymaps.Map("tour_path_scheme", { 599 center: [59.938793, 30.314430], 600 zoom: 16, 601 controls: ['zoomControl'] 602 }); 603 myMap.behaviors.disable('scrollZoom'); 604 605 /* ÐаÑалÑнÑй адÑÐµÑ Ð¼ÐµÑки */ 606 var address = 'РоÑÑиÑ, СанкÑ-ÐеÑеÑбÑÑг, ' + data[1]; 607 608 ymaps.geocode(address).then(function (res) { 609 var coord = res.geoObjects.get(0).geometry.getCoordinates(); 610 611 var myPlacemark = new ymaps.Placemark(coord, { 612 balloonContent: data[1], 613 iconContent: data[0] 614 } 615 , { 616 preset: "islands#darkBlueStretchyIcon", 617 // ÐÑклÑÑаем ÐºÐ½Ð¾Ð¿ÐºÑ Ð·Ð°ÐºÑÑÑÐ¸Ñ Ð±Ð°Ð»Ñна. 618 balloonCloseButton: false, 619 // ÐалÑн бÑдем оÑкÑÑваÑÑ Ð¸ закÑÑваÑÑ ÐºÐ»Ð¸ÐºÐ¾Ð¼ по иконке меÑки. 620 hideIconOnBalloonOpen: false 621 }); 622 623 myMap.geoObjects.add(myPlacemark); 624 myMap.setCenter(coord, 15); 625 }); 626 } 627 catch (err) { 628 console.error("ÐÑибка загÑÑзки даннÑÑ ÐºÐ°ÑÑÑ", err); 629 } 630 } 631} 632 633//ÐÑбиÑаем даннÑе 634function getData(data_type, menu, id) { 635 document.body.style.cursor = "progress"; 636 637 clearInterval(mouseClick); // Ñнимаем оÑÑлеживание пеÑÐµÑ Ð¾Ð´Ð° по Ñ ÑÑ 638 639 // ÑоÑмиÑÑем даннÑе 640 let FD = new FormData(); 641 FD.append("data_type", data_type); 642 FD.append("menu", menu); 643 FD.append("id", id); 644 645 postData("../user/getAjaxData.php", FD, false, "GET").then(response => { 646 if (data_type === "timetable" || data_type === "tours") { 647 document.querySelector("section#article_page").innerHTML = response; 648 649 } else if (data_type === "tourfiltr" || data_type === "catalog") { 650 document.querySelector("div#tour_cards").innerHTML = response; 651 window.scrollTo({ top: 290, behavior: "smooth" }); 652 653 } else if (data_type === "feedback") { 654 document.querySelector("section#article_page").innerHTML = response; 655 if (/^r_.*/.test(id)) { 656 window.scrollTo({ top: 250, behavior: "smooth" }); 657 const respInput = document.querySelector("#user_response"); 658 if (respInput) respInput.focus(); 659 } 660 661 } else if (data_type === "ufeedback") { 662 document.querySelector("section#article_page").innerHTML = response; 663 664 } else if (data_type === "faq") { 665 document.querySelector("div.blleft").innerHTML = response; 666 } 667 668 // запÑÐµÑ Ð½Ð° Enter в input 669 document.querySelectorAll("input").forEach(inp => { 670 inp.addEventListener("keydown", e => { 671 if (e.keyCode === 13) e.preventDefault(); 672 }); 673 }); 674 675 document.body.style.cursor = "default"; 676 }); 677} 678// ÐÑовеÑÑем ÑÑо ÑекÑÑÐ°Ñ Ð´Ð°Ñа болÑге Ñем в аÑгеменÑе 679function checkDate(targetDate, targetTime, closeTime) { 680 681 // ÑазбиÑаем даÑÑ 682 const [year, month, day] = targetDate.split('-'); 683 const [hours, minutes] = targetTime.split(':'); 684 685 // ÑоздаÑм обÑÐµÐºÑ Ð´Ð°ÑÑ ÑкÑкÑÑÑии 686 const tourDateTime = new Date( 687 year, 688 month - 1, // JS меÑÑÑÑ Ñ Ð½ÑÐ»Ñ 689 day, 690 hours, 691 minutes 692 ); 693 694 // ÑекÑÑее вÑÐµÐ¼Ñ + бÑÑÐµÑ Ð·Ð°ÐºÑÑÑÐ¸Ñ 695 const now = new Date(); 696 const closeBorder = new Date( 697 tourDateTime.getTime() - closeTime * 60 * 1000 698 ); 699 700 // пÑовеÑка 701 return now >= closeBorder; 702} 703//ÐапÑÐ¾Ñ ÑкÑкÑÑÑий по ÑаÑам на вÑбÑаннÑй Ð´ÐµÐ½Ñ Ð½Ð° ÑÑÑаниÑÑ ÑаÑпиÑÐ°Ð½Ð¸Ñ 704function getTourHours(date, printType, obj) { 705 document.body.style.cursor = "progress"; 706 707 const ulSute = document.querySelector("div#ul_sute ul"); 708 if (ulSute) { 709 ulSute.innerHTML = "<p style='text-align: center; padding: 150px 0; font-size: 17pt;'><img id='aj' src='../images/ajax-loader-big.gif' /></p>"; 710 } 711 712 // пеÑеклÑÑаем акÑивнÑй Ð´ÐµÐ½Ñ 713 document.querySelectorAll("div.myCalendar span.active").forEach(el => el.classList.remove("pick_day")); 714 obj.classList.add("pick_day"); 715 716 setTimeout(() => { 717 const fd = new FormData(); 718 fd.append("data_type", "get_tour_hours"); 719 fd.append("menu", date); 720 fd.append("id", printType); 721 722 postData("../user/getAjaxData.php", fd, false, "GET").then(data => { 723 if (!data || data.length <= 10) { 724 document.body.style.cursor = "auto"; 725 return; 726 } 727 728 if (printType === 0) { 729 document.querySelectorAll("div.flyTimeWindow").forEach(el => el.remove()); 730 731 if (!document.querySelector("div.flyTimeWindow")) { 732 // ÑоздаÑÑ Ð±Ð»Ð¾Ðº 733 const timeWindow = document.createElement("div"); 734 timeWindow.classList.add("flyTimeWindow"); 735 timeWindow.innerHTML = data; 736 document.body.appendChild(timeWindow); 737 738 const linkCount = timeWindow.querySelectorAll('a').length; 739 const formatted = date.replace(/^(\d{4})-(\d{2})-(\d{2})$/, '$3.$2.$1'); 740 // ÐобавлÑем заголовок 741 const title = `<h3><a href="/tours/all?date=${date}">ÐкÑкÑÑÑий: ${linkCount}</a> [${formatted}]</h3>`; 742 timeWindow.insertAdjacentHTML("afterbegin", title); 743 744 const rect = obj.getBoundingClientRect(); 745 const objWidth = obj.offsetWidth; 746 747 timeWindow.classList.add("visible"); // плавноÑÑÑ ÑеÑез CSS 748 const twWidth = 800; 749 750 timeWindow.style.width = window.outerWidth > 640 ? twWidth + "px" : "100%"; 751 752 timeWindow.style.left = window.outerWidth > 640 ? rect.left + 5 - (twWidth + rect.width) / 2 + "px" : 0; 753 timeWindow.style.top = window.outerWidth > 640 ? (rect.top + window.scrollY + 74) + "px" : (rect.top + window.scrollY + 44) + "px"; 754 755 756 document.body.style.cursor = "auto"; 757 } 758 } else { 759 const blleft = document.querySelector("div.blleft_inline"); 760 if (blleft) blleft.innerHTML = data; 761 let count = document.querySelectorAll("div.blleft_inline #ul_sute li"); 762 let title = document.querySelector("div.blleft_inline h3.time_out_title strong span"); 763 if (title) { 764 title.insertAdjacentText("beforeend", ` [${[...count].length}]`); 765 } else { 766 let title = document.querySelector("div.blleft_inline h3.time_out_title strong"); 767 title.insertAdjacentHTML("beforeend", `<span> [${[...count].length}]</span>`); 768 } 769 document.body.style.cursor = "auto"; 770 } 771 });
772 }, 500); 773} 774// ÐоÑавиÑÑ Ð´Ð°ÑÑ Ð² поле 775function setInputDate(ndate, fs, obj) { 776 const input = document.querySelector("input[name=tdate]"); 777 input.dataset.value = ndate; 778 779 const date = new Date(ndate); 780 781 // ФоÑмаÑиÑÑем Ð´ÐµÐ½Ñ Ð¸ меÑÑÑ 782 const dayMonth = date.toLocaleDateString('ru-RU', { 783 day: 'numeric', 784 month: 'long' 785 }); 786 787 // ФоÑмаÑиÑÑем Ð´ÐµÐ½Ñ Ð½ÐµÐ´ÐµÐ»Ð¸ 788 const weekday = date.toLocaleDateString('ru-RU', { 789 weekday: 'short' 790 }); 791 792 // ÐбÑезаем ÑоÑÐºÑ Ñ ÑокÑаÑÐµÐ½Ð¸Ñ Ð´Ð½Ñ Ð½ÐµÐ´ÐµÐ»Ð¸ (ÐÑ. -> ÐÑ) 793 const weekdayShort = weekday.replace('.', ''); 794 input.value = `${dayMonth} (${weekdayShort})`; 795 796 obj.closest(".flyTimeWindow").remove(); 797} 798// ÐÑплÑваÑÑий календаÑÑ Ð¿Ñи вÑбоÑе даÑÑ ÑÑÑа на ÑÑÑаниÑе ÑÑÑа и оплаÑÑ 799// id - id запиÑи из ÑаблиÑÑ ÑаÑпиÑÐ°Ð½Ð¸Ñ 800function showFlyCalendar(id, obj, udate, filter = false, foreng = 0) { 801 document.body.style.cursor = "progress"; 802 803 // пÑовеÑим, ÑÑо пÑиÑло название Ð¿Ð¾Ð»Ñ 804 if (Object.prototype.toString.call(udate) !== '[object Date]') { 805 udate = document.querySelector(`input[name="${udate}"]`)?.value; 806 } 807 808 let picketDate = new Date(udate); 809 810 udate = picketDate.getFullYear() + '-' + 811 String(picketDate.getMonth() + 1).padStart(2, '0') + '-' + 812 String(picketDate.getDate()).padStart(2, '0'); 813 814 const fd = new FormData(); 815 fd.append("data_type", "tourCalendar"); 816 fd.append("id", id); 817 fd.append("udate", udate); 818 fd.append("filter", filter); 819 fd.append("foreng", foreng); 820 821 postData("../user/getAjaxData.php", fd, false, "GET").then(data => { 822 if (!document.querySelector("div.flyTimeWindow")) { 823 const timeWindow = document.createElement("div"); 824 timeWindow.classList.add("flyTimeWindow"); 825 timeWindow.innerHTML = data; 826 document.body.appendChild(timeWindow); 827 828 const rect = obj.getBoundingClientRect(); 829 const objWidth = obj.offsetWidth; 830 const mqMobile = window.innerWidth; 831 832 if (mqMobile > 640) { 833 timeWindow.style.left = (rect.left + window.scrollX + objWidth / 2 - 200) + "px"; 834 timeWindow.style.top = (rect.top + window.scrollY + obj.offsetHeight + 8 + 30) + "px"; 835 } else { 836 timeWindow.style.left = "1rem"; 837 timeWindow.style.top = (rect.top + window.scrollY + obj.offsetHeight + 6) + "px"; 838 } 839 840 timeWindow.style.width = "340px"; 841 timeWindow.classList.add("visible"); 842 document.body.style.cursor = "auto"; 843 } else { 844 document.querySelectorAll("div.flyTimeWindow").forEach(el => el.remove()); 845 document.body.style.cursor = "auto"; 846 } 847 }); 848} 849 850// подÑÑавлÑем ближайÑÑÑ Ð´Ð°ÑÑ Ð½Ð° ÑÑÑаниÑÑ ÑÑÑа. Ð ÐµÐ½Ð´ÐµÑ Ð¿ÑоиÑÑ Ð¾Ð´Ð¸Ñ Ð¸Ð· кÑÑа, даÑÑ Ð½Ðµ ÑооÑвеÑÑÑвÑÑÑ 851// опÑеделиÑÑ Ð½Ð° ÑеÑвеÑе ближайÑÑÑ Ð´Ð°ÑÑ Ð² вÑдаÑÑ Ð¼Ð°ÑÑив 852// алгоÑиÑм пÑимеÑно Ñакйо же как и клик пÑи изменении даÑÑ 853function renderExcursionDate() { 854 855 const tour_id = document.querySelector("input[name=id_tour]")?.value; 856 857 if (!tour_id) { 858 return; 859 } 860 861 // ÐапÑоÑиÑÑ Ð±Ð»Ð¾Ðº Ñен 862 document.body.style.cursor = "progress"; 863 864 const fd = new FormData(); 865 fd.append("tour_id", tour_id); 866 fd.append("data_type", "tourHours"); 867 868 postData("../user/getAjaxData.php", fd, false, "GET").then(data => { 869 870 let ourStarPointTime = [...document.querySelectorAll("#thisStartPointUp, #thisStartPointDown")]; 871 let crossStarPointTime = [...document.querySelectorAll("#crossStartPointUp, #crossStartPointDown")]; 872 873 try { 874 let times = JSON.parse(data); 875 if (times.hours.our.length != 0) { 876 ourStarPointTime.forEach(el => { 877 el.textContent = ""; 878 let selected = " selected_date"; 879 let disabled = ""; 880 times.hours.our.forEach(time => {
881 if (checkDate(time["date_tour"], time["time_tour"], el.dataset.closetime)) { 882 disabled = " disabled_date"; 883 } else { 884 disabled = ""; 885 } 886 el.insertAdjacentHTML('beforeend', `<button type="button" class="application__time time-slot${selected}${disabled}" data-timeid="${time["id"]}" data-run-script="true" data-script="%7B%22script%22%3A%22setDate%22%2C%22param%22%3A%7B%22id%22%3A${time["id"]}%2C%22date%22%3A%22${time["date_tour"] + " " + time["time_tour"]}%22%2C%22foreng%22%3A0%7D%7D">${time["time_tour"]}</button>`); 887 selected = ""; 888 }); 889 }); 890 } 891 892 // ==== ÐамениÑÑ Ð±Ð»Ð¾Ðº Ñен, Ñ.к. Ñледим за даÑами акÑий 893 const cost_block = document.querySelector("#cost-block"); 894 cost_block.innerHTML = times.cost_block; 895 896 const top_cost_block = document.querySelector("#top_cost_block"); 897 top_cost_block.innerHTML = times.top_block; 898 899 // ÐоказÑваем кÑоÑÑÑ, еÑли они еÑÑÑ 900 if (times.hours.cross.length != 0) { 901 crossStarPointTime.forEach(el => { 902 el.textContent = ""; 903 let disabled = ""; 904 times.hours.cross.forEach(time => { 905 if (checkDate(time["date_tour"], time["time_tour"], el.dataset.closetime)) { 906 disabled = " disabled_date"; 907 } else { 908 disabled = ""; 909 } 910 el.insertAdjacentHTML('beforeend', `<button type="button" class="application__time time-slot${disabled}" data-timeid="${time["id"]}" data-run-script="true" data-script="%7B%22script%22%3A%22setDate%22%2C%22param%22%3A%7B%22id%22%3A${time["id"]}%2C%22date%22%3A%22${time["date_tour"] + " " + time["time_tour"]}%22%2C%22foreng%22%3A1%7D%7D">${time["time_tour"]}</button>`); 911 }); 912 }); 913 } else { 914 crossStarPointTime.forEach(el => { 915 el.innerHTML = ""; 916 }); 917 } 918 919 // ТепеÑÑ Ð½Ð°Ð´Ð¾ кликнÑÑÑ Ð¿Ð¾ пеÑÐ²Ð¾Ð¼Ñ Ð²Ñемени Ð´Ð»Ñ Ð²ÑбоÑа 920 let time_cmd = document.querySelector("#thisStartPointDown button.application__time:not(.disabled_date)"); 921 if (!time_cmd) { 922 time_cmd = document.querySelector("#crossStartPointDown button.application__time:not(.disabled_date)"); 923 // Ð Ð²Ð¾Ñ ÑепеÑÑ Ñ Ð½Ð°Ñ Ð½ÐµÑ Ð²Ñемени по кÑоÑÑам 924 if (!time_cmd) { 925 time_cmd = document.querySelector("#crossStartPointDown button.application__time"); 926 } 927 } 928 929 if (time_cmd) { 930 const event = new MouseEvent('click', { 931 bubbles: true, 932 cancelable: true, 933 view: window 934 }); 935 time_cmd.dispatchEvent(event); 936 } 937 938 recalcSum(); 939 940 } 941 catch (err) { 942 console.error(err); 943 } 944 document.body.style.cursor = "auto"; 945 }); 946} 947function renderTimeButtons(container, times, foreng) { 948 949 container.textContent = ""; 950 951 let selected = " selected_date"; 952 953 times.forEach(time => { 954 955 const disabled = checkDate( 956 time.date_tour, 957 time.time_tour, 958 container.dataset.closetime 959 ) ? " disabled_date" : ""; 960 961 container.insertAdjacentHTML("beforeend", ` 962 <button 963 type="button" 964 class="application__time time-slot${selected}${disabled}" 965 data-timeid="${time.id}" 966 data-run-script="true" 967 data-script="%7B%22script%22%3A%22setDate%22%2C%22param%22%3A%7B%22foreng%22%3A${foreng}%2C%22id%22%3A${time.id}%2C%22date%22%3A%22${time.date_tour} ${time.time_tour}%22%7D%7D"> 968 ${time.time_tour} 969 </button> 970 `); 971 972 // selected ÑолÑко Ð´Ð»Ñ Ð¿ÐµÑвой доÑÑÑпной 973 if (!disabled) { 974 selected = ""; 975 } 976 }); 977} 978//ÐодÑÑавлÑем даÑÑ Ð² Ð¿Ð¾Ð»Ñ ÑÑÑаниÑÑ ÑкÑкÑÑÑий и покÑпки билеÑа 979function displayDate(obj) { 980 // У Ð½Ð°Ñ ÐµÑÑÑ id вÑбÑанного днÑ, но Ñ ÑÑÑами по вÑÐµÐ¼Ñ Ð²Ñемени 981 // ÐÑе даннÑе Ð½Ð°Ñ Ð¾Ð´ÑÑÑÑ Ð² аÑÑибÑÑе date_data 982 const req_array = obj.getAttribute("date_data").split(";"); 983 984 document.querySelector("#nearest_date").textContent = req_array[2]; 985 document.querySelector("#nearest_date_buyblock").textContent = req_array[2]; 986 document.querySelector("input[name=id_time]").value = req_array[0]; 987 document.querySelector("input[name=sp_time]").value = req_array[5] + " " + req_array[1]; 988 989 const flyWin = document.querySelector("div.flyTimeWindow"); 990 if (flyWin) flyWin.remove(); 991 992 // ÐапÑоÑиÑÑ Ð±Ð»Ð¾Ðº Ñен 993 document.body.style.cursor = "progress"; 994 995 const fd = new FormData(); 996 fd.append("data_type", "tourHours"); 997 fd.append("tour_id", req_array[4]); 998 fd.append("date", req_array[5]); 999 1000 postData("../user/getAjaxData.php", fd, false, "GET").then(data => { 1001 1002 let ourStarPointTime = [...document.querySelectorAll("#thisStartPointUp, #thisStartPointDown")];
1003 let crossStarPointTime = [...document.querySelectorAll("#crossStartPointUp, #crossStartPointDown")]; 1004 1005 try { 1006 let times = JSON.parse(data); 1007 if (times.hours.our.length != 0) { 1008 ourStarPointTime.forEach(el => { 1009 el.textContent = ""; 1010 let selected = " selected_date"; 1011 let disabled = ""; 1012 times.hours.our.forEach(time => { 1013 if (checkDate(time["date_tour"], time["time_tour"], el.dataset.closetime)) { 1014 disabled = " disabled_date"; 1015 } else { 1016 disabled = ""; 1017 } 1018 el.insertAdjacentHTML('beforeend', `<button type="button" class="application__time time-slot${selected}${disabled}" data-timeid="${time["id"]}" data-run-script="true" data-script="%7B%22script%22%3A%22setDate%22%2C%22param%22%3A%7B%22id%22%3A${time["id"]}%2C%22date%22%3A%22${time["date_tour"] + " " + time["time_tour"]}%22%2C%22foreng%22%3A0%7D%7D">${time["time_tour"]}</button>`); 1019 selected = ""; 1020 }); 1021 }); 1022 } 1023 1024 // ==== ÐамениÑÑ Ð±Ð»Ð¾Ðº Ñен, Ñ.к. Ñледим за даÑами акÑий 1025 const cost_block = document.querySelector("#cost-block"); 1026 cost_block.innerHTML = times.cost_block; 1027 1028 const top_cost_block = document.querySelector("#top_cost_block"); 1029 top_cost_block.innerHTML = times.top_block; 1030 1031 // ÐоказÑваем кÑоÑÑÑ, еÑли они еÑÑÑ 1032 if (times.hours.cross.length != 0) { 1033 crossStarPointTime.forEach(el => { 1034 1035 let parentBlock = el.closest(".box-booking__item"); 1036 if (!parentBlock) { 1037 parentBlock = el.closest(".application__block"); 1038 } 1039 parentBlock.classList.remove("hidden"); 1040 1041 el.textContent = ""; 1042 let disabled = ""; 1043 times.hours.cross.forEach(time => { 1044 if (checkDate(time["date_tour"], time["time_tour"], el.dataset.closetime)) { 1045 disabled = " disabled_date"; 1046 } else { 1047 disabled = ""; 1048 } 1049 el.insertAdjacentHTML('beforeend', `<button type="button" class="application__time time-slot${disabled}" data-timeid="${time["id"]}" data-run-script="true" data-script="%7B%22script%22%3A%22setDate%22%2C%22param%22%3A%7B%22id%22%3A${time["id"]}%2C%22date%22%3A%22${time["date_tour"] + " " + time["time_tour"]}%22%2C%22foreng%22%3A1%7D%7D">${time["time_tour"]}</button>`); 1050 }); 1051 }); 1052 } else { 1053 crossStarPointTime.forEach(el => { 1054 1055 let parentBlock = el.closest(".box-booking__item"); 1056 if (!parentBlock) { 1057 parentBlock = el.closest(".application__block"); 1058 } 1059 parentBlock.classList.add("hidden"); 1060 1061 el.innerHTML = ""; 1062 }); 1063 } 1064 1065 // ТепеÑÑ Ð½Ð°Ð´Ð¾ кликнÑÑÑ Ð¿Ð¾ пеÑÐ²Ð¾Ð¼Ñ Ð²Ñемени Ð´Ð»Ñ Ð²ÑбоÑа 1066 let time_cmd = document.querySelector("#thisStartPointDown button.application__time:not(.disabled_date)"); 1067 if (!time_cmd) { 1068 time_cmd = document.querySelector("#crossStartPointDown button.application__time:not(.disabled_date)"); 1069 } 1070 1071 if (time_cmd) { 1072 const event = new MouseEvent('click', { 1073 bubbles: true, 1074 cancelable: true, 1075 view: window 1076 }); 1077 time_cmd.dispatchEvent(event); 1078 } 1079 1080 recalcSum(); 1081 1082 } 1083 catch (err) { 1084 console.error(err); 1085 } 1086 document.body.style.cursor = "auto"; 1087 }); 1088} 1089//ÐÑбиÑаем вÑÐµÐ¼Ñ ÑÑÑа 1090function showFlyTime(obj) { 1091 const id = document.querySelector("input[name=id_time]").value; 1092 1093 const fd = new FormData(); 1094 fd.append("data_type", "tourTimes"); 1095 fd.append("id", id); 1096 1097 postData("../user/getAjaxData.php", fd, false, "GET").then(data => { 1098 if (!document.querySelector("div.flyTimeWindow")) { 1099 let width = 150; 1100 if (/neva/.test(data)) width = 450; 1101 1102 // ÑоздаÑÑ Ð±Ð»Ð¾Ðº 1103 const timeWindow = document.createElement("div"); 1104 timeWindow.classList.add("flyTimeWindow"); 1105 timeWindow.innerHTML = data; 1106 document.body.appendChild(timeWindow); 1107 1108 const rect = obj.getBoundingClientRect(); 1109 const objWidth = obj.offsetWidth; 1110 const objHeight = obj.offsetHeight; 1111 1112 timeWindow.style.width = width + "px"; 1113 1114 // ÑенÑÑиÑÑем оÑноÑиÑелÑно ÑлеменÑа 1115 const left = rect.left + window.scrollX + objWidth / 2 - width / 2 - 30; 1116 const top = rect.top + window.scrollY + objHeight; 1117 1118 timeWindow.style.left = left + "px"; 1119 timeWindow.style.top = top - 8 + "px"; 1120 1121 // плавное поÑвление ÑеÑез CSSâtransition 1122 timeWindow.classList.add("visible"); 1123 1124 document.body.style.cursor = "auto"; 1125 } else { 1126 document.querySelectorAll("div.flyTimeWindow").forEach(el => el.remove()); 1127 document.body.style.cursor = "auto"; 1128 } 1129 }); 1130} 1131function displayTime(obj) { 1132 // УÑÑановиÑÑ Ð²ÑбÑанное вÑÐµÐ¼Ñ 1133 // document.querySelector("div#picked_time").textContent = obj.textContent; // еÑли нÑжно оÑобÑазиÑÑ ÑекÑÑ 1134 document.querySelector("input[name=id_time]").value = obj.getAttribute("date_id"); 1135 1136 const flyWin = document.querySelector("div.flyTimeWindow"); 1137 if (flyWin) flyWin.remove(); 1138 1139 const menu = window.location.href.match(/\/tour\/([\w\d-,]*)#?/); 1140 1141 // ÐапÑоÑиÑÑ Ð±Ð»Ð¾Ðº Ñен 1142 document.body.style.cursor = "progress"; 1143 1144 const fd = new FormData(); 1145 fd.append("data_type", "tour"); 1146 fd.append("menu", menu[1]); 1147 fd.append("id", obj.getAttribute("date_id")); 1148 1149 postData("../user/getAjaxData.php", fd, false, "GET").then(data => { 1150 const viewTour = document.querySelector(".view_tour_right"); 1151 if (viewTour) viewTour.innerHTML = data; 1152 1153 // ÐбновиÑÑ ÐºÐ°ÑÑÑ 1154 const map_block = document.querySelector("div.map_place"); 1155 if (map_block) { 1156 map_block.innerHTML = ""; 1157 const map_data = document.querySelector("div#pier"); 1158 if (map_data) { 1159 map_block.setAttribute("data_addr", map_data.getAttribute("data_addr")); 1160 initYMap();
1161 } 1162 } 1163 }); 1164} 1165function mainSearch(obj) { 1166 if (obj.value.length < 3) return false; 1167 1168 document.body.style.cursor = "progress"; 1169 1170 const fd = new FormData(); 1171 fd.append("data_type", "get_search"); 1172 fd.append("menu", obj.value); 1173 1174 postData("../user/getAjaxData.php", fd, false, "GET").then(data => { 1175 // еÑли даннÑÑ Ð¼Ð°Ð»Ð¾ â вÑÑ Ð¾Ð´Ð¸Ð¼ 1176 if (!data || data.length < 30) { 1177 document.body.style.cursor = "auto"; 1178 return false; 1179 } 1180 1181 let flyWin = document.querySelector("div.flyTimeWindow"); 1182 1183 if (!flyWin) { 1184 // ÑоздаÑÑ Ð±Ð»Ð¾Ðº 1185 flyWin = document.createElement("div"); 1186 flyWin.classList.add("flyTimeWindow"); 1187 flyWin.innerHTML = data; 1188 document.body.appendChild(flyWin); 1189 1190 const rect = obj.getBoundingClientRect(); 1191 flyWin.style.width = "520px"; 1192 flyWin.style.left = (rect.left - 260) + "px"; 1193 flyWin.style.top = "478px"; 1194 1195 // плавное поÑвление ÑеÑез CSS 1196 flyWin.classList.add("visible"); 1197 1198 document.body.style.cursor = "auto"; 1199 } else { 1200 flyWin.innerHTML = data; 1201 document.body.style.cursor = "auto"; 1202 } 1203 }); 1204} 1205function getToursInterval() 1206{ 1207 var b_date = document.querySelector("input[name=d_start]").value; 1208 var e_date = document.querySelector("input[name=d_end]").value; 1209 1210 if (typeof b_date == "undefined" || typeof e_date == "undefined") 1211 { 1212 alert("ÐожалÑйÑÑа вÑбеÑиÑе инÑеÑвал Ð´Ð°Ñ Ð² полÑÑ Ð¸ повÑоÑиÑе запÑоÑ!"); 1213 }else{ 1214 var link = "/tours/interval_"+b_date+"_"+e_date; 1215 window.location.href = link; 1216 } 1217 return false; 1218} 1219function mainSearchDate() 1220{ 1221 var b_date = document.querySelector(":input[name=b_date]").value; 1222 1223 if (b_date.length == 0) 1224 { 1225 alert("ÐожалÑйÑÑа вÑбеÑиÑе даÑÑ Ð² поле и повÑоÑиÑе запÑоÑ!"); 1226 }else{ 1227 var link = "/tours/date_"+b_date; 1228 window.location.href = link; 1229 } 1230} 1231// function flowTourHours(faa) { 1232// const winEl = document.querySelector("div.blleft_inline"); 1233// const listEl = document.querySelector("ul.absolute"); 1234 1235// if (!winEl || !listEl) return; 1236
1237// // вÑÑоÑа окна и ÑпиÑка 1238// const winHeight = winEl.offsetHeight - 148; 1239// const listHeight = listEl.scrollHeight; 1240 1241// if (listHeight <= winHeight) return; 1242 1243// // ÑекÑÑий marginTop 1244// let posList = parseInt(getComputedStyle(listEl).marginTop) || 0; 1245 1246// if (listHeight - (winHeight - posList) > 0) { 1247// if (Math.abs(posList) + winHeight < listHeight - winHeight) { 1248// posList = posList - winHeight; 1249// listEl.style.marginTop = posList + "px"; 1250// } else { 1251// posList = listHeight - winHeight; 1252// listEl.style.marginTop = "-" + posList + "px"; 1253// } 1254// } else { 1255// listEl.style.marginTop = "0px"; 1256// } 1257// } 1258 1259function recalcSum() { 1260 1261 let sum = 0, full_cost = 0, count = 0, sum_ppay = 0; 1262 1263 const form = document.querySelector("form[name=ticket_count]"); 1264 const tickets = form.querySelector("input[name=check_types]").value.split(","); 1265 const ppay = parseInt(form.querySelector("input[name=prepay_sum]")?.value) || 0; 1266 const payment_type = form.querySelector("input[name=fullPay]:checked")?.value || 1; 1267 const pay_sum = form.querySelector("input[name=pay_sum]"); 1268 1269 tickets.forEach(ticket => { 1270 const cur_t_count = parseInt(form.querySelector(`input[name="tickets[${ticket}]"]`).value) || 0; 1271 const cur_t_cost = parseInt(form.querySelector(`input[name="cost[${ticket}]"]`).value) || 0; 1272 const ful_t_cost = parseInt(form.querySelector(`input[name="fcost[${ticket}]"]`).value) || 0; 1273 1274 full_cost += cur_t_count * ful_t_cost; 1275 sum += cur_t_count * cur_t_cost; 1276 sum_ppay += ppay * cur_t_count; 1277 count += cur_t_count; 1278 }); 1279 1280 // ÐÑомокод 1281 let promo_sum = document.querySelector("input[name=promo_sum]").value; 1282 promo_sum *= count; 1283 1284 let promo_span = document.querySelector("#promo_sum span"); 1285 if (promo_span) promo_span.textContent = promo_sum; 1286 1287 // ÐолиÑеÑÑво билеÑов 1288 let t_count = document.querySelector("#t_count"); 1289 if (t_count) t_count.textContent = count; 1290 1291 // ÐÐ¾Ð»Ð½Ð°Ñ Ñена билеÑов 1292 let f_cost = document.querySelector("#full_cost span"); 1293 if (f_cost) f_cost.textContent = full_cost; 1294 1295 // Ñкидка % 1296 let sale = document.querySelector("#sale"); 1297 sale.textContent = parseInt(100 - (sum / full_cost * 100)) + "%" || 0 + "%"; 1298 // Ñкидка денÑгов 1299 let sale_sum = document.querySelector("#sale_sum span"); 1300 sale_sum.textContent = parseInt(full_cost - sum); 1301 // иÑого 1302 if (sum == 0) { 1303 // Ðе вÑбÑали билеÑÑ, пÑомокод не ÑÑиÑаем 1304 promo_sum = 0; 1305 } 1306 let itog = document.querySelector("#itog span"); 1307 itog.textContent = parseInt(sum - promo_sum); 1308 // иÑого, пÑедоплаÑа 1309 let prepay = document.querySelector("#prepay span"); 1310 // ÐоплаÑа 1311 let doplata = document.querySelector("#doplata span"); 1312 1313 if (payment_type != 1) { 1314 prepay.closest(".bottom-booking__box").style.display = "flex"; 1315 doplata.closest(".bottom-booking__box").style.display = "flex"; 1316 prepay.textContent = parseInt(sum_ppay); 1317 doplata.textContent = parseInt(sum - promo_sum - sum_ppay); 1318 pay_sum.value = parseInt(sum_ppay); 1319 } else { 1320 // ÐÑедоплаÑа оÑклÑÑена 1321 prepay.closest(".bottom-booking__box").style.display = "none"; 1322 doplata.closest(".bottom-booking__box").style.display = "none"; 1323 prepay.textContent = parseInt(sum - promo_sum); 1324 pay_sum.value = parseInt(sum - promo_sum); 1325 1326 } 1327 1328 return count; 1329 1330} 1331function showRoadMap(id_tour) { 1332 1333 var myMap = null; // обÑÑвлÑем в облаÑÑи видимоÑÑи ÑÑнкÑии 1334 1335 function initRoadMap(obj) { 1336 // ÐÑовеÑка конÑейнеÑа 1337 var container = document.getElementById("view_road"); 1338 if (!container) { 1339 console.error('ÐонÑÐµÐ¹Ð½ÐµÑ #view_road не найден'); 1340 return; 1341 } 1342 1343 // ÐниÑиализаÑÐ¸Ñ ÐºÐ°ÑÑÑ 1344 myMap = new ymaps.Map("view_road", { 1345 center: obj.data.options.dispatch_points, 1346 zoom: 14, 1347 controls: ['zoomControl'] 1348 }); 1349 1350 // ÐобавлÑем вÑе ÑоÑки на каÑÑÑ
1351 ymapAddMarkers(obj); 1352 1353 // ÐвÑомаÑиÑеÑки маÑÑÑабиÑÑем каÑÑÑ Ð¿Ð¾Ð´ вÑе меÑки 1354 fitMapToMarkers(); 1355 } 1356 1357 // Ðобавление меÑок на каÑÑÑ â ÑÑандаÑÑнÑе иконки 1358 function ymapAddMarkers(obj) { 1359 1360 // 1. СÑаÑÑ â кÑаÑÐ½Ð°Ñ Ð¼ÐµÑка 1361 var startCoords = obj.data.options.dispatch_points; 1362 if (isValidCoords(startCoords)) { 1363 var startMarker = new ymaps.Placemark( 1364 startCoords, 1365 { 1366 balloonContentHeader: "СÑаÑÑ", 1367 balloonContentBody: obj.data.options.dp_name, 1368 hintContent: "ÐаÑало ÑкÑкÑÑÑии: " + obj.data.options.dp_name 1369 }, 1370 { 1371 preset: 'islands#redIcon' 1372 } 1373 ); 1374 myMap.geoObjects.add(startMarker); 1375 } 1376 1377 // 2. ÐÑомежÑÑоÑнÑе ÑоÑки â Ñиние меÑки (ÑÑандаÑÑнÑе) 1378 obj.data.points.forEach(function(item, index) { 1379 if (isValidCoords(item.point)) { 1380 var marker = new ymaps.Placemark( 1381 item.point, 1382 { 1383 balloonContentHeader: "ÐÑÑановка " + (index + 1), 1384 balloonContentBody: item.title, 1385 hintContent: item.title 1386 }, 1387 { 1388 preset: 'islands#blueIcon' 1389 } 1390 ); 1391 myMap.geoObjects.add(marker); 1392 } 1393 }); 1394 1395 // 3. Ð¤Ð¸Ð½Ð¸Ñ â зелÑÐ½Ð°Ñ Ð¼ÐµÑка 1396 var endCoords = obj.data.options.arrival_points; 1397 if (isValidCoords(endCoords)) { 1398 var endMarker = new ymaps.Placemark( 1399 endCoords, 1400 { 1401 balloonContentHeader: "ФиниÑ", 1402 balloonContentBody: obj.data.options.arr_name, 1403 hintContent: "ÐконÑание: " + obj.data.options.arr_name 1404 }, 1405 { 1406 preset: 'islands#greenIcon' 1407 } 1408 ); 1409 myMap.geoObjects.add(endMarker); 1410 } 1411 } 1412 1413 // ÐаÑÑÑабиÑование каÑÑÑ Ð¿Ð¾Ð´ вÑе меÑки 1414 function fitMapToMarkers() { 1415 1416 if (!myMap) return; 1417 1418 var bounds = myMap.geoObjects.getBounds(); 1419 1420 if (bounds) { 1421 myMap.setBounds(bounds, { 1422 checkZoomRange: true, 1423 zoomMargin: 40 1424 }); 1425 } 1426 1427 } 1428 1429 // ÐÑовеÑка кооÑÐ´Ð¸Ð½Ð°Ñ 1430 function isValidCoords(coords) { 1431 return Array.isArray(coords) 1432 && coords.length === 2 1433 && typeof coords[0] === 'number' 1434 && typeof coords[1] === 'number' 1435 && !isNaN(coords[0]) && !isNaN(coords[1]); 1436 } 1437 1438 // ===== ÐСÐÐÐÐÐÐ ÐÐÐÐ ÐС ===== 1439 const fd = new FormData(); 1440 fd.append("tour", id_tour); 1441 1442 postData("../user/getRoadPointJSON.php", fd, true, "GET").then(obj => { 1443 1444 // СоздаÑм инÑеÑÑÐµÐ¹Ñ 1445 const bgHeight = document.documentElement.scrollHeight + "px"; 1446 1447 // Ñон 1448 const winBg = document.createElement("div"); 1449 winBg.classList.add("win-bg"); 1450 winBg.style.height = bgHeight; 1451 document.body.appendChild(winBg); 1452 winBg.classList.add("visible"); // плавное поÑвление ÑеÑез CSS 1453 1454 // конÑÐµÐ¹Ð½ÐµÑ ÐºÐ°ÑÑÑ 1455 const winDiv = document.createElement("div"); 1456 winDiv.id = "view_road"; 1457 winDiv.style.opacity = "1"; 1458 document.body.appendChild(winDiv); 1459 1460 winDiv.innerHTML = "<span class='close'></span>"; 1461 1462 // ÐакÑÑÑие 1463 winBg.addEventListener("click", () => {
1464 if (myMap) { 1465 myMap.geoObjects.removeAll(); 1466 myMap.destroy(); 1467 myMap = null; 1468 } 1469 winDiv.remove(); 1470 winBg.remove(); 1471 }); 1472 1473 setTimeout(() => { 1474 winBg.classList.add("visible"); 1475 document.querySelector("#view_road").classList.add("visible"); 1476 1477 document.querySelector(".close").addEventListener("click", e => { 1478 if (myMap) { 1479 myMap.geoObjects.removeAll(); 1480 myMap.destroy(); 1481 myMap = null; 1482 } 1483 winDiv.remove(); 1484 winBg.remove(); 1485 }); 1486 }, 10); 1487 1488 // ÐниÑиализаÑÐ¸Ñ Ñ Ð¿ÑовеÑкой API 1489 if (typeof ymaps === 'undefined') { 1490 alert('ЯндекÑ.ÐаÑÑÑ Ð½Ðµ загÑÑженÑ'); 1491 return; 1492 } 1493 1494 ymaps.ready(() => { 1495 initRoadMap(obj); 1496 }); 1497 }).catch(err => { 1498 console.error('ÐÑибка загÑÑзки даннÑÑ :', err); 1499 alert('Ðе ÑдалоÑÑ Ð·Ð°Ð³ÑÑзиÑÑ Ð´Ð°Ð½Ð½Ñе ÑкÑкÑÑÑии'); 1500 }); 1501} 1502 1503function newTour_filtr() 1504{ 1505 let loc = "/tours/region_" + document.querySelector("select[name=region]").value; 1506 if (document.querySelector("select[name=region]").value == "all") loc = "/tours/" + document.querySelector("select[name=region]").value; 1507 1508 const dateInput = document.querySelector("input[name=tdate]"); 1509 const dateValue = dateInput.dataset.value; 1510 1511 if (dateValue) { 1512 loc += "?date=" + dateValue; 1513 } 1514 1515 window.location.href = loc; 1516} 1517function getCalendar(date, id, fs, fnct, $foreng = 0) 1518{ 1519 document.body.style.cursor = "progress"; 1520 //ÐпÑеделÑем ÑÑо за блок заÑÑебовал календаÑÑ 1521 var pafrentBlock = document.querySelector("div.myCalendar").parentElement; 1522 const fd = new FormData(); 1523 fd.append("data_type", "tourCalendarMonth"); 1524 fd.append("date", date); 1525 fd.append("id", id); 1526 fd.append("fs", fs); 1527 fd.append("fnct", fnct); 1528 fd.append("foreng", $foreng); 1529 1530 postData("../user/getAjaxData.php", fd, false, "GET").then(data => { 1531 pafrentBlock.innerHTML = data; 1532 document.body.style.cursor = "auto"; 1533 }); 1534} 1535function saveData(menu, fb, e) 1536{ 1537 if (e) e.preventDefault(); 1538 1539 let fd, valid, form, uphone_value, inputs; 1540 OPTIONS.reload = false; 1541 1542 switch(menu) 1543 { 1544 case "reserve": 1545 1546 valid = true; 1547 form = document.querySelector("form[name=ticket_count]"); 1548 inputs = form.querySelectorAll("input"); 1549 1550 inputs.forEach(input => { 1551 if (!Validator.validate(input)) { 1552 valid = false; 1553 } 1554 }); 1555 1556 let all_tic_count = recalcSum(); 1557 1558 if (!all_tic_count) { 1559 const html = ` 1560 <div class="win-close" onclick="closeFlyWindow();"></div> 1561 <img src="../images/errrrrr.jpg" /> 1562 <h2 style="text-align: center;">ÐбÑаÑиÑе внимание</h2> 1563 <p style="text-align: center;"> 1564 ÐÑ Ð½Ðµ вÑбÑали колиÑеÑÑво билеÑов!<br>ÐоÑеÑение ÑкÑкÑÑÑии пÑоводиÑÑÑ Ð¿Ð¾ заÑанее забÑониÑованнÑм меÑÑам. 1565 </p> 1566 <button onclick="closeFlyWindow('booking-tcount');">ÐÑбÑаÑÑ Ð±Ð¸Ð»ÐµÑÑ</button>`; 1567 1568 createFlyWindow(html); 1569 return false; 1570 } else { 1571 const html = `<div class="win-close" onclick="closeFlyWindow();"></div> 1572 <div class='msg'> 1573 <div id='ajax'> 1574 <div class='loader_a'></div> 1575 <div class='loader_b'></div> 1576 </div> 1577 <p>ÐÑпÑавлÑем заÑÐ²ÐºÑ ...</p> 1578 </div>`; 1579 createFlyWindow(html); 1580 } 1581 1582 const p_pixel = (tour_id, cost) => { 1583 _tmr.push({ type: 'reachGoal', id: 3318706, value: cost, goal: 'purchase', params: { product_id: tour_id } }); 1584 }; 1585 p_pixel(form.querySelector("input[name=id_tour]").value, form.querySelector("input[name=pay_sum]").value); 1586 1587 const p_urlObj = new URL(window.location.href); 1588 const p_title_en = p_urlObj.pathname.split('/').pop(); // ÐолÑÑаем Ð¸Ð¼Ñ ÑÑÑа 1589 1590 document.body.style.cursor = "progress"; 1591 var p_saveData = new FormData(form); 1592 1593 p_saveData.append("data", "reserve"); 1594 p_saveData.append("title_en", p_title_en); 1595 1596 postData("../user/saveData.php", p_saveData).then(response => { 1597 if (!response.ok) { 1598 const html = ` 1599 <div class="win-close" onclick="closeFlyWindow();"></div> 1600 <img src="../images/site-errror.jpg" /> 1601 <h2 style="text-align: center">ÐÑибка ÑезеÑвиÑованиÑ</h2> 1602 <p>${response.error || response}</p> 1603 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 1604 `; 1605 createFlyWindow(html); 1606 } else { 1607 const html = ` 1608 <div class="win-close" onclick="closeFlyWindow();"></div> 1609 <img src="../images/zvonok1.jpg" /> 1610 <h2 style="text-align: center">РезеÑвиÑование ÑÑпеÑно завеÑÑено</h2> 1611 <p>Ðа поÑÑÑ Ð¾ÑпÑавлено пиÑÑмо Ñ ÐºÐ¾Ð¿Ð¸ÐµÐ¹ заказа. ÐÐ°Ñ Ð¼ÐµÐ½ÐµÐ´Ð¶ÐµÑ ÑвÑжеÑÑÑ Ñ Ðами в ближайÑее вÑемÑ.</p> 1612 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 1613 `; 1614 createFlyWindow(html, true); 1615 } 1616 }); 1617 1618 break; 1619 1620 case "order": 1621 1622 valid = true; 1623 form = document.querySelector("form[name=ticket_count]"); 1624 inputs = form.querySelectorAll("input"); 1625
1626 inputs.forEach(input => { 1627 if (!Validator.validate(input)) { 1628 valid = false; 1629 } 1630 }); 1631 1632 // ==== ÐонÑÑÐ¾Ð»Ñ Ð²Ñемени закÑÑÑÐ¸Ñ ÑÑÑа ==== 1633 1634 // вÑÐµÐ¼Ñ Ð·Ð°ÐºÑÑÑÐ¸Ñ Ð² минÑÑÐ°Ñ 1635 const closeTime = parseInt(form.close_time_minutes.value, 10); 1636 1637 // вÑбÑаннÑе даÑа и вÑÐµÐ¼Ñ 1638 const tourDateText = document.querySelector("#itog_data").textContent.trim(); 1639 const tourTimeText = document.querySelector("#itog_time").textContent.trim(); 1640 1641 // 05.05.2026 1642 // 10:30 1643 1644 // ÑазбиÑаем даÑÑ 1645 const [day, month, year] = tourDateText.split('.'); 1646 const [hours, minutes] = tourTimeText.split(':'); 1647 1648 // ÑоздаÑм обÑÐµÐºÑ Ð´Ð°ÑÑ ÑкÑкÑÑÑии 1649 const tourDateTime = new Date( 1650 year, 1651 month - 1, // JS меÑÑÑÑ Ñ Ð½ÑÐ»Ñ 1652 day, 1653 hours, 1654 minutes 1655 ); 1656 1657 // ÑекÑÑее вÑÐµÐ¼Ñ + бÑÑÐµÑ Ð·Ð°ÐºÑÑÑÐ¸Ñ 1658 const now = new Date(); 1659 1660 const closeBorder = new Date( 1661 now.getTime() + closeTime * 60 * 1000 1662 ); 1663 1664 // пÑовеÑка 1665 const canOrder = closeBorder <= tourDateTime; 1666 1667 console.log("ТÑÑ:", tourDateTime); 1668 console.log("СейÑаÑ+бÑÑеÑ:", closeBorder); 1669 console.log("Ðожно бÑониÑоваÑÑ:", canOrder); 1670 1671 // еÑли нÑжно запÑеÑиÑÑ 1672 if (!canOrder) { 1673 const html = ` 1674 <div class="win-close" onclick="closeFlyWindow();"></div> 1675 <img src="../images/errrrrr.jpg" /> 1676 <h2 style="text-align: center;">ÐбÑаÑиÑе внимание</h2> 1677 <p style="text-align: center;"> 1678 Ðнлайн пÑодажа на ÑÑо вÑÐµÐ¼Ñ Ñже закÑÑÑа. ÐÑбеÑиÑе дÑÑгое вÑÐµÐ¼Ñ Ð¸Ð»Ð¸ ÑвÑжиÑеÑÑ Ñ Ð½Ð°Ð¼Ð¸ по ÑелеÑонÑ: <a class="phone" href="tel:89990443323">+7 (999) 044-33-23</a> 1679 </p> 1680 <button onclick="closeFlyWindow('user-data');">ÐÑбÑаÑÑ Ð²ÑемÑ</button>`; 1681 1682 createFlyWindow(html); 1683 return false; 1684 } 1685 1686 1687 let all_t_count = recalcSum(); 1688 if(!valid){ 1689 const html = ` 1690 <div class="win-close" onclick="closeFlyWindow();"></div> 1691 <img src="../images/errrrrr.jpg" /> 1692 <h2 style="text-align: center;">ÐбÑаÑиÑе внимание</h2> 1693 <p style="text-align: center;"> 1694 ÐаполниÑе ÐаÑи конÑакÑнÑе даннÑе.<br> ÐбÑаÑиÑе внимание на подÑказки ÑайÑа, ÑказаннÑе в полÑÑ . 1695 </p> 1696 <button onclick="closeFlyWindow('user-data');">ÐÑпÑавиÑÑ</button>`; 1697 1698 createFlyWindow(html); 1699 return false; 1700 } else if (!all_t_count) { 1701 const html = ` 1702 <div class="win-close" onclick="closeFlyWindow();"></div> 1703 <img src="../images/errrrrr.jpg" /> 1704 <h2 style="text-align: center;">ÐбÑаÑиÑе внимание</h2> 1705 <p style="text-align: center;"> 1706 ÐÑ Ð½Ðµ вÑбÑали колиÑеÑÑво билеÑов!<br>ÐоÑеÑение ÑкÑкÑÑÑии пÑоводиÑÑÑ Ð¿Ð¾ заÑанее забÑониÑованнÑм меÑÑам. 1707 </p> 1708 <button onclick="closeFlyWindow('booking-tcount');">ÐÑбÑаÑÑ Ð±Ð¸Ð»ÐµÑÑ</button>`; 1709 1710 createFlyWindow(html); 1711 return false; 1712 } else { 1713 const html = `<div class="win-close" onclick="closeFlyWindow();"></div> 1714 <div class='msg'> 1715 <div id='ajax'> 1716 <div class='loader_a'></div> 1717 <div class='loader_b'></div> 1718 </div> 1719 <p>ÐеÑенапÑавление на плаÑеж ...</p> 1720 </div>`; 1721 createFlyWindow(html); 1722 } 1723 1724 const pixel = (tour_id, cost) => { 1725 _tmr.push({ type: 'reachGoal', id: 3318706, value: cost, goal: 'purchase', params: { product_id: tour_id } }); 1726 }; 1727 pixel(form.querySelector("input[name=id_tour]").value, form.querySelector("input[name=pay_sum]").value); 1728 1729 const urlObj = new URL(window.location.href); 1730 const title_en = urlObj.pathname.split('/').pop(); // ÐолÑÑаем Ð¸Ð¼Ñ ÑÑÑа 1731 1732 document.body.style.cursor = "progress"; 1733 var saveData = new FormData(form); 1734 1735 saveData.append("data", "order"); 1736 saveData.append("title_en", title_en); 1737 1738 postData("../user/saveData.php", saveData).then(response => { 1739 if (!response.ok) { 1740 const html = ` 1741 <div class="win-close" onclick="closeFlyWindow();"></div> 1742 <img src="../images/site-errror.jpg" /> 1743 <h2 style="text-align: center">Ðе полÑÑаеÑÑÑ ÐºÑпиÑÑ</h2> 1744 <p>${response.error || response}</p> 1745 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 1746 `; 1747 createFlyWindow(html); 1748 } else { 1749 window.location.href = response.href; 1750 } 1751 }); 1752 1753 break; 1754 1755 case "send-callbackQuery": 1756 1757 form = document.callbackQuery; 1758 inputs = form.querySelectorAll("input"); 1759 1760 valid = true; 1761
1762 inputs.forEach(input => { 1763 if (!Validator.validate(input)) { 1764 valid = false; 1765 } 1766 }); 1767 1768 if(!valid){ 1769 return false; 1770 } 1771 1772 uphone_value = form.user_phone.value; 1773 1774 fd = new FormData(form); 1775 fd.append("data", "send_callbackQuery"); 1776 1777 const html = `<div class="win-close" onclick="closeFlyWindow();"></div> 1778 <div class='msg'> 1779 <div id='ajax'> 1780 <div class='loader_a'></div> 1781 <div class='loader_b'></div> 1782 </div> 1783 <p>ÐÑпÑавка ÑообÑÐµÐ½Ð¸Ñ ...</p> 1784 </div>`; 1785 createFlyWindow(html); 1786 1787 postData("../user/saveData.php", fd).then(response => { 1788 try { 1789 if (response.ok) { 1790 const flyWindow = ` 1791 <div class="win-close" onclick="closeFlyWindow();"></div> 1792 <img src="../images/zvonok1.jpg" /> 1793 <h2 style="text-align: center;">СпаÑибо за обÑаÑение</h2> 1794 <p style="text-align: center;"> 1795 СпаÑибо за ÐаÑÑ Ð·Ð°ÑвкÑ, Ð¼Ñ Ð¿ÐµÑезвоним Ðам на Ð½Ð¾Ð¼ÐµÑ 1796 <span style="display: block; text-align: center; font-size: 1.5em; color: #fd736c; margin: 0.5em;"> 1797 ${uphone_value} 1798 </span> 1799 в ближайÑее вÑемÑ. 1800 </p> 1801 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 1802 `; 1803 createFlyWindow(flyWindow); 1804 } else { 1805 const flyWindow = ` 1806 <div class="win-close" onclick="closeFlyWindow();"></div> 1807 <img src="../images/site-errror.jpg" /> 1808 <p style="text-align: center;"> 1809 <p>ÐÑибка оÑпÑавки ÑообÑениÑ: ${response}</p> 1810 </p> 1811 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 1812 `; 1813 createFlyWindow(flyWindow); 1814 } 1815 } catch (err) { 1816 console.error("call_back " + response, err); 1817 } 1818 1819 }); 1820 1821 break; 1822 1823 case "send_wish": 1824 1825 form = document.callbackWhish; 1826 inputs = form.querySelectorAll("input"); 1827 1828 valid = true; 1829 1830 inputs.forEach(input => { 1831 if (!Validator.validate(input)) { 1832 valid = false; 1833 } 1834 }); 1835 1836 if(!valid){ 1837 return false; 1838 } 1839 1840 uphone_value = form.user_phone.value; 1841 1842 fd = new FormData(form); 1843 fd.append("data", "send_wish"); 1844 1845 const w_html = `<div class="win-close" onclick="closeFlyWindow();"></div> 1846 <div class='msg'> 1847 <div id='ajax'> 1848 <div class='loader_a'></div> 1849 <div class='loader_b'></div> 1850 </div> 1851 <p>ÐÑпÑавлÑем запÑÐ¾Ñ ...</p> 1852 </div>`; 1853 createFlyWindow(w_html); 1854 1855 postData("../user/saveData.php", fd).then(response => { 1856 try { 1857 if (response.ok) { 1858 const flyWindow = ` 1859 <div class="win-close" onclick="closeFlyWindow();"></div> 1860 <img src="../images/zvonok1.jpg" /> 1861 <h2 style="text-align: center;">СпаÑибо за обÑаÑение</h2> 1862 <p style="text-align: center;"> 1863 СпаÑибо за ÐаÑÑ Ð·Ð°ÑвкÑ, Ð¼Ñ Ð¿ÐµÑезвоним Ðам на Ð½Ð¾Ð¼ÐµÑ 1864 <span style="display: block; text-align: center; font-size: 1.5em; color: #fd736c; margin: 0.5em;"> 1865 ${uphone_value} 1866 </span> 1867 в ближайÑее вÑемÑ. 1868 </p> 1869 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 1870 `; 1871 createFlyWindow(flyWindow); 1872 document.callbackWhish.reset(); 1873 } else { 1874 const flyWindow = ` 1875 <div class="win-close" onclick="closeFlyWindow();"></div> 1876 <img src="../images/site-errror.jpg" /> 1877 <p style="text-align: center;"> 1878 <p>ÐÑибка оÑпÑавки ÑообÑениÑ: ${response}</p> 1879 </p> 1880 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 1881 `; 1882 createFlyWindow(flyWindow); 1883 } 1884 } catch (err) { 1885 console.error("call_back " + response, err); 1886 } 1887 1888 }); 1889 1890 break; 1891 1892 case "send-callback": 1893 1894 form = document.callback; 1895 const cb__phone = document.querySelector("input[name=callback_uphone]"); 1896 uphone_value = cb__phone.value; 1897 1898 valid = true; 1899 if(!Validator.validate(cb__phone)){ 1900 valid = false; 1901 } 1902 1903 if(!valid){ 1904 return false; 1905 } 1906 1907 var formData = new FormData(form); 1908 formData.append("data", "call_back"); 1909 1910 const cb_html = `<div class="win-close" onclick="closeFlyWindow();"></div> 1911 <div class='msg'> 1912 <div id='ajax'> 1913 <div class='loader_a'></div> 1914 <div class='loader_b'></div> 1915 </div> 1916 <p>ÐÑпÑавлÑем запÑÐ¾Ñ ...</p> 1917 </div>`; 1918 createFlyWindow(cb_html); 1919 1920 postData("../user/saveData.php", formData).then(response => { 1921 try { 1922 if (response.ok) { 1923 const html = ` 1924 <div class="win-close" onclick="closeFlyWindow();"></div> 1925 <img src="../images/zvonok1.jpg" /> 1926 <h2 style="text-align: center;">СпаÑибо за обÑаÑение</h2> 1927 <p style="text-align: center;"> 1928 ÐÑ Ð¿ÐµÑезвоним Ðам на номеÑ
1929 <span style="display: block; text-align: center; font-size: 1.5em; color: #fd736c; margin: 0.5em;"> 1930 ${uphone_value} 1931 </span> 1932 в ближайÑее вÑемÑ. 1933 </p> 1934 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 1935 `; 1936 createFlyWindow(html); 1937 } else { 1938 const flyWindow = ` 1939 <div class="win-close" onclick="closeFlyWindow();"></div> 1940 <img src="../images/site-errror.jpg" /> 1941 <p style="text-align: center;"> 1942 <p>ÐÑибка оÑпÑавки ÑообÑениÑ: ${response}</p> 1943 </p> 1944 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 1945 `; 1946 createFlyWindow(flyWindow); 1947 } 1948 } catch (err) { 1949 console.error("call_back " + response, err); 1950 } 1951 }); 1952 1953 break; 1954 1955 case "reit": 1956 1957 var formReit = document.querySelector("form[name=reit]"); 1958 var uphone = formReit.querySelector("input[name=uphone]").value; 1959 var uname = formReit.querySelector("input[name=uname]").value; 1960 var responseText = formReit.querySelector(`[name="response"]`).value; 1961 1962 if (uname.length === 0) { 1963 alert("ÐожалÑйÑÑа ÑкажиÑе ÐаÑе имÑ"); 1964 formReit.querySelector("input[name=uname]").focus(); 1965 return; 1966 } 1967 1968 if (responseText.length === 0) { 1969 alert("ÐожалÑйÑÑа напиÑиÑе ÐÐ°Ñ Ð¾ÑзÑв."); 1970 formReit.querySelector("input[name=response]").focus(); 1971 return; 1972 } 1973 1974 if (uphone.length !== 0) { 1975 if (!/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,4})+$/.test(uphone)) { 1976 if (!/^[\+\d\s]{0,3}\({0,1}\d{3,4}[\)\s]{0,2}[\d\-\s]{7,10}$/.test(uphone)) { 1977 alert("ÐожалÑйÑÑа введиÑе e-mail или конÑакÑнÑй ÑелеÑон."); 1978 formReit.querySelector("input[name=uphone]").focus(); 1979 return; 1980 } 1981 } 1982 } else { 1983 alert("ÐожалÑйÑÑа введиÑе e-mail или конÑакÑнÑй ÑелеÑон."); 1984 formReit.querySelector("input[name=uphone]").focus(); 1985 return; 1986 } 1987 1988 var saveDataReit = new FormData(formReit); 1989 saveDataReit.append("data", "reit"); 1990 1991 postData("../user/saveData.php", saveDataReit).then(response => { 1992 if (response.ok) { 1993 const html = ` 1994 <div class="win-close" onclick="closeFlyWindow();"></div> 1995 <img src="../images/box-faq-image.webp" /> 1996 <h2 style="text-align: center;">СпаÑибо за ÐÐ°Ñ Ð¾ÑзÑв</h2> 1997 <p style="text-align: center;"> 1998 ÐÑ Ð±Ð»Ð°Ð³Ð¾Ð´Ð°ÑнÑ, ÑÑо ÐÑ Ð¿Ð¾Ð·Ð²Ð¾Ð»ÑеÑе ÑделаÑÑ Ð½Ð°Ñи ÑкÑкÑÑÑии лÑÑÑе. ÐÑзÑв бÑÐ´ÐµÑ Ð¾Ð¿Ñбликован поÑле модеÑаÑии. 1999 </p> 2000 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 2001 `; 2002 createFlyWindow(html); 2003 formReit.reset(); 2004 } else { 2005 const flyWindow = ` 2006 <div class="win-close" onclick="closeFlyWindow();"></div> 2007 <img src="../images/site-errror.jpg" /> 2008 <p style="text-align: center;"> 2009 <p>ÐÑибка оÑпÑавки ÑообÑениÑ: ${response}</p> 2010 </p> 2011 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 2012 `; 2013 createFlyWindow(flyWindow); 2014 } 2015 }); 2016 2017 break; 2018 2019 } 2020 2021 2022} 2023function fillOptionList(list) { 2024 switch (list) { 2025 case "place": 2026 const region = document.querySelector("form[name=tour_filters] input[name=region]").value; 2027 2028 const fd = new FormData(); 2029 fd.append("data_type", "option_list"); 2030 fd.append("list", list); 2031 fd.append("region", region); 2032 2033 postData("../user/getAjaxData.php", fd, false, "GET").then(response => { 2034 const select_place = document.querySelector("form[name=tour_filters] select[name=place]"); 2035 if (!select_place) return; 2036 2037 // оÑиÑÑиÑÑ ÑÑаÑÑе option 2038 select_place.innerHTML = ""; 2039 2040 // добавиÑÑ "ÐÑе доÑÑопÑимеÑаÑелÑноÑÑи"
2041 const optAll = document.createElement("option"); 2042 optAll.textContent = "ÐÑе доÑÑопÑимеÑаÑелÑноÑÑи"; 2043 optAll.value = "all"; 2044 optAll.selected = true; 2045 select_place.appendChild(optAll); 2046 2047 // добавиÑÑ Ð¾ÑÑалÑнÑе 2048 try { 2049 console.log("fillOptionList JSON:", response); 2050 const data = JSON.parse(response); 2051 data.forEach(value => { 2052 const opt = document.createElement("option"); 2053 opt.textContent = value[1]; 2054 opt.value = value[0]; 2055 select_place.appendChild(opt); 2056 }); 2057 } 2058 catch (err) { 2059 console.error("fillOptionList error", err); 2060 } 2061 }); 2062 break; 2063 } 2064} 2065function createFlyWindow(htmlInside, reload = false) { 2066 2067 OPTIONS.reload = reload; 2068 OPTIONS.justOpenedWindow = true; 2069 let winDiv = document.querySelector(".window"); 2070 2071 if (!winDiv) { 2072 const bgHeight = document.documentElement.scrollHeight + "px"; 2073 const winBg = document.createElement("div"); 2074 winBg.classList.add("win-bg"); 2075 winBg.style.height = bgHeight; 2076 document.body.appendChild(winBg); 2077 winBg.classList.add("visible"); 2078 2079 winDiv = document.createElement("div"); 2080 winDiv.classList.add("window"); 2081 document.body.appendChild(winDiv); 2082 } 2083 2084 const flyWindow = ` 2085 <div class="win-close" onclick="closeFlyWindow();"></div> 2086 ${htmlInside}`; 2087 winDiv.innerHTML = flyWindow; 2088 2089 if (!winDiv.classList.contains("visible")) { 2090 winDiv.classList.add("visible"); 2091 } 2092 2093 // ÑбÑаÑÑваем Ñлаг поÑле завеÑÑÐµÐ½Ð¸Ñ ÑекÑÑего Ñикла ÑобÑÑий 2094 setTimeout(() => { 2095 OPTIONS.justOpenedWindow = false; 2096 }, 0); 2097} 2098 2099function closeFlyWindow(scroll_hash = "") { 2100 const winDiv = document.querySelector("div.window"); 2101 const winBg = document.querySelector("div.win-bg"); 2102 2103 if (winDiv) { 2104 winDiv.remove(); 2105 } 2106 2107 if (winBg) { 2108 winBg.remove(); 2109 } 2110 2111 // СкÑолим, еÑли Ñказали кÑда 2112 if (scroll_hash.length != 0) { 2113 scrollToAnchor(scroll_hash); 2114 } 2115 // ÐеÑегÑÑжаем, еÑли Ñказано 2116 if (OPTIONS.reload) { 2117 window.location.reload(); 2118 } 2119} 2120async function postData(func, formData = null, json = true, method = "POST") { 2121 let options = { method }; 2122 2123 if (method === "POST" && formData) { 2124 options.body = formData; 2125 } 2126 2127 if (method === "GET" && formData) { 2128 const params = new URLSearchParams(formData).toString(); 2129 func += (func.includes("?") ? "&" : "?") + params; 2130 } 2131 2132 const response = await fetch(func, options); 2133 const text = await response.text(); 2134 2135 if (json) { 2136 try { 2137 return JSON.parse(text); 2138 } catch (err) { 2139 console.error("ÐÑибка паÑÑинга JSON:", err, "СÑÑой оÑвеÑ:", text); 2140 return text; // возвÑаÑаем ÑÑÑокÑ, ÑÑÐ¾Ð±Ñ Ð½Ðµ ÑеÑÑÑÑ Ð²Ñполнение 2141 } 2142 } 2143 2144 return text; 2145} 2146 2147 2148function getCookie(name) { 2149 let cookies = document.cookie.split("; "); 2150 for (let c of cookies) { 2151 let [key, value] = c.split("="); 2152 if (key === name) return decodeURIComponent(value); 2153 } 2154 return undefined; 2155} 2156function checkCookie() { 2157 document.cookie = "userCookie=check; path=/; max-age=3600"; 2158 let cBlock = document.querySelector("div#cookieBlock"); 2159 cBlock.style.display = "none"; 2160} 2161async function load_lazy_scripts() { 2162 2163 if (lazyScriptsLoaded) return; 2164 lazyScriptsLoaded = true; 2165 2166 const scripts = await postData("/user/lazy_scripts.php", new FormData(), true); 2167 2168 scripts.forEach(item => { 2169 2170 let code = item.code ? decodeHtml(item.code) : ""; 2171 2172 // пÑопÑÑкаем каÑÑÑ ÐµÑли не tour 2173 if (!window.location.pathname.startsWith("/tour") && code.includes("api-maps")) { 2174 return; 2175 } 2176 2177 // внеÑний src 2178 if (item.src) { 2179 2180 if ([...document.scripts].some(s => s.src === item.src)) { 2181 return; 2182 } 2183 2184 const s = document.createElement("script"); 2185 s.src = item.src; 2186 s.async = true; 2187 document.head.appendChild(s); 2188 2189 } 2190 2191 // inline 2192 else if (code) { 2193 2194 // заÑиÑа Ð¾Ñ Ð¿Ð¾Ð²ÑоÑной вÑÑавки 2195 if (document.body.innerHTML.includes(code.substring(0,50))) { 2196 return; 2197 } 2198 2199 injectCode(code); 2200 2201 } 2202 2203 }); 2204 2205} 2206 2207function injectCode(html) { 2208 const parser = new DOMParser(); 2209 const doc = parser.parseFromString(html, "text/html"); 2210 2211 doc.querySelectorAll("script").forEach(scr => { 2212 const s = document.createElement("script"); 2213 if (scr.src) {
2214 s.src = scr.src.trim(); // важно: ÑбÑаÑÑ Ð¿ÑобелÑ! 2215 s.async = true; 2216 } else { 2217 s.textContent = scr.textContent; 2218 } 2219 document.head.appendChild(s); // head пÑедпоÑÑиÑелÑнее Ð´Ð»Ñ Ð¼ÐµÑÑик 2220 }); 2221} 2222function decodeHtml(html) { 2223 const txt = document.createElement("textarea"); 2224 txt.innerHTML = html; 2225 return txt.value; 2226} 2227function toHex(bytes) { 2228 return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join(' '); 2229} 2230const observer = new IntersectionObserver(entries => { 2231 entries.forEach(entry => { 2232 if (entry.isIntersecting) { 2233 const el = entry.target; 2234 el.style.backgroundImage = `url(${el.dataset.bg})`; 2235 observer.unobserve(el); 2236 } 2237 }); 2238}); 2239 2240document.querySelectorAll('.lazy-bg').forEach(el => { 2241 observer.observe(el); 2242}); 2243 2244function FeedBackSlider() { 2245 const s = document.querySelector('.box-reviews__slider'); 2246 const b = document.querySelector('.box-reviews__block'); 2247 if (!s) return; 2248 const w = s.querySelector('.box-reviews__wrapper'), 2249 prev = b.querySelector('.box-reviews__prev'), 2250 next = b.querySelector('.box-reviews__next'), 2251 slides = s.querySelectorAll('.box-reviews__slide'); 2252 2253 let i = 0, per = 3, startX = 0, isDrag = false; 2254 2255 const getPer = () => window.innerWidth < 768 ? 1 : window.innerWidth < 1200 ? 2 : 3; 2256 2257 const move = () => { 2258 const slideEl = slides[0]; 2259 2260 if (!slideEl) return; 2261 2262 const wrapperStyle = getComputedStyle(w); 2263 2264 // ÐеÑÑм gap из wrapper (еÑли иÑполÑзÑеÑÑÑ) 2265 const gap = parseInt(wrapperStyle.gap) || 0; 2266 2267 // ÐÐ¾Ð»Ð½Ð°Ñ ÑиÑина Ñага: Ñлайд + оÑÑÑÑп поÑле него 2268 const slideWidthPx = slideEl.offsetWidth; 2269 const stepWidth = slideWidthPx + gap; 2270 2271 w.style.transform = `translateX(-${i * stepWidth}px)`; 2272 }; 2273 2274 const update = () => { 2275 per = getPer(); 2276 i = Math.min(i, Math.max(0, slides.length - per)); 2277 move(); 2278 }; 2279 2280 prev?.addEventListener('click', () => { 2281 if (i > 0) { i--; move(); } 2282 }); 2283 2284 next?.addEventListener('click', () => { 2285 const maxI = Math.max(0, slides.length - per); 2286 if (i < maxI) { i++; move(); } 2287 }); 2288 2289 // Touch/Mouse swipe 2290 const onS = (e) => { 2291 startX = e.touches?.[0]?.clientX ?? e.clientX; 2292 isDrag = true; 2293 }; 2294 2295 const onM = (e) => { 2296 if (!isDrag) return; 2297 const x = e.touches?.[0]?.clientX ?? e.clientX; 2298 const diff = startX - x; 2299 if (Math.abs(diff) > 50) { 2300 const maxI = Math.max(0, slides.length - per); 2301 if (diff > 0 && i < maxI) { i++; move(); } 2302 else if (diff < 0 && i > 0) { i--; move(); } 2303 isDrag = false; 2304 } 2305 }; 2306 2307 const onE = () => isDrag = false; 2308 2309 s.addEventListener('touchstart', onS, { passive: true }); 2310 s.addEventListener('touchmove', onM, { passive: true }); 2311 s.addEventListener('touchend', onE); 2312 s.addEventListener('mousedown', onS); 2313 s.addEventListener('mousemove', onM); 2314 s.addEventListener('mouseup', onE); 2315 s.addEventListener('mouseleave', onE); 2316 2317 window.addEventListener('resize', update); 2318 update(); 2319} 2320function bindEvents() { 2321 2322 if (document._myEventsBound) return; 2323 document._myEventsBound = true; 2324 2325 // ÐÑивÑзÑваем обÑабоÑÑики ÑобÑÑий ко вÑÐµÐ¼Ñ Ð´Ð¾ÐºÑменÑÑ 2326 Object.keys(eventHandlers).forEach((eventType) => { 2327 document.addEventListener(eventType, (event) => { 2328 2329 // Ðнопки +- на билеÑÐ°Ñ 2330 const cmdsPlus = event.target.closest(".quantity__button.quantity__button--plus"); 2331 if (cmdsPlus) { 2332 let input = cmdsPlus.closest("[data-quantity]").querySelector("input[name^=tickets]"); 2333 input.value++; 2334 recalcSum(); 2335 } 2336 2337 const cmdsMinus = event.target.closest(".quantity__button.quantity__button--minus"); 2338 if (cmdsMinus) { 2339 let input = cmdsMinus.closest("[data-quantity]").querySelector("input[name^=tickets]"); 2340 input.value--; 2341 if (input.value < 0) input.value = 0; 2342 recalcSum(); 2343 } 2344 2345 // ÐÑем ближайÑий ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ñ Ð°ÑÑибÑÑом data-run-script="true" 2346 const targetElement = event.target.closest('[data-run-script="true"]'); 2347 if (!targetElement) return; 2348 2349 // ÐÑовеÑÑем, ÑооÑвеÑÑÑвÑÐµÑ Ð»Ð¸ ÑекÑÑий Ñип ÑобÑÑÐ¸Ñ Ð¾Ð¶Ð¸Ð´Ð°ÐµÐ¼Ð¾Ð¼Ñ 2350 const dataEvent = (targetElement.dataset.event || 'click').split(/\s+/).map(e => e.trim()); 2351 2352 if (!dataEvent.includes(eventType)) return; 2353 eventHandlers[eventType](event, targetElement); 2354 2355 }, true); 2356 }); 2357} 2358// ÐбÑÐµÐºÑ Ð´Ð»Ñ Ñ ÑÐ°Ð½ÐµÐ½Ð¸Ñ ÑобÑÑий и Ð¸Ñ Ð¾Ð±ÑабоÑÑиков 2359const eventHandlers = { 2360 click: handleBindEvents, 2361}; 2362function handleBindEvents(event, element) { 2363 2364 let template, clone, form; 2365 2366 try { 2367 const scriptData = element.dataset.script; 2368 if (!scriptData) { 2369 console.error('ÐÐ»ÐµÐ¼ÐµÐ½Ñ Ð½Ðµ ÑодеÑÐ¶Ð¸Ñ data-script'); 2370 return; 2371 } 2372 2373 const { script, param } = JSON.parse(decodeURIComponent(scriptData)); 2374 2375 switch (script) { 2376 2377 case ("logoff"): 2378 2379 event.preventDefault(); 2380 2381 let logofData = new FormData(); 2382 logofData.append("data", "p_logoff"); 2383 2384 postData("../user/saveData.php", logofData).then(response => { 2385 if (response.ok) { 2386 window.location.reload(); 2387 } 2388 }); 2389 2390 break; 2391 2392 case ("login"): 2393 2394 let loginForm = document.logon; 2395 let inputs = loginForm.querySelectorAll("input"); 2396 2397 let valid = true; 2398
2399 inputs.forEach(input => { 2400 if (!Validator.validate(input)) { 2401 valid = false; 2402 } 2403 }); 2404 2405 if(!valid){ 2406 return false; 2407 } 2408 2409 let logonData = new FormData(loginForm); 2410 logonData.append("data", "p_logon"); 2411 2412 postData("../user/saveData.php", logonData).then(response => { 2413 if (!response.ok) { 2414 const html = ` 2415 <div class="win-close" onclick="closeFlyWindow();"></div> 2416 <img src="../images/site-errror.jpg" /> 2417 <h2 style="text-align: center">ÐÑибка Ð²Ñ Ð¾Ð´Ð°</h2> 2418 <p>${response.message || response}</p> 2419 <button onclick="closeFlyWindow();">ХоÑоÑо</button> 2420 `; 2421 createFlyWindow(html); 2422 } else { 2423 window.location.reload(); 2424 } 2425 }); 2426 2427 break; 2428 2429 case ("parthner-logon"): 2430 2431 // Ðкно Ð²Ñ Ð¾Ð´Ñ Ð´Ð»Ñ Ð¿Ð°ÑÑнеÑов 2432 event.preventDefault(); 2433 2434 let logon = ` 2435 <form name="logon" onsubmit="return false;"><div class="logon"> 2436 <label>Ðогин 2437 <div class="field"> 2438 <input class="bottom-booking__input" type="text" name="login" value="" data-required data-validate-text="Ðоле обÑзаÑелÑное"> 2439 </div> 2440 </label> 2441 <label>ÐаÑÐ¾Ð»Ñ 2442 <div class="field"> 2443 <input class="bottom-booking__input" name="password" type="password" value="" data-required data-validate-text="Ðоле обÑзаÑелÑное"> 2444 </div> 2445 </label> 2446 <button data-run-script="true" data-script="%7B%22script%22%3A%22login%22%2C%22param%22%3A%7B%7D%7D">ÐÑ Ð¾Ð´</button> 2447 </div></form>`; 2448 2449 createFlyWindow(logon); 2450 2451 break; 2452 2453 case ("check_personalData"): 2454 2455 // ÐÑовеÑÑем, ÑÑо клик по ÑÑÑлке 2456 let link = event.target.closest('a'); 2457 if (link) { 2458 event.preventDefault(); 2459 let href = link.getAttribute("href"); 2460 window.open(href); 2461 return; 2462 } 2463 2464 // ÐÑÐ¸Ð½Ð¸Ð¼Ð°Ñ 2465 let checkPD = event.target.closest("div").querySelector("input[type=checkbox]"); 2466 2467 if (checkPD) { 2468 let cmd = checkPD.closest(".box-body").querySelector("button"); 2469 if (checkPD.checked) { 2470 cmd.disabled = false; 2471 } else { 2472 cmd.disabled = true; 2473 } 2474 } 2475 2476 break; 2477 2478 case ("show-feedback"): 2479 2480 let article = ` 2481 <div class="win-close" onclick="closeFlyWindow();"></div> 2482 <p>${param.user_name}</p> 2483 <div class="box-reviews__rating"> 2484 <div class="box-reviews__stars">${drawRatingStars(param.reit)}</div> 2485 <div class="box-reviews__value">${param.reit}</div> 2486 </div> 2487 <p>${param.article}</p> 2488 <button onclick="closeFlyWindow();">ÐакÑÑÑÑ</button>`; 2489 2490 createFlyWindow(article); 2491 break; 2492 2493 case ("reserve"): 2494 2495 event.preventDefault(); 2496 saveData("reserve"); 2497 2498 break; 2499 2500 case ("gotoBank"): 2501 2502 event.preventDefault(); 2503 saveData("order"); 2504 2505 break; 2506 2507 case ("callbackQuery"): 2508 2509 event.preventDefault(); 2510 template = document.getElementById('callbackForm'); 2511 clone = template.content.cloneNode(true); 2512 form = clone.querySelector('form'); 2513 createFlyWindow(form.outerHTML); 2514 2515 break; 2516 2517 case ("send-wish"): 2518 2519 event.preventDefault(); 2520 saveData("send_wish"); 2521 2522 break; 2523 2524 case ("send-callback"): 2525 case ("send-callbackQuery"): 2526 2527 event.preventDefault(); 2528 saveData(script); 2529 2530 break; 2531 2532 case ("callback"): 2533 2534 event.preventDefault(); 2535 template = document.getElementById('callback'); 2536 clone = template.content.cloneNode(true); 2537 form = clone.querySelector('form'); 2538 createFlyWindow(form.outerHTML); 2539 2540 break; 2541 2542 case ("scroll-article"): 2543 // СкÑолим пÑи ÑвоÑаÑивании ÑÑаÑÑи до видимоÑÑи кнопки 2544 let check = document.querySelector(param.checkbox).checked; 2545 2546 if (check) { 2547 setTimeout(() => { 2548 let cmd = document.querySelector(".box-program"); 2549 let coo = cmd.getBoundingClientRect(); 2550 2551 window.scrollTo({ 2552 top: window.scrollY + coo.top + coo.height - 800, 2553 behavior: "smooth" 2554 }); 2555 }, 100); 2556 } 2557 2558 break; 2559 2560 case "setDate": 2561 2562 // еÑли Ñ Ð½Ð°Ñ Ð²ÑÐµÐ¼Ñ Ð²ÑклÑÑено, Ñо ниÑего не делаем 2563 if (element.classList.contains("disabled_date")) { 2564 return false; 2565 } 2566 2567 const foreng = document.querySelector("input[name=foreng]"); 2568 const id_time = document.querySelector("input[name=id_time]"); 2569 const datePlace = document.querySelector("#itog_data"); 2570 const timePlace = document.querySelector("#itog_time"); 2571 const startPoint = document.querySelector("#itog_startpoint"); 2572 2573 const timeBlocksUp = document.querySelector("#thisStartPointUp"); 2574 const timeBlocksDown = document.querySelector("#thisStartPointDown"); 2575 2576 const crossBlocksUp = document.querySelector("#crossStartPointUp"); 2577 const crossBlocksDown = document.querySelector("#crossStartPointDown"); 2578 2579 const dateSpInput = document.querySelector("input[name=sp_time]"); 2580 const strtPointInput = document.querySelector("input[name=start_point]"); 2581 2582 const transp = document.querySelector("input[name=transp]"); 2583 const close_time_minutes = document.querySelector("input[name=close_time_minutes]"); 2584 2585 const spBlock = element.closest("div[data-startpoint]"); 2586 2587 const fullPayInput = document.querySelectorAll("input[name=fullPay]"); 2588 const options__item = document.querySelectorAll(".options__item"); 2589 2590 dateSpInput.value = param.date; 2591 strtPointInput.value = spBlock.dataset.startpoint; 2592 startPoint.textContent = spBlock.dataset.startpoint; 2593 id_time.value = param.id; 2594 transp.value = spBlock.dataset.transp; 2595 close_time_minutes.value = spBlock.dataset.closetime; 2596 2597 let updateMap = false; 2598 //ÐлÑÑ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ°ÑÑÑ 2599 if (foreng.value != param.foreng) { 2600 updateMap = true; 2601 } 2602 foreng.value = param.foreng; 2603 2604 let picketDate = new Date(param.date); 2605
2606 datePlace.textContent = picketDate.toLocaleString('ru-RU', { 2607 day: '2-digit', 2608 month: '2-digit', 2609 year: 'numeric' 2610 }); 2611 2612 timePlace.textContent = picketDate.toLocaleString('ru-RU', { 2613 hour: '2-digit', 2614 minute: '2-digit' 2615 }); 2616 2617 if (param.foreng == 0) { 2618 if (fullPayInput.length != 0) { 2619 fullPayInput[0].checked = true; 2620 options__item[1].style.display = "block"; 2621 } 2622 2623 // УдалиÑÑ Ð²Ñе меÑки вÑемени на внеÑней ÑоÑке 2624 if (crossBlocksDown) { 2625 [crossBlocksUp, crossBlocksDown].forEach(timeBlock => { 2626 let timeCmds = timeBlock.querySelectorAll("button"); 2627 if (timeCmds) { 2628 timeCmds.forEach(timeCmd => { 2629 timeCmd.classList.remove("selected_date"); 2630 }); 2631 } 2632 }); 2633 } 2634 2635 // СделаÑÑ Ð¼ÐµÑÐºÑ Ð²Ñемени 2636 if (timeBlocksUp) { 2637 [timeBlocksUp, timeBlocksDown].forEach(timeBlock => { 2638 let timeCmds = timeBlock.querySelectorAll("button"); 2639 if (timeCmds) { 2640 timeCmds.forEach(timeCmd => { 2641 if (timeCmd.dataset.timeid == param.id) { 2642 timeCmd.classList.add("selected_date"); 2643 } else { 2644 timeCmd.classList.remove("selected_date"); 2645 } 2646 }); 2647 } 2648 }); 2649 } 2650 } else { 2651 if (fullPayInput.length != 0) { 2652 fullPayInput[0].checked = true; 2653 options__item[1].style.display = "none"; 2654 } 2655 if (timeBlocksUp) { 2656 [timeBlocksUp, timeBlocksDown].forEach(timeBlock => { 2657 let timeCmds = timeBlock.querySelectorAll("button"); 2658 if (timeCmds) { 2659 timeCmds.forEach(timeCmd => { 2660 timeCmd.classList.remove("selected_date"); 2661 }); 2662 } 2663 }); 2664 } 2665 2666 if (crossBlocksUp) { 2667 [crossBlocksUp, crossBlocksDown].forEach(timeBlock => { 2668 let timeCmds = timeBlock.querySelectorAll("button"); 2669 if (timeCmds) { 2670 timeCmds.forEach(timeCmd => { 2671 if (timeCmd.dataset.timeid == param.id) { 2672 timeCmd.classList.add("selected_date"); 2673 } else { 2674 timeCmd.classList.remove("selected_date"); 2675 } 2676 }); 2677 } 2678 }); 2679 } 2680 } 2681 2682 //Ðбновим каÑÑÑ Ð¿Ð¾ клÑÑÑ 2683 if (updateMap) { 2684 const ya_map_input = document.querySelector("input[name=ya_map]"); 2685 ya_map_input.value = spBlock.dataset.map; 2686 2687 // ÐÑеобÑазÑем кооÑдинаÑÑ Ð² маÑÑив 2688 let ya_map = spBlock.dataset.map.split(","); 2689 const lat = ya_map[0].trim(); 2690 const lon = ya_map[1].trim(); 2691 2692 let img = document.querySelector("img#static_ymap"); 2693 img.src = `https://static-maps.yandex.ru/1.x/?ll=${lon},${lat}&z=15&l=map&pt=${lon},${lat},pm2al&size=328,328`; 2694 2695 } 2696 2697 break; 2698 2699 } 2700 2701 } catch (error) { 2702 console.error('ÐÑибка обÑабоÑки командÑ:', error); 2703 } 2704} 2705 2706// наблÑдаем видимоÑÑÑ Ð±Ð»Ð¾ÐºÐ° покÑпки 2707const booking_block = document.querySelector('#booking'); 2708const scroll_observer = new IntersectionObserver((entries) => { 2709 2710 entries.forEach(entry => { 2711 2712 if(entry.isIntersecting){ 2713 OPTIONS.booking_block_visible = true; 2714 } else { 2715 OPTIONS.booking_block_visible = false; 2716 } 2717 2718 }); 2719 2720}, { 2721 threshold: 0.2 2722}); 2723 2724if (booking_block) { 2725 scroll_observer.observe(booking_block); 2726} 2727 2728function isVisible(el){ 2729 return el.offsetParent !== null; 2730} 2731function drawRatingStars(rating) { 2732 // ÐоÑмализÑем ÑейÑинг: ÑиÑло Ð¾Ñ 0 до 5 2733 rating = Math.max(0, Math.min(5, parseFloat(rating) || 0)); 2734 2735 const fullStars = Math.floor(rating); // Ð¦ÐµÐ»Ð°Ñ ÑаÑÑÑ (полнÑе звÑздÑ) 2736 const hasHalfStar = (rating - fullStars) > 0; // ÐÑÑÑ Ð»Ð¸ дÑÐ¾Ð±Ð½Ð°Ñ ÑаÑÑÑ 2737 const emptyStarsCount = 5 - Math.ceil(rating); // ÐÑÑÑÑе звÑÐ·Ð´Ñ Ð´Ð¾ 5 2738 2739 // УникалÑнÑй ID Ð´Ð»Ñ clipPath, ÑÑÐ¾Ð±Ñ Ð¸Ð·Ð±ÐµÐ¶Ð°ÑÑ ÐºÐ¾Ð½ÑликÑов пÑи множеÑÑвеннÑÑ Ð²ÑÐ·Ð¾Ð²Ð°Ñ 2740 const uniqueId = 'half-star-' + Math.random().toString(36).substr(2, 9); 2741 2742 let response = ''; 2743 2744 // SVG: Ð¿Ð¾Ð»Ð½Ð°Ñ Ð·Ð²ÐµÐ·Ð´Ð° 2745 const fullStarSVG = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 2746 <rect width="24" height="24" fill="white"/> 2747 <path d="M11.9998 17.75L5.82784 20.995L7.00684 14.122L2.00684 9.25495L8.90684 8.25495L11.9928 2.00195L15.0788 8.25495L21.9788 9.25495L16.9788 14.122L18.1578 20.995L11.9998 17.75Z" 2748 fill="#FFCC02" stroke="#FFCC02" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 2749 </svg>`; 2750 2751 // SVG: половина Ð·Ð²ÐµÐ·Ð´Ñ (Ñ clipPath) 2752 const halfStarSVG = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 2753 <defs> 2754 <clipPath id="${uniqueId}"> 2755 <rect x="0" y="0" width="12" height="24"/> 2756 </clipPath> 2757 </defs> 2758 <rect width="24" height="24" fill="white"/> 2759 <path d="M11.9998 17.75L5.82784 20.995L7.00684 14.122L2.00684 9.25495L8.90684 8.25495L11.9928 2.00195L15.0788 8.25495L21.9788 9.25495L16.9788 14.122L18.1578 20.995L11.9998 17.75Z" 2760 fill="none" stroke="#FFCC02" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 2761 <path d="M11.9998 17.75L5.82784 20.995L7.00684 14.122L2.00684 9.25495L8.90684 8.25495L11.9928 2.00195L15.0788 8.25495L21.9788 9.25495L16.9788 14.122L18.1578 20.995L11.9998 17.75Z" 2762 fill="#FFCC02" stroke="none" clip-path="url(#${uniqueId})"/> 2763 </svg>`; 2764 2765 // SVG: пÑÑÑÐ°Ñ Ð·Ð²ÐµÐ·Ð´Ð° 2766 const emptyStarSVG = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 2767 <rect width="24" height="24" fill="white"/> 2768 <path d="M11.9998 17.75L5.82784 20.995L7.00684 14.122L2.00684 9.25495L8.90684 8.25495L11.9928 2.00195L15.0788 8.25495L21.9788 9.25495L16.9788 14.122L18.1578 20.995L11.9998 17.75Z" 2769 fill="transparent" stroke="#FFCC02" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 2770 </svg>`; 2771 2772 // ÐобавлÑем полнÑе звÑÐ·Ð´Ñ 2773 for (let i = 0; i < fullStars; i++) { 2774 response += fullStarSVG; 2775 } 2776 2777 // ÐобавлÑем Ð¿Ð¾Ð»Ð¾Ð²Ð¸Ð½Ñ Ð·Ð²ÐµÐ·Ð´Ñ, еÑли еÑÑÑ Ð´ÑÐ¾Ð±Ð½Ð°Ñ ÑаÑÑÑ 2778 if (hasHalfStar) { 2779 response += halfStarSVG; 2780 } 2781 2782 // ÐобавлÑем пÑÑÑÑе звÑÐ·Ð´Ñ 2783 for (let i = 0; i < emptyStarsCount; i++) { 2784 response += emptyStarSVG; 2785 } 2786 2787 return response; 2788} 2789// ÐелегиÑование на document Ð´Ð»Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑкой валидаÑии полей 2790const ValidatorModule = (() => { 2791 document.addEventListener('blur', (e) => { 2792 const field = e.target; 2793 if (field.matches('input[data-validate-text]')) { 2794 Validator?.validate(field); 2795 } 2796 }, true); // true = capture phase, ÑÑÐ¾Ð±Ñ Ð»Ð¾Ð²Ð¸ÑÑ blur 2797 2798 return { 2799 // Ðожно добавиÑÑ Ð¼ÐµÑÐ¾Ð´Ñ Ð´Ð»Ñ Ð¿ÐµÑеиниÑиализаÑии 2800 reinit: () => { 2801 console.log('ÐалидаÑÐ¸Ñ Ð°ÐºÑивна Ð´Ð»Ñ Ð²ÑÐµÑ Ð¿Ð¾Ð»ÐµÐ¹, вклÑÑÐ°Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑкие'); 2802 } 2803 }; 2804})(); 2805function scrollToAnchor(id) { 2806 let more = 200; // ÐпÑÑÑиÑÑ Ð½ÐµÐ¼Ð½Ð¾Ð³Ð¾ ниже 2807 2808 const el = document.getElementById(id); 2809 if (!el) return; 2810 2811 const y = el.getBoundingClientRect().top + window.pageYOffset; 2812 2813 window.scrollTo({ 2814 top: y - more, 2815 behavior: 'smooth' 2816 });
vendor: 1 bytes, line 2817
2817}
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.