Единый форум поддержки

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Единый форум поддержки » Новые возможности форумов » Запросы по скриптам #11


Запросы по скриптам #11

Сообщений 1761 страница 1761 из 1761

1

В этой теме просим о создании различных скриптов

Здесь вы можете оставить запрос на разработку нового скрипта для форума. Пожалуйста, внимательно ознакомьтесь с правилами темы. Просьба быть внимательным: эта тема касается только вопросов о создании новых скриптов!
Вопросы по оформлению форума и прочим CSS-кодам, просьба, задавать в темах Общие вопросы от новичков (63) #3 и Общие вопросы по оформлению (65) #2

Информируем о следующем:

  • Участники форума оказывают помощь в написании скриптов исключительно по собственному желанию.

  • Администрация форума не может гарантировать исполнение и корректность каждого запроса.

  • Пожалуйста, уважайте чужое время и усилия других пользователей, старайтесь писать грамотно и доходчиво.

  • Будьте взаимовежливы: Грубое или требовательное отношение к участникам форума неприемлемо и может привести к отказу в помощи на всём форуме.

  • Все вопросы, не касающиеся запросов скриптов, будут удаляться!

Сформулируйте свой запрос максимально подробно, чтобы повысить вероятность отклика:

  • Опишите желаемую функциональность: Что конкретно должен делать скрипт?

  • Укажите конечный результат: Что вы хотите получить в итоге? Где и как будет использоваться скрипт?

  • Если есть примеры, покажите: Укажите ссылки на схожий функционал скрипта или нарисуйте макет (на скриншоте), чего именно вы ожидаете получить - всё это значительно упростит задачу.

Если на ваш запрос долго нет ответа, пожалуйста, воздержитесь от повторных сообщений или обвинений. Возможно, задача оказалась слишком сложной или трудозатратой по времени, будьте готовы к тому, что участники могут предложить свои услуги на платной основе. Обсуждение условий и оплаты происходит между вами и участником (исполнителем) в личных сообщениях или иных средствах связи (но не в теме!). Администрация форума не несет никакой ответственности за подобные договоренности и их выполнение.

Если скрипт был написан на безвозмездной основе, автор может разместить его в общем каталоге скриптов для других пользователей.

Предыдущая тема - Запросы по скриптам[10]

Инструменты для поиска и редактирования стиля (скриптов).

Как с помощью браузера можно определить элемент дизайна.

Каталог скриптов/CSS

Полезные скрипты, необходимые темы для новичков, а также ссылки на сайты рассказывающие что такое НТМЛ и CSS.

Типовые Вопросы (ЧаВо)

Ответы на часто задаваемые вопросы.

Как правильно задавать вопросы. В чём разница между стилем и скриптом.

Плюс к названию темы еще и Памятка.

+1

1761

📖  «Аккордеон-спойлер» для скрытия полей мини-профиля в топиках

🎯 Назначение
Скрипт автоматически находит мини-профили пользователей в топиках форума и сворачивает менее важные поля (IP, возраст, город, кол-во сообщений и т.д.) в компактный аккордеон. Пользователь видит только основные поля (аватар, ник, статус), а всё остальное раскрывается по клику на кнопку со стрелкой.
Ключевое отличие от аналогов: код написан на чистом vanilla JavaScript без использования jQuery или других библиотек. Это означает:

  • ✅ Минимальный размер — нет лишних килобайт зависимостей

  • ✅ Высокая производительность — прямая работа с DOM через нативные API

  • ✅ Совместимость — работает в любом современном браузере без дополнительных плагинов

  • ✅ Современные подходы — используются querySelectorAll, MutationObserver, classList, CSS Grid и другие актуальные стандарты


👀 Как это выглядит

Спойлер закрыт

[html]<img class="postimg" loading="lazy" src="https://upforme.ru/uploads/001a/f0/7d/2/580448.webp" alt="https://upforme.ru/uploads/001a/f0/7d/2/580448.webp">[/html]

Спойлер открыт

[html]<img class="postimg" loading="lazy" src="https://upforme.ru/uploads/001a/f0/7d/2/108643.webp" alt="https://upforme.ru/uploads/001a/f0/7d/2/108643.webp">[/html]


🧱 Структура, которую создаёт скрипт
Для каждого мини-профиля (.post-author) скрипт генерирует такую DOM-структуру:

Показать структуру

.post-author
├── .pa-avatar          ← остаётся на месте (SHOW)
├── .pa-author          ← остаётся на месте (SHOW)
├── .pa-title           ← остаётся на месте (SHOW)

├── .msp-wrap           ← ← ← НОВЫЙ контейнер (вставляется сюда)
│   ├── .msp-toggle     ← кнопка-стрелка с тултипом
│   │   └── <img>       ← иконка стрелки (поворачивается на 180°)
│   │
│   └── .msp-spoiler    ← grid-обёртка (анимирует высоту)
│       └── .msp-spoiler-inner  ← реальный контейнер контента
│           ├── .pa-ip          ← перенесено внутрь (HIDE)
│           ├── .pa-age         ← перенесено внутрь (HIDE)
│           ├── .pa-from        ← перенесено внутрь (HIDE)
│           ├── .pa-posts       ← перенесено внутрь (HIDE)
│           ├── .pa-respect     ← перенесено внутрь (HIDE)
│           ├── .pa-sex         ← перенесено внутрь (HIDE)
│           └── .pa-ua          ← перенесено внутрь (HIDE)


⚙️ Как работает JavaScript

Показать

1. Конфигурация — что показывать, что скрывать

var SHOW = ['pa-author','pa-title','pa-avatar'];
var HIDE = ['pa-ip','pa-age','pa-from','pa-posts','pa-respect','pa-sex','pa-ua'];

  • SHOW — поля, которые всегда видны. Скрипт ищет последнее из них, чтобы вставить спойлер сразу после.

  • HIDE — поля, которые будут «упакованы» внутрь спойлера.

2. Инициализация — поиск и перенос элементов

document.querySelectorAll('.post-author').forEach(function (box) {

Для каждого мини-профиля:

  • Проверка box.dataset.mspDone — чтобы не обработать один и тот же блок дважды.

  • Сбор скрытых полей — скрипт перебирает массив HIDE, находит соответствующие элементы внутри .post-author и складывает в массив hidden.

  • Создание DOM-структуры — создаются .msp-wrap, .msp-toggle, .msp-spoiler, .msp-spoiler-inner.

  • Перенос элементов — все найденные скрытые поля физически перемещаются внутрь .msp-spoiler-inner через appendChild() (браузер сам удаляет элемент со старого места).

  • Вставка спойлера — скрипт ищет последний видимый элемент из SHOW и вставляет .msp-wrap сразу после него через insertBefore(wrap, anchor.nextSibling).

3. Обработчик клика

btn.addEventListener('click', function () {
  wrap.classList.toggle('msp-open');
});

При клике просто добавляется/убирается класс .msp-open на обёртке. Вся анимация — на CSS.
4. Защита от динамической подгрузки

new MutationObserver(init).observe(document.body, { childList: true, subtree: true });

MutationObserver следит за изменениями DOM. Если форум подгружает новые сообщения через AJAX (бесконечная прокрутка, переход по страницам без перезагрузки), скрипт автоматически обработает новые мини-профили.


🎨 Как работает CSS-анимация (Grid-трюк)
Это самая интересная часть — анимация высоты без JavaScript.

Показать

Проблема обычной анимации
Чтобы анимировать height: 0 → auto, нужно знать точную высоту контента в пикселях. Но высота зависит от контента, шрифтов, адаптивности... Раньше это решали так:

// ❌ Старый подход: JS считает высоту
element.style.height = element.scrollHeight + 'px';

Это требует пересчёта при каждом изменении контента, при ресайзе окна, и работает дёрганно.

Решение через CSS Grid

.msp-spoiler {
  display: grid;
  grid-template-rows: 0fr;          /* ← свёрнуто */
  transition: grid-template-rows 0.4s ease-out;
}
.msp-wrap.msp-open .msp-spoiler {
  grid-template-rows: 1fr;          /* ← развёрнуто */
}
.msp-spoiler > .msp-spoiler-inner {
  overflow: hidden;
  min-height: 0;                     /* ← обязательно! */
}

Пошаговая механика

1. msp-spoiler — это grid-контейнер с одной строкой
2. grid-template-rows: 0fr — высота строки = 0 долей от доступного пространства. Фактически 0px.
3. grid-template-rows: 1fr — высота строки = 1 доля = весь доступный контент. Браузер сам вычисляет нужную высоту.
4. transition плавно интерполирует между 0fr и 1fr за 0.4 секунды
5. msp-spoiler-inner с overflow: hidden обрезает контент, который вылезает за пределы grid-ячейки
6. min-height: 0критически важно! Без этого grid-элемент не может стать меньше своего минимального контента (по спецификации CSS grid min-height: auto по умолчанию), и анимация не сожмётся до нуля

Почему это работает

0fr → 0.1fr → 0.3fr → 0.6fr → 0.9fr → 1fr
0px    12px    38px    72px   108px   120px  (пример)

Браузер линейно интерполирует значение fr от 0 до 1, а высота grid-ячейки плавно растёт. Внутренний overflow: hidden обрезает контент на каждом кадре — получается плавное «раскрытие».

Поддержка браузерами - Chrome, Firefox, Safari, Edge поддерживают CSS-анимацию с 2023 года.
На момент 2026 года это работает во всех актуальных браузерах.


🖱️ Интерактивные элементы

Показать

Кнопка-стрелка

.msp-toggle img {
  transition: transform 0.3s;
}
.msp-wrap.msp-open .msp-toggle img {
  transform: rotate(180deg);    /* стрелка переворачивается */
}

Стрелка плавно поворачивается на 180° при раскрытии — визуальная подсказка состояния.

Тултип (всплывающая подсказка) при наведении

.msp-toggle::after {
  content: attr(data-tip);      /* берёт текст из data-tip="Развернуть/Свернуть" */
  position: absolute;
  bottom: 100%;
  opacity: 0;
  transition: opacity 0.2s;
}
.msp-toggle:hover::after { opacity: 1; }

Псевдоэлемент ::after создаёт всплывающую подсказку над кнопкой. Текст берётся из атрибута data-tip — удобно менять без правки CSS.


🔄 Полный цикл работы

Развернуть

Страница загружается (или подгружается через AJAX)

init() находит все .post-author на странице

Для каждого: проверяет dataset.mspDone
(уже обработан? → пропускаем)

Собирает поля из массива HIDE
(pa-ip, pa-age, pa-from и т.д.)

Создаёт DOM: .msp-wrap > .msp-toggle + .msp-spoiler
Переносит скрытые поля внутрь .msp-spoiler-inner

Вставляет .msp-wrap после последнего поля из SHOW

Пользователь кликает на .msp-toggle
→ toggle('msp-open')
→ CSS анимирует grid-template-rows: 0fr ↔ 1fr
→ Стрелка поворачивается на 180°


💡 Ключевые преимущества этого подхода

Развернуть
  • Без JS-расчётов - не нужно измерять scrollHeight, не нужно пересчитывать при ресайзе

  • Плавная анимация - CSS transition работает на GPU, 60fps без лагов

  • Адаптивность - высота подстраивается под любой контент автоматически

  • Производительность - один MutationObserver на всю страницу, а не слушатели на каждом элементе

  • Защита от повторов - dataset.mspDone гарантирует, что каждый блок обработан ровно один раз

  • Совместимость с AJAX - MutationObserver ловит динамически подгруженные сообщения


🔧 Как настроить под себя

Развернуть

// Какие поля оставить видимыми (CSS-классы без точки)
var SHOW = ['pa-author', 'pa-title', 'pa-avatar'];

// Какие поля спрятать в спойлер
var HIDE = ['pa-ip', 'pa-age', 'pa-from', 'pa-posts', 'pa-respect', 'pa-sex', 'pa-ua'];

// Текст всплывающей подсказки
var TIP = 'Развернуть/Свернуть';

// URL иконки-стрелки (32×16 px)
var IMG = 'https://forumstatic.ru/files/001a/f0/7d/19517.png';


Достаточно поменять массивы SHOW / HIDE — и скрипт автоматически перераспределит поля. Порядок в SHOW определяет, после какого поля появится кнопка спойлера (скрипт берёт последний найденный).


📝 Исходный код

Показать код
Код:
<!--НАЧАЛО  html-верх - Спойлер для скрытия полей мини-профиля в топиках-->
<style>
.msp-wrap {
  display: block;
  margin: 2px 0;
}

.msp-toggle {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  padding: 0 6px;
  margin: 2px 0;
  border-radius: 4px;
  background: rgba(0,0,0,0.05);
  position: relative;
  vertical-align: middle;
  transition: background 0.2s;
}
.msp-toggle:hover { background: rgba(0,0,0,0.1); }
.msp-toggle img {
  width: 32px;
  height: 16px;
  display: block;
  transition: transform 0.3s;
}
.msp-wrap.msp-open .msp-toggle img {
  transform: rotate(180deg);
}

/* Магия grid-анимации */
.msp-spoiler {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.4s ease-out;
}
.msp-wrap.msp-open .msp-spoiler {
  grid-template-rows: 1fr;
}
.msp-spoiler > .msp-spoiler-inner {
  overflow: hidden;
  min-height: 0;
}
.msp-toggle::after {
  content: attr(data-tip);
  position: absolute;
  bottom: 100%;
  left: 0;
  transform: translateY(-4px);
  background: #333;
  color: #fff;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 11px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
  z-index: 1000;
  margin-bottom: 4px;
}
</style>

<script>
(function () {
  'use strict';

  var SHOW = ['pa-author','pa-title','pa-avatar'];
  var HIDE = ['pa-ip','pa-age','pa-from','pa-posts','pa-respect','pa-sex','pa-ua'];
  var TIP = 'Развернуть/Свернуть';
  var IMG = 'https://forumstatic.ru/files/001a/f0/7d/19517.png';

  function init() {
    document.querySelectorAll('.post-author').forEach(function (box) {
      if (box.dataset.mspDone) return;
      box.dataset.mspDone = '1';

      var hidden = [];
      HIDE.forEach(function (c) {
        var el = box.querySelector('.' + c);
        if (el) hidden.push(el);
      });
      if (!hidden.length) return;

      var wrap = document.createElement('div');
      wrap.className = 'msp-wrap';

      var btn = document.createElement('div');
      btn.className = 'msp-toggle';
      btn.setAttribute('data-tip', TIP);
      btn.innerHTML = '<img src="' + IMG + '" alt="">';

      var spoiler = document.createElement('div');
      spoiler.className = 'msp-spoiler';

      // Внутренняя обёртка обязательна для grid-трюка
      var inner = document.createElement('div');
      inner.className = 'msp-spoiler-inner';
      hidden.forEach(function (el) { inner.appendChild(el); });
      spoiler.appendChild(inner);

      wrap.appendChild(btn);
      wrap.appendChild(spoiler);

      var anchor = null;
      for (var i = SHOW.length - 1; i >= 0; i--) {
        anchor = box.querySelector('.' + SHOW[i]);
        if (anchor) break;
      }

      if (anchor && anchor.parentNode) {
        anchor.parentNode.insertBefore(wrap, anchor.nextSibling);
      } else {
        box.appendChild(wrap);
      }

      btn.addEventListener('click', function () {
        wrap.classList.toggle('msp-open');
      });
    });
  }

  document.readyState === 'loading'
    ? document.addEventListener('DOMContentLoaded', init)
    : init();

  new MutationObserver(init).observe(document.body, { childList: true, subtree: true });
})();
</script>
<!-- КОНЕЦ Спойлер для скрытия полей мини-профиля в топиках--->

P.S. Пример реального кода на моём форуме, с небольшими добавлениями  (с дополнительными полями):

Показать код
Код:
<!--НАЧАЛО  html-верх - Спойлер для скрытия полей мини-профиля в топиках-->
<style>
.msp-wrap {
  display: block;
  margin: 2px 0;
}

.msp-toggle {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  padding: 0 6px;
  margin: 2px 0;
  border-radius: 4px;
  background: rgba(0,0,0,0.05);
  position: relative;
  vertical-align: middle;
  transition: background 0.2s;
}
.msp-toggle:hover { background: rgba(0,0,0,0.1); }
.msp-toggle img {
  width: 32px;
  height: 16px;
  display: block;
  transition: transform 0.3s;
}
.msp-wrap.msp-open .msp-toggle img {
  transform: rotate(180deg);
}

.msp-toggle::after {
  content: attr(data-tip);
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  background: #333;
  color: #fff;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 11px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
  z-index: 10;
}
.msp-toggle:hover::after { opacity: 1; }

/* Магия grid-анимации */
.msp-spoiler {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.4s ease-out;
}
.msp-wrap.msp-open .msp-spoiler {
  grid-template-rows: 1fr;
}
.msp-spoiler > .msp-spoiler-inner {
  overflow: hidden;
  min-height: 0;
}
.msp-toggle::after {
  content: attr(data-tip);
  position: absolute;
  bottom: 100%;
  left: 0; /* Вместо left: 50% */
  transform: translateY(-4px); /* Убираем translateX */
  background: #333;
  color: #fff;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 11px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
  z-index: 1000; /* Поверх всего */
  margin-bottom: 4px;
}
</style>

<script>
(function () {
  'use strict';

  var SHOW = ['pa-author','pa-title','pa-fld1','pa-avatar'];
  var HIDE = ['pa-ip','pa-age','pa-from','pa-posts','pa-respect','pa-sex','pa-fld2','pa-ua'];
  var TIP = 'Развернуть/Свернуть';
  var IMG = 'https://forumstatic.ru/files/001a/f0/7d/19517.png';

  function init() {
    document.querySelectorAll('.post-author').forEach(function (box) {
      if (box.dataset.mspDone) return;
      box.dataset.mspDone = '1';

      var hidden = [];
      HIDE.forEach(function (c) {
        var el = box.querySelector('.' + c);
        if (el) hidden.push(el);
      });
      if (!hidden.length) return;

      var wrap = document.createElement('div');
      wrap.className = 'msp-wrap';

      var btn = document.createElement('div');
      btn.className = 'msp-toggle';
      btn.setAttribute('data-tip', TIP);
      btn.innerHTML = '<img src="' + IMG + '" alt="">';

      var spoiler = document.createElement('div');
      spoiler.className = 'msp-spoiler';

      // Внутренняя обёртка обязательна для grid-трюка
      var inner = document.createElement('div');
      inner.className = 'msp-spoiler-inner';
      hidden.forEach(function (el) { inner.appendChild(el); });
      spoiler.appendChild(inner);

      wrap.appendChild(btn);
      wrap.appendChild(spoiler);

      var anchor = null;
      for (var i = SHOW.length - 1; i >= 0; i--) {
        anchor = box.querySelector('.' + SHOW[i]);
        if (anchor) break;
      }

      if (anchor && anchor.parentNode) {
        anchor.parentNode.insertBefore(wrap, anchor.nextSibling);
      } else {
        box.appendChild(wrap);
      }

      btn.addEventListener('click', function () {
        wrap.classList.toggle('msp-open');
      });
    });
  }

  document.readyState === 'loading'
    ? document.addEventListener('DOMContentLoaded', init)
    : init();

  new MutationObserver(init).observe(document.body, { childList: true, subtree: true });
})();
</script>
<!-- КОНЕЦ Спойлер для скрытия полей мини-профиля в топиках--->

Отредактировано Merlin777 (Сегодня 01:38:04)

0


Вы здесь » Единый форум поддержки » Новые возможности форумов » Запросы по скриптам #11