1(function () { 2 'use strict'; 3 4 var YM_COUNTER_ID = 87874798; 5 var MOBILE_FILTER_MEDIA = '(max-width: 900px)'; 6 var basketStateRequestId = 0; 7 var basketStateRefreshTimer = null; 8 var basketStateEventBound = false; 9 var BASKET_LOADING_MIN_MS = 650; 10 var mobileFilterState = { 11 open: false, 12 scrollY: 0, 13 trigger: null, 14 snapshot: null, 15 baseHistoryState: null, 16 closePending: false 17 }; 18 19 function reachGoal(goal, params) { 20 if (!goal) { 21 return; 22 } 23 24 if (typeof window.afReachYandexGoal === 'function') { 25 window.afReachYandexGoal(goal, params); 26 return; 27 } 28 29 if (typeof window.ym === 'function') { 30 window.ym(YM_COUNTER_ID, 'reachGoal', goal, params || {}); 31 } 32 } 33 34 35 document.addEventListener('DOMContentLoaded', function () { 36 normalizeFilterLayout(); 37 initMobileCatalogFilter(); 38 syncMobileFilterUi(); 39 initShortCartPanel(); 40 initVisualRequestModal(); 41 initLegacyGalleryHandlers(); 42 initLegacyDetailGalleryControls(); 43 initGalleryThumbs(); 44 initPopularShowcaseSliders(); 45 syncStickyPanel(); 46 initFastSizes(); 47 initDetailBasketState(); 48 }); 49 50 document.addEventListener('af:catalog-ajax-updated', function () { 51 normalizeFilterLayout(); 52 syncMobileFilterUi(); 53 }); 54 55 document.addEventListener('click', function (event) { 56 /* 57 * data-ym-goal обÑабаÑÑваеÑÑÑ Ð³Ð»Ð¾Ð±Ð°Ð»ÑнÑм analytics-goals.js. 58 */ 59 60 var filterToggle = event.target.closest('[data-af-filter-toggle]'); 61 if (filterToggle) { 62 event.preventDefault(); 63 openMobileCatalogFilter(filterToggle); 64 return; 65 } 66 67 var filterClose = event.target.closest('[data-af-filter-close]'); 68 if (filterClose) { 69 event.preventDefault(); 70 requestCloseMobileCatalogFilter(); 71 return; 72 } 73 74 var filterMore = event.target.closest('[data-af-filter-more]'); 75 if (filterMore) { 76 event.preventDefault(); 77 expandMobileFilterValues(filterMore); 78 return; 79 } 80 81 var filterChip = event.target.closest('[data-af-filter-chip]'); 82 if (filterChip) { 83 event.preventDefault(); 84 removeMobileFilterChip(filterChip); 85 return; 86 } 87 88 var fastButton = event.target.closest('[data-af-fast-size]'); 89 if (fastButton && !event.ctrlKey && !event.metaKey && !event.shiftKey && !event.altKey) { 90 event.preventDefault(); 91 chooseFastSize(fastButton); 92 return; 93 } 94 var customSize = event.target.closest('[data-af-fast-custom]'); 95 if (customSize) { 96 event.preventDefault(); 97 var customGroup = document.querySelector('[data-af-fast-sizes]'); 98 if (customGroup) { 99 customGroup.setAttribute('data-selected', ''); 100 commitFastState(false); 101 document.querySelector('[data-af-width]').focus(); 102 scheduleCurrentProductBasketStateRefresh(); 103 } 104 return; 105 } 106 107 var factureCurrent = event.target.closest('[data-af-facture-current]'); 108 if (factureCurrent) { 109 var select = factureCurrent.closest('[data-af-facture-select]'); 110 if (select) { 111 var isOpen = select.classList.toggle('is-open'); 112 factureCurrent.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); 113 } 114 } 115 116 var factureOption = event.target.closest('.af-facture-option'); 117 if (factureOption) { 118 selectFacture(factureOption); 119 } 120 121 var customBasket = event.target.closest('[data-af-add-custom-basket]'); 122 if (customBasket) { 123 event.preventDefault(); 124 addCustomBasket(customBasket); 125 } 126 127 var readyBasket = event.target.closest('[data-ready-add-to-basket]'); 128 if (readyBasket) { 129 event.preventDefault(); 130 addReadyBasket(readyBasket); 131 } 132 133 var shortAdd = event.target.closest('[data-af-short-add]'); 134 if (shortAdd) { 135 event.preventDefault(); 136 addCustomBasket(shortAdd); 137 } 138 139 var openVisual = event.target.closest('[data-af-open-visual], #openModalVisual'); 140 if (openVisual) { 141 event.preventDefault(); 142 openVisualRequestModal(); 143 } 144 145 var closeVisual = event.target.closest('[data-af-close-visual], #closeModalVisuale'); 146 if (closeVisual) { 147 event.preventDefault(); 148 closeVisualRequestModal(); 149 } 150 151 if (event.target && event.target.id === 'modalVisulate') { 152 closeVisualRequestModal(); 153 } 154 155 var galleryThumb = event.target.closest('[data-af-gallery-thumb]'); 156 if (galleryThumb) { 157 switchGalleryImage(galleryThumb); 158 } 159 160 if (!event.target.closest('[data-af-facture-select]')) { 161 closeFactureSelects(); 162 } 163 }); 164 165 document.addEventListener('keydown', function (event) { 166 if (!mobileFilterState.open) { 167 return; 168 } 169 170 if (event.key === 'Escape') { 171 event.preventDefault(); 172 requestCloseMobileCatalogFilter(); 173 return; 174 } 175 176 if (event.key === 'Tab') { 177 trapMobileFilterFocus(event); 178 } 179 }); 180 181 document.addEventListener('input', function (event) { 182 var filterSearch = event.target.closest('[data-af-filter-search]'); 183 if (filterSearch) { 184 filterMobileFilterValues(filterSearch); 185 return; 186 } 187 188 var phoneField = event.target.closest('[data-af-phone-mask]'); 189 if (phoneField) { 190 phoneField.value = formatPhone(phoneField.value); 191 toggleFastBuyButton(phoneField.closest('form')); 192 } 193 194 var fastBuyField = event.target.closest('.fast_buy_form input'); 195 if (fastBuyField) { 196 toggleFastBuyButton(fastBuyField.closest('form')); 197 } 198 199 var field = event.target.closest('[data-af-width], [data-af-height]'); 200 if (!field) { 201 return; 202 } 203 var calc = field.closest('[data-af-price-calculator]'); 204 if (calc) { 205 reconcileFastDimensions(calc); 206 updatePrice(calc, true); 207 commitFastState(true); 208 syncStickyPanel(); 209 scheduleCurrentProductBasketStateRefresh(); 210 } 211 }); 212 213 document.addEventListener('submit', function (event) { 214 var form = event.target.closest('.fast_buy_form'); 215 if (!form) { 216 return; 217 } 218 219 event.preventDefault(); 220 submitFastBuy(form); 221 }); 222 223 224 function initPopularShowcaseSliders() { 225 document.querySelectorAll('[data-af-popular-slider]').forEach(function (slider) { 226 var track = slider.querySelector('.af-products-grid'); 227 var prev = slider.querySelector('[data-af-popular-prev]'); 228 var next = slider.querySelector('[data-af-popular-next]'); 229 if (!track || !prev || !next) { 230 return; 231 } 232 233 var getStep = function () { 234 var card = track.querySelector('.af-product-card'); 235 if (!card) { 236 return Math.max(280, Math.round(track.clientWidth * 0.8)); 237 } 238 var gap = parseInt(window.getComputedStyle(track).columnGap || window.getComputedStyle(track).gap || '18', 10); 239 if (isNaN(gap)) { 240 gap = 18; 241 } 242 return card.getBoundingClientRect().width + gap; 243 }; 244 245 var updateState = function () { 246 var maxScroll = track.scrollWidth - track.clientWidth - 2; 247 var hasOverflow = maxScroll > 0; 248 prev.disabled = !hasOverflow || track.scrollLeft <= 2; 249 next.disabled = !hasOverflow || track.scrollLeft >= maxScroll; 250 slider.classList.toggle('af-popular-products--no-arrows', !hasOverflow); 251 }; 252 253 prev.addEventListener('click', function () { 254 track.scrollBy({ left: -getStep(), behavior: 'smooth' }); 255 }); 256 257 next.addEventListener('click', function () { 258 track.scrollBy({ left: getStep(), behavior: 'smooth' }); 259 }); 260 261 track.addEventListener('scroll', updateState, { passive: true }); 262 window.addEventListener('resize', updateState); 263 updateState(); 264 setTimeout(updateState, 300); 265 }); 266 } 267 268 function closeFactureSelects() { 269 document.querySelectorAll('[data-af-facture-select].is-open').forEach(function (select) { 270 select.classList.remove('is-open'); 271 var current = select.querySelector('[data-af-facture-current]'); 272 if (current) { 273 current.setAttribute('aria-expanded', 'false'); 274 } 275 }); 276 } 277 278 function selectFacture(option) { 279 var root = option.closest('[data-product-id]') || document; 280 var select = option.closest('[data-af-facture-select]'); 281 var calc = root.querySelector('[data-af-price-calculator]'); 282 var options = select ? select.querySelectorAll('.af-facture-option') : []; 283 var picture = option.getAttribute('data-picture') || ''; 284 var name = option.getAttribute('data-name') || ''; 285 var printPrice = option.getAttribute('data-print-price') || ''; 286 287 options.forEach(function (btn) { btn.classList.remove('is-active'); }); 288 option.classList.add('is-active'); 289 290 if (select) { 291 var nameNode = select.querySelector('[data-af-facture-current-name]'); 292 var priceNode = select.querySelector('[data-af-facture-current-price]'); 293 var pictureNode = select.querySelector('[data-af-facture-current-picture]'); 294 295 if (nameNode) { nameNode.textContent = name; } 296 if (priceNode) { priceNode.textContent = printPrice; } 297 if (pictureNode) { 298 pictureNode.innerHTML = picture 299 ? '<img src="' + escapeHtml(picture) + '" alt="' + escapeHtml(name) + '">' 300 : '<span>Ф</span>'; 301 } 302 } 303 304 if (calc) { 305 calc.setAttribute('data-price-per-meter', option.getAttribute('data-price') || '0'); 306 calc.setAttribute('data-facture-id', option.getAttribute('data-facture-id') || ''); 307 updatePrice(calc); 308 } 309 310 var stickyFacture = document.getElementById('sticky__facture'); 311 if (stickyFacture) { stickyFacture.textContent = name; } 312 syncStickyPanel(); 313 scheduleCurrentProductBasketStateRefresh(); 314 315 commitFastState(false); 316 closeFactureSelects(); 317 } 318 319 var restoringFastState = false;
320 var fastTyping = false; 321 var fastBaseSchema = null; 322 var fastBaseMeta = null; 323 var fastCanonicalBase = ''; 324 325 function getSelectedFastSize() { 326 var group = document.querySelector('[data-af-fast-sizes]'); 327 return group ? (group.getAttribute('data-selected') || '') : ''; 328 } 329 330 function fastSnapshot() { 331 var context = getCurrentProductBasketContext(); 332 return context ? Object.assign({}, context) : null; 333 } 334 335 function fastBasePath() { 336 var group = document.querySelector('[data-af-fast-sizes]'); 337 if (!group) { return ''; } 338 var prefix = window.location.pathname.split('/catalog/')[0]; 339 return prefix + group.getAttribute('data-base-url'); 340 } 341 342 function fastOption(id) { 343 return Array.prototype.find.call(document.querySelectorAll('.af-facture-option'), function (option) { 344 return option.getAttribute('data-facture-id') === String(id); 345 }); 346 } 347 348 function renderFastState() { 349 var selected = getSelectedFastSize(); 350 document.querySelectorAll('[data-af-fast-size]').forEach(function (button) { 351 var active = button.getAttribute('data-af-fast-size') === selected; 352 button.classList.toggle('is-active', active); 353 button.setAttribute('aria-pressed', active ? 'true' : 'false'); 354 }); 355 var custom = document.querySelector('[data-af-fast-custom]'); 356 if (custom) { custom.setAttribute('aria-pressed', selected ? 'false' : 'true'); } 357 } 358 359 function reconcileFastDimensions(calc) { 360 var group = document.querySelector('[data-af-fast-sizes]'); 361 if (!group) { return; } 362 var selected = getSelectedFastSize(); 363 var dimensions = selected.split('_'); 364 if (String(calc.querySelector('[data-af-width]').value) !== dimensions[0] || 365 String(calc.querySelector('[data-af-height]').value) !== dimensions[1]) { 366 group.setAttribute('data-selected', ''); 367 } 368 } 369 370 function syncFastMetadata(path, snapshot) { 371 if (!fastBaseSchema || !snapshot) { return; } 372 var schema = JSON.parse(JSON.stringify(fastBaseSchema)); 373 var catalogPath = path.substring(path.indexOf('/catalog/')); 374 var variantSuffix = catalogPath.match(/\/([0-9]+_[0-9]+\/[^/]+)\/?$/); 375 var canonicalPath = fastCanonicalBase 376 ? fastCanonicalBase + (variantSuffix ? '/' + variantSuffix[1] + '/' : '') 377 : catalogPath; 378 var url = 'https://art-fresco.ru' + canonicalPath; 379 var option = fastOption(snapshot.factureId); 380 var title = fastBaseMeta ? fastBaseMeta.name : schema.name; 381 var metaDescription = fastBaseMeta ? fastBaseMeta.description : (schema.description || ''); 382 if (snapshot.fastSize && option) { 383 var sizeLabel = snapshot.width + ' à ' + snapshot.height + ' Ñм'; 384 var factureName = option.getAttribute('data-name'); 385 title += ' â ' + sizeLabel + ', ' + factureName; 386 metaDescription = 'ФоÑообои «' + (fastBaseMeta ? fastBaseMeta.name : fastBaseSchema.name) 387 + '», ÑÐ°Ð·Ð¼ÐµÑ Ð¿Ð¾Ð»Ð¾Ñна ' + sizeLabel + ', ÑакÑÑÑа «' + factureName 388 + '». ÐÐ°ÐºÐµÑ Ð¿Ð¾Ð´Ð³Ð¾Ñовлен к пеÑаÑи. ÐзгоÑовление на ÑледÑÑÑий ÑабоÑий денÑ. ArtFresco.'; 389 schema.name = title; 390 schema.description = metaDescription; 391 schema.url = url; 392 schema['@id'] = url + '#product'; 393 schema.sku = 'af-' + snapshot.productId + '-' + snapshot.fastSize + '-' + snapshot.factureId; 394 schema.size = sizeLabel; 395 schema.material = factureName; 396 var calc = document.querySelector('[data-af-price-calculator]'); 397 var area = Math.max(Number(calc.getAttribute('data-min-area') || '1'), Number(snapshot.width) * Number(snapshot.height) / 10000); 398 if (calc.getAttribute('data-area-rounding') === 'ceil') { area = Math.ceil(area); } 399 area = Math.round((area + Number.EPSILON) * 100) / 100; 400 schema.offers = { '@type': 'Offer', '@id': url + '#offer', url: url, 401 price: Math.round(area * Number(option.getAttribute('data-price')) * 100) / 100, 402 priceCurrency: 'RUB', itemCondition: 'https://schema.org/NewCondition' }; 403 } 404 var metaTitle = title; 405 if (snapshot.fastSize && fastBaseMeta && fastBaseMeta.code && 406 metaTitle.toLowerCase().indexOf(String(fastBaseMeta.code).toLowerCase()) === -1) { 407 var productName = fastBaseMeta.name; 408 metaTitle = productName + ' ' + fastBaseMeta.code + title.substring(productName.length); 409 }
410 document.title = !snapshot.fastSize && fastBaseMeta ? fastBaseMeta.title : metaTitle + ' | ArtFresco'; 411 var description = document.querySelector('meta[name="description"]'); 412 if (!description) { 413 description = document.createElement('meta'); 414 description.name = 'description'; 415 document.head.appendChild(description); 416 } 417 description.content = metaDescription; 418 var ogDescription = document.querySelector('meta[property="og:description"]'); 419 if (ogDescription) { ogDescription.content = metaDescription; } 420 var ogUrl = document.querySelector('meta[property="og:url"]'); 421 if (ogUrl) { ogUrl.content = url; } 422 var ogTitle = document.querySelector('meta[property="og:title"]'); 423 if (ogTitle) { ogTitle.content = document.title; } 424 var canonical = document.querySelector('link[rel="canonical"]'); 425 if (canonical) { canonical.href = url; } 426 var node = document.querySelector('[data-af-product-schema]'); 427 if (node) { node.textContent = JSON.stringify(schema); } 428 } 429 430 function commitFastState(fromInput) { 431 var group = document.querySelector('[data-af-fast-sizes]'); 432 if (!group || restoringFastState) { return; } 433 var snapshot = fastSnapshot(); 434 var option = fastOption(snapshot.factureId); 435 var slug = option ? option.getAttribute('data-facture-code') : ''; 436 // A material without a public slug remains available for an individual order. 437 if (snapshot.fastSize && !slug) { 438 group.setAttribute('data-selected', ''); 439 snapshot.fastSize = ''; 440 } 441 var path = fastBasePath(); 442 if (snapshot.fastSize) { path += snapshot.fastSize + '/' + slug + '/'; } 443 renderFastState(); 444 var next = Object.assign({}, window.history.state || {}, { afFast: snapshot }); 445 if (path !== window.location.pathname || window.location.search) { 446 window.history.pushState(next, '', path); 447 } else if ((fromInput && !fastTyping) || (!fromInput && JSON.stringify((window.history.state || {}).afFast) !== JSON.stringify(snapshot))) { 448 window.history.pushState(next, '', path); 449 } else { 450 window.history.replaceState(next, '', path); 451 } 452 fastTyping = !!fromInput; 453 syncFastMetadata(path, snapshot); 454 } 455 456 function chooseFastSize(button) { 457 var group = document.querySelector('[data-af-fast-sizes]'); 458 var option = fastOption(button.getAttribute('data-default-facture')); 459 if (!group || !option) { window.location.assign(button.href); return; } 460 group.setAttribute('data-selected', button.getAttribute('data-af-fast-size')); 461 document.querySelector('[data-af-width]').value = button.getAttribute('data-width'); 462 document.querySelector('[data-af-height]').value = button.getAttribute('data-height'); 463 selectFacture(option); // Shared price/sticky/basket refresh, then history. 464 reachGoal('catalog_prepared_size_select', { size: getSelectedFastSize(), facture_id: option.getAttribute('data-facture-id') }); 465 } 466 467 function initFastSizes() { 468 var group = document.querySelector('[data-af-fast-sizes]'); 469 if (!group) { return; } 470 var canonicalNode = document.querySelector('link[rel="canonical"]'); 471 if (canonicalNode) { 472 try { 473 var canonicalMatch = new URL(canonicalNode.href, window.location.href).pathname.match( 474 /^(\/catalog\/[^/]+\/[^/]+)(?:\/[0-9]+_[0-9]+\/[^/]+)?\/?$/ 475 ); 476 if (canonicalMatch) { fastCanonicalBase = canonicalMatch[1]; } 477 } catch (ignore) {} 478 } 479 var baseSchemaNode = document.querySelector('[data-af-base-schema]'); 480 if (baseSchemaNode) { 481 try { fastBaseSchema = JSON.parse(baseSchemaNode.textContent); } catch (ignore) {} 482 } 483 var baseMetaNode = document.querySelector('[data-af-base-meta]'); 484 if (baseMetaNode) { 485 try { fastBaseMeta = JSON.parse(baseMetaNode.textContent); } catch (ignore) {} 486 } 487 window.history.replaceState(Object.assign({}, window.history.state || {}, { afFast: fastSnapshot() }), '', window.location.href); 488 renderFastState(); 489 group.addEventListener('keydown', function (event) { 490 var button = event.target.closest('[data-af-fast-size]'); 491 if (button && event.key === ' ') { event.preventDefault(); chooseFastSize(button); } 492 }); 493 window.addEventListener('popstate', function (event) { 494 var snapshot = event.state && event.state.afFast; 495 var current = getCurrentProductBasketContext(); 496 if (!snapshot || !current || snapshot.productId !== current.productId) { return; } 497 var option = fastOption(snapshot.factureId); 498 if (!option) { window.location.reload(); return; } 499 restoringFastState = true; 500 group.setAttribute('data-selected', snapshot.fastSize || ''); 501 document.querySelector('[data-af-width]').value = snapshot.width; 502 document.querySelector('[data-af-height]').value = snapshot.height; 503 selectFacture(option); 504 restoringFastState = false;
505 fastTyping = false; 506 renderFastState(); 507 syncFastMetadata(window.location.pathname, snapshot); 508 }); 509 } 510 511 function updatePrice(calc, userInitiated) { 512 var width = parseInt((calc.querySelector('[data-af-width]') || {}).value || '100', 10); 513 var height = parseInt((calc.querySelector('[data-af-height]') || {}).value || '100', 10); 514 var pricePerMeter = parseFloat(calc.getAttribute('data-price-per-meter') || '0'); 515 var area = Math.max(parseFloat(calc.getAttribute('data-min-area') || '1'), (width / 100) * (height / 100)); 516 if (calc.getAttribute('data-area-rounding') === 'ceil') { area = Math.ceil(area); } 517 area = Math.round((area + Number.EPSILON) * 100) / 100; 518 var price = Math.round(area * pricePerMeter); 519 var priceNode = calc.querySelector('[data-af-price]'); 520 if (priceNode) { 521 priceNode.textContent = formatPrice(price) + ' â½'; 522 } 523 var shortPrice = document.querySelector('[data-af-short-price], #sticky__price'); 524 if (shortPrice) { 525 shortPrice.textContent = formatPrice(price) + ' â½'; 526 } 527 var stickySize = document.getElementById('sticky__size'); 528 if (stickySize) { stickySize.textContent = width + ' x ' + height + ' Ñм'; } 529 530 if (userInitiated === true) { 531 var product = calc.closest('[data-product-id]'); 532 document.dispatchEvent(new CustomEvent('af:price-recalculated', { 533 detail: { 534 product_id: product ? String(product.getAttribute('data-product-id') || '') : '', 535 width: width, 536 height: height, 537 price: price 538 } 539 })); 540 } 541 } 542 543 function getBitrixSessid() { 544 if ( 545 window.BX && 546 typeof window.BX.bitrix_sessid === 'function' 547 ) { 548 var bxSessid = window.BX.bitrix_sessid(); 549 550 if (bxSessid) { 551 return bxSessid; 552 } 553 } 554 555 if ( 556 window.BX && 557 typeof window.BX.message === 'function' 558 ) { 559 var messageSessid = window.BX.message('bitrix_sessid'); 560 561 if (messageSessid) { 562 return messageSessid; 563 } 564 } 565 566 var input = document.querySelector( 567 'input[name="sessid"], input[name="bitrix_sessid"]' 568 ); 569 570 if (input && input.value) { 571 return input.value; 572 } 573 574 return ''; 575 } 576 577 function appendBitrixSessid(data) { 578 var sessid = getBitrixSessid(); 579 580 if (sessid) { 581 data.set('sessid', sessid); 582 } 583 } 584 585 function setBasketButtonText(button, text) { 586 if (!button) { return; } 587 var textNode = button.querySelector('.buy_button_text'); 588 if (textNode) { 589 textNode.textContent = text; 590 } else { 591 button.textContent = text; 592 } 593 } 594 595 function finishBasketLoading(startedAt, callback) { 596 var elapsed = Math.max(0, Date.now() - startedAt); 597 var delay = Math.max(0, BASKET_LOADING_MIN_MS - elapsed); 598 599 if (delay === 0) { 600 callback(); 601 return; 602 } 603 604 window.setTimeout(callback, delay); 605 } 606 607 function getBasketButtons(productId) { 608 productId = String(productId || '').replace(/[^0-9]/g, ''); 609 if (!productId) { return []; } 610 611 var selectors = [ 612 '[data-af-add-custom-basket][data-product-id="' + productId + '"]', 613 '[data-af-short-add][data-product-id="' + productId + '"]', 614 '[data-ready-add-to-basket][data-product-id="' + productId + '"]' 615 ]; 616 617 return Array.prototype.slice.call(document.querySelectorAll(selectors.join(','))); 618 } 619 620 function rememberBasketAddGoal(button) { 621 if (!button || button.hasAttribute('data-af-basket-add-goal')) { return; } 622 var goal = button.getAttribute('data-ym-goal') || ''; 623 button.setAttribute('data-af-basket-add-goal', goal); 624 } 625 626 function restoreBasketAddGoal(button) { 627 if (!button) { return; } 628 var goal = button.getAttribute('data-af-basket-add-goal'); 629 if (goal) { 630 button.setAttribute('data-ym-goal', goal); 631 } 632 } 633 634 function setBasketButtonState(button, state) { 635 if (!button) { return; } 636 rememberBasketAddGoal(button); 637 638 button.classList.remove('is-added', 'is-loading', 'is-checking'); 639 button.removeAttribute('aria-busy'); 640 button.setAttribute('data-af-basket-state', state); 641 642 var spinner = button.querySelector('.buy_button_spinner'); 643 if (spinner) { 644 spinner.style.display = state === 'loading' ? '' : 'none'; 645 } 646 647 if (state === 'in-cart') { 648 button.classList.add('is-added'); 649 button.disabled = false;
650 button.removeAttribute('data-ym-goal'); 651 setBasketButtonText(button, 'РкоÑзине'); 652 return; 653 } 654 655 if (state === 'loading') { 656 button.classList.add('is-loading'); 657 button.disabled = true; 658 button.setAttribute('aria-busy', 'true'); 659 button.removeAttribute('data-ym-goal'); 660 setBasketButtonText(button, 'ÐобавлÑем...'); 661 return; 662 } 663 664 if (state === 'checking') { 665 button.classList.add('is-checking'); 666 button.disabled = true; 667 button.setAttribute('aria-busy', 'true'); 668 button.removeAttribute('data-ym-goal'); 669 setBasketButtonText(button, 'ÐÑовеÑÑем...'); 670 return; 671 } 672 673 button.disabled = false; 674 restoreBasketAddGoal(button); 675 setBasketButtonText(button, 'РкоÑзинÑ'); 676 } 677 678 function setBasketButtonsState(productId, state) { 679 getBasketButtons(productId).forEach(function (button) { 680 setBasketButtonState(button, state); 681 }); 682 } 683 684 function syncAddedBasketButtons(productId) { 685 setBasketButtonsState(productId, 'in-cart'); 686 } 687 688 function isBasketButtonInCart(button) { 689 return !!button && button.getAttribute('data-af-basket-state') === 'in-cart'; 690 } 691 692 function getBasketUrl(button) { 693 var url = button ? (button.getAttribute('data-cart-url') || '') : ''; 694 if (url) { return url; } 695 696 var basketLink = document.querySelector('a[href*="/personal/cart/"]'); 697 return basketLink ? basketLink.getAttribute('href') : '/personal/cart/'; 698 } 699 700 function openBasket(button) { 701 window.location.href = getBasketUrl(button); 702 } 703 704 function getCurrentProductBasketContext() { 705 var product = document.querySelector('.af-product-detail[data-product-id], .af-product-detail'); 706 if (!product) { return null; } 707 708 var productId = product.getAttribute('data-product-id') || ''; 709 if (!productId) { 710 var anyButton = product.querySelector('[data-product-id][data-af-add-custom-basket], [data-product-id][data-af-short-add], [data-product-id][data-ready-add-to-basket]'); 711 productId = anyButton ? (anyButton.getAttribute('data-product-id') || '') : ''; 712 } 713 productId = String(productId || '').replace(/[^0-9]/g, ''); 714 if (!productId) { return null; } 715 716 var readyButton = product.querySelector('[data-ready-add-to-basket][data-product-id="' + productId + '"]'); 717 if (readyButton) { 718 return { 719 productId: productId, 720 ready: true, 721 factureId: '', 722 width: '', 723 height: '' 724 }; 725 } 726 727 var calc = product.querySelector('[data-af-price-calculator]') || document.querySelector('[data-af-price-calculator]'); 728 if (!calc) { return null; } 729 var widthField = calc.querySelector('[data-af-width]'); 730 var heightField = calc.querySelector('[data-af-height]'); 731 732 return { 733 productId: productId, 734 ready: false, 735 factureId: String(calc.getAttribute('data-facture-id') || ''), 736 width: widthField ? String(widthField.value || '') : '', 737 height: heightField ? String(heightField.value || '') : '', 738 fastSize: getSelectedFastSize() 739 }; 740 } 741 742 function appendBasketContext(data, context) { 743 data.append('product_id', context.productId); 744 if (!context.ready) { 745 data.append('facture_id', context.factureId || ''); 746 data.append('width', context.width || ''); 747 data.append('height', context.height || ''); 748 data.append('fast_size', context.fastSize || ''); 749 } 750 } 751 752 function refreshCurrentProductBasketState(showChecking) { 753 var context = getCurrentProductBasketContext(); 754 if (!context) { return Promise.resolve(); } 755 756 var requestId = ++basketStateRequestId; 757 if (showChecking !== false) { 758 setBasketButtonsState(context.productId, 'checking'); 759 } 760 761 var data = new FormData(); 762 data.append('action', 'state'); 763 appendBasketContext(data, context); 764 appendBitrixSessid(data); 765 766 return fetch('/local/ajax/catalog_add_to_basket.php', { 767 method: 'POST', 768 body: data, 769 credentials: 'same-origin' 770 }) 771 .then(function (res) { return res.json(); }) 772 .then(function (json) { 773 if (requestId !== basketStateRequestId) { return; } 774 if (!json.success) { 775 setBasketButtonsState(context.productId, 'idle'); 776 return; 777 } 778 setBasketButtonsState(context.productId, json.in_basket ? 'in-cart' : 'idle'); 779 updateHeaderBasketFallback(json); 780 }) 781 .catch(function () { 782 if (requestId === basketStateRequestId) { 783 setBasketButtonsState(context.productId, 'idle'); 784 } 785 }); 786 } 787 788 function scheduleCurrentProductBasketStateRefresh(showChecking) { 789 var context = getCurrentProductBasketContext(); 790 if (!context) { return; } 791 ++basketStateRequestId; // Invalidate old responses before the debounce delay. 792 if (showChecking !== false) { setBasketButtonsState(context.productId, 'checking'); } 793 if (basketStateRefreshTimer) { 794 clearTimeout(basketStateRefreshTimer); 795 } 796 basketStateRefreshTimer = setTimeout(function () { 797 basketStateRefreshTimer = null; 798 refreshCurrentProductBasketState(showChecking !== false); 799 }, 180); 800 } 801 802 function initDetailBasketState() { 803 var context = getCurrentProductBasketContext(); 804 if (!context) { return; } 805 806 refreshCurrentProductBasketState(true); 807 808 if (!basketStateEventBound && window.BX && typeof BX.addCustomEvent === 'function') { 809 basketStateEventBound = true; 810 BX.addCustomEvent(window, 'OnBasketChange', function () { 811 // Basket line/header still refreshes through the shared Bitrix event, 812 // but the product button must not flash through "ÐÑовеÑÑем..." 813 // immediately after a successful add/remove operation. 814 scheduleCurrentProductBasketStateRefresh(false); 815 }); 816 } 817 } 818 819 function updateHeaderBasketFallback(json) { 820 var count = parseInt((json && json.basket_count), 10); 821 if (isNaN(count) || count < 0) { return; } 822
823 document.querySelectorAll('a[href*="/personal/cart/"]').forEach(function (link) { 824 var icon = link.querySelector('img[src*="Card.svg"]'); 825 if (!icon) { return; } 826 827 var counter = link.querySelector('.catalog-cart-counter-menu'); 828 if (count < 1) { 829 if (counter) { counter.textContent = ''; counter.style.display = 'none'; } 830 return; 831 } 832 833 if (!counter) { 834 counter = document.createElement('span'); 835 counter.className = 'catalog-cart-counter-menu catalog-cart-counter-menu_custom'; 836 counter.style.background = '#7D0808'; 837 counter.style.top = '14px'; 838 link.appendChild(counter); 839 } 840 counter.style.display = ''; 841 counter.textContent = String(count); 842 }); 843 } 844 845 function notifyBasketChanged(json) { 846 if (window.BX && typeof BX.onCustomEvent === 'function') { 847 BX.onCustomEvent('OnBasketChange'); 848 } 849 updateHeaderBasketFallback(json || {}); 850 } 851 852 function addCustomBasket(button) { 853 if (isBasketButtonInCart(button)) { 854 openBasket(button); 855 return; 856 } 857 if (button.disabled) { return; } 858 859 var product = button.closest('.af-product-detail') || document.querySelector('.af-product-detail'); 860 var calc = product ? product.querySelector('[data-af-price-calculator]') : document.querySelector('[data-af-price-calculator]'); 861 if (!calc) { 862 window.afFormMessage.at(button.closest('.af-product-detail, .af-product-card') || button.parentElement, "error")('Ðе ÑдалоÑÑ Ð½Ð°Ð¹Ñи блок ÑаÑÑÑÑа ÑазмеÑа'); 863 return; 864 } 865 866 var widthField = calc.querySelector('[data-af-width]'); 867 var heightField = calc.querySelector('[data-af-height]'); 868 var activeFacture = (product || document).querySelector('.af-facture-option.is-active, .af-facture-item.is-active'); 869 var productId = button.getAttribute('data-product-id') || (product && product.getAttribute('data-product-id')) || ''; 870 871 if (!productId) { 872 window.afFormMessage.at(button.closest('.af-product-detail, .af-product-card') || button.parentElement, "error")('Ðе ÑдалоÑÑ Ð¾Ð¿ÑеделиÑÑ ÑоваÑ'); 873 return; 874 } 875 876 var data = new FormData(); 877 data.append('product_id', productId); 878 data.append('facture_id', calc.getAttribute('data-facture-id') || (activeFacture ? activeFacture.getAttribute('data-facture-id') : '') || ''); 879 data.append('width', widthField ? (widthField.value || '100') : '100'); 880 data.append('height', heightField ? (heightField.value || '100') : '100'); 881 data.append('fast_size', getSelectedFastSize()); 882 var addedContextKey = JSON.stringify(getCurrentProductBasketContext()); 883 appendBitrixSessid(data); 884 885 var loadingStartedAt = Date.now(); 886 ++basketStateRequestId; 887 if (basketStateRefreshTimer) { clearTimeout(basketStateRefreshTimer); basketStateRefreshTimer = null; } 888 setBasketButtonsState(productId, 'loading'); 889 fetch('/local/ajax/catalog_add_to_basket.php', { method: 'POST', body: data, credentials: 'same-origin' }) 890 .then(function (res) { return res.json(); }) 891 .then(function (json) { 892 if (!json.success) { 893 setBasketButtonsState(productId, 'idle'); 894 window.afFormMessage.at(button.closest('.af-product-detail, .af-product-card') || button.parentElement, "error")(json.message || 'Ðе ÑдалоÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸ÑÑ ÑÐ¾Ð²Ð°Ñ Ð² коÑзинÑ'); 895 return; 896 } 897 898 if (json.added === true) { 899 reachGoal('catalog_custom_add_to_cart_success'); 900 reachGoal('ecom_add_to_cart', { 901 product_id: String(productId), 902 product_type: data.get('fast_size') ? 'prepared_wallpaper' : 'custom_wallpaper', 903 size: data.get('fast_size') || '', 904 facture_id: data.get('facture_id') || '' 905 }); 906 } 907 908 finishBasketLoading(loadingStartedAt, function () { 909 if (addedContextKey === JSON.stringify(getCurrentProductBasketContext())) { 910 syncAddedBasketButtons(productId); 911 } else { 912 scheduleCurrentProductBasketStateRefresh(); 913 } 914 if (json.added === true) { 915 notifyBasketChanged(json); 916 } else { 917 updateHeaderBasketFallback(json); 918 } 919 }); 920 }) 921 .catch(function () { 922 setBasketButtonsState(productId, 'idle'); 923 window.afFormMessage.at(button.closest('.af-product-detail, .af-product-card') || button.parentElement, "error")('ÐÑибка Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð² коÑзин
923Ñ'); 924 scheduleCurrentProductBasketStateRefresh(); 925 }); 926 } 927 928 929 function toggleFastBuyButton(form) { 930 if (!form) { 931 return; 932 } 933 var phone = form.querySelector('input[name="phone"], input[name="value"]'); 934 var button = form.querySelector('.fast_buy_button'); 935 if (!phone || !button || button.classList.contains('success')) { 936 return; 937 } 938 var digits = phone.value.replace(/\D/g, ''); 939 button.disabled = digits.length < 10; 940 } 941 942 function submitFastBuy(form) { 943 var button = 944 form.querySelector('.fast_buy_button'); 945 946 var phone = 947 form.querySelector( 948 'input[name="phone"], input[name="value"]' 949 ); 950 951 var name = 952 form.querySelector('input[name="name"]'); 953 954 var url = 955 form.querySelector('input[name="url"]'); 956 957 if ( 958 !phone 959 || phone.value.replace(/\D/g, '').length < 10 960 ) { 961 return; 962 } 963 964 var attribution = 965 window.afMetrikaAttribution 966 ? window.afMetrikaAttribution.get() 967 : { 968 clientId: '', 969 yclid: '', 970 token: '' 971 }; 972 973 var data = new FormData(); 974 975 data.append('value', phone.value); 976 data.append( 977 'name', 978 name ? name.value : '' 979 ); 980 data.append( 981 'url', 982 url ? url.value : window.location.href 983 ); 984 data.append( 985 'page_url', 986 window.location.href 987 ); 988 data.append( 989 'ym_client_id', 990 attribution.clientId || '' 991 ); 992 data.append( 993 'yclid', 994 attribution.yclid || '' 995 ); 996 data.append( 997 'attribution_token', 998 attribution.token || '' 999 ); 1000 1001 if (button) { 1002 button.disabled = true; 1003 button.textContent = 'ÐÑпÑавлÑем...'; 1004 } 1005 1006 var persistPromise = Promise.resolve(); 1007 1008 if ( 1009 window.afMetrikaAttribution 1010 && typeof window.afMetrikaAttribution.persist === 'function' 1011 ) { 1012 persistPromise = 1013 window.afMetrikaAttribution 1014 .persist('site_form') 1015 .catch(function (error) { 1016 console.warn( 1017 '[ArtFresco] catalog fast buy attribution persist failed', 1018 error 1019 ); 1020 }); 1021 } 1022 1023 persistPromise 1024 .then(function () { 1025 return window.afFormGuard.fetch( 1026 '/local/templates/fresco/ajax/fast_buy.php', 1027 { 1028 method: 'POST', 1029 body: data, 1030 credentials: 'same-origin' 1031 } 1032 ); 1033 }) 1034 .then(function (res) { 1035 return res.json(); 1036 }) 1037 .then(function (json) { 1038 if (!json || json.STATUS !== true) { 1039 throw new Error( 1040 json && json.MESSAGE 1041 ? json.MESSAGE 1042 : 'bad-response' 1043 ); 1044 } 1045 1046 /* 1047 * Stage 11.1: 1048 * FastBuy â единÑÑÐ²ÐµÐ½Ð½Ð°Ñ ÐºÐ°Ð½Ð¾Ð½Ð¸ÑеÑÐºÐ°Ñ ÑÐµÐ»Ñ 1049 * ÑÑпеÑного бÑÑÑÑого заказа. 1050 */ 1051 reachGoal('FastBuy'); 1052 1053 renderFastBuyPromo( 1054 form, 1055 json.PROMO_CODE || 'WALL2205', 1056 json.PROMO_VALID_UNTIL || '' 1057 ); 1058 }) 1059 .catch(function (error) { 1060 console.error( 1061 '[ArtFresco] fast buy failed', 1062 error 1063 ); 1064 1065 if (button) { 1066 button.textContent = 1067 'ÐопÑобоваÑÑ ÐµÑÑ Ñаз'; 1068 button.disabled = false;
1069 } 1070 1071 window.afFormMessage.at(form, "error")( 1072 'Ðе ÑдалоÑÑ Ð¾ÑпÑавиÑÑ Ð±ÑÑÑÑÑй заказ. ' 1073 + 'ÐопÑобÑйÑе еÑÑ Ñаз или ÑвÑжиÑеÑÑ Ñ Ð½Ð°Ð¼Ð¸ по ÑелеÑонÑ.' 1074 ); 1075 }); 1076 } 1077 1078 function renderFastBuyPromo( 1079 form, 1080 promoCode, 1081 validUntil 1082 ) { 1083 if (!form) { 1084 return; 1085 } 1086 1087 var code = String( 1088 promoCode || 'WALL2205' 1089 ); 1090 1091 form.innerHTML = ''; 1092 1093 var box = document.createElement('div'); 1094 box.className = 1095 'af-fast-buy-promo-success'; 1096 1097 box.style.padding = '18px'; 1098 box.style.border = 1099 '1px solid #dfd3ca'; 1100 box.style.borderRadius = '14px'; 1101 box.style.background = '#fff'; 1102 1103 var title = document.createElement('div'); 1104 title.textContent = 'ÐаÑвка оÑпÑавлена'; 1105 title.style.fontSize = '18px'; 1106 title.style.fontWeight = '700'; 1107 title.style.marginBottom = '8px'; 1108 1109 var text = document.createElement('div'); 1110 text.textContent = 1111 'СпаÑибо! ÐÐ°Ñ Ð¿Ñомокод ' 1112 + 'на ÑпеÑиалÑное пÑедложение:'; 1113 text.style.fontSize = '14px'; 1114 text.style.lineHeight = '1.45'; 1115 text.style.marginBottom = '14px'; 1116 1117 var row = document.createElement('div'); 1118 row.style.display = 'flex'; 1119 row.style.alignItems = 'center'; 1120 row.style.gap = '10px'; 1121 row.style.flexWrap = 'wrap'; 1122 row.style.padding = '12px'; 1123 row.style.border = 1124 '1px dashed #9b1111'; 1125 row.style.borderRadius = '10px'; 1126 row.style.background = '#faf7f4'; 1127 1128 var strong = 1129 document.createElement('strong'); 1130 strong.textContent = code; 1131 strong.style.fontSize = '22px'; 1132 strong.style.letterSpacing = '1px'; 1133 1134 var copy = 1135 document.createElement('button'); 1136 copy.type = 'button'; 1137 copy.textContent = 'СкопиÑоваÑÑ'; 1138 copy.style.marginLeft = 'auto'; 1139 copy.style.padding = '9px 14px'; 1140 copy.style.border = '0'; 1141 copy.style.borderRadius = '8px'; 1142 copy.style.background = '#8f0909'; 1143 copy.style.color = '#fff'; 1144 copy.style.fontWeight = '600'; 1145 copy.style.cursor = 'pointer'; 1146 1147 copy.addEventListener( 1148 'click', 1149 function () { 1150 copyPromoCode( 1151 code, 1152 copy 1153 ); 1154 } 1155 ); 1156 1157 row.appendChild(strong); 1158 row.appendChild(copy); 1159 1160 box.appendChild(title); 1161 box.appendChild(text); 1162 box.appendChild(row); 1163 1164 if (validUntil) { 1165 var until = 1166 document.createElement('div'); 1167 1168 until.textContent = 1169 'ÐейÑÑвÑÐµÑ Ð´Ð¾ ' 1170 + String(validUntil) 1171 + ' г.'; 1172 1173 until.style.marginTop = '10px'; 1174 until.style.fontSize = '13px'; 1175 until.style.color = '#777'; 1176 1177 box.appendChild(until); 1178 } 1179 1180 form.appendChild(box); 1181 form.classList.add('is-success'); 1182 } 1183 1184 function copyPromoCode(code, button) { 1185 function done() { 1186 var oldText = button.textContent; 1187 1188 button.textContent = 1189 'â СкопиÑовано'; 1190 1191 setTimeout( 1192 function () { 1193 button.textContent = 1194 oldText; 1195 }, 1196 1800 1197 ); 1198 } 1199 1200 function fallback() { 1201 var area = 1202 document.createElement( 1203 'textarea' 1204 ); 1205 1206 area.value = code; 1207 area.setAttribute( 1208 'readonly', 1209 'readonly' 1210 ); 1211 area.style.position = 'fixed'; 1212 area.style.opacity = '0'; 1213 1214 document.body.appendChild(area); 1215 area.select(); 1216 1217 try { 1218 document.execCommand('copy'); 1219 done(); 1220 } catch (e) { 1221 window.afFormMessage.at(null, "status")('ÐÑомокод: ' + code); 1222 } 1223 1224 area.remove(); 1225 } 1226 1227 if ( 1228 navigator.clipboard 1229 && typeof navigator.clipboard.writeText 1230 === 'function' 1231 ) { 1232 navigator.clipboard 1233 .writeText(code) 1234 .then(done) 1235 .catch(fallback); 1236 } else { 1237 fallback(); 1238 } 1239 } 1240 1241 1242 1243 function initLegacyGalleryHandlers() { 1244 // fix62: Ð½Ð¾Ð²Ð°Ñ ÐºÐ°ÑÑоÑка иÑполÑзÑÐµÑ ÑÑаÑÑе глобаÐ
1244»ÑнÑе ÑÑнкÑии галеÑеи. 1245 // ÐеÑеклÑÑаем главное изобÑажение напÑÑмÑÑ ÑеÑез #main_fresca_image img. 1246 window.selectImageSlider = function (image) { 1247 image = normalizeGalleryThumb(image); 1248 if (!image) { return false; } 1249 1250 var gallery = getGalleryFromElement(image) || document.querySelector('[data-af-legacy-gallery]') || document; 1251 var mainFrescaImage = document.getElementById('main_fresca_image'); 1252 var mainFrescoIframe = document.getElementById('main_fresco_iframe'); 1253 var mainImage = mainFrescaImage ? (mainFrescaImage.querySelector('[data-af-main-image]') || mainFrescaImage.querySelector('img')) : null; 1254 1255 if (!mainFrescaImage || !mainImage) { return false; } 1256 1257 getGalleryThumbs(gallery).forEach(function (item) { 1258 item.classList.remove('select', 'is-active'); 1259 }); 1260 image.classList.add('select', 'is-active'); 1261 syncLegacySwiperClasses(gallery, image); 1262 1263 var currentMedia = getThumbMediaElement(image); 1264 var iframeSrc = getThumbIframeSrc(image, currentMedia); 1265 var imageSrc = getThumbImageSrc(image, currentMedia); 1266 1267 if (iframeSrc && mainFrescoIframe) { 1268 mainFrescaImage.style.display = 'none'; 1269 var iframe = mainFrescoIframe.querySelector('iframe'); 1270 if (iframe) { 1271 iframe.setAttribute('src', iframeSrc); 1272 } 1273 mainFrescoIframe.style.display = 'block'; 1274 scrollActiveThumbIntoView(gallery, image); 1275 return false; 1276 } 1277 1278 if (!imageSrc) { 1279 scrollActiveThumbIntoView(gallery, image); 1280 return false; 1281 } 1282 1283 mainFrescaImage.style.display = 'block'; 1284 if (mainFrescoIframe) { 1285 mainFrescoIframe.style.display = 'none'; 1286 } 1287 mainFrescaImage.classList.add('element_image_wrap'); 1288 mainFrescaImage.classList.remove('img_wrap'); 1289 1290 mainImage.classList.remove('hide'); 1291 mainImage.setAttribute('src', imageSrc); 1292 mainImage.setAttribute('alt', image.getAttribute('data-alt') || mainImage.getAttribute('alt') || ''); 1293 1294 var editorImage = document.getElementById('image'); 1295 if (editorImage) { 1296 editorImage.setAttribute('src', imageSrc); 1297 } 1298 1299 scrollActiveThumbIntoView(gallery, image); 1300 return false; 1301 }; 1302 1303 window.nextSelectImage = function (elem) { 1304 var gallery = getGalleryFromElement(elem) || document.querySelector('[data-af-legacy-gallery]') || document; 1305 var thumbs = getGalleryThumbs(gallery); 1306 if (!thumbs.length) { return false; } 1307 var currentIndex = getActiveThumbIndex(thumbs); 1308 var nextIndex = currentIndex >= 0 ? (currentIndex + 1) % thumbs.length : 0; 1309 return window.selectImageSlider(thumbs[nextIndex]); 1310 }; 1311 1312 window.prevSelectImage = function (elem) { 1313 var gallery = getGalleryFromElement(elem) || document.querySelector('[data-af-legacy-gallery]') || document; 1314 var thumbs = getGalleryThumbs(gallery); 1315 if (!thumbs.length) { return false; } 1316 var currentIndex = getActiveThumbIndex(thumbs); 1317 var prevIndex = currentIndex >= 0 ? (currentIndex - 1 + thumbs.length) % thumbs.length : thumbs.length - 1; 1318 return window.selectImageSlider(thumbs[prevIndex]); 1319 }; 1320 } 1321 1322 function initLegacyDetailGalleryControls() { 1323 document.querySelectorAll('[data-af-legacy-gallery]').forEach(function (gallery) { 1324 var thumbs = getGalleryThumbs(gallery); 1325 var prev = gallery.querySelector('[data-af-gallery-prev], .product__swiper-button-p_container'); 1326 var next = gallery.querySelector('[data-af-gallery-next], .product__swiper-button-n_container'); 1327 var slider = gallery.querySelector('[data-af-gallery-slider], .product__swiper, .swiper_custom_mobile'); 1328 1329 gallery.classList.toggle('af-product-detail__gallery--single', thumbs.length <= 1); 1330 if (prev) { prev.style.display = thumbs.length > 1 ? '' : 'none'; } 1331 if (next) { next.style.display = thumbs.length > 1 ? '' : 'none'; } 1332 1333 if (slider) { 1334 initDragScroll(slider); 1335 initWheelHorizontalScroll(slider); 1336 } 1337 1338 // fix61: не глÑÑим inline onclick ÑÑаÑой галеÑеи. 1339 // ÐÑевÑÑ Ð² Ñаблоне вÑзÑÐ²Ð°ÐµÑ selectImageSlider(this), как в ÑÑаÑой веÑÑии. 1340 // JS ниже нÑжен ÑолÑко как ÑезеÑв, еÑли inline-обÑабоÑÑик не ÑÑабоÑал. 1341 gallery.querySelectorAll('[data-af-gallery-thumb], .img_wrap').forEach(function (thumb) { 1342 if (thumb.getAttribute('data-af-gallery-click-ready') === 'Y') { return; } 1343 thumb.setAttribute('data-af-gallery-click-ready', 'Y'); 1344 thumb.addEventListener('click', function (event) { 1345 if (slider && slider.getAttribute('data-af-gallery-dragging') === 'Y') { 1346 return; 1347 } 1348 1349 if (typeof window.selectImageSlider === 'function') { 1350 event.preventDefault(); 1351 window.selectImageSlider(thumb); 1352 } 1353 }, false); 1354 }); 1355 }); 1356 } 1357 1358 function normalizeGalleryThumb(element) { 1359 if (!element) { return null; } 1360 if (element.matches && element.matches('.img_wrap')) { return element; } 1361 if (element.closest) { return element.closest('.img_wrap'); } 1362 return null; 1363 } 1364 1365 function getThumbMediaElement(thumb) { 1366 if (!thumb) { return null; } 1367 return thumb.querySelector('img, iframe, picture, video') || thumb.firstElementChild || null; 1368 } 1369 1370 function getThumbImageSrc(thumb, media) { 1371 if (!thumb) { return ''; } 1372 1373 var src = thumb.getAttribute('data-src') || 1374 thumb.getAttribute('data-lazy-src') || 1375 thumb.getAttribute('data-original') || 1376 ''; 1377 1378 if (!src && media) { 1379 src = media.getAttribute('data-src') || 1380 media.getAttribute('data-lazy-src') || 1381 media.getAttribute('data-original') || 1382 media.getAttribute('src') || 1383 ''; 1384 } 1385 1386 if (!src && media && media.tagName && media.tagName.toUpperCase() === 'PICTURE') { 1387 var pictureImage = media.querySelector('img'); 1388 if (pictureImage) { 1389 src = pictureImage.getAttribute('data-src') || 1390 pictureImage.getAttribute('data-lazy-src') || 1391 pictureImage.getAttribute('src') || 1392 ''; 1393 } 1394 } 1395 1396 if (!src) { 1397 var nestedImage = thumb.querySelector('img'); 1398 if (nestedImage) { 1399 src = nestedImage.getAttribute('data-src') || 1400 nestedImage.getAttribute('data-lazy-src') || 1401 nestedImage.getAttribute('src') || 1402 ''; 1403 } 1404 } 1405 1406 return src || ''; 1407 } 1408 1409 function getThumbIframeSrc(thumb, media) { 1410 if (!thumb) { return ''; } 1411 var iframe = media && media.tagName && media.tagName.toUpperCase() === 'IFRAME' 1412 ? media 1413 : thumb.querySelector('iframe'); 1414 return iframe ? (iframe.getAttribute('data-src') || iframe.getAttribute('src') || '') : ''; 1415 } 1416 1417 function getGalleryFromElement(element) { 1418 if (!element || !element.closest) { return null; } 1419 return element.closest('[data-af-legacy-gallery]') || element.closest('.af-product-detail__gallery'); 1420 } 1421 1422 function getGalleryThumbs(gallery) { 1423 var root = gallery || document; 1424 var thumbs = Array.prototype.slice.call(root.querySelectorAll('[data-af-gallery-thumb], [data-af-gallery-slider] .img_wrap, .product__swiper .img_wrap, .swiper_custom_mobile .img_wrap')); 1425 return thumbs.filter(function (thumb, index, list) { 1426 return !!thumb.firstElementChild && 1427 thumb.id !== 'main_fresca_image' && 1428 list.indexOf(thumb) === index; 1429 }); 1430 } 1431
1432 function getActiveThumbIndex(thumbs) { 1433 return thumbs.findIndex(function (thumb) { 1434 return thumb.classList.contains('select') || thumb.classList.contains('is-active'); 1435 }); 1436 } 1437 1438 function scrollActiveThumbIntoView(gallery, thumb) { 1439 var slider = gallery ? gallery.querySelector('[data-af-gallery-slider], .product__swiper, .swiper_custom_mobile') : null; 1440 if (!slider || !thumb || !thumb.closest) { return; } 1441 1442 var slide = thumb.closest('.swiper-slide') || thumb; 1443 if (typeof slide.scrollIntoView === 'function') { 1444 slide.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); 1445 } 1446 } 1447 1448 function initDragScroll(slider) { 1449 if (slider.getAttribute('data-af-drag-scroll-ready') === 'Y') { return; } 1450 slider.setAttribute('data-af-drag-scroll-ready', 'Y'); 1451 1452 var isDown = false; 1453 var isDragged = false; 1454 var startX = 0; 1455 var scrollLeft = 0; 1456 var startThumb = null; 1457 1458 slider.setAttribute('data-af-gallery-dragging', 'N'); 1459 1460 slider.addEventListener('dragstart', function (event) { 1461 event.preventDefault(); 1462 }); 1463 1464 slider.addEventListener('pointerdown', function (event) { 1465 if (event.button !== undefined && event.button !== 0) { return; } 1466 isDown = true; 1467 isDragged = false; 1468 startX = event.clientX; 1469 scrollLeft = slider.scrollLeft; 1470 startThumb = event.target && event.target.closest ? event.target.closest('.img_wrap') : null; 1471 slider.classList.add('is-dragging'); 1472 // Ðе даÑм бÑаÑзеÑÑ Ð½Ð°ÑаÑÑ drag каÑÑинки внÑÑÑи пÑевÑÑ. Ðлик обÑабаÑÑваем на pointerup. 1473 event.preventDefault(); 1474 if (slider.setPointerCapture && event.pointerId !== undefined) { 1475 try { slider.setPointerCapture(event.pointerId); } catch (e) {} 1476 } 1477 }); 1478 1479 slider.addEventListener('pointermove', function (event) { 1480 if (!isDown) { return; } 1481 var dx = event.clientX - startX; 1482 if (Math.abs(dx) > 6) { 1483 isDragged = true; 1484 slider.setAttribute('data-af-gallery-dragging', 'Y'); 1485 slider.setAttribute('data-af-gallery-last-drag-at', String(Date.now())); 1486 } 1487 slider.scrollLeft = scrollLeft - dx; 1488 }); 1489 1490 var finishDrag = function (event, shouldSelect) { 1491 if (!isDown) { return; } 1492 var wasDragged = isDragged; 1493 var selectedThumb = startThumb; 1494 isDown = false; 1495 startThumb = null; 1496 slider.classList.remove('is-dragging'); 1497 1498 if (shouldSelect && !wasDragged && selectedThumb && typeof window.selectImageSlider === 'function') { 1499 if (event) { 1500 event.preventDefault(); 1501 event.stopPropagation(); 1502 } 1503 window.selectImageSlider(selectedThumb); 1504 } 1505 1506 window.setTimeout(function () { 1507 isDragged = false; 1508 slider.setAttribute('data-af-gallery-dragging', 'N'); 1509 }, 80); 1510 }; 1511 1512 slider.addEventListener('pointerup', function (event) { 1513 finishDrag(event, true); 1514 }); 1515 slider.addEventListener('pointercancel', function (event) { 1516 finishDrag(event, false); 1517 }); 1518 slider.addEventListener('pointerleave', function (event) { 1519 if (isDown) { finishDrag(event, false); } 1520 }); 1521 1522 slider.addEventListener('click', function (event) { 1523 if (isDragged) { 1524 event.preventDefault(); 1525 event.stopPropagation(); 1526 } 1527 }, true); 1528 } 1529 1530 function initWheelHorizontalScroll(slider) { 1531 if (slider.getAttribute('data-af-wheel-scroll-ready') === 'Y') { return; } 1532 slider.setAttribute('data-af-wheel-scroll-ready', 'Y'); 1533 1534 slider.addEventListener('wheel', function (event) { 1535 if (Math.abs(event.deltaY) <= Math.abs(event.deltaX)) { return; } 1536 if (slider.scrollWidth <= slider.clientWidth) { return; } 1537 event.preventDefault(); 1538 slider.scrollLeft += event.deltaY; 1539 }, { passive: false }); 1540 } 1541 1542 function syncLegacySwiperClasses(gallery, activeThumb) { 1543 var slides = Array.prototype.slice.call(gallery.querySelectorAll('.swiper-slide')); 1544 if (!slides.length) { return; } 1545
1546 slides.forEach(function (slide) { 1547 slide.classList.remove('swiper-slide-active', 'swiper-slide-next', 'swiper-slide-prev'); 1548 }); 1549 1550 var activeSlide = activeThumb.closest('.swiper-slide'); 1551 var activeIndex = slides.indexOf(activeSlide); 1552 if (activeIndex < 0) { return; } 1553 1554 slides[activeIndex].classList.add('swiper-slide-active'); 1555 slides[(activeIndex + 1) % slides.length].classList.add('swiper-slide-next'); 1556 slides[(activeIndex - 1 + slides.length) % slides.length].classList.add('swiper-slide-prev'); 1557 } 1558 1559 function initGalleryThumbs() { 1560 document.querySelectorAll('[data-af-gallery-thumb].is-active, [data-af-gallery-thumb].select').forEach(function (thumb) { 1561 if (typeof window.selectImageSlider === 'function') { 1562 window.selectImageSlider(thumb); 1563 return; 1564 } 1565 1566 var src = thumb.getAttribute('data-src'); 1567 var main = thumb.closest('.af-product-detail__gallery')?.querySelector('[data-af-main-image]'); 1568 if (src && main && !main.getAttribute('src')) { 1569 main.setAttribute('src', src); 1570 } 1571 }); 1572 } 1573 1574 function switchGalleryImage(button) { 1575 if (typeof window.selectImageSlider === 'function') { 1576 window.selectImageSlider(button); 1577 return; 1578 } 1579 1580 var gallery = button.closest('.af-product-detail__gallery'); 1581 if (!gallery) { return; } 1582 var main = gallery.querySelector('[data-af-main-image]'); 1583 var src = button.getAttribute('data-src'); 1584 if (!main || !src) { return; } 1585 main.setAttribute('src', src); 1586 var alt = button.getAttribute('data-alt') || main.getAttribute('alt') || ''; 1587 main.setAttribute('alt', alt); 1588 gallery.querySelectorAll('[data-af-gallery-thumb]').forEach(function (item) { 1589 item.classList.remove('is-active'); 1590 }); 1591 button.classList.add('is-active'); 1592 } 1593 1594 function syncLegacySelfLayoutSize() { 1595 var widthInput = document.getElementById('width_holst') || document.querySelector('[data-af-width]'); 1596 var heightInput = document.getElementById('height_holst') || document.querySelector('[data-af-height]'); 1597 var calc = widthInput ? widthInput.closest('[data-af-price-calculator]') : document.querySelector('[data-af-price-calculator]'); 1598 1599 if (calc) { 1600 updatePrice(calc); 1601 } 1602 1603 if (widthInput) { 1604 widthInput.dispatchEvent(new Event('input', { bubbles: true })); 1605 } 1606 if (heightInput) { 1607 heightInput.dispatchEvent(new Event('input', { bubbles: true })); 1608 } 1609 1610 syncStickyPanel(); 1611 } 1612 1613 if (typeof window.setSize !== 'function') { 1614 window.setSize = function (callback) { 1615 syncLegacySelfLayoutSize(); 1616 if (typeof callback === 'function') { 1617 callback(); 1618 } 1619 }; 1620 } 1621 1622 function addReadyBasket(button) { 1623 if (isBasketButtonInCart(button)) { 1624 openBasket(button); 1625 return; 1626 } 1627 if (button.disabled) { return; } 1628 1629 var productId = String(button.getAttribute('data-product-id') || ''); 1630 if (!productId) { 1631 window.afFormMessage.at(button.closest('.af-product-detail, .af-product-card') || button.parentElement, "error")('Ðе ÑдалоÑÑ Ð¾Ð¿ÑеделиÑÑ ÑоваÑ'); 1632 return; 1633 } 1634 1635 var data = new FormData(); 1636 data.append('product_id', productId); 1637 appendBitrixSessid(data); 1638 var loadingStartedAt = Date.now(); 1639 setBasketButtonsState(productId, 'loading'); 1640 1641 fetch('/local/ajax/catalog_add_to_basket.php', { method: 'POST', body: data, credentials: 'same-origin' }) 1642 .then(function (res) { return res.json(); }) 1643 .then(function (json) { 1644 if (!json.success) { 1645 setBasketButtonsState(productId, 'idle'); 1646 window.afFormMessage.at(button.closest('.af-product-detail, .af-product-card') || button.parentElement, "error")(json.message || 'Ðе ÑдалоÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸ÑÑ ÑÐ¾Ð²Ð°Ñ Ð² коÑзин
1646Ñ'); 1647 return; 1648 } 1649 1650 if (json.added === true) { 1651 reachGoal('catalog_ready_add_to_cart_success'); 1652 reachGoal('ecom_add_to_cart', { 1653 product_id: productId, 1654 product_type: 'ready_product' 1655 }); 1656 } 1657 1658 finishBasketLoading(loadingStartedAt, function () { 1659 syncAddedBasketButtons(productId); 1660 if (json.added === true) { 1661 notifyBasketChanged(json); 1662 } else { 1663 updateHeaderBasketFallback(json); 1664 } 1665 }); 1666 }) 1667 .catch(function () { 1668 setBasketButtonsState(productId, 'idle'); 1669 window.afFormMessage.at(button.closest('.af-product-detail, .af-product-card') || button.parentElement, "error")('ÐÑибка Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð² коÑзинÑ'); 1670 scheduleCurrentProductBasketStateRefresh(); 1671 }); 1672 } 1673 1674 function initVisualRequestModal() { 1675 var modal = document.getElementById('modalVisulate'); 1676 if (!modal) { return; } 1677 document.querySelectorAll('.visual_form').forEach(function (form) { 1678 if (form.dataset.afBound === 'Y') { return; } 1679 form.dataset.afBound = 'Y'; 1680 form.addEventListener('submit', function (event) { 1681 event.preventDefault(); 1682 1683 var attribution = 1684 window.afMetrikaAttribution 1685 ? window.afMetrikaAttribution.get() 1686 : { 1687 clientId: '', 1688 yclid: '', 1689 token: '' 1690 }; 1691 1692 var data = new FormData(form); 1693 1694 data.set( 1695 'ym_client_id', 1696 attribution.clientId || '' 1697 ); 1698 data.set( 1699 'yclid', 1700 attribution.yclid || '' 1701 ); 1702 data.set( 1703 'attribution_token', 1704 attribution.token || '' 1705 ); 1706 data.set( 1707 'page_url', 1708 window.location.href 1709 ); 1710 1711 var persistPromise = 1712 Promise.resolve(); 1713 1714 if ( 1715 window.afMetrikaAttribution 1716 && typeof window.afMetrikaAttribution.persist === 'function' 1717 ) { 1718 persistPromise = 1719 window.afMetrikaAttribution 1720 .persist('site_form') 1721 .catch(function (error) { 1722 console.warn( 1723 '[ArtFresco] visual form attribution persist failed', 1724 error 1725 ); 1726 }); 1727 } 1728 1729 persistPromise 1730 .then(function () { 1731 return window.afFormGuard.fetch( 1732 '/local/templates/fresco/ajax/send_visual_request.php', 1733 { 1734 method: 'POST', 1735 body: data, 1736 credentials: 'same-origin' 1737 } 1738 ); 1739 }) 1740 .then(function (res) { 1741 if (!res.ok) { 1742 throw new Error( 1743 'bad-response' 1744 ); 1745 } 1746 1747 return res.json(); 1748 }) 1749 .then(function (json) { 1750 if ( 1751 !json 1752 || json.STATUS !== true 1753 ) { 1754 throw new Error( 1755 json && json.MESSAGE 1756 ? json.MESSAGE 1757 : 'bad-response' 1758 ); 1759 } 1760 1761 window.afFormMessage.at(null, "status")( 1762 'ФоÑма ÑÑпеÑно оÑпÑавлена!' 1763 ); 1764 closeVisualRequestModal(); 1765 form.reset(); 1766 }) 1767 .catch(function (error) { 1768 console.error( 1769 '[ArtFresco] visual form failed', 1770 error 1771 ); 1772 window.afFormMessage.at(form, "error")('ÐÑибка оÑпÑавки'); 1773 }); 1774 }); 1775 }); 1776 } 1777 1778 function openVisualRequestModal() { 1779 var modal = document.getElementById('modalVisulate'); 1780 if (modal) { 1781 modal.style.display = 'flex'; 1782 modal.setAttribute('aria-hidden', 'false'); 1783 } 1784 } 1785 1786 function closeVisualRequestModal() { 1787 var modal = document.getElementById('modalVisulate'); 1788 if (modal) { 1789 modal.style.display = 'none'; 1790 modal.setAttribute('aria-hidden', 'true'); 1791 } 1792 } 1793 1794 function syncStickyPanel() { 1795 var calc = document.querySelector('[data-af-price-calculator]'); 1796 if (!calc) { return; } 1797 updatePrice(calc); 1798 } 1799 1800 function isMobileFilterViewport() { 1801 if (window.matchMedia) { 1802 return window.matchMedia(MOBILE_FILTER_MEDIA).matches; 1803 } 1804 1805 return (window.innerWidth || document.documentElement.clientWidth) <= 900; 1806 } 1807 1808 function getMobileFilterPanel() { 1809 return document.getElementById('afCatalogFilterPanel'); 1810 } 1811 1812 function getMobileFilterForm() { 1813 var panel = getMobileFilterPanel(); 1814 return panel ? panel.querySelector('form.af-smart-filter[data-af-sef-filter="Y"]') : null; 1815 } 1816 1817 function createMobileFilterSnapshot(form) { 1818 var applyLabel = form.querySelector('[data-af-filter-appl
1818y-label]'); 1819 1820 return { 1821 values: Array.prototype.map.call( 1822 form.querySelectorAll('input[type="checkbox"], input[type="radio"]'), 1823 function (input) { 1824 return { 1825 input: input, 1826 checked: input.checked 1827 }; 1828 } 1829 ), 1830 applyText: applyLabel ? applyLabel.textContent : '', 1831 resultCount: form.getAttribute('data-af-result-count') || '' 1832 }; 1833 } 1834 1835 function restoreMobileFilterSnapshot() { 1836 var snapshot = mobileFilterState.snapshot; 1837 var form = getMobileFilterForm(); 1838 1839 if (!snapshot || !form) { 1840 return; 1841 } 1842 1843 snapshot.values.forEach(function (item) { 1844 if (item.input && item.input.isConnected) { 1845 item.input.checked = !!item.checked; 1846 } 1847 }); 1848 1849 var applyLabel = form.querySelector('[data-af-filter-apply-label]'); 1850 if (applyLabel && snapshot.applyText) { 1851 applyLabel.textContent = snapshot.applyText; 1852 } 1853 1854 if (snapshot.resultCount !== '') { 1855 form.setAttribute('data-af-result-count', snapshot.resultCount); 1856 } 1857 } 1858 1859 function resetMobileFilterSearchState(form) { 1860 if (!form) { 1861 return; 1862 } 1863 1864 form.querySelectorAll('[data-af-filter-search]').forEach(function (input) { 1865 input.value = ''; 1866 }); 1867 1868 form.querySelectorAll('[data-af-filter-value][hidden]').forEach(function (value) { 1869 value.hidden = false; 1870 }); 1871 1872 form.querySelectorAll('[data-af-filter-group].is-af-searching').forEach(function (group) { 1873 group.classList.remove('is-af-searching'); 1874 }); 1875 1876 form.querySelectorAll('[data-af-filter-search-empty]').forEach(function (empty) { 1877 empty.hidden = true; 1878 }); 1879 } 1880 1881 function prepareMobileFilterGroups(form) { 1882 if (!form) { 1883 return; 1884 } 1885 1886 form.querySelectorAll('[data-af-filter-group]').forEach(function (group) { 1887 var hasChecked = !!group.querySelector('input[type="checkbox"]:checked, input[type="radio"]:checked'); 1888 group.open = hasChecked; 1889 group.classList.remove('is-af-values-expanded', 'is-af-searching'); 1890 1891 var more = group.querySelector('[data-af-filter-more]'); 1892 if (more) { 1893 more.hidden = false; 1894 } 1895 }); 1896 } 1897 1898 function syncMobileFilterUi() { 1899 var form = getMobileFilterForm(); 1900 var toggle = document.querySelector('[data-af-filter-toggle]'); 1901 1902 if (!form) { 1903 return; 1904 } 1905 1906 var checked = Array.prototype.slice.call( 1907 form.querySelectorAll('input[type="checkbox"]:checked, input[type="radio"]:checked') 1908 ); 1909 1910 form.querySelectorAll('[data-af-filter-value]').forEach(function (valueNode) { 1911 var input = valueNode.querySelector('input[type="checkbox"], input[type="radio"]'); 1912 valueNode.classList.toggle('is-checked', !!(input && input.checked)); 1913 }); 1914 1915 form.querySelectorAll('[data-af-filter-group]').forEach(function (group) { 1916 var count = group.querySelectorAll('input[type="checkbox"]:checked, input[type="radio"]:checked').length; 1917 var countNode = group.querySelector('[data-af-filter-group-selected-count]'); 1918 1919 if (countNode) { 1920 countNode.textContent = count ? String(count) : ''; 1921 countNode.hidden = count === 0; 1922 } 1923 }); 1924 1925 var activeCountNodes = form.querySelectorAll('[data-af-mobile-filter-active-count]'); 1926 activeCountNodes.forEach(function (node) { 1927 node.textContent = checked.length ? '· ' + checked.length : ''; 1928 node.hidden = checked.length === 0; 1929 }); 1930 1931 if (toggle) { 1932 var toggleCount = toggle.querySelector('[data-af-filter-toggle-count]'); 1933 toggle.setAttribute('aria-label', checked.length ? 'ФилÑÑÑÑ, вÑбÑано: ' + checked.length : 'ФилÑÑÑÑ'); 1934 1935 if (toggleCount) { 1936 toggleCount.textContent = checked.length ? String(checked.length) : ''; 1937 toggleCount.hidden = checked.length === 0; 1938 } 1939 } 1940 1941 var zeroState = form.querySelector('[data-af-filter-zero]'); 1942 var resultCount = parseInt(form.getAttribute('data-af-result-count') || '',
194210); 1943 if (zeroState && !isNaN(resultCount)) { 1944 zeroState.hidden = resultCount !== 0; 1945 } 1946 1947 syncMobileFilterSelectedChips(form, checked); 1948 } 1949 1950 function syncMobileFilterSelectedChips(form, checked) { 1951 var section = form.querySelector('[data-af-filter-selected]'); 1952 var chips = form.querySelector('[data-af-filter-selected-chips]'); 1953 1954 if (!section || !chips) { 1955 return; 1956 } 1957 1958 chips.innerHTML = ''; 1959 1960 checked.forEach(function (input) { 1961 var valueNode = input.closest('[data-af-filter-value]'); 1962 var textNode = valueNode ? valueNode.querySelector('.af-filter-value__text') : null; 1963 var text = textNode ? textNode.textContent.trim() : ''; 1964 1965 if (!text) { 1966 return; 1967 } 1968 1969 var chip = document.createElement('button'); 1970 chip.type = 'button'; 1971 chip.className = 'af-mobile-filter__chip'; 1972 chip.setAttribute('data-af-filter-chip', 'Y'); 1973 chip.setAttribute('aria-label', 'УбÑаÑÑ ÑилÑÑÑ Â«' + text + '»'); 1974 chip.textContent = text; 1975 chip.afFilterInput = input; 1976 1977 var close = document.createElement('span'); 1978 close.setAttribute('aria-hidden', 'true'); 1979 close.textContent = 'Ã'; 1980 chip.appendChild(close); 1981 chips.appendChild(chip); 1982 }); 1983 1984 section.hidden = chips.children.length === 0; 1985 } 1986 1987 function filterMobileFilterValues(input) { 1988 var group = input.closest('[data-af-filter-group]'); 1989 if (!group) { 1990 return; 1991 } 1992 1993 var query = String(input.value || '').trim().toLocaleLowerCase('ru-RU'); 1994 var matched = 0; 1995 1996 group.classList.toggle('is-af-searching', query !== ''); 1997 1998 group.querySelectorAll('[data-af-filter-value]').forEach(function (valueNode) { 1999 var textNode = valueNode.querySelector('.af-filter-value__text'); 2000 var text = textNode ? textNode.textContent.toLocaleLowerCase('ru-RU') : ''; 2001 var visible = !query || text.indexOf(query) !== -1; 2002 2003 valueNode.hidden = !visible; 2004 if (visible) { 2005 matched += 1; 2006 } 2007 }); 2008 2009 var empty = group.querySelector('[data-af-filter-search-empty]'); 2010 if (empty) { 2011 empty.hidden = query === '' || matched > 0; 2012 } 2013 } 2014 2015 function expandMobileFilterValues(button) { 2016 var group = button.closest('[data-af-filter-group]'); 2017 if (!group) { 2018 return; 2019 } 2020 2021 group.classList.add('is-af-values-expanded'); 2022 button.hidden = true; 2023 } 2024 2025 function removeMobileFilterChip(chip) { 2026 var input = chip.afFilterInput; 2027 if (!input || !input.isConnected) { 2028 return; 2029 } 2030 2031 input.checked = false; 2032 input.dispatchEvent(new Event('change', { bubbles: true })); 2033 syncMobileFilterUi(); 2034 } 2035 2036 function focusWithoutScroll(element) { 2037 if (!element || typeof element.focus !== 'function') { 2038 return; 2039 } 2040 2041 try { 2042 element.focus({ preventScroll: true }); 2043 } catch (ignore) { 2044 element.focus(); 2045 } 2046 } 2047 2048 function lockMobileFilterBody(panel) { 2049 mobileFilterState.scrollY = window.pageYOffset || document.documentElement.scrollTop || 0; 2050 document.body.style.setProperty('--af-filter-lock-top', '-' + mobileFilterState.scrollY + 'px'); 2051 document.body.classList.add('af-filter-open'); 2052 2053 panel.setAttribute('role', 'dialog'); 2054 panel.setAttribute('aria-modal', 'true'); 2055 panel.setAttribute('aria-label', 'ФилÑÑÑÑ ÐºÐ°Ñалога'); 2056 panel.setAttribute('aria-hidden', 'false'); 2057 } 2058 2059 function unlockMobileFilterBody(panel) { 2060 document.body.classList.remove('af-filter-open'); 2061 document.body.style.removeProperty('--af-filter-lock-top'); 2062 2063 if (panel) { 2064 panel.removeAttribute('role'); 2065 panel.removeAttribute('aria-modal'); 2066 panel.removeAttribute('aria-label'); 2067 if (isMobileFilterViewport()) { 2068 panel.setAttribute('aria-hidden', 'true'); 2069 } else { 2070 panel.removeAttribute('aria-hidden'); 2071 } 2072 } 2073 2074 window.scrollTo(0, mobileFilterState.scrollY || 0); 2075 } 2076 2077 function openMobileCatalogFilter(trigger, options) { 2078 options = options || {}; 2079 2080 if (!isMobileFilterViewport() || mobileFilterState.open) { 2081 return false;
2082 } 2083 2084 var panel = getMobileFilterPanel(); 2085 var form = getMobileFilterForm(); 2086 2087 if (!panel || !form || panel.hasAttribute('hidden')) { 2088 return false; 2089 } 2090 2091 mobileFilterState.open = true; 2092 mobileFilterState.closePending = false; 2093 mobileFilterState.trigger = trigger || document.querySelector('[data-af-filter-toggle]'); 2094 mobileFilterState.snapshot = createMobileFilterSnapshot(form); 2095 mobileFilterState.baseHistoryState = window.history.state; 2096 2097 resetMobileFilterSearchState(form); 2098 prepareMobileFilterGroups(form); 2099 syncMobileFilterUi(); 2100 lockMobileFilterBody(panel); 2101 2102 var toggle = document.querySelector('[data-af-filter-toggle]'); 2103 if (toggle) { 2104 toggle.setAttribute('aria-expanded', 'true'); 2105 } 2106 2107 if (options.pushHistory !== false && window.history && window.history.pushState) { 2108 var nextState = Object.assign({}, window.history.state || {}, { afFilterOverlay: true }); 2109 window.history.pushState(nextState, '', window.location.href); 2110 } 2111 2112 document.dispatchEvent(new CustomEvent('af:mobile-filter-opened')); 2113 2114 window.requestAnimationFrame(function () { 2115 var close = panel.querySelector('[data-af-filter-close]'); 2116 if (close) { 2117 focusWithoutScroll(close); 2118 } 2119 }); 2120 2121 return true; 2122 } 2123 2124 function closeMobileCatalogFilter(options) { 2125 options = options || {}; 2126 2127 if (!mobileFilterState.open) { 2128 return false; 2129 } 2130 2131 var panel = getMobileFilterPanel(); 2132 var trigger = mobileFilterState.trigger; 2133 2134 if (options.discard !== false) { 2135 restoreMobileFilterSnapshot(); 2136 } 2137 2138 resetMobileFilterSearchState(getMobileFilterForm()); 2139 syncMobileFilterUi(); 2140 unlockMobileFilterBody(panel); 2141 2142 mobileFilterState.open = false; 2143 mobileFilterState.closePending = false; 2144 mobileFilterState.snapshot = null; 2145 2146 var toggle = document.querySelector('[data-af-filter-toggle]'); 2147 if (toggle) { 2148 toggle.setAttribute('aria-expanded', 'false'); 2149 } 2150 2151 document.dispatchEvent(new CustomEvent('af:mobile-filter-closed', { 2152 detail: { discard: options.discard !== false } 2153 })); 2154 2155 if (options.restoreFocus !== false) { 2156 if (!trigger || !trigger.isConnected) { 2157 trigger = document.querySelector('[data-af-filter-toggle]'); 2158 } 2159 2160 if (trigger) { 2161 window.requestAnimationFrame(function () { 2162 focusWithoutScroll(trigger); 2163 }); 2164 } 2165 } 2166 2167 mobileFilterState.trigger = null; 2168 return true; 2169 } 2170 2171 function requestCloseMobileCatalogFilter() { 2172 if (!mobileFilterState.open || mobileFilterState.closePending) { 2173 return; 2174 } 2175 2176 if (window.history && window.history.state && window.history.state.afFilterOverlay) { 2177 mobileFilterState.closePending = true; 2178 window.history.back(); 2179 return; 2180 } 2181 2182 closeMobileCatalogFilter({ discard: true }); 2183 } 2184 2185 function commitAndCloseMobileCatalogFilter() { 2186 closeMobileCatalogFilter({ discard: false }); 2187 } 2188 2189 function abandonMobileCatalogFilterForNavigation() { 2190 if (!mobileFilterState.open) { 2191 return; 2192 } 2193 2194 if (window.history && window.history.replaceState && window.history.state && window.history.state.afFilterOverlay) { 2195 window.history.replaceState( 2196 mobileFilterState.baseHistoryState || {}, 2197 '', 2198 window.location.href 2199 ); 2200 } 2201 2202 closeMobileCatalogFilter({ discard: false, restoreFocus: false }); 2203 } 2204 2205 function handleMobileCatalogFilterPopState(event) { 2206 if (mobileFilterState.open) { 2207 closeMobileCatalogFilter({ discard: true }); 2208 return true; 2209 } 2210 2211 if ( 2212 isMobileFilterViewport() && 2213 event && 2214 event.state && 2215 event.state.afFilterOverlay 2216 ) { 2217 return openMobileCatalogFilter( 2218 document.querySelector('[data-af-filter-toggle]'),
2219 { pushHistory: false } 2220 ); 2221 } 2222 2223 return false; 2224 } 2225 2226 function trapMobileFilterFocus(event) { 2227 var panel = getMobileFilterPanel(); 2228 if (!panel) { 2229 return; 2230 } 2231 2232 var focusable = Array.prototype.filter.call( 2233 panel.querySelectorAll( 2234 'button:not([disabled]), a[href], summary, input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])' 2235 ), 2236 function (element) { 2237 return !element.hidden && element.getClientRects().length > 0; 2238 } 2239 ); 2240 2241 if (!focusable.length) { 2242 return; 2243 } 2244 2245 var first = focusable[0]; 2246 var last = focusable[focusable.length - 1]; 2247 2248 if (event.shiftKey && document.activeElement === first) { 2249 event.preventDefault(); 2250 last.focus(); 2251 } else if (!event.shiftKey && document.activeElement === last) { 2252 event.preventDefault(); 2253 first.focus(); 2254 } 2255 } 2256 2257 function initMobileCatalogFilter() { 2258 var panel = getMobileFilterPanel(); 2259 if (panel && isMobileFilterViewport() && !mobileFilterState.open) { 2260 panel.setAttribute('aria-hidden', 'true'); 2261 } 2262 2263 window.addEventListener('resize', function () { 2264 var currentPanel = getMobileFilterPanel(); 2265 2266 if (!isMobileFilterViewport()) { 2267 if (mobileFilterState.open) { 2268 requestCloseMobileCatalogFilter(); 2269 } else if (currentPanel) { 2270 currentPanel.removeAttribute('aria-hidden'); 2271 } 2272 } else if (currentPanel && !mobileFilterState.open) { 2273 currentPanel.setAttribute('aria-hidden', 'true'); 2274 } 2275 }); 2276 } 2277 2278 window.afCatalogMobileFilter = { 2279 isOpen: function () { 2280 return mobileFilterState.open; 2281 }, 2282 sync: syncMobileFilterUi, 2283 handlePopState: handleMobileCatalogFilterPopState, 2284 commitAndClose: commitAndCloseMobileCatalogFilter, 2285 abandonForNavigation: abandonMobileCatalogFilterForNavigation 2286 }; 2287 2288 function normalizeFilterLayout() { 2289 var layout = document.querySelector('.af-section-layout'); 2290 var filter = document.querySelector('.af-section-filter'); 2291 var mobileButton = document.querySelector('[data-af-filter-toggle]'); 2292 2293 if (!layout || !filter) { 2294 return; 2295 } 2296 2297 if (!filter.querySelector('.af-smart-filter')) { 2298 layout.classList.add('af-section-layout--no-filter'); 2299 filter.setAttribute('hidden', 'hidden'); 2300 if (mobileButton) { 2301 mobileButton.setAttribute('hidden', 'hidden'); 2302 } 2303 return; 2304 } 2305 2306 layout.classList.remove('af-section-layout--no-filter'); 2307 filter.removeAttribute('hidden'); 2308 if (mobileButton) { 2309 mobileButton.removeAttribute('hidden'); 2310 } 2311 } 2312 2313 function initShortCartPanel() { 2314 var panel = document.querySelector('.sticky__menu'); 2315 if (!panel) { 2316 return; 2317 } 2318 2319 var targetSelectors = ['.af-ready-info', '.af-size-calc']; 2320 2321 var getTargetBlocks = function () { 2322 return targetSelectors 2323 .map(function (selector) { return document.querySelector(selector); }) 2324 .filter(function (element) { 2325 return element && element.getClientRects().length > 0; 2326 }); 2327 }; 2328 2329 var isModalOpen = function () { 2330 var orderModal = document.querySelector('#orderModal'); 2331 if (orderModal && orderModal.classList.contains('show')) { 2332 return true; 2333 } 2334 2335 var visualModal = document.querySelector('#modalVisulate'); 2336 if (visualModal && (visualModal.classList.contains('show') || visualModal.getAttribute('aria-hidden') === 'false')) { 2337 return true; 2338 } 2339 2340 return !!document.querySelector('.modal.show'); 2341 }; 2342 2343 var closePanel = function () { 2344 panel.classList.add('closed'); 2345 panel.classList.remove('is-visible'); 2346 }; 2347 2348 var openPanel = function () { 2349 panel.classList.remove('closed'); 2350 panel.classList.add('is-visible'); 2351 }; 2352 2353 var isBlockVisible = function (element) { 2354 var rect = element.getBoundingClientRect();
2355 var viewportHeight = window.innerHeight || document.documentElement.clientHeight; 2356 return rect.bottom > 0 && rect.top < viewportHeight; 2357 }; 2358 2359 var toggle = function () { 2360 if (isModalOpen()) { 2361 closePanel(); 2362 return; 2363 } 2364 2365 var targetBlocks = getTargetBlocks(); 2366 if (!targetBlocks.length) { 2367 closePanel(); 2368 return; 2369 } 2370 2371 var hasVisibleTargetBlock = targetBlocks.some(function (block) { 2372 return isBlockVisible(block); 2373 }); 2374 2375 if (hasVisibleTargetBlock) { 2376 closePanel(); 2377 } else { 2378 openPanel(); 2379 } 2380 }; 2381 2382 toggle(); 2383 window.addEventListener('scroll', toggle, { passive: true }); 2384 window.addEventListener('resize', toggle); 2385 document.addEventListener('shown.bs.modal', toggle); 2386 document.addEventListener('hidden.bs.modal', toggle); 2387 } 2388 2389 function formatPhone(value) { 2390 var digits = String(value || '').replace(/\D/g, ''); 2391 if (digits[0] === '8') { 2392 digits = '7' + digits.slice(1); 2393 } 2394 if (digits[0] !== '7') { 2395 digits = '7' + digits; 2396 } 2397 digits = digits.slice(0, 11); 2398 2399 var result = '+7'; 2400 if (digits.length > 1) { result += ' (' + digits.slice(1, 4); } 2401 if (digits.length >= 4) { result += ')'; } 2402 if (digits.length > 4) { result += ' ' + digits.slice(4, 7); } 2403 if (digits.length > 7) { result += '-' + digits.slice(7, 9); } 2404 if (digits.length > 9) { result += '-' + digits.slice(9, 11); } 2405 return result; 2406 } 2407 2408 function escapeHtml(value) { 2409 return String(value || '') 2410 .replace(/&/g, '&') 2411 .replace(/</g, '<') 2412 .replace(/>/g, '>') 2413 .replace(/"/g, '"') 2414 .replace(/'/g, '''); 2415 } 2416 2417 function formatPrice(value) { 2418 return String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ' '); 2419 } 2420})();
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.