Скрипт предназначен для работы с модулем подписок на uCoz.
Его основная задача отображать список подписанных тем и обновлять его при изменениях, при этом работая быстро и экономно.
Принцип работы:
Подсчет количества тем Скрипт не перебирает все темы и не анализирует каждый элемент страницы — это было бы медленно. Вместо этого он берет число тем из системного элемента, который уже показывает uCoz. Это позволяет почти мгновенно определить, есть ли изменения.
Кэширование Все загруженные темы сохраняются в LocalStorage. При загрузке страницы скрипт сначала проверяет кэш: если количество тем не изменилось, он использует сохраненные данные и не делает лишних запросов.
Проверка изменений Если количество тем изменилось, скрипт загружает список подписанных тем заново, удаляет старые записи и формирует новый HTML с актуальной информацией.
Загрузка темы и деталей Для каждой темы скрипт получает:
Название темы
Ссылку на тему
Аватар (первое изображение в теме, если есть)
Описание темы (текст из span.thDescr, если присутствует)
Всё это собирается в блоки .subs-item, которые отображаются в контейнере.
Кликабельность
Клик по счетчику подписок открывает страницу списка подписок в той же вкладке.
Клик по блоку темы открывает тему в той же вкладке, при этом клики по ссылкам внутри блока игнорируются (чтобы не ломать стандартное поведение).
Экономия ресурсов Скрипт работает минимально, делает запросы только при необходимости, что уменьшает нагрузку на сервер и ускоряет работу страницы.
Стабильность и расширяемость Скрипт сохраняет все данные в кэш и позволяет легко добавлять новые функции или визуальные улучшения, сохраняя при этом простоту и производительность.
.subs-desc { font-size:12px; /* на 1px меньше */ color:#555; line-height:1.4; white-space:normal; /* полный текст */ }
/* ======= Пустой блок (узкий и ниже по высоте) ======= */ .subs-empty { padding:0px 0px; /* меньше сверху/снизу */ text-align:center; color:#999; font-size:14px; max-width:300px; /* узкий блок по ширине */ margin:20px auto; /* по центру контейнера */ border-radius:6px; /* чуть скругления */ background:#f9f9f9; /* легкий фон, чтобы выделялся */ box-shadow:0 2px 6px rgba(0,0,0,0.05); }
.subs-empty::before { content:"👥"; display:block; font-size:30px; /* чуть меньше, чтобы не было огромного смайла */ margin-bottom:8px; opacity:0.3; }
/* ======= Подсчет с фоном как в старом ВК ======= */ .subs-footer { background: linear-gradient(#fbf3c2, #ffe58a); /* фон старого ВК */ color: #6b5d00; /* цвет текста */ font-size:11px; font-weight:700; padding:4px 8px; text-align:left; border-top:1px solid #e6c700; /* легкий контур как ВК */ border-radius:0 0 0px 0px; /* скругляем низ блока */ box-shadow: inset 0 1px 0 rgba(255,255,255,0.8), inset 0 -1px 0 rgba(0,0,0,0.06), 0 1px 1px rgba(0,0,0,0.08); }
// Число подписок кликабельно counter.style.cursor = 'pointer'; counter.title = 'Перейти к списку подписок'; counter.onclick = () => { // открываем в этой же вкладке window.location.href = forumURL; };
// Функция, чтобы навесить клик на все блоки function makeItemsClickable() { document.querySelectorAll('.subs-item').forEach(item => { item.style.cursor = 'pointer'; item.onclick = e => { if(e.target.tagName.toLowerCase() === 'a') return; // открываем тему в этой же вкладке window.location.href = item.dataset.link; }; }); }
// Сразу показываем кэш, если есть let cached = JSON.parse(localStorage.getItem(localKey) || 'null'); if(cached){ container.innerHTML = cached.html; counter.textContent = `${cached.count} подписок`; makeItemsClickable(); // навешиваем клики сразу }
try { // Параллельно проверяем число тем на сервере let page = await fetch(forumURL, {credentials:'include'}); let html = await page.text(); let doc = parser.parseFromString(html,'text/html');
let threadsTd = doc.querySelector('td.threadsDetails b'); let count = threadsTd ? parseInt(threadsTd.textContent.trim()) : 0; counter.textContent = `${count} подписок`;
// Если кэш есть и число не изменилось используем старый кэш и выходим if(cached && cached.count === count){ console.log('Кэш актуален, обновление не требуется'); return; }
// Загружаем все темы заново let rows = doc.querySelectorAll('tr[id^="tt"]'); if(!rows.length){ container.innerHTML = '<div class="subs-empty">Нет подписок</div>'; counter.textContent = '0 подписок'; localStorage.removeItem(localKey); return; }
let resultHTML = '';
for(let row of rows){ let topicEl = row.querySelector('.topic-item-title'); if(!topicEl) continue;
let topic = topicEl.textContent.trim(); let topicLink = topicEl.href;
let avatar = '/img/default_avatar.png'; let topicDesc = '';
try { let topicPage = await fetch(topicLink, {credentials:'include'}); let topicHTML = await topicPage.text(); let topicDoc = parser.parseFromString(topicHTML,'text/html');
let firstImg = topicDoc.querySelector('.post-content-main img'); if(firstImg) avatar = firstImg.src;
Использовать подписки как «группы» В uCoz можно подписываться на темы или разделы. По сути, это уже готовый механизм уведомлений и контроля доступа. Вместо того чтобы делать полноценный форумный раздел с кучей настроек, можно просто использовать подписку на тему как «группу участников».
Эмуляция страницы типа «ВКонтакте» Можно сделать скрипт, который будет выводить не весь форум, а только те темы, на которые подписан пользователь. Это будет выглядеть как лента новостей или «групповой стенки».
Подписка на тему - участие в группе.
Контент темы -посты группы.
Аватар, описание темы, количество сообщений - как карточка группы.
Контроль доступа
Если нужно, можно «запролить» тему или раздел: доступ только избранным пользователям.
Скрипт будет проверять подписки текущего пользователя и показывать только то, на что он подписан.
Таким образом, можно сделать закрытую мини-сеть внутри форума, где пользователи видят только свои «группы».
Удобство и кастомизация
Лента может быть полностью кастомной: только нужная информация, без лишних колонок форума.
Можно добавить аватар темы, последние посты, описание, количество новых сообщений.
Всё это формируется на клиентской стороне через скрипт, без необходимости переделывать серверную часть.
Почему это удобно
Не нужно создавать отдельную социальную сеть используешь существующую инфраструктуру форума.
Подписки уже хранятся в системе, это упрощает хранение и отображение контента.
Можно полностью контролировать визуальное оформление и логику показа.
Можно легко расширять функционал: лайки, комментарии, фильтры и т.д., просто добавляя JS на фронтенд.
Это одна из самых ранних разработок. Основное внимание в ней было уделено дизайну визуальная часть находилась в приоритете. Сам же скрипт, его «сердце», довольно примитивен: по сути, это простой парсер, который обрабатывает лишь ограничённый набор данных и не содержит какой-либо логики. Иными словами, перед вами скрипт без «мозгов» простой, как одноклеточный организм.
Однако суть не в этом. Если вам понравился дизайн данного блока подписок, вы можете взять скриптовую часть из более продвинутого модуля и заменить её в результате вы получите знакомый дизайн, но уже с «новым мозгом» и расширенными возможностями современного модуля.
let topicEl = row.querySelector('.topic-item-title'); if(!topicEl) continue;
let topic = topicEl.textContent.trim(); let topicLink = topicEl.href;
/* === ИЗВЛЕКАЕМ ПЕРВУЮ КАРТИНКУ ИЗ ПЕРВОГО ПОСТА === */ let avatar='/.s/img/icon/user.png'; let topicDesc='';
try{ let topicPage = await fetch(topicLink,{credentials:'include'}); let topicHTML = await topicPage.text(); let topicDoc = parser.parseFromString(topicHTML,'text/html');
// Первая картинка из поста let firstImg = topicDoc.querySelector('.post-content-main img'); if(firstImg && firstImg.src) avatar = firstImg.src;
// Описание темы let thDescrEl = topicDoc.querySelector('span.thDescr'); topicDesc = thDescrEl ? thDescrEl.textContent.trim() : '';
}catch(e){ console.warn('Не удалось получить пост/картинку/описание', topicLink, e); }