1document.addEventListener('DOMContentLoaded', function () { 2 const forms = document.querySelectorAll('header .jsSearchForm, .menu__search .jsSearchForm'); 3 const header = document.querySelector('header.header'); 4 const headerSearch = document.querySelector('.headerSearch'); 5 6 const menuHeader = document.querySelector('.menu__header'); 7 const menuSearch = document.querySelector('.menuSearch'); 8 9 const closeButtons = document.querySelectorAll('.jsSearchClose'); 10 11 let activeForm = null; 12 let activePanel = null; 13 let debounceTimer = null; 14 let currentXhr = null; 15 let currentItemsXhr = null; 16 let pointerDownInsideSearch = false; 17 18 function setHeaderHeightVar() { 19 if (!header) return; 20 21 document.documentElement.style.setProperty( 22 '--header-height', 23 header.offsetHeight + 'px' 24 ); 25 } 26 27 function setMenuHeaderHeightVar() { 28 if (!menuHeader) return; 29 30 document.documentElement.style.setProperty( 31 '--menu-header-height', 32 menuHeader.offsetHeight + 'px' 33 ); 34 } 35 36 function lockBodyScroll() { 37 document.body.classList.add('search-opened'); 38 } 39 40 function unlockBodyScroll() { 41 document.body.classList.remove('search-opened'); 42 } 43 44 function isSearchForm(form) { 45 return form && form.classList && form.classList.contains('jsSearchForm'); 46 } 47 48 function isAnySearchOpened() { 49 return Array.from(forms).some(function (form) { 50 const row = form.querySelector('.jsSearchRow'); 51 return row && row.classList.contains('is-open'); 52 }); 53 } 54 55 function getSearchContext(form) { 56 if (form.closest('.menu__search')) { 57 return { 58 panel: menuSearch, 59 loader: document.querySelector('.jsSearchLoaderMobile'), 60 itemsWrapper: menuSearch ? menuSearch.querySelector('.jsSearchItems') : null, 61 sectionsWrapper: menuSearch ? menuSearch.querySelector('.jsSearchSections') : null, 62 emptyBlock: menuSearch ? menuSearch.querySelector('.menuSearch__empty') : null, 63 popularBlock: menuSearch ? menuSearch.querySelector('.jsSearchPopular') : null, 64 resultsBlock: menuSearch ? menuSearch.querySelector('.jsSearchResults') : null, 65 moreLink: menuSearch ? menuSearch.querySelector('.menuSearch__more') : null, 66 totalCounter: menuSearch ? menuSearch.querySelector('.jsSearchTotal') : null, 67 }; 68 } 69 70 return { 71 panel: headerSearch, 72 loader: document.querySelector('.jsSearchLoader'), 73 itemsWrapper: headerSearch ? headerSearch.querySelector('.jsSearchItems') : null, 74 sectionsWrapper: headerSearch ? headerSearch.querySelector('.jsSearchSections') : null, 75 emptyBlock: headerSearch ? headerSearch.querySelector('.headerSearch__empty') : null, 76 popularBlock: headerSearch ? headerSearch.querySelector('.jsSearchPopular') : null, 77 resultsBlock: headerSearch ? headerSearch.querySelector('.jsSearchResults') : null, 78 moreLink: headerSearch ? headerSearch.querySelector('.headerSearch__more') : null, 79 totalCounter: headerSearch ? headerSearch.querySelector('.jsSearchTotal') : null, 80 }; 81 } 82 83 function showLoader(ctx) { 84 if (!ctx) return; 85 86 if (ctx.loader) ctx.loader.classList.add('is-visible'); 87 if (ctx.popularBlock) ctx.popularBlock.style.display = 'none'; 88 if (ctx.resultsBlock) ctx.resultsBlock.style.display = 'none'; 89 if (ctx.emptyBlock) ctx.emptyBlock.style.display = 'none'; 90 } 91 92 function showPopular(ctx) { 93 if (!ctx) return; 94 95 if (ctx.loader) ctx.loader.classList.remove('is-visible'); 96 if (ctx.popularBlock) ctx.popularBlock.style.display = ''; 97 if (ctx.resultsBlock) ctx.resultsBlock.style.display = 'none'; 98 if (ctx.emptyBlock) ctx.emptyBlock.style.display = 'none'; 99 } 100 101 function showEmpty(ctx) { 102 if (!ctx) return; 103 104 if (ctx.loader) ctx.loader.classList.remove('is-visible'); 105 if (ctx.popularBlock) ctx.popularBlock.style.display = ''; 106 if (ctx.resultsBlock) ctx.resultsBlock.style.display = 'none'; 107 if (ctx.emptyBlock) ctx.emptyBlock.style.display = ''; 108 } 109 110 function showResults(ctx) { 111 if (!ctx) return; 112 113 if (ctx.loader) ctx.loader.classList.remove('is-visible'); 114 if (ctx.popularBlock) ctx.popularBlock.style.display = 'none'; 115 if (ctx.resultsBlock) ctx.resultsBlock.style.display = ''; 116 if (ctx.emptyBlock) ctx.emptyBlock.style.display = 'none'; 117 } 118 119 function abortAjax() { 120 if (currentXhr) { 121 currentXhr.abort(); 122 currentXhr = null; 123 } 124 125 if (currentItemsXhr) { 126 currentItemsXhr.abort(); 127 currentItemsXhr = null; 128 } 129 } 130 131 function initSwiperForWrapper(wrapper) { 132 if (!wrapper || typeof Swiper === 'undefined') return; 133 134 var container = wrapper.closest('.jsProductSearchSlider'); 135 if (!container) return; 136 137 var swiperEl = container.querySelector('.jsSliderInit'); 138 if (!swiperEl) return; 139 140 if (swiperEl.swiper) { 141 swiperEl.swiper.destroy(true, true); 142 } 143 144 new Swiper(swiperEl, { 145 slidesPerView: 'auto', 146 spaceBetween: 8, 147 loop: false, 148 scrollbar: { 149 el: container.querySelector('.jsSliderScroll') 150 }, 151 breakpoints: { 152 768: { 153 spaceBetween: 16, 154 slidesPerView: 3 155 }, 156 991: { 157 spaceBetween: 16, 158 slidesPerView: 4 159 }, 160 1200: { 161 slidesPerView: 5, 162 spaceBetween: 24 163 }, 164 }, 165 }); 166 } 167 168 function resetSearchForm(form, options) { 169 if (!isSearchForm(form)) return; 170 171 const settings = Object.assign({ 172 clearInput: true, 173 blurInput: false 174 }, options || {}); 175
176 const row = form.querySelector('.jsSearchRow'); 177 const input = form.querySelector('.jsSearchBlockInput'); 178 179 if (input) { 180 if (settings.clearInput) { 181 input.value = ''; 182 } 183 184 if (settings.blurInput && document.activeElement === input) { 185 input.blur(); 186 } 187 } 188 189 if (row) { 190 row.classList.remove('is-open'); 191 row.classList.remove('is-active'); 192 } 193 } 194 195 function closeAllSearch(options) { 196 const settings = Object.assign({ 197 clearInput: true, 198 blurInput: false 199 }, options || {}); 200 201 if (!isAnySearchOpened() && !activeForm && !activePanel) { 202 return; 203 } 204 205 const desktopLoader = document.querySelector('.jsSearchLoader'); 206 const mobileLoader = document.querySelector('.jsSearchLoaderMobile'); 207 208 forms.forEach(function (form) { 209 resetSearchForm(form, settings); 210 }); 211 212 if (headerSearch) { 213 headerSearch.classList.remove('is-open'); 214 } 215 216 if (menuSearch) { 217 menuSearch.classList.remove('is-open'); 218 } 219 220 if (desktopLoader) { 221 desktopLoader.classList.remove('is-visible'); 222 } 223 224 if (mobileLoader) { 225 mobileLoader.classList.remove('is-visible'); 226 } 227 228 unlockBodyScroll(); 229 230 activeForm = null; 231 activePanel = null; 232 pointerDownInsideSearch = false; 233 234 abortAjax(); 235 clearTimeout(debounceTimer); 236 } 237 238 function openSearch(form) { 239 const row = form.querySelector('.jsSearchRow'); 240 const input = form.querySelector('.jsSearchBlockInput'); 241 242 if (!row || !input) return; 243 244 const context = getSearchContext(form); 245 const isMenuSearch = !!form.closest('.menu__search'); 246 247 closeAllSearch(true); 248 249 if (!isMenuSearch) { 250 document.dispatchEvent(new CustomEvent('app:search-open')); 251 } 252 253 activeForm = form; 254 activePanel = context.panel; 255 256 row.classList.add('is-open'); 257 258 if (context.panel) { 259 context.panel.classList.add('is-open'); 260 } 261 262 lockBodyScroll(); 263 setHeaderHeightVar(); 264 setMenuHeaderHeightVar(); 265 266 showPopular(context); 267 input.focus(); 268 } 269 270 function doSearch(form, query) { 271 if (!isSearchForm(form)) return; 272 273 var ctx = getSearchContext(form); 274 275 if (!query || query.length < 2) { 276 showPopular(ctx); 277 return; 278 } 279 280 showLoader(ctx); 281 abortAjax(); 282 283 currentXhr = $.ajax({ 284 url: '/ajax/search.php', 285 method: 'POST', 286 data: { 287 ajax_call: 'y', 288 q: query 289 }, 290 dataType: 'json', 291 success: function (data) { 292 if (!activeForm || activeForm !== form) { 293 return; 294 } 295 296 if (!data || !data.items || data.items.length === 0) { 297 showEmpty(ctx); 298 return; 299 } 300 301 if (ctx.totalCounter) { 302 ctx.totalCounter.textContent = data.total || 0; 303 } 304 305 if (ctx.moreLink && data.search_url) { 306 ctx.moreLink.href = data.search_url; 307 } 308 309 if (ctx.sectionsWrapper) { 310 var tagsHtml = ''; 311 312 if (data.sections && data.sections.length > 0) { 313 data.sections.forEach(function (s) { 314 tagsHtml += '<a href="' + s.url + '">' + s.name + ' <span>' + s.count + '</span></a>'; 315 }); 316 } 317 318 ctx.sectionsWrapper.innerHTML = tagsHtml; 319 } 320 321 if (data.ids && ctx.itemsWrapper) { 322 currentItemsXhr = $.ajax({ 323 url: '/ajax/search_items.php', 324 method: 'POST', 325 data: { 326 ids: data.ids 327 }, 328 success: function (html) { 329 if (!activeForm || activeForm !== form) { 330 return; 331 } 332 333 $(ctx.itemsWrapper).html(html); 334 initSwiperForWrapper(ctx.itemsWrapper); 335 336 if (typeof BX !== 'undefined' && BX.Sale && BX.Sale.BasketComponent) { 337 BX.Sale.BasketComponent.init(); 338 } 339 340 showResults(ctx); 341 }, 342 error: function (xhr, status) { 343 if (status === 'abort') return; 344 showResults(ctx); 345 } 346 }); 347 } else { 348 showResults(ctx); 349 } 350 }, 351 error: function (xhr, status) { 352 if (status === 'abort') return; 353 showPopular(ctx); 354 } 355 }); 356 } 357 358 function initAnimatedPlaceholder(inputs, phrases) { 359 inputs = Array.from(inputs); 360 361 if (!inputs.length || !phrases.length) return; 362 363 let phraseIndex = 0; 364 let charIndex = 0; 365 let isDeleting = false;
366 367 function hasUserValue() { 368 return inputs.some(function (input) { 369 return input.value.trim() !== ''; 370 }); 371 } 372 373 function setPlaceholder(text) { 374 inputs.forEach(function (input) { 375 if (document.activeElement !== input && input.value.trim() === '') { 376 input.setAttribute('placeholder', text); 377 } 378 }); 379 } 380 381 function tick() { 382 if (isAnySearchOpened() || hasUserValue()) { 383 setTimeout(tick, 400); 384 return; 385 } 386 387 const currentPhrase = phrases[phraseIndex]; 388 let currentText = ''; 389 390 if (isDeleting) { 391 charIndex--; 392 currentText = currentPhrase.substring(0, charIndex); 393 } else { 394 charIndex++; 395 currentText = currentPhrase.substring(0, charIndex); 396 } 397 398 setPlaceholder(currentText); 399 400 let delay = isDeleting ? 45 : 90; 401 402 if (!isDeleting && charIndex === currentPhrase.length) { 403 delay = 1400; 404 isDeleting = true; 405 } else if (isDeleting && charIndex === 0) { 406 isDeleting = false; 407 phraseIndex = (phraseIndex + 1) % phrases.length; 408 delay = 350; 409 } 410 411 setTimeout(tick, delay); 412 } 413 414 inputs.forEach(function (input) { 415 input.addEventListener('focus', function () { 416 input.setAttribute('placeholder', 'ÐоиÑк по ÑоваÑам'); 417 }); 418 419 input.addEventListener('blur', function () { 420 if (input.value.trim() === '' && !isAnySearchOpened()) { 421 input.setAttribute('placeholder', ''); 422 } 423 }); 424 425 input.addEventListener('input', function () { 426 if (input.value.trim() !== '') { 427 input.setAttribute('placeholder', 'ÐоиÑк по ÑоваÑам'); 428 } 429 }); 430 }); 431 432 tick(); 433 } 434 435 setHeaderHeightVar(); 436 setMenuHeaderHeightVar(); 437 438 window.addEventListener('resize', function () { 439 setHeaderHeightVar(); 440 setMenuHeaderHeightVar(); 441 }); 442 443 forms.forEach(function (form) { 444 const row = form.querySelector('.jsSearchRow'); 445 const input = form.querySelector('.jsSearchBlockInput'); 446 const submitBtn = form.querySelector('.search-block__button'); 447 const clearBtn = form.querySelector('.jsSearchFormClear'); 448 449 if (!row || !input) return; 450 451 input.addEventListener('input', function () { 452 clearTimeout(debounceTimer); 453 454 const query = input.value.trim(); 455 const context = getSearchContext(form); 456 457 if (query.length >= 2) { 458 showLoader(context); 459 } else { 460 showPopular(context); 461 } 462 463 debounceTimer = setTimeout(function () { 464 doSearch(form, query); 465 }, 600); 466 }); 467 468 if (clearBtn) { 469 clearBtn.addEventListener('click', function (e) { 470 e.preventDefault(); 471 e.stopPropagation(); 472 473 input.value = ''; 474 input.focus(); 475 476 abortAjax(); 477 clearTimeout(debounceTimer); 478 479 showPopular(getSearchContext(form)); 480 }); 481 } 482 483 row.addEventListener('click', function (e) { 484 if (!row.classList.contains('is-open')) { 485 e.preventDefault(); 486 e.stopPropagation(); 487 openSearch(form); 488 } 489 }); 490 491 input.addEventListener('click', function (e) { 492 e.stopPropagation(); 493 }); 494 495 if (submitBtn) { 496 submitBtn.addEventListener('click', function (e) { 497 e.stopPropagation(); 498 499 if (!row.classList.contains('is-open')) { 500 e.preventDefault(); 501 openSearch(form); 502 return; 503 } 504 505 if (input.value.trim() === '') { 506 e.preventDefault(); 507 input.focus(); 508 } 509 }); 510 } 511 }); 512 513 document.addEventListener('mousedown', function (e) { 514 if (!isAnySearchOpened()) { 515 pointerDownInsideSearch = false;
516 return; 517 } 518 519 const insideActiveForm = activeForm ? activeForm.contains(e.target) : false; 520 const insideActivePanel = activePanel ? activePanel.contains(e.target) : false; 521 522 pointerDownInsideSearch = insideActiveForm || insideActivePanel; 523 }); 524 525 document.addEventListener('touchstart', function (e) { 526 if (!isAnySearchOpened()) { 527 pointerDownInsideSearch = false; 528 return; 529 } 530 531 const touch = e.touches && e.touches.length ? e.touches[0] : e; 532 const target = touch.target || e.target; 533 534 const insideActiveForm = activeForm ? activeForm.contains(target) : false; 535 const insideActivePanel = activePanel ? activePanel.contains(target) : false; 536 537 pointerDownInsideSearch = insideActiveForm || insideActivePanel; 538 }, { passive: true }); 539 540 document.addEventListener('click', function (e) { 541 if (!isAnySearchOpened()) { 542 pointerDownInsideSearch = false; 543 return; 544 } 545 546 const clickedInsideActiveForm = activeForm ? activeForm.contains(e.target) : false; 547 const clickedInsideActivePanel = activePanel ? activePanel.contains(e.target) : false; 548 549 if (pointerDownInsideSearch) { 550 pointerDownInsideSearch = false; 551 return; 552 } 553 554 if (!clickedInsideActiveForm && !clickedInsideActivePanel) { 555 closeAllSearch({ 556 clearInput: true, 557 blurInput: false 558 }); 559 } 560 }); 561 562 document.addEventListener('mouseup', function () { 563 setTimeout(function () { 564 pointerDownInsideSearch = false; 565 }, 0); 566 }); 567 568 document.addEventListener('touchend', function () { 569 setTimeout(function () { 570 pointerDownInsideSearch = false; 571 }, 0); 572 }, { passive: true }); 573 574 document.addEventListener('keydown', function (e) { 575 if (e.key === 'Escape') { 576 closeAllSearch({ 577 clearInput: true, 578 blurInput: true 579 }); 580 } 581 }); 582 583 document.addEventListener('app:menu-open', function () { 584 closeAllSearch({ 585 clearInput: true, 586 blurInput: false 587 }); 588 }); 589 590 closeButtons.forEach(function (btn) { 591 btn.addEventListener('click', function (e) { 592 e.preventDefault(); 593 e.stopPropagation(); 594 595 closeAllSearch({ 596 clearInput: true, 597 blurInput: true 598 }); 599 }); 600 }); 601 602 initAnimatedPlaceholder( 603 document.querySelectorAll('header .jsSearchBlockInput, .menu__search .jsSearchBlockInput'), 604 [ 605 'СÑÑнÑе коÑзинÑ', 606 'ÐаÑмезан', 607 'СÑÑ Ñ Ð³Ð¾Ð»Ñбой плеÑенÑÑ', 608 'ÐодаÑоÑÐ½Ð°Ñ ÐºÐ¾Ñзина', 609 'ÐÑÑÑаÑа', 610 'ТÑÑÑелÑнÑй ÑÑÑ' 611 ] 612 ); 613 614 if (typeof Swiper !== 'undefined') { 615 $('.jsProductSearchSlider').each(function () { 616 var that = $(this); 617 var sliderEl = that.find('.jsSliderInit')[0]; 618 619 if (!sliderEl) return; 620 621 new Swiper(sliderEl, { 622 slidesPerView: 'auto', 623 spaceBetween: 8, 624 loop: false, 625 scrollbar: { 626 el: that.find('.jsSliderScroll')[0], 627 }, 628 navigation: { 629 nextEl: that.find('.jsSliderBtnNext')[0], 630 prevEl: that.find('.jsSliderBtnPrev')[0], 631 }, 632 breakpoints: { 633 768: { 634 spaceBetween: 16, 635 slidesPerView: 3, 636 }, 637 991: { 638 spaceBetween: 16, 639 slidesPerView: 4, 640 }, 641 1200: { 642 slidesPerView: 5, 643 spaceBetween: 24 644 }, 645 }, 646 on: { 647 init: function () { 648 if ($(window).width() > 1199 && this.slides.length <= 4) { 649 that.find('.slider__btn').addClass('d-none'); 650 } 651 }, 652 }, 653 }); 654 }); 655 } 656}); 657 658// footer 659$(function () { 660 const $social = $('.footer__social'); 661 662 function closeSocialItems($excludeItem) { 663 let $items = $social.find('.footer__social-item'); 664 665 if ($excludeItem && $excludeItem.length) { 666 $items = $items.not($excludeItem); 667 } 668 669 $items.removeClass('is-open'); 670 $items.children('.footer__social-itemContent:visible').stop(true, true).slide
670Up(200); 671 } 672 673 $social.on('click', '.footer__social-link', function (e) { 674 const $item = $(this).closest('.footer__social-item'); 675 const $content = $item.children('.footer__social-itemContent'); 676 677 if (!$content.length) return; 678 679 e.preventDefault(); 680 e.stopPropagation(); 681 682 if ($item.hasClass('is-open')) { 683 $item.removeClass('is-open'); 684 $content.stop(true, true).slideUp(400); 685 } else { 686 closeSocialItems($item); 687 $item.addClass('is-open'); 688 $content.stop(true, true).slideDown(400); 689 } 690 }); 691 692 $social.on('click', '.footer__social-itemContent', function (e) { 693 e.stopPropagation(); 694 }); 695 696 $(document).on('click', function (e) { 697 if (!$(e.target).closest('.footer__social').length) { 698 closeSocialItems(); 699 } 700 }); 701});
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.