(function () { const css = ` .reviews-masonry { --reviews-gap: 1.25rem; --reviews-cols-desktop: 3; --reviews-cols-tablet: 2; --reviews-cols-mobile: 1; --reviews-initial-height-desktop: 40rem; --reviews-initial-height-tablet: 42rem; --reviews-initial-height-mobile: 44rem; --reviews-load-step-desktop: 28rem; --reviews-load-step-tablet: 26rem; --reviews-load-step-mobile: 44rem; --reviews-current-cols: var(--reviews-cols-desktop); --reviews-current-initial-height: var(--reviews-initial-height-desktop); --reviews-current-load-step: var(--reviews-load-step-desktop); display: block; column-count: var(--reviews-current-cols); column-gap: var(--reviews-gap); } .reviews-masonry > * { break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; margin-bottom: var(--reviews-gap); } .reviews-masonry::after { content: none !important; display: none !important; } .reviews-masonry-clip { position: relative; overflow: hidden; max-height: 0; transition: max-height 0.45s ease; } [data-reviews-fade] { position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; pointer-events: none; transition: opacity 0.25s ease, visibility 0.25s ease; } [data-reviews-fade].is-hidden { opacity: 0 !important; visibility: hidden !important; } [data-reviews-load-more].is-hidden { display: none !important; } [data-reviews-load-more-icon] { display: inline-flex; transform-origin: center; transition: transform 0.25s ease; } [data-reviews-load-more].is-expanded [data-reviews-load-more-icon] { transform: rotate(180deg); } @media (max-width: 61.9375rem) { .reviews-masonry { --reviews-current-cols: var(--reviews-cols-tablet); --reviews-current-initial-height: var(--reviews-initial-height-tablet); --reviews-current-load-step: var(--reviews-load-step-tablet); } } @media (max-width: 29.9375rem) { .reviews-masonry { --reviews-current-cols: var(--reviews-cols-mobile); --reviews-current-initial-height: var(--reviews-initial-height-mobile); --reviews-current-load-step: var(--reviews-load-step-mobile); } } `; function injectCSS() { if (document.getElementById('reviews-masonry-cut-toggle-css')) return; const style = document.createElement('style'); style.id = 'reviews-masonry-cut-toggle-css'; style.textContent = css; const target = document.head || document.documentElement; target.appendChild(style); } injectCSS(); const gridSelector = '.reviews-masonry'; const buttonSelector = '[data-reviews-load-more]'; const fadeSelector = '[data-reviews-fade]'; const buttonTextSelector = '[data-reviews-load-more-text]'; const clipClass = 'reviews-masonry-clip'; const hiddenClass = 'is-hidden'; const expandedClass = 'is-expanded'; function getRootFontSize() { return parseFloat(getComputedStyle(document.documentElement).fontSize) || 16; } function cssLengthToPx(value) { if (!value) return 0; const trimmed = String(value).trim(); if (trimmed.endsWith('rem')) { return parseFloat(trimmed) * getRootFontSize(); } if (trimmed.endsWith('px')) { return parseFloat(trimmed); } if (trimmed.endsWith('em')) { return parseFloat(trimmed) * getRootFontSize(); } return parseFloat(trimmed) || 0; } function getCSSVarPx(element, varName, fallbackPx) { const value = getComputedStyle(element).getPropertyValue(varName).trim(); const px = cssLengthToPx(value); return px > 0 ? px : fallbackPx; } function createClipWrapper(grid) { const existingClip = grid.closest('.' + clipClass); if (existingClip) { return existingClip; } const clip = document.createElement('div'); clip.className = clipClass; grid.parentNode.insertBefore(clip, grid); clip.appendChild(grid); return clip; } function findButton(referenceElement) { let nextElement = referenceElement.nextElementSibling; while (nextElement) { if (nextElement.matches && nextElement.matches(buttonSelector)) { return nextElement; } if (nextElement.querySelector) { const nestedButton = nextElement.querySelector(buttonSelector); if (nestedButton) { return nestedButton; } } nextElement = nextElement.nextElementSibling; } if (referenceElement.parentElement) { const parentButton = referenceElement.parentElement.querySelector(buttonSelector); if (parentButton) { return parentButton; } } return document.querySelector(buttonSelector); } function findFade(grid, clip) { let fade = clip.querySelector(fadeSelector); if (fade) { return fade; } if (clip.parentElement) { fade = clip.parentElement.querySelector(fadeSelector); if (fade) { return fade; } } if (grid.parentElement) { fade = grid.parentElement.querySelector(fadeSelector); if (fade) { return fade; } } return document.querySelector(fadeSelector); } function getFullHeight(grid) { return Math.ceil(Math.max( grid.scrollHeight, grid.offsetHeight, grid.getBoundingClientRect().height )); } function initReviewsCut(grid) { if (grid.dataset.reviewsCutInitialized === 'true') return; grid.dataset.reviewsCutInitialized = 'true'; const clip = createClipWrapper(grid); const button = findButton(clip); const fade = findFade(grid, clip); if (fade && fade.parentNode !== clip) { clip.appendChild(fade); } const buttonText = button ? button.querySelector(buttonTextSelector) : null; const moreText = button ? button.getAttribute('data-reviews-text-more') || (buttonText ? buttonText.textContent.trim() : '') || 'Load more review' : 'Load more review'; const collapseText = button ? button.getAttribute('data-reviews-text-collapse') || 'Свернуть все отзывы' : 'Свернуть все отзывы'; let currentHeight = 0; let expandClicks = 0; let isFullyExpanded = false; function getInitialHeight() { return getCSSVarPx(grid, '--reviews-current-initial-height', 700); } function getLoadStep() { return getCSSVarPx(grid, '--reviews-current-load-step', 400); } function setUI(state) { const isStatic = state === 'static'; const isExpanded = state === 'expanded'; if (button) { button.classList.toggle(hiddenClass, isStatic); button.classList.toggle(expandedClass, isExpanded); button.setAttribute('aria-expanded', isExpanded ? 'true' : 'false'); if (buttonText) { buttonText.textContent = isExpanded ? collapseText : moreText; } } if (fade) { fade.classList.toggle(hiddenClass, isStatic || isExpanded); } } function render() { const fullHeight = getFullHeight(grid); const initialHeight = getInitialHeight(); if (fullHeight <= initialHeight + 2) { currentHeight = fullHeight; clip.style.maxHeight = currentHeight + 'px'; isFullyExpanded = false; setUI('static'); return; } if (isFullyExpanded) { currentHeight = fullHeight; clip.style.maxHeight = currentHeight + 'px'; setUI('expanded'); return; } currentHeight = Math.min( fullHeight, initialHeight + expandClicks * getLoadStep() ); clip.style.maxHeight = currentHeight + 'px'; if (currentHeight >= fullHeight - 2) { isFullyExpanded = true; currentHeight = fullHeight; clip.style.maxHeight = currentHeight + 'px'; setUI('expanded'); } else { setUI('collapsed'); } } function expandMore() { expandClicks += 1; render(); } function collapseAll() { expandClicks = 0; isFullyExpanded = false; render(); } render(); if (button) { button.addEventListener('click', function (event) { event.preventDefault(); if (isFullyExpanded) { collapseAll(); } else { expandMore(); } }); } let resizeTimer; window.addEventListener('resize', function () { clearTimeout(resizeTimer); resizeTimer = setTimeout(function () { render(); }, 150); }); } function init() { injectCSS(); document.querySelectorAll(gridSelector).forEach(function (grid) { initReviewsCut(grid); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();