// js/unfold.js
(function () {
"use strict";
// ----------------------------------------
// НАСТРОЙКИ - Изменяйте эти значения свободно
// ----------------------------------------
const CONFIG = {
targetClass: "unfold-section", // CSS-класс на вашей секции Elementor
expandedClass: "is-expanded", // Класс, добавляемый при раскрытии
collapsedHeight: "300px", // Высота в свёрнутом состоянии
btnTextMore: "Развернуть ▼", // Текст кнопки в свёрнутом состоянии
btnTextLess: "Свернуть ▲", // Текст кнопки в развёрнутом состоянии
showOverlay: true, // Показывать градиентное затухание
scrollToTop: true, // Прокручивать вверх при сворачивании
};
// ----------------------------------------
/**
* Инициализация всех сворачиваемых секций на странице
*/
function initUnfold() {
// Находим все секции с целевым классом
const sections = document.querySelectorAll("." + CONFIG.targetClass);
if (sections.length === 0) {
console.warn("Unfold: Секции с классом ." + CONFIG.targetClass + " не найдены");
return;
}
sections.forEach(function (section, index) {
// ✅ ЗАЩИТА: Пропускаем, если секция уже инициализирована
if (section.dataset.unfoldInit === "true") {
return; // Останавливаемся, уже выполнено
}
section.dataset.unfoldInit = "true";
// Устанавливаем высоту свёрнутого состояния из настроек
const customHeight = section.dataset.collapseHeight || CONFIG.collapsedHeight;
section.style.maxHeight = customHeight;
section.style.overflow = "hidden";
section.style.position = "relative";
section.style.transition = "max-height 0.6s ease-in-out";
// Добавляем градиентное затухание
if (CONFIG.showOverlay) {
addOverlay(section);
}
// Создаём кнопку «Развернуть»
const btnWrapper = createButton(section, index);
// Вставляем кнопку ПОСЛЕ секции
if (btnWrapper !== null) {
section.parentNode.insertBefore(btnWrapper, section.nextSibling);
}
});
}
/**
* Добавляем градиентный оверлей внутрь секции
*/
function addOverlay(section) {
const overlay = document.createElement("div");
overlay.classList.add("unfold-overlay");
// По возможности подбираем цвет фона секции
const bgColor = getComputedStyle(section).backgroundColor;
if (bgColor && bgColor !== "rgba(0, 0, 0, 0)") {
overlay.style.background =
"linear-gradient(to bottom, rgba(255,255,255,0), " + bgColor + ")";
}
section.appendChild(overlay);
}
/**
* Создаём кнопку «Развернуть» / «Свернуть»
*/
function createButton(section, index) {
// ✅ ПРОВЕРКА: Если кнопка рядом с секцией уже существует — пропускаем
const nextEl = section.nextElementSibling;
if (nextEl && nextEl.classList.contains("unfold-btn-wrapper")) {
return null; // Кнопка уже есть, повторно не создаём
}
const wrapper = document.createElement("div");
wrapper.classList.add("unfold-btn-wrapper");
const btn = document.createElement("button");
btn.classList.add("unfold-btn");
btn.setAttribute("aria-expanded", "false");
btn.setAttribute("aria-controls", "unfold-section-" + index);
btn.textContent = CONFIG.btnTextMore;
section.setAttribute("id", "unfold-section-" + index);
btn.addEventListener("click", function () {
toggleSection(section, btn);
});
wrapper.appendChild(btn);
return wrapper;
}
/**
* Переключаем состояние: развернуть / свернуть
*/
function toggleSection(section, btn) {
const isExpanded = section.classList.contains(CONFIG.expandedClass);
if (!isExpanded) {
// --- РАЗВОРАЧИВАЕМ ---
expandSection(section, btn);
} else {
// --- СВОРАЧИВАЕМ ---
collapseSection(section, btn);
}
}
/**
* Разворачиваем секцию
*/
function expandSection(section, btn) {
// Получаем реальную полную высоту
const fullHeight = section.scrollHeight + "px";
section.style.maxHeight = fullHeight;
section.style.transition = "max-height 0.8s ease-in-out";
section.classList.add(CONFIG.expandedClass);
btn.textContent = CONFIG.btnTextLess;
btn.setAttribute("aria-expanded", "true");
// После завершения анимации снимаем ограничение для динамического контента
section.addEventListener("transitionend", function handler() {
if (section.classList.contains(CONFIG.expandedClass)) {
section.style.maxHeight = "none";
}
section.removeEventListener("transitionend", handler);
});
}
/**
* Сворачиваем секцию
*/
function collapseSection(section, btn) {
// Перед анимацией необходимо задать явную высоту
section.style.maxHeight = section.scrollHeight + "px";
// Принудительный пересчёт макета браузером
section.offsetHeight;
// Запускаем анимацию до свёрнутой высоты
section.style.transition = "max-height 0.6s ease-in-out";
section.style.maxHeight = CONFIG.collapsedHeight;
section.classList.remove(CONFIG.expandedClass);
btn.textContent = CONFIG.btnTextMore;
btn.setAttribute("aria-expanded", "false");
// Прокручиваем страницу к началу секции
if (CONFIG.scrollToTop) {
setTimeout(function () {
section.scrollIntoView({ behavior: "smooth", block: "start" });
}, 300);
}
}
// ----------------------------------------
// Запуск после загрузки DOM и готовности Elementor
// ----------------------------------------
// Стандартное событие готовности DOM
document.addEventListener("DOMContentLoaded", function () {
initUnfold();
});
// Событие готовности Elementor Frontend (для динамических виджетов)
window.addEventListener("elementor/frontend/init", function () {
if (window.elementorFrontend) {
elementorFrontend.hooks.addAction(
"frontend/element_ready/global",
function () {
initUnfold(); // Повторная инициализация при добавлении новых виджетов
}
);
}
});
})();