Форма комментариев -VK социальная сеть V 1.0 uCoz функционал
Дата: Понедельник, 16.02.2026, 04:27 | Сообщение # 1 |
|
Написал: Узнаваемый
Автор темы
Мурчанн
не в сети
Сообщений: 211
Здравствуйте, уважаемый читатель. Как вы уже, вероятно, догадались, я публикую открытые исходные коды. Делается это с одной целью чтобы как можно больше людей могли подхватить идею, развить её, улучшить под свои задачи и создать нечто более продвинутое. Только через открытость, практику и совместное развитие можно добиться реального прогресса и вывести проект на новый уровень.А теперь давайте начнём по порядку. Ниже я подробно опишу, какие изменения и обновления были внесены. Данная форма комментариев была изначально разработана для каталога статей сайта на платформе uCoz. Однако это не должно вас ограничивать форму можно легко адаптировать под любой модуль, и она будет корректно работать практически везде.Основные возможности формы: Отправка комментариев непосредственно к материалу и в систему комментариев модуля «Страница материала». Стилистика интерфейса выполнена в духе классических социальных сетей: можно заметить лёгкое сходство, однако дизайн полностью авторский и переработан.Несколько режимов работы: Режим «Невидимка» возможность оставлять комментарии скрытно. Подписка на комментарии получение уведомлений о новых ответах и обновлениях обсуждения. Встроенный набор смайлов для выражения эмоций. Реализовано компактное всплывающее окно для быстрой отправки эмоций и реакций. Добавлена функция прикрепления изображения (в стиле классического VK): при нажатии на значок скрепки открывается всплывающее окно, где можно указать ссылку на изображение без загрузки файла на сервер.Описание скрипта Скрипт структурирован и разбит на логические секции, что значительно упрощает его расширение и добавление нового функционала. Открытый исходный код остаётся понятным и удобным для навигации даже при первом знакомстве с ним сложно «заблудиться». Каждая часть оформлена отдельными блоками, благодаря чему дополнительный функционал можно внедрять прямо секциями, без необходимости перерабатывать весь код. Такой подход делает систему гибкой и удобной для модификации. При значительном увеличении объёма скрипта его можно без проблем вынести в отдельный файл, что позволит сохранить читаемость, упростит поддержку и дальнейшее развитие проекта.Описание работы скрипта формы комментариев Данный скрипт реализует современную интерактивную форму комментариев с расширенным функционалом, ориентированную на удобство пользователя и работу без перезагрузки страницы. Скрипт построен на чистом JavaScript и активируется после полной загрузки DOM-структуры страницы.Общий принцип работы После загрузки страницы скрипт находит все блоки публикаций с классом .vk-modern-post и инициализирует для каждого из них систему формы комментариев. Архитектура построена модульно, что позволяет легко расширять функционал и адаптировать скрипт под различные задачи.Основные функции скрипта 1. Переключение формы (свернутая / развернутая) По умолчанию отображается компактная (свернутая) форма. При клике форма раскрывается и активируется поле ввода текста. При клике вне формы она автоматически сворачивается обратно.Это создаёт поведение, аналогичное современным социальным сетям. Режим «Аноним» Позволяет отправлять комментарий без указания пользователя. При активации: В оригинальной форме включается флаг anonymous Очищаются поля user_id и email Визуально кнопка подсвечиваетсяРежим переключается без перезагрузки страницы. Подписка на комментарии (колокольчик) При включении пользователь автоматически подписывается на ответы и новые комментарии к материалу. В основной форме устанавливается флаг subscribeСостояние кнопки отображается визуально Прикрепление изображения (скрепка + модальное окно) Реализован механизм добавления изображения по прямой ссылке: 1. При нажатии на кнопку скрепки открывается модальное окно. 2. Пользователь вводит прямую ссылку на изображение. 3.Скрипт проверяет: ....ссылка не пустая ........начинается с http или https 4. В текст комментария автоматически вставляется BB-код:Изображение не загружается на сервер ,используется внешняя ссылка. Отправка комментария без перезагрузки Отправка реализована через скрытый iframe и встроенную форму uCoz.Процесс: 1.Пользователь нажимает кнопку отправки. 2. Проверяется наличие текста. 3. Отображается статус: «Идёт отправка…» 4. Скрипт загружает страницу комментариев материала в iframe. 5. Автоматически заполняются поля формы: ....текст комментария .....режим анонимности .......подписка 6. Выполняется отправка: через функцию addcom() (если доступна) либо стандартный form.submit()Уведомления и статус После успешной отправки: Форма очищается Форма сворачивается Показывается уведомление об успешной отправке Статус автоматически скрывается через несколько секундВ случае ошибки: Показывается сообщение «Ошибка отправки» Ошибка выводится в консольРабота без перезагрузки (AJAX-поведение) Несмотря на использование стандартной формы uCoz, пользователь взаимодействует с системой без перезагрузки страницы: Форма открывается динамически Модальные окна работают мгновенно Отправка происходит в фоне Интерфейс остаётся активнымАрхитектура и расширяемость Скрипт: Разбит на логические блоки Использует делегирование событий Не конфликтует с другими скриптами Может быть расширен новыми модулями Поддерживает перенос в отдельный файл при росте проектаИсходной код вид материалов каталога статей.. . Код
<!-- ЛЕНТА НОВОСТЕЙ --> <link rel="stylesheet" href="https://bro.usite.pro/css/bro-anon.css?v=2" media="all"> <div class="vk-modern-feed"> <div class="vk-modern-post"> <!-- HEADER --> <div class="vk-modern-header"> <div class="vk-modern-avatar"> <?if($AVATAR_URL$)?><img src="$AVATAR_URL$" alt="$USERNAME$"><?else?><img src="/.s/img/avatar.png"><?endif?> </div> <div class="vk-modern-author"> <div class="vk-modern-name"><a href="$PROFILE_URL$">$USERNAME$</a></div> <div class="vk-modern-time" title="$TIME$"> <img src="https://bro.usite.pro/icon/clock-icon.png" alt="Дата публикации" height="22"> <span>$DATE$</span> </div> </div> <?if($MODER_PANEL$)?><div class="entry-moder-container">$MODER_PANEL$</div><?endif?> <script> document.addEventListener('DOMContentLoaded', function() { document.querySelectorAll('.u-mpanel').forEach(panel => { // Проверяем, есть ли уже кнопка if(panel.querySelector('.custom-edit-btn')) return; // Создаём кнопку с тремя точками const btn = document.createElement('div'); btn.className = 'custom-edit-btn'; btn.textContent = '•••'; panel.prepend(btn); // вставляем сверху панели // Клик по кнопке: вызываем стандартный toggle панели btn.addEventListener('click', e => { e.stopPropagation(); const toggle = panel.querySelector('.u-mpanel-toggle'); if(toggle) toggle.click(); // вызывает оригинальный модер панель }); }); }); </script> </div> <!-- TEXT --> <?if($MESSAGE$)?><div class="vk-modern-text"> <div class="post" data-id="$ID$">$MESSAGE$</div> </div><?endif?> <!-- IMAGE --> <?if($COVER_IMAGE$)?><div class="vk-modern-attach"> <picture> <source srcset="$COVER_SMALL_URL$" media="(min-width:769px)"> <img src="$COVER_URL$" alt="$TITLE$" loading="lazy"> </picture> </div><?endif?> <!-- ACTIONS --> <div class="vk-modern-actions"> <div class="vk-actions-left"> <div class="vk-like" data-entryid="$ID$"> <span class="likeHeart" title="Поставить лайк"></span> <span class="uLikeCount">$RATED$</span> </div> <style> /* Контейнер лайка */ .vk-like { display: inline-flex; align-items: center; gap: 6px; font-family: Arial, sans-serif; } /* Сердечко ВК с обводкой */ .likeHeart { cursor: pointer; font-size: 26px; transition: transform 0.2s ease; user-select: none; } .likeHeart::before { content: "❤"; color: #fff; /* белое сердечко */ text-shadow: 0 0 1px #999, /* лёгкая серая обводка */ 0 0 2px #999, /* увеличиваем толщину */ 0 0 3px #999; /* ещё толще */ transition: color 0.3s ease, text-shadow 0.3s ease, transform 0.3s ease; } /* Hover эффект */ .likeHeart:hover::before { color: #ff4d4d; /* красное при наведении */ text-shadow: 0 0 2px #ff9999, 0 0 3px #ff9999, 0 0 4px #ff9999; transform: scale(1.2); } /* Состояние "лайк поставлен" */ .likeHeart.liked::before { color: #ff0000; /* красное сердечко */ text-shadow: none; /* без обводки */ transform: scale(1.1); } /* Счётчик лайков */ .uLikeCount { font-size: 14px; color: #626d7a; user-select: none; } </style> <script> (function() { const likeBlocks = document.querySelectorAll('.vk-like'); let votedPosts = JSON.parse(localStorage.getItem('votedPosts') || '[]'); likeBlocks.forEach(block => { const entryID = parseInt(block.dataset.entryid); const heart = block.querySelector('.likeHeart'); const likeCount = block.querySelector('.uLikeCount'); if (votedPosts.includes(entryID)) { heart.classList.add('liked'); } heart.addEventListener('click', function() { if (heart.classList.contains('liked')) return; heart.classList.add('liked'); votedPosts.push(entryID); localStorage.setItem('votedPosts', JSON.stringify(votedPosts)); if (likeCount) { likeCount.textContent = parseInt(likeCount.textContent || '0') + 1; } _uPostForm('', { type: 'POST', url: '/publ', data: { a: 65, id: entryID, mark: 5, mod: 'publ', ajax: '2' } }); }); }); })(); </script> <!-- COMMENTS --> <?if($COMMENTS_URL$)?> <a class="vk-action" href="$COMMENTS_URL$"> <svg viewBox="0 0 24 24"> <path d="M21 6h-18v10h4v4l4-4h10z"/> </svg> <span>$COMMENTS_NUM$</span> </a> <?endif?> <!-- READS --> <div class="vk-action"> <button class="vkShareBtn" onclick="vkShare(event)" aria-label="Поделиться" title="Поделиться"> <span class="vkShareRipple"></span> <svg viewBox="0 0 24 24" class="vkShareIcon"> <path d="M11.996 3.725A2.15 2.15 0 0 0 10 5.87l-.001 2.117-.02.005a9.904 9.904 0 0 0-7.827 10.721c.083.811 1.116 1.103 1.611.455l.187-.237a9.08 9.08 0 0 1 5.836-3.265l.213-.026.001 2.494a2.15 2.15 0 0 0 3.476 1.692l7.824-6.132a2.15 2.15 0 0 0 0-3.384l-7.824-6.132a2.15 2.15 0 0 0-1.326-.458z" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> <script> function vkShare(e){ const btn = e.currentTarget; const url = location.href; // ripple const rect = btn.getBoundingClientRect(); const ripple = btn.querySelector('.vkShareRipple'); ripple.style.left = (e.clientX - rect.left) + 'px'; ripple.style.top = (e.clientY - rect.top) + 'px'; ripple.classList.remove('show'); void ripple.offsetWidth; ripple.classList.add('show'); // share if (navigator.share) { navigator.share({ url }); } else { window.open('https://vk.com/share.php?url=' + encodeURIComponent(url),'_blank'); } } </script> </div> </div> <!-- Контейнер для просмотров --> <a class="vkViewBtn" href="$ENTRY_URL$" title="Перейти к новости"> <!-- Иконка глаза --> <svg viewBox="0 0 24 24" class="vkViewIcon" width="20" height="20"> <path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <circle cx="12" cy="12" r="3" fill="currentColor"/> </svg> <!-- Количество просмотров --> <span class="vkViewCount"> $READS$ </span> </a> </div> <!-- Форма комментариев --> <div class="vk-add-form"> <!-- Collapsed вид --> <div class="collapsed">Что у Вас нового?</div> <!-- Раскрытая форма --> <div class="expanded" style="display:none; position:relative;"> <!-- Аватар + поле + смайл --> <div class="vk-input-row" style="position:relative;"> <img class="vk-avatar" src="/avatar/00/00/00107456.png"> <textarea class="vk-textarea" placeholder="Напишите комментарий..."></textarea> <!-- Кнопка смайлов --> <button type="button" class="vk-smile-btn" title="Вставить смайл"> <img src="https://bro.usite.pro/icon/eisbaer.png" alt="смайл" style="width:22px; height:24px; display:block;"> </button> <!-- Popup со смайлами --> <div class="smiles smiles-grid" style="display:none;"> <a href="#" class="sml1" data-smile=">("><img src="/.s/sm/2/angry.gif" title="angry"></a> <a href="#" class="sml1" data-smile=":D"><img src="/.s/sm/2/biggrin.gif" title="biggrin"></a> <a href="#" class="sml1" data-smile="B)"><img src="/.s/sm/2/cool.gif" title="cool"></a> <a href="#" class="sml1" data-smile=":'("><img src="/.s/sm/2/cry.gif" title="cry"></a> <a href="#" class="sml1" data-smile="<_<"><img src="/.s/sm/2/dry.gif" title="dry"></a> <a href="#" class="sml1" data-smile="^_^"><img src="/.s/sm/2/happy.gif" title="happy"></a> <a href="#" class="sml1" data-smile=":("><img src="/.s/sm/2/sad.gif" title="sad"></a> <a href="#" class="sml1" data-smile=":)"><img src="/.s/sm/2/smile.gif" title="smile"></a> <a href="#" class="sml1" data-smile=":o"><img src="/.s/sm/2/surprised.gif" title="surprised"></a> <a href="#" class="sml1" data-smile=":p"><img src="/.s/sm/2/tongue.gif" title="tongue"></a> <a href="#" class="sml1" data-smile="%)"><img src="/.s/sm/2/wacko.gif" title="wacko"></a> <a href="#" class="sml1" data-smile=";)"><img src="/.s/sm/2/wink.gif" title="wink"></a> </div> </div> <!-- Действия --> <div class="vk-actions-row"> <div class="vk-left-group"> <button class="vkSendBtn">Отправить</button> <button type="button" class="vkAttachBtn" title="Прикрепить изображение"> <img src="https://www.svgrepo.com/show/278366/paper-clip.svg" alt="Прикрепить" width="24" height="24"> </button> <span class="vkStatus"></span> </div> <div class="vk-right-group"> <label class="vk-bell-wrapper" title="Подписаться на комментарии"> <svg class="vk-bell-icon"> <use xlink:href="/.s/t/2301/icons/icons.svg#bell_icon"></use> </svg> <input type="checkbox" class="vkBell" hidden> </label> <label class="vk-anon-wrapper" title="Анонимно"> <svg class="vk-anon-icon"> <use xlink:href="/.s/t/2301/icons/icons.svg#incognito_icon"></use> </svg> <input type="checkbox" class="vkAnon" hidden> </label> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Проверяем, не был ли уже навешан обработчик if (window.vkSmileHandlerAdded) return; window.vkSmileHandlerAdded = true; document.addEventListener('click', function(e) { // --- открыть форму при клике на collapsed --- const collapsed = e.target.closest('.vk-add-form .collapsed'); if (collapsed) { const form = collapsed.closest('.vk-add-form'); const expanded = form.querySelector('.expanded'); const textarea = form.querySelector('.vk-textarea'); collapsed.style.display = 'none'; expanded.style.display = 'block'; textarea.focus(); return; } // --- клик по кнопке смайлов --- const smileBtn = e.target.closest('.vk-add-form .vk-smile-btn'); if (smileBtn) { const form = smileBtn.closest('.vk-add-form'); const smilePopup = form.querySelector('.smiles'); smilePopup.style.display = (smilePopup.style.display === 'block') ? 'none' : 'block'; e.stopPropagation(); // чтобы клик не дошёл до document return; } // --- клик по смайлу --- const smileLink = e.target.closest('.vk-add-form .smiles a'); if (smileLink) { const form = smileLink.closest('.vk-add-form'); const textarea = form.querySelector('.vk-textarea'); const smile = smileLink.dataset.smile || ''; const start = textarea.selectionStart; const end = textarea.selectionEnd; const text = textarea.value; textarea.value = text.slice(0, start) + smile + text.slice(end); textarea.focus(); textarea.selectionEnd = start + smile.length; // закрываем popup const smilePopup = form.querySelector('.smiles'); smilePopup.style.display = 'none'; e.preventDefault(); return; } // --- клик вне формы закрывает форму и popup --- document.querySelectorAll('.vk-add-form').forEach(form => { if (!form.contains(e.target)) { const collapsed = form.querySelector('.collapsed'); const expanded = form.querySelector('.expanded'); const smilePopup = form.querySelector('.smiles'); if (collapsed && expanded) { collapsed.style.display = 'block'; expanded.style.display = 'none'; } if (smilePopup) smilePopup.style.display = 'none'; } }); }); }); </script> </div> </div> <iframe id="commentFrame" style="width:0;height:0;border:0;position:absolute;left:-9999px;"></iframe> <!-- Прокачанное уведомление --> <div id="vkSuccessMsg"> <div class="vk-tail"></div> <div class="vk-icon1">✓</div> <div class="vk-text"> Ваш комментарий успешно отправлен! Теперь он виден всем пользователям. </div> </div> <!-- Ставим перед скриптом модалку --> <div id="vkAttachModal" style="display:none;"> <div class="vkAttachOverlay"></div> <div class="vkAttachBox"> <div class="vkAttachHeader"> <img class="vkAttachIcon" src="https://www.svgrepo.com/show/509003/avatar-thinking-6.svg" alt="скрепка" width="16" height="16"> <span class="vkAttachTitle">Вставьте ссылку на изображение</span> </div> <input type="text" class="vkAttachInput" placeholder="https://"> <div class="vkAttachButtons"> <button class="vkAttachCancel">Отмена</button> <button class="vkAttachOk">OK</button> </div> </div> </div> <script> document.addEventListener("DOMContentLoaded", function(){ document.querySelectorAll('.vk-modern-post').forEach(post => { const collapsed = post.querySelector('.vk-add-form .collapsed'); const expanded = post.querySelector('.vk-add-form .expanded'); if(!collapsed || !expanded) return; const textarea = expanded.querySelector('.vk-textarea'); const sendBtn = expanded.querySelector('.vkSendBtn'); const status = expanded.querySelector('.vkStatus'); const anonCheck = expanded.querySelector('.vkAnon'); const anonWrap = expanded.querySelector('.vk-anon-wrapper'); const bell = expanded.querySelector('.vk-bell-wrapper'); const bellCheck = expanded.querySelector('.vkBell'); const iframe = document.getElementById('commentFrame'); const successMsg = document.getElementById('vkSuccessMsg'); /* ---------------- АНОНИМ ---------------- */ if(anonWrap){ anonWrap.addEventListener('click', e=>{ e.stopPropagation(); anonCheck.checked = !anonCheck.checked; anonWrap.classList.toggle('active', anonCheck.checked); }); } /* ---------------- КОЛОКОЛ ---------------- */ if(bell){ bell.addEventListener('click', e=>{ e.stopPropagation(); bellCheck.checked = !bellCheck.checked; bell.classList.toggle('active', bellCheck.checked); }); } /* ------------------- Скрипт скрепки с модалкой ------------------- */ const attachBtn = expanded.querySelector('.vkAttachBtn'); if(attachBtn && !attachBtn.dataset.handlerAdded){ attachBtn.dataset.handlerAdded = "true"; attachBtn.addEventListener('click', e=>{ e.stopPropagation(); const modal = document.getElementById('vkAttachModal'); const input = modal.querySelector('.vkAttachInput'); const okBtn = modal.querySelector('.vkAttachOk'); const cancelBtn = modal.querySelector('.vkAttachCancel'); modal.style.display = 'flex'; input.value = ''; input.focus(); cancelBtn.onclick = ()=> { modal.style.display = 'none'; } okBtn.onclick = ()=> { const url = input.value.trim(); if(!url){ alert('Ссылка не может быть пустой'); input.focus(); return; } if(!/^https?:\/\//i.test(url)){ alert('Нужна прямая ссылка на изображение'); input.focus(); return; } // Вставляем BB-код в textarea const imgTag = `[img]${url}[/img]`; textarea.value += (textarea.value ? '\n' : '') + imgTag; textarea.focus(); modal.style.display = 'none'; } }); } /* ---------------- ОТКРЫТЬ ФОРМУ ---------------- */ collapsed.addEventListener('click', ()=>{ collapsed.style.display='none'; expanded.style.display='block'; textarea?.focus(); }); /* ---------------- ЗАКРЫТЬ СНАРУЖИ ---------------- */ document.addEventListener('click', e=>{ if(!post.contains(e.target)){ collapsed.style.display='block'; expanded.style.display='none'; } }); /* ---------------- ОТПРАВКА ---------------- */ if(sendBtn){ sendBtn.addEventListener('click', ()=>{ const msg = textarea?.value.trim(); if(!msg) return; // ==== статус как ВК ==== status.textContent = 'Идёт отправка...'; status.classList.add('show'); // ==== старая проверенная логика отправки ==== const postId = post.querySelector('.post')?.dataset?.id; if(!postId){ status.textContent = 'ID поста не найден'; return; } iframe.src = `/publ/1-1-0-${postId}`; iframe.onload = () => { try{ const doc = iframe.contentDocument; const w = iframe.contentWindow; const form = doc.getElementById('acform'); if(!form){ status.textContent='Форма не найдена'; return; } // текст комментария const msgField = form.querySelector('textarea[name="message"]'); if(msgField) msgField.value = msg; // аноним if(anonCheck?.checked){ const realAnon = form.querySelector('input[name="anonymous"]'); if(realAnon) realAnon.checked = true; const uid = form.querySelector('input[name="user_id"]'); if(uid) uid.value = ''; const email = form.querySelector('input[name="email"]'); if(email) email.value = ''; } // колокольчик (подписка) const realSub = form.querySelector('input[name="subscribe"]'); if(realSub){ realSub.checked = !!bellCheck?.checked; } // отправка if(typeof w.addcom === 'function'){ w.addcom(form); }else{ form.submit(); } // очистка формы textarea.value = ''; collapsed.style.display='block'; expanded.style.display='none'; // ==== уведомления ==== if(successMsg){ successMsg.classList.add('show'); setTimeout(()=> successMsg.classList.remove('show'), 6000); } // ==== скрываем статус через 3 секунды ==== setTimeout(()=>{ status.classList.remove('show'); status.textContent = ''; }, 3000); }catch(e){ console.error(e); status.textContent='Ошибка отправки'; status.classList.add('show'); setTimeout(()=>{ status.classList.remove('show'); }, 3000); } }; // ==== конец старой логики отправки ==== }); } }); }); </script>
Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
Дата: Вторник, 17.02.2026, 05:04 | Сообщение # 2 |
|
Написал: Узнаваемый
Автор темы
Мурчанн
не в сети
Сообщений: 211
На Юкозе нет переменных в виде материала, которые позволяют взять аватар авторизованного пользователя и автоматически подставить его в форму комментариев. Поэтому был написан скрипт, который вытаскивает аватар прямо из блока профиля и подставляет его туда, куда мне нужно.Внесены изменения в интерфейс формы: 1. Уменьшены иконки колокольчика, анонимности, смайлов и скрепки. 2. Изменены расстояния между элементами, переработана структура формы почти полностью.Сделано больше правок, чтобы форма максимально походила на старую форму отправки ВКонтакте. На первый взгляд кажется: да что там, просто аватарку вставить. Но это Юкоз тут есть жёсткий список переменных, и ты не можешь вывести то, чего нет в шаблоне. Поэтому приходится писать скрипты и вытаскивать данные вручную. Если скриптом данные получить нельзя , используется другой способ: страница не создаётся, она загружается скрыто через iframe, после чего из неё перехватываются нужные данные.Аватарку - можно вытащить скриптом.Работа с сервером и отправкой данных - уже совсем другой уровень.Скрипт небольшой, он решает задачу. Прежде чем его написать, ты обычно перебираешь кучу вариантов, тратишь кучу времени и ничего не получается сразу идеально. Здесь же всё максимально прямо: скрипт делает именно то, что нужно, без лишних заморочек и догадок.Пример Код
<script> document.addEventListener("DOMContentLoaded", function() { const userAvatarEl = document.querySelector('#userMenu .real-avatar'); const commentAvatars = document.querySelectorAll('.commentUserAvatar'); if (userAvatarEl && userAvatarEl.src) { commentAvatars.forEach(img => img.src = userAvatarEl.src); } else { commentAvatars.forEach(img => img.src = 'https://bro.usite.pro/icon/vk_large.png'); } }); </script>
Исходник полностью со всеми правками. Код
<!-- ЛЕНТА НОВОСТЕЙ --> <link rel="stylesheet" href="https://bro.usite.pro/css/bro-anon.css?v=2" media="all"> <div class="vk-modern-feed"> <div class="vk-modern-post"> <!-- HEADER --> <div class="vk-modern-header"> <div class="vk-modern-avatar"> <?if($AVATAR_URL$)?><img src="$AVATAR_URL$" alt="$USERNAME$"><?else?><img src="/.s/img/avatar.png"><?endif?> </div> <div class="vk-modern-author"> <div class="vk-modern-name"><a href="$PROFILE_URL$">$USERNAME$</a></div> <div class="vk-modern-time" title="$TIME$"> <img src="https://bro.usite.pro/icon/clock-icon.png" alt="Дата публикации" height="22"> <span>$DATE$</span> </div> </div> <?if($MODER_PANEL$)?><div class="entry-moder-container">$MODER_PANEL$</div><?endif?> <script> document.addEventListener('DOMContentLoaded', function() { document.querySelectorAll('.u-mpanel').forEach(panel => { // Проверяем, есть ли уже кнопка if(panel.querySelector('.custom-edit-btn')) return; // Создаём кнопку с тремя точками const btn = document.createElement('div'); btn.className = 'custom-edit-btn'; btn.textContent = '•••'; panel.prepend(btn); // вставляем сверху панели // Клик по кнопке: вызываем стандартный toggle панели btn.addEventListener('click', e => { e.stopPropagation(); const toggle = panel.querySelector('.u-mpanel-toggle'); if(toggle) toggle.click(); // вызывает оригинальный модер панель }); }); }); </script> </div> <!-- TEXT --> <?if($MESSAGE$)?><div class="vk-modern-text"> <div class="post" data-id="$ID$">$MESSAGE$</div> </div><?endif?> <!-- IMAGE --> <?if($COVER_IMAGE$)?><div class="vk-modern-attach"> <picture> <source srcset="$COVER_SMALL_URL$" media="(min-width:769px)"> <img src="$COVER_URL$" alt="$TITLE$" loading="lazy"> </picture> </div><?endif?> <!-- ACTIONS --> <div class="vk-modern-actions"> <div class="vk-actions-left"> <div class="vk-like" data-entryid="$ID$"> <span class="likeHeart" title="Поставить лайк"></span> <span class="uLikeCount">$RATED$</span> </div> <style> /* Контейнер лайка */ .vk-like { display: inline-flex; align-items: center; gap: 6px; font-family: Arial, sans-serif; } /* Сердечко ВК с обводкой */ .likeHeart { cursor: pointer; font-size: 26px; transition: transform 0.2s ease; user-select: none; } .likeHeart::before { content: "❤"; color: #fff; /* белое сердечко */ text-shadow: 0 0 1px #999, /* лёгкая серая обводка */ 0 0 2px #999, /* увеличиваем толщину */ 0 0 3px #999; /* ещё толще */ transition: color 0.3s ease, text-shadow 0.3s ease, transform 0.3s ease; } /* Hover эффект */ .likeHeart:hover::before { color: #ff4d4d; /* красное при наведении */ text-shadow: 0 0 2px #ff9999, 0 0 3px #ff9999, 0 0 4px #ff9999; transform: scale(1.2); } /* Состояние "лайк поставлен" */ .likeHeart.liked::before { color: #ff0000; /* красное сердечко */ text-shadow: none; /* без обводки */ transform: scale(1.1); } /* Счётчик лайков */ .uLikeCount { font-size: 14px; color: #626d7a; user-select: none; } </style> <script> (function() { const likeBlocks = document.querySelectorAll('.vk-like'); let votedPosts = JSON.parse(localStorage.getItem('votedPosts') || '[]'); likeBlocks.forEach(block => { const entryID = parseInt(block.dataset.entryid); const heart = block.querySelector('.likeHeart'); const likeCount = block.querySelector('.uLikeCount'); if (votedPosts.includes(entryID)) { heart.classList.add('liked'); } heart.addEventListener('click', function() { if (heart.classList.contains('liked')) return; heart.classList.add('liked'); votedPosts.push(entryID); localStorage.setItem('votedPosts', JSON.stringify(votedPosts)); if (likeCount) { likeCount.textContent = parseInt(likeCount.textContent || '0') + 1; } _uPostForm('', { type: 'POST', url: '/publ', data: { a: 65, id: entryID, mark: 5, mod: 'publ', ajax: '2' } }); }); }); })(); </script> <!-- COMMENTS --> <?if($COMMENTS_URL$)?> <a class="vk-action" href="$COMMENTS_URL$"> <svg viewBox="0 0 24 24"> <path d="M21 6h-18v10h4v4l4-4h10z"/> </svg> <span>$COMMENTS_NUM$</span> </a> <?endif?> <!-- READS --> <div class="vk-action"> <button class="vkShareBtn" onclick="vkShare(event)" aria-label="Поделиться" title="Поделиться"> <span class="vkShareRipple"></span> <svg viewBox="0 0 24 24" class="vkShareIcon"> <path d="M11.996 3.725A2.15 2.15 0 0 0 10 5.87l-.001 2.117-.02.005a9.904 9.904 0 0 0-7.827 10.721c.083.811 1.116 1.103 1.611.455l.187-.237a9.08 9.08 0 0 1 5.836-3.265l.213-.026.001 2.494a2.15 2.15 0 0 0 3.476 1.692l7.824-6.132a2.15 2.15 0 0 0 0-3.384l-7.824-6.132a2.15 2.15 0 0 0-1.326-.458z" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> <script> function vkShare(e){ const btn = e.currentTarget; const url = location.href; // ripple const rect = btn.getBoundingClientRect(); const ripple = btn.querySelector('.vkShareRipple'); ripple.style.left = (e.clientX - rect.left) + 'px'; ripple.style.top = (e.clientY - rect.top) + 'px'; ripple.classList.remove('show'); void ripple.offsetWidth; ripple.classList.add('show'); // share if (navigator.share) { navigator.share({ url }); } else { window.open('https://vk.com/share.php?url=' + encodeURIComponent(url),'_blank'); } } </script> </div> </div> <!-- Контейнер для просмотров --> <a class="vkViewBtn" href="$ENTRY_URL$" title="Перейти к новости"> <!-- Иконка глаза --> <svg viewBox="0 0 24 24" class="vkViewIcon" width="20" height="20"> <path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <circle cx="12" cy="12" r="3" fill="currentColor"/> </svg> <!-- Количество просмотров --> <span class="vkViewCount"> $READS$ </span> </a> </div> <!-- Форма комментариев --> <div class="vk-add-form"> <!-- Collapsed вид --> <div class="collapsed">Что у Вас нового?</div> <!-- Раскрытая форма --> <div class="expanded" style="display:none; position:relative;"> <!-- Аватар + поле + смайл --> <div class="vk-input-row" style="position:relative; display:flex; align-items:flex-start; gap:5px;"> <!-- Картинка для аватара --> <img class="vk-avatar commentUserAvatar" src="https://bro.usite.pro/icon/vk_large.png" alt="Ваш аватар" style="width:37px; height:37px; border-radius:50%; object-fit:cover; border:1px solid #cfd6e0;"> <script> document.addEventListener("DOMContentLoaded", function() { const userAvatarEl = document.querySelector('#userMenu .real-avatar'); const commentAvatars = document.querySelectorAll('.commentUserAvatar'); if (userAvatarEl && userAvatarEl.src) { commentAvatars.forEach(img => img.src = userAvatarEl.src); } else { commentAvatars.forEach(img => img.src = 'https://bro.usite.pro/icon/vk_large.png'); } }); </script> <textarea class="vk-textarea" placeholder="Напишите комментарий..."></textarea> <!-- Кнопка смайлов --> <button type="button" class="vk-smile-btn" title="Вставить смайл"> <img src="https://bro.usite.pro/img/yksmile.webp" alt="смайл" style="width:20px; height:20px; display:block;"> </button> <!-- Popup со смайлами --> <div class="smiles smiles-grid" style="display:none;"> <a href="#" class="sml1" data-smile=">("><img src="/.s/sm/2/angry.gif" title="angry"></a> <a href="#" class="sml1" data-smile=":D"><img src="/.s/sm/2/biggrin.gif" title="biggrin"></a> <a href="#" class="sml1" data-smile="B)"><img src="/.s/sm/2/cool.gif" title="cool"></a> <a href="#" class="sml1" data-smile=":'("><img src="/.s/sm/2/cry.gif" title="cry"></a> <a href="#" class="sml1" data-smile="<_<"><img src="/.s/sm/2/dry.gif" title="dry"></a> <a href="#" class="sml1" data-smile="^_^"><img src="/.s/sm/2/happy.gif" title="happy"></a> <a href="#" class="sml1" data-smile=":("><img src="/.s/sm/2/sad.gif" title="sad"></a> <a href="#" class="sml1" data-smile=":)"><img src="/.s/sm/2/smile.gif" title="smile"></a> <a href="#" class="sml1" data-smile=":o"><img src="/.s/sm/2/surprised.gif" title="surprised"></a> <a href="#" class="sml1" data-smile=":p"><img src="/.s/sm/2/tongue.gif" title="tongue"></a> <a href="#" class="sml1" data-smile="%)"><img src="/.s/sm/2/wacko.gif" title="wacko"></a> <a href="#" class="sml1" data-smile=";)"><img src="/.s/sm/2/wink.gif" title="wink"></a> </div> </div> <!-- Действия --> <div class="vk-actions-row"> <div class="vk-left-group"> <button class="vkSendBtn">Отправить</button> <button type="button" class="vkAttachBtn" title="Прикрепить изображение"> <img src="https://www.svgrepo.com/show/278366/paper-clip.svg" alt="Прикрепить" width="24" height="24"> </button> <span class="vkStatus"></span> </div> <div class="vk-right-group"> <label class="vk-bell-wrapper" title="Подписаться на комментарии"> <svg class="vk-bell-icon"> <use xlink:href="/.s/t/2301/icons/icons.svg#bell_icon"></use> </svg> <input type="checkbox" class="vkBell" hidden> </label> <label class="vk-anon-wrapper" title="Анонимно"> <svg class="vk-anon-icon"> <use xlink:href="/.s/t/2301/icons/icons.svg#incognito_icon"></use> </svg> <input type="checkbox" class="vkAnon" hidden> </label> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Проверяем, не был ли уже навешан обработчик if (window.vkSmileHandlerAdded) return; window.vkSmileHandlerAdded = true; document.addEventListener('click', function(e) { // --- открыть форму при клике на collapsed --- const collapsed = e.target.closest('.vk-add-form .collapsed'); if (collapsed) { const form = collapsed.closest('.vk-add-form'); const expanded = form.querySelector('.expanded'); const textarea = form.querySelector('.vk-textarea'); collapsed.style.display = 'none'; expanded.style.display = 'block'; textarea.focus(); return; } // --- клик по кнопке смайлов --- const smileBtn = e.target.closest('.vk-add-form .vk-smile-btn'); if (smileBtn) { const form = smileBtn.closest('.vk-add-form'); const smilePopup = form.querySelector('.smiles'); smilePopup.style.display = (smilePopup.style.display === 'block') ? 'none' : 'block'; e.stopPropagation(); // чтобы клик не дошёл до document return; } // --- клик по смайлу --- const smileLink = e.target.closest('.vk-add-form .smiles a'); if (smileLink) { const form = smileLink.closest('.vk-add-form'); const textarea = form.querySelector('.vk-textarea'); const smile = smileLink.dataset.smile || ''; const start = textarea.selectionStart; const end = textarea.selectionEnd; const text = textarea.value; textarea.value = text.slice(0, start) + smile + text.slice(end); textarea.focus(); textarea.selectionEnd = start + smile.length; // закрываем popup const smilePopup = form.querySelector('.smiles'); smilePopup.style.display = 'none'; e.preventDefault(); return; } // --- клик вне формы закрывает форму и popup --- document.querySelectorAll('.vk-add-form').forEach(form => { if (!form.contains(e.target)) { const collapsed = form.querySelector('.collapsed'); const expanded = form.querySelector('.expanded'); const smilePopup = form.querySelector('.smiles'); if (collapsed && expanded) { collapsed.style.display = 'block'; expanded.style.display = 'none'; } if (smilePopup) smilePopup.style.display = 'none'; } }); }); }); </script> </div> </div> <iframe id="commentFrame" style="width:0;height:0;border:0;position:absolute;left:-9999px;"></iframe> <!-- Прокачанное уведомление --> <div id="vkSuccessMsg"> <div class="vk-tail"></div> <div class="vk-icon1">✓</div> <div class="vk-text"> Ваш комментарий успешно отправлен! Теперь он виден всем пользователям. </div> </div> <!-- Ставим перед скриптом модалку --> <div id="vkAttachModal" style="display:none;"> <div class="vkAttachOverlay"></div> <div class="vkAttachBox"> <div class="vkAttachHeader"> <img class="vkAttachIcon" src="https://www.svgrepo.com/show/509003/avatar-thinking-6.svg" alt="скрепка" width="16" height="16"> <span class="vkAttachTitle">Вставьте ссылку на изображение</span> </div> <input type="text" class="vkAttachInput" placeholder="https://"> <div class="vkAttachButtons"> <button class="vkAttachCancel">Отмена</button> <button class="vkAttachOk">OK</button> </div> </div> </div> <script> document.addEventListener("DOMContentLoaded", function(){ document.querySelectorAll('.vk-modern-post').forEach(post => { const collapsed = post.querySelector('.vk-add-form .collapsed'); const expanded = post.querySelector('.vk-add-form .expanded'); if(!collapsed || !expanded) return; const textarea = expanded.querySelector('.vk-textarea'); const sendBtn = expanded.querySelector('.vkSendBtn'); const status = expanded.querySelector('.vkStatus'); const anonCheck = expanded.querySelector('.vkAnon'); const anonWrap = expanded.querySelector('.vk-anon-wrapper'); const bell = expanded.querySelector('.vk-bell-wrapper'); const bellCheck = expanded.querySelector('.vkBell'); const iframe = document.getElementById('commentFrame'); const successMsg = document.getElementById('vkSuccessMsg'); /* ---------------- АНОНИМ ---------------- */ if(anonWrap){ anonWrap.addEventListener('click', e=>{ e.stopPropagation(); anonCheck.checked = !anonCheck.checked; anonWrap.classList.toggle('active', anonCheck.checked); }); } /* ---------------- КОЛОКОЛ ---------------- */ if(bell){ bell.addEventListener('click', e=>{ e.stopPropagation(); bellCheck.checked = !bellCheck.checked; bell.classList.toggle('active', bellCheck.checked); }); } /* ------------------- Скрипт скрепки с модалкой ------------------- */ const attachBtn = expanded.querySelector('.vkAttachBtn'); if(attachBtn && !attachBtn.dataset.handlerAdded){ attachBtn.dataset.handlerAdded = "true"; attachBtn.addEventListener('click', e=>{ e.stopPropagation(); const modal = document.getElementById('vkAttachModal'); const input = modal.querySelector('.vkAttachInput'); const okBtn = modal.querySelector('.vkAttachOk'); const cancelBtn = modal.querySelector('.vkAttachCancel'); modal.style.display = 'flex'; input.value = ''; input.focus(); cancelBtn.onclick = ()=> { modal.style.display = 'none'; } okBtn.onclick = ()=> { const url = input.value.trim(); if(!url){ alert('Ссылка не может быть пустой'); input.focus(); return; } if(!/^https?:\/\//i.test(url)){ alert('Нужна прямая ссылка на изображение'); input.focus(); return; } // Вставляем BB-код в textarea const imgTag = `[img]${url}[/img]`; textarea.value += (textarea.value ? '\n' : '') + imgTag; textarea.focus(); modal.style.display = 'none'; } }); } /* ---------------- ОТКРЫТЬ ФОРМУ ---------------- */ collapsed.addEventListener('click', ()=>{ collapsed.style.display='none'; expanded.style.display='block'; textarea?.focus(); }); /* ---------------- ЗАКРЫТЬ СНАРУЖИ ---------------- */ document.addEventListener('click', e=>{ if(!post.contains(e.target)){ collapsed.style.display='block'; expanded.style.display='none'; } }); /* ---------------- ОТПРАВКА ---------------- */ if(sendBtn){ sendBtn.addEventListener('click', ()=>{ const msg = textarea?.value.trim(); if(!msg) return; // ==== статус как ВК ==== status.textContent = 'Идёт отправка...'; status.classList.add('show'); // ==== старая проверенная логика отправки ==== const postId = post.querySelector('.post')?.dataset?.id; if(!postId){ status.textContent = 'ID поста не найден'; return; } iframe.src = `/publ/1-1-0-${postId}`; iframe.onload = () => { try{ const doc = iframe.contentDocument; const w = iframe.contentWindow; const form = doc.getElementById('acform'); if(!form){ status.textContent='Форма не найдена'; return; } // текст комментария const msgField = form.querySelector('textarea[name="message"]'); if(msgField) msgField.value = msg; // аноним if(anonCheck?.checked){ const realAnon = form.querySelector('input[name="anonymous"]'); if(realAnon) realAnon.checked = true; const uid = form.querySelector('input[name="user_id"]'); if(uid) uid.value = ''; const email = form.querySelector('input[name="email"]'); if(email) email.value = ''; } // колокольчик (подписка) const realSub = form.querySelector('input[name="subscribe"]'); if(realSub){ realSub.checked = !!bellCheck?.checked; } // отправка if(typeof w.addcom === 'function'){ w.addcom(form); }else{ form.submit(); } // очистка формы textarea.value = ''; collapsed.style.display='block'; expanded.style.display='none'; // ==== уведомления ==== if(successMsg){ successMsg.classList.add('show'); setTimeout(()=> successMsg.classList.remove('show'), 6000); } // ==== скрываем статус через 3 секунды ==== setTimeout(()=>{ status.classList.remove('show'); status.textContent = ''; }, 3000); }catch(e){ console.error(e); status.textContent='Ошибка отправки'; status.classList.add('show'); setTimeout(()=>{ status.classList.remove('show'); }, 3000); } }; // ==== конец старой логики отправки ==== }); } }); }); </script>
Пока писал текст, выявился ещё один баг: после прогрузки следующего материала скрипт не видит аватарку и автоматически подставляет дефолтную. Скрипт будет дорабатываться, и уже продумывается решение этой задачи. Как только появится рабочий способ, я внесу соответствующие изменения.
Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
Дата: Вторник, 17.02.2026, 05:59 | Сообщение # 3 |
|
Написал: Узнаваемый
Автор темы
Мурчанн
не в сети
Сообщений: 211
Скрипт работал только при первой загрузке страницы, потому что был привязан к событию DOMContentLoaded. Когда комментарии подгружались кнопкой (через AJAX), страница не перезагружалась и скрипт больше не выполнялся, поэтому показывалась дефолтная аватарка.Я сделал чтобы скрипт запускался не один раз, а каждый раз при изменении страницы: 1. Вынес установку аватарки в отдельную функцию applyUserAvatar(). 2. Оставил запуск при первой загрузке страницы (DOMContentLoaded). 3. Добавил MutationObserver, который следит за изменениями DOM. 4. Когда кнопка подгружает новые комментарии и они появляются на странице наблюдатель это видит и снова запускает функцию установки аватарки. 5. В итоге у новых комментариев сразу подставляется аватарка вместо дефолтной.Итого: скрипт стал работать не только при загрузке страницы, но и при динамической подгрузке комментариев.Код
<script> function applyUserAvatar() { const userAvatarEl = document.querySelector('#userMenu .real-avatar'); const commentAvatars = document.querySelectorAll('.commentUserAvatar'); let avatar = 'https://bro.usite.pro/icon/vk_large.png'; if (userAvatarEl && userAvatarEl.src) { avatar = userAvatarEl.src; } commentAvatars.forEach(img => { img.src = avatar; }); } // при первой загрузке document.addEventListener("DOMContentLoaded", applyUserAvatar); // отслеживаем подгрузку новых комментариев (AJAX / динамика) const observer = new MutationObserver(() => { applyUserAvatar(); }); observer.observe(document.body, { childList: true, subtree: true }); </script>
Полностью исходной код .. Код
<!-- ЛЕНТА НОВОСТЕЙ --> <link rel="stylesheet" href="https://bro.usite.pro/css/bro-anon.css?v=2" media="all"> <div class="vk-modern-feed"> <div class="vk-modern-post"> <!-- HEADER --> <div class="vk-modern-header"> <div class="vk-modern-avatar"> <?if($AVATAR_URL$)?><img src="$AVATAR_URL$" alt="$USERNAME$"><?else?><img src="/.s/img/avatar.png"><?endif?> </div> <div class="vk-modern-author"> <div class="vk-modern-name"><a href="$PROFILE_URL$">$USERNAME$</a></div> <div class="vk-modern-time" title="$TIME$"> <img src="https://bro.usite.pro/icon/clock-icon.png" alt="Дата публикации" height="22"> <span>$DATE$</span> </div> </div> <?if($MODER_PANEL$)?><div class="entry-moder-container">$MODER_PANEL$</div><?endif?> <script> document.addEventListener('DOMContentLoaded', function() { document.querySelectorAll('.u-mpanel').forEach(panel => { // Проверяем, есть ли уже кнопка if(panel.querySelector('.custom-edit-btn')) return; // Создаём кнопку с тремя точками const btn = document.createElement('div'); btn.className = 'custom-edit-btn'; btn.textContent = '•••'; panel.prepend(btn); // вставляем сверху панели // Клик по кнопке: вызываем стандартный toggle панели btn.addEventListener('click', e => { e.stopPropagation(); const toggle = panel.querySelector('.u-mpanel-toggle'); if(toggle) toggle.click(); // вызывает оригинальный модер панель }); }); }); </script> </div> <!-- TEXT --> <?if($MESSAGE$)?><div class="vk-modern-text"> <div class="post" data-id="$ID$">$MESSAGE$</div> </div><?endif?> <!-- IMAGE --> <?if($COVER_IMAGE$)?><div class="vk-modern-attach"> <picture> <source srcset="$COVER_SMALL_URL$" media="(min-width:769px)"> <img src="$COVER_URL$" alt="$TITLE$" loading="lazy"> </picture> </div><?endif?> <!-- ACTIONS --> <div class="vk-modern-actions"> <div class="vk-actions-left"> <div class="vk-like" data-entryid="$ID$"> <span class="likeHeart" title="Поставить лайк"></span> <span class="uLikeCount">$RATED$</span> </div> <style> /* Контейнер лайка */ .vk-like { display: inline-flex; align-items: center; gap: 6px; font-family: Arial, sans-serif; } /* Сердечко ВК с обводкой */ .likeHeart { cursor: pointer; font-size: 26px; transition: transform 0.2s ease; user-select: none; } .likeHeart::before { content: "❤"; color: #fff; /* белое сердечко */ text-shadow: 0 0 1px #999, /* лёгкая серая обводка */ 0 0 2px #999, /* увеличиваем толщину */ 0 0 3px #999; /* ещё толще */ transition: color 0.3s ease, text-shadow 0.3s ease, transform 0.3s ease; } /* Hover эффект */ .likeHeart:hover::before { color: #ff4d4d; /* красное при наведении */ text-shadow: 0 0 2px #ff9999, 0 0 3px #ff9999, 0 0 4px #ff9999; transform: scale(1.2); } /* Состояние "лайк поставлен" */ .likeHeart.liked::before { color: #ff0000; /* красное сердечко */ text-shadow: none; /* без обводки */ transform: scale(1.1); } /* Счётчик лайков */ .uLikeCount { font-size: 14px; color: #626d7a; user-select: none; } </style> <script> (function() { const likeBlocks = document.querySelectorAll('.vk-like'); let votedPosts = JSON.parse(localStorage.getItem('votedPosts') || '[]'); likeBlocks.forEach(block => { const entryID = parseInt(block.dataset.entryid); const heart = block.querySelector('.likeHeart'); const likeCount = block.querySelector('.uLikeCount'); if (votedPosts.includes(entryID)) { heart.classList.add('liked'); } heart.addEventListener('click', function() { if (heart.classList.contains('liked')) return; heart.classList.add('liked'); votedPosts.push(entryID); localStorage.setItem('votedPosts', JSON.stringify(votedPosts)); if (likeCount) { likeCount.textContent = parseInt(likeCount.textContent || '0') + 1; } _uPostForm('', { type: 'POST', url: '/publ', data: { a: 65, id: entryID, mark: 5, mod: 'publ', ajax: '2' } }); }); }); })(); </script> <!-- COMMENTS --> <?if($COMMENTS_URL$)?> <a class="vk-action" href="$COMMENTS_URL$"> <svg viewBox="0 0 24 24"> <path d="M21 6h-18v10h4v4l4-4h10z"/> </svg> <span>$COMMENTS_NUM$</span> </a> <?endif?> <!-- READS --> <div class="vk-action"> <button class="vkShareBtn" onclick="vkShare(event)" aria-label="Поделиться" title="Поделиться"> <span class="vkShareRipple"></span> <svg viewBox="0 0 24 24" class="vkShareIcon"> <path d="M11.996 3.725A2.15 2.15 0 0 0 10 5.87l-.001 2.117-.02.005a9.904 9.904 0 0 0-7.827 10.721c.083.811 1.116 1.103 1.611.455l.187-.237a9.08 9.08 0 0 1 5.836-3.265l.213-.026.001 2.494a2.15 2.15 0 0 0 3.476 1.692l7.824-6.132a2.15 2.15 0 0 0 0-3.384l-7.824-6.132a2.15 2.15 0 0 0-1.326-.458z" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> <script> function vkShare(e){ const btn = e.currentTarget; const url = location.href; // ripple const rect = btn.getBoundingClientRect(); const ripple = btn.querySelector('.vkShareRipple'); ripple.style.left = (e.clientX - rect.left) + 'px'; ripple.style.top = (e.clientY - rect.top) + 'px'; ripple.classList.remove('show'); void ripple.offsetWidth; ripple.classList.add('show'); // share if (navigator.share) { navigator.share({ url }); } else { window.open('https://vk.com/share.php?url=' + encodeURIComponent(url),'_blank'); } } </script> </div> </div> <!-- Контейнер для просмотров --> <a class="vkViewBtn" href="$ENTRY_URL$" title="Перейти к новости"> <!-- Иконка глаза --> <svg viewBox="0 0 24 24" class="vkViewIcon" width="20" height="20"> <path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <circle cx="12" cy="12" r="3" fill="currentColor"/> </svg> <!-- Количество просмотров --> <span class="vkViewCount"> $READS$ </span> </a> </div> <!-- Форма комментариев --> <div class="vk-add-form"> <!-- Collapsed вид --> <div class="collapsed">Что у Вас нового?</div> <!-- Раскрытая форма --> <div class="expanded" style="display:none; position:relative;"> <!-- Аватар + поле + смайл --> <div class="vk-input-row" style="position:relative; display:flex; align-items:flex-start; gap:5px;"> <!-- Картинка для аватара --> <img class="vk-avatar commentUserAvatar" src="https://bro.usite.pro/icon/vk_large.png" alt="Ваш аватар" style="width:35px; height:35px; border-radius:50%; object-fit:cover; border:1px solid #cfd6e0;"> <script> function applyUserAvatar() { const userAvatarEl = document.querySelector('#userMenu .real-avatar'); const commentAvatars = document.querySelectorAll('.commentUserAvatar'); let avatar = 'https://bro.usite.pro/icon/vk_large.png'; if (userAvatarEl && userAvatarEl.src) { avatar = userAvatarEl.src; } commentAvatars.forEach(img => { img.src = avatar; }); } // при первой загрузке document.addEventListener("DOMContentLoaded", applyUserAvatar); // отслеживаем подгрузку новых комментариев (AJAX / динамика) const observer = new MutationObserver(() => { applyUserAvatar(); }); observer.observe(document.body, { childList: true, subtree: true }); </script> <textarea class="vk-textarea" placeholder="Напишите комментарий..."></textarea> <!-- Кнопка смайлов --> <button type="button" class="vk-smile-btn" title="Вставить смайл"> <img src="https://bro.usite.pro/img/yksmile.webp" alt="смайл" style="width:20px; height:20px; display:block;"> </button> <!-- Popup со смайлами --> <div class="smiles smiles-grid" style="display:none;"> <a href="#" class="sml1" data-smile=">("><img src="/.s/sm/2/angry.gif" title="angry"></a> <a href="#" class="sml1" data-smile=":D"><img src="/.s/sm/2/biggrin.gif" title="biggrin"></a> <a href="#" class="sml1" data-smile="B)"><img src="/.s/sm/2/cool.gif" title="cool"></a> <a href="#" class="sml1" data-smile=":'("><img src="/.s/sm/2/cry.gif" title="cry"></a> <a href="#" class="sml1" data-smile="<_<"><img src="/.s/sm/2/dry.gif" title="dry"></a> <a href="#" class="sml1" data-smile="^_^"><img src="/.s/sm/2/happy.gif" title="happy"></a> <a href="#" class="sml1" data-smile=":("><img src="/.s/sm/2/sad.gif" title="sad"></a> <a href="#" class="sml1" data-smile=":)"><img src="/.s/sm/2/smile.gif" title="smile"></a> <a href="#" class="sml1" data-smile=":o"><img src="/.s/sm/2/surprised.gif" title="surprised"></a> <a href="#" class="sml1" data-smile=":p"><img src="/.s/sm/2/tongue.gif" title="tongue"></a> <a href="#" class="sml1" data-smile="%)"><img src="/.s/sm/2/wacko.gif" title="wacko"></a> <a href="#" class="sml1" data-smile=";)"><img src="/.s/sm/2/wink.gif" title="wink"></a> </div> </div> <!-- Действия --> <div class="vk-actions-row"> <div class="vk-left-group"> <button class="vkSendBtn">Отправить</button> <button type="button" class="vkAttachBtn" title="Прикрепить изображение"> <img src="https://www.svgrepo.com/show/278366/paper-clip.svg" alt="Прикрепить" width="24" height="24"> </button> <span class="vkStatus"></span> </div> <div class="vk-right-group"> <label class="vk-bell-wrapper" title="Подписаться на комментарии"> <svg class="vk-bell-icon"> <use xlink:href="/.s/t/2301/icons/icons.svg#bell_icon"></use> </svg> <input type="checkbox" class="vkBell" hidden> </label> <label class="vk-anon-wrapper" title="Анонимно"> <svg class="vk-anon-icon"> <use xlink:href="/.s/t/2301/icons/icons.svg#incognito_icon"></use> </svg> <input type="checkbox" class="vkAnon" hidden> </label> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Проверяем, не был ли уже навешан обработчик if (window.vkSmileHandlerAdded) return; window.vkSmileHandlerAdded = true; document.addEventListener('click', function(e) { // --- открыть форму при клике на collapsed --- const collapsed = e.target.closest('.vk-add-form .collapsed'); if (collapsed) { const form = collapsed.closest('.vk-add-form'); const expanded = form.querySelector('.expanded'); const textarea = form.querySelector('.vk-textarea'); collapsed.style.display = 'none'; expanded.style.display = 'block'; textarea.focus(); return; } // --- клик по кнопке смайлов --- const smileBtn = e.target.closest('.vk-add-form .vk-smile-btn'); if (smileBtn) { const form = smileBtn.closest('.vk-add-form'); const smilePopup = form.querySelector('.smiles'); smilePopup.style.display = (smilePopup.style.display === 'block') ? 'none' : 'block'; e.stopPropagation(); // чтобы клик не дошёл до document return; } // --- клик по смайлу --- const smileLink = e.target.closest('.vk-add-form .smiles a'); if (smileLink) { const form = smileLink.closest('.vk-add-form'); const textarea = form.querySelector('.vk-textarea'); const smile = smileLink.dataset.smile || ''; const start = textarea.selectionStart; const end = textarea.selectionEnd; const text = textarea.value; textarea.value = text.slice(0, start) + smile + text.slice(end); textarea.focus(); textarea.selectionEnd = start + smile.length; // закрываем popup const smilePopup = form.querySelector('.smiles'); smilePopup.style.display = 'none'; e.preventDefault(); return; } // --- клик вне формы закрывает форму и popup --- document.querySelectorAll('.vk-add-form').forEach(form => { if (!form.contains(e.target)) { const collapsed = form.querySelector('.collapsed'); const expanded = form.querySelector('.expanded'); const smilePopup = form.querySelector('.smiles'); if (collapsed && expanded) { collapsed.style.display = 'block'; expanded.style.display = 'none'; } if (smilePopup) smilePopup.style.display = 'none'; } }); }); }); </script> </div> </div> <iframe id="commentFrame" style="width:0;height:0;border:0;position:absolute;left:-9999px;"></iframe> <!-- Прокачанное уведомление --> <div id="vkSuccessMsg"> <div class="vk-tail"></div> <div class="vk-icon1">✓</div> <div class="vk-text"> Ваш комментарий успешно отправлен! Теперь он виден всем пользователям. </div> </div> <!-- Ставим перед скриптом модалку --> <div id="vkAttachModal" style="display:none;"> <div class="vkAttachOverlay"></div> <div class="vkAttachBox"> <div class="vkAttachHeader"> <img class="vkAttachIcon" src="https://www.svgrepo.com/show/509003/avatar-thinking-6.svg" alt="скрепка" width="16" height="16"> <span class="vkAttachTitle">Вставьте ссылку на изображение</span> </div> <input type="text" class="vkAttachInput" placeholder="https://"> <div class="vkAttachButtons"> <button class="vkAttachCancel">Отмена</button> <button class="vkAttachOk">OK</button> </div> </div> </div> <script> document.addEventListener("DOMContentLoaded", function(){ document.querySelectorAll('.vk-modern-post').forEach(post => { const collapsed = post.querySelector('.vk-add-form .collapsed'); const expanded = post.querySelector('.vk-add-form .expanded'); if(!collapsed || !expanded) return; const textarea = expanded.querySelector('.vk-textarea'); const sendBtn = expanded.querySelector('.vkSendBtn'); const status = expanded.querySelector('.vkStatus'); const anonCheck = expanded.querySelector('.vkAnon'); const anonWrap = expanded.querySelector('.vk-anon-wrapper'); const bell = expanded.querySelector('.vk-bell-wrapper'); const bellCheck = expanded.querySelector('.vkBell'); const iframe = document.getElementById('commentFrame'); const successMsg = document.getElementById('vkSuccessMsg'); /* ---------------- АНОНИМ ---------------- */ if(anonWrap){ anonWrap.addEventListener('click', e=>{ e.stopPropagation(); anonCheck.checked = !anonCheck.checked; anonWrap.classList.toggle('active', anonCheck.checked); }); } /* ---------------- КОЛОКОЛ ---------------- */ if(bell){ bell.addEventListener('click', e=>{ e.stopPropagation(); bellCheck.checked = !bellCheck.checked; bell.classList.toggle('active', bellCheck.checked); }); } /* ------------------- Скрипт скрепки с модалкой ------------------- */ const attachBtn = expanded.querySelector('.vkAttachBtn'); if(attachBtn && !attachBtn.dataset.handlerAdded){ attachBtn.dataset.handlerAdded = "true"; attachBtn.addEventListener('click', e=>{ e.stopPropagation(); const modal = document.getElementById('vkAttachModal'); const input = modal.querySelector('.vkAttachInput'); const okBtn = modal.querySelector('.vkAttachOk'); const cancelBtn = modal.querySelector('.vkAttachCancel'); modal.style.display = 'flex'; input.value = ''; input.focus(); cancelBtn.onclick = ()=> { modal.style.display = 'none'; } okBtn.onclick = ()=> { const url = input.value.trim(); if(!url){ alert('Ссылка не может быть пустой'); input.focus(); return; } if(!/^https?:\/\//i.test(url)){ alert('Нужна прямая ссылка на изображение'); input.focus(); return; } // Вставляем BB-код в textarea const imgTag = `[img]${url}[/img]`; textarea.value += (textarea.value ? '\n' : '') + imgTag; textarea.focus(); modal.style.display = 'none'; } }); } /* ---------------- ОТКРЫТЬ ФОРМУ ---------------- */ collapsed.addEventListener('click', ()=>{ collapsed.style.display='none'; expanded.style.display='block'; textarea?.focus(); }); /* ---------------- ЗАКРЫТЬ СНАРУЖИ ---------------- */ document.addEventListener('click', e=>{ if(!post.contains(e.target)){ collapsed.style.display='block'; expanded.style.display='none'; } }); /* ---------------- ОТПРАВКА ---------------- */ if(sendBtn){ sendBtn.addEventListener('click', ()=>{ const msg = textarea?.value.trim(); if(!msg) return; // ==== статус как ВК ==== status.textContent = 'Идёт отправка...'; status.classList.add('show'); // ==== старая проверенная логика отправки ==== const postId = post.querySelector('.post')?.dataset?.id; if(!postId){ status.textContent = 'ID поста не найден'; return; } iframe.src = `/publ/1-1-0-${postId}`; iframe.onload = () => { try{ const doc = iframe.contentDocument; const w = iframe.contentWindow; const form = doc.getElementById('acform'); if(!form){ status.textContent='Форма не найдена'; return; } // текст комментария const msgField = form.querySelector('textarea[name="message"]'); if(msgField) msgField.value = msg; // аноним if(anonCheck?.checked){ const realAnon = form.querySelector('input[name="anonymous"]'); if(realAnon) realAnon.checked = true; const uid = form.querySelector('input[name="user_id"]'); if(uid) uid.value = ''; const email = form.querySelector('input[name="email"]'); if(email) email.value = ''; } // колокольчик (подписка) const realSub = form.querySelector('input[name="subscribe"]'); if(realSub){ realSub.checked = !!bellCheck?.checked; } // отправка if(typeof w.addcom === 'function'){ w.addcom(form); }else{ form.submit(); } // очистка формы textarea.value = ''; collapsed.style.display='block'; expanded.style.display='none'; // ==== уведомления ==== if(successMsg){ successMsg.classList.add('show'); setTimeout(()=> successMsg.classList.remove('show'), 6000); } // ==== скрываем статус через 3 секунды ==== setTimeout(()=>{ status.classList.remove('show'); status.textContent = ''; }, 3000); }catch(e){ console.error(e); status.textContent='Ошибка отправки'; status.classList.add('show'); setTimeout(()=>{ status.classList.remove('show'); }, 3000); } }; // ==== конец старой логики отправки ==== }); } }); }); </script>
Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
Дата: Вторник, 17.02.2026, 07:55 | Сообщение # 4 |
|
Написал: Узнаваемый
Автор темы
Мурчанн
не в сети
Сообщений: 211
Упаковал скрипты, чтобы они занимали меньше места и были максимально компактными. Работа с формой завершена , она функционирует стабильно. Если у вас есть идеи, предложения или пожелания по улучшению скриптов пишите в тему. Рассмотрим ваши предложения, если они будут интересными или полезными, внесём изменения или добавим новые функции.Код
<!-- ЛЕНТА НОВОСТЕЙ --> <link rel="stylesheet" href="https://bro.usite.pro/css/bro-anon.css?v=2" media="all"> <div class="vk-modern-feed"> <div class="vk-modern-post"> <!-- HEADER --> <div class="vk-modern-header"> <div class="vk-modern-avatar"> <?if($AVATAR_URL$)?><img src="$AVATAR_URL$" alt="$USERNAME$"><?else?><img src="/.s/img/avatar.png"><?endif?> </div> <div class="vk-modern-author"> <div class="vk-modern-name"><a href="$PROFILE_URL$">$USERNAME$</a></div> <div class="vk-modern-time" title="$TIME$"> <img src="https://bro.usite.pro/icon/clock-icon.png" alt="Дата публикации" height="22"> <span>$DATE$</span> </div> </div> <?if($MODER_PANEL$)?><div class="entry-moder-container">$MODER_PANEL$</div><?endif?> <script> document.addEventListener('DOMContentLoaded', function() { document.querySelectorAll('.u-mpanel').forEach(panel => { // Проверяем, есть ли уже кнопка if(panel.querySelector('.custom-edit-btn')) return; // Создаём кнопку с тремя точками const btn = document.createElement('div'); btn.className = 'custom-edit-btn'; btn.textContent = '•••'; panel.prepend(btn); // вставляем сверху панели // Клик по кнопке: вызываем стандартный toggle панели btn.addEventListener('click', e => { e.stopPropagation(); const toggle = panel.querySelector('.u-mpanel-toggle'); if(toggle) toggle.click(); // вызывает оригинальный модер панель }); }); }); </script> </div> <!-- TEXT --> <?if($MESSAGE$)?><div class="vk-modern-text"> <div class="post" data-id="$ID$">$MESSAGE$</div> </div><?endif?> <!-- IMAGE --> <?if($COVER_IMAGE$)?><div class="vk-modern-attach"> <picture> <source srcset="$COVER_SMALL_URL$" media="(min-width:769px)"> <img src="$COVER_URL$" alt="$TITLE$" loading="lazy"> </picture> </div><?endif?> <!-- ACTIONS --> <div class="vk-modern-actions"> <div class="vk-actions-left"> <div class="vk-like" data-entryid="$ID$"> <span class="likeHeart" title="Поставить лайк"></span> <span class="uLikeCount">$RATED$</span> </div> <script src="/js/likeSystem.js" defer></script> <!-- COMMENTS --> <?if($COMMENTS_URL$)?> <a class="vk-action" href="$COMMENTS_URL$"> <svg viewBox="0 0 24 24"> <path d="M21 6h-18v10h4v4l4-4h10z"/> </svg> <span>$COMMENTS_NUM$</span> </a> <?endif?> <!-- READS --> <div class="vk-action"> <button class="vkShareBtn" onclick="vkShare(event)" aria-label="Поделиться" title="Поделиться"> <span class="vkShareRipple"></span> <svg viewBox="0 0 24 24" class="vkShareIcon"> <path d="M11.996 3.725A2.15 2.15 0 0 0 10 5.87l-.001 2.117-.02.005a9.904 9.904 0 0 0-7.827 10.721c.083.811 1.116 1.103 1.611.455l.187-.237a9.08 9.08 0 0 1 5.836-3.265l.213-.026.001 2.494a2.15 2.15 0 0 0 3.476 1.692l7.824-6.132a2.15 2.15 0 0 0 0-3.384l-7.824-6.132a2.15 2.15 0 0 0-1.326-.458z" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> <script> function vkShare(e){ const btn = e.currentTarget; const url = location.href; // ripple const rect = btn.getBoundingClientRect(); const ripple = btn.querySelector('.vkShareRipple'); ripple.style.left = (e.clientX - rect.left) + 'px'; ripple.style.top = (e.clientY - rect.top) + 'px'; ripple.classList.remove('show'); void ripple.offsetWidth; ripple.classList.add('show'); // share if (navigator.share) { navigator.share({ url }); } else { window.open('https://vk.com/share.php?url=' + encodeURIComponent(url),'_blank'); } } </script> </div> </div> <!-- Контейнер для просмотров --> <a class="vkViewBtn" href="$ENTRY_URL$" title="Перейти к новости"> <!-- Иконка глаза --> <svg viewBox="0 0 24 24" class="vkViewIcon" width="20" height="20"> <path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <circle cx="12" cy="12" r="3" fill="currentColor"/> </svg> <!-- Количество просмотров --> <span class="vkViewCount"> $READS$ </span> </a> </div> <!-- Форма комментариев --> <div class="vk-add-form"> <!-- Collapsed вид --> <div class="collapsed">Что у Вас нового?</div> <!-- Раскрытая форма --> <div class="expanded" style="display:none; position:relative;"> <!-- Аватар + поле + смайл --> <div class="vk-input-row" style="position:relative; display:flex; align-items:flex-start; gap:5px;"> <!-- Картинка для аватара --> <img class="vk-avatar commentUserAvatar" src="https://bro.usite.pro/icon/vk_large.png" alt="Ваш аватар" style="width:35px; height:35px; border-radius:50%; object-fit:cover; border:1px solid #cfd6e0;"> <script> function applyUserAvatar() { const userAvatarEl = document.querySelector('#userMenu .real-avatar'); const commentAvatars = document.querySelectorAll('.commentUserAvatar'); let avatar = 'https://bro.usite.pro/icon/vk_large.png'; if (userAvatarEl && userAvatarEl.src) { avatar = userAvatarEl.src; } commentAvatars.forEach(img => { img.src = avatar; }); } // при первой загрузке document.addEventListener("DOMContentLoaded", applyUserAvatar); // отслеживаем подгрузку новых комментариев (AJAX / динамика) const observer = new MutationObserver(() => { applyUserAvatar(); }); observer.observe(document.body, { childList: true, subtree: true }); </script> <textarea class="vk-textarea" placeholder="Напишите комментарий..."></textarea> <!-- Кнопка смайлов --> <button type="button" class="vk-smile-btn" title="Вставить смайл"> <img src="https://bro.usite.pro/img/yksmile.webp" alt="смайл" style="width:20px; height:20px; display:block;"> </button> <!-- Popup со смайлами --> <div class="smiles smiles-grid" style="display:none;"> <a href="#" class="sml1" data-smile=">("><img src="/.s/sm/2/angry.gif" title="angry"></a> <a href="#" class="sml1" data-smile=":D"><img src="/.s/sm/2/biggrin.gif" title="biggrin"></a> <a href="#" class="sml1" data-smile="B)"><img src="/.s/sm/2/cool.gif" title="cool"></a> <a href="#" class="sml1" data-smile=":'("><img src="/.s/sm/2/cry.gif" title="cry"></a> <a href="#" class="sml1" data-smile="<_<"><img src="/.s/sm/2/dry.gif" title="dry"></a> <a href="#" class="sml1" data-smile="^_^"><img src="/.s/sm/2/happy.gif" title="happy"></a> <a href="#" class="sml1" data-smile=":("><img src="/.s/sm/2/sad.gif" title="sad"></a> <a href="#" class="sml1" data-smile=":)"><img src="/.s/sm/2/smile.gif" title="smile"></a> <a href="#" class="sml1" data-smile=":o"><img src="/.s/sm/2/surprised.gif" title="surprised"></a> <a href="#" class="sml1" data-smile=":p"><img src="/.s/sm/2/tongue.gif" title="tongue"></a> <a href="#" class="sml1" data-smile="%)"><img src="/.s/sm/2/wacko.gif" title="wacko"></a> <a href="#" class="sml1" data-smile=";)"><img src="/.s/sm/2/wink.gif" title="wink"></a> </div> </div> <!-- Действия --> <div class="vk-actions-row"> <div class="vk-left-group"> <button class="vkSendBtn">Отправить</button> <button type="button" class="vkAttachBtn" title="Прикрепить изображение"> <img src="https://www.svgrepo.com/show/278366/paper-clip.svg" alt="Прикрепить" width="24" height="24"> </button> <span class="vkStatus"></span> </div> <div class="vk-right-group"> <label class="vk-bell-wrapper" title="Подписаться на комментарии"> <svg class="vk-bell-icon"> <use xlink:href="/.s/t/2301/icons/icons.svg#bell_icon"></use> </svg> <input type="checkbox" class="vkBell" hidden> </label> <label class="vk-anon-wrapper" title="Анонимно"> <svg class="vk-anon-icon"> <use xlink:href="/.s/t/2301/icons/icons.svg#incognito_icon"></use> </svg> <input type="checkbox" class="vkAnon" hidden> </label> </div> </div> </div> </div> <script type="module" src="/js/vkCommentSmiles.js"></script> </div> </div> <iframe id="commentFrame" style="width:0;height:0;border:0;position:absolute;left:-9999px;"></iframe> <!-- Прокачанное уведомление --> <div id="vkSuccessMsg"> <div class="vk-tail"></div> <div class="vk-icon1">✓</div> <div class="vk-text"> Ваш комментарий успешно отправлен! Теперь он виден всем пользователям. </div> </div> <!-- Ставим перед скриптом модалку --> <div id="vkAttachModal" style="display:none;"> <div class="vkAttachOverlay"></div> <div class="vkAttachBox"> <div class="vkAttachHeader"> <img class="vkAttachIcon" src="https://www.svgrepo.com/show/509003/avatar-thinking-6.svg" alt="скрепка" width="16" height="16"> <span class="vkAttachTitle">Вставьте ссылку на изображение</span> </div> <input type="text" class="vkAttachInput" placeholder="https://"> <div class="vkAttachButtons"> <button class="vkAttachCancel">Отмена</button> <button class="vkAttachOk">OK</button> </div> </div> </div> <script src="/js/commentSystem.js"></script>
Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
Дата: Среда, 18.02.2026, 09:57 | Сообщение # 5 |
|
Написал: Узнаваемый
Автор темы
Мурчанн
не в сети
Сообщений: 211
Обнаружен баг в скрипте: после подгрузки материалов форма редактирования (три точки) пропадает. Скрипт был переписан, логика изменена. Нужно просто заменить старый скрипт на новый.Код
<script> (function() { function initMPanels(root = document) { root.querySelectorAll('.u-mpanel').forEach(panel => { // если кнопка уже есть — не создаём вторую if (panel.querySelector('.custom-edit-btn')) return; const btn = document.createElement('div'); btn.className = 'custom-edit-btn'; btn.textContent = '•••'; panel.prepend(btn); btn.addEventListener('click', function(e) { e.stopPropagation(); const toggle = panel.querySelector('.u-mpanel-toggle'); if (toggle) toggle.click(); }); }); } // первый запуск document.addEventListener('DOMContentLoaded', () => initMPanels()); // наблюдатель за динамической подгрузкой const observer = new MutationObserver(mutations => { for (const m of mutations) { if (m.addedNodes.length) { m.addedNodes.forEach(node => { if (node.nodeType !== 1) return; // если сама панель добавилась if (node.classList?.contains('u-mpanel')) { initMPanels(node.parentNode); } // если внутри появились панели if (node.querySelectorAll) { const panels = node.querySelectorAll('.u-mpanel'); if (panels.length) initMPanels(node); } }); } } }); observer.observe(document.body, { childList: true, subtree: true }); })(); </script>
Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
Дата: Пятница, 20.02.2026, 06:44 | Сообщение # 6 |
|
Написал: Узнаваемый
Автор темы
Мурчанн
не в сети
Сообщений: 211
В режиме тестирования всё работает корректно, однако в процессе реальной эксплуатации постепенно выявляются мелкие недочёты. В этот раз было замечено, что в форме комментария не подставлялась дефолтная аватарка. Скрипт постоянно пытался установить изображение по умолчанию, но из-за некорректной логики проверки выполнял это действие повторно при каждом изменении DOM. В результате происходила многократная перезапись src, что вызывало визуальный эффект моргания и мерцания аватара.Старый скрипт можно полностью заменить новой версией. Код
<script> function applyUserAvatar() { const userAvatarEl = document.querySelector('#userMenu .real-avatar'); const commentAvatars = document.querySelectorAll('.commentUserAvatar'); let avatar = '/.s/src/profile/img/profile_photo_thumbnail.png'; if (userAvatarEl && userAvatarEl.src) { const src = userAvatarEl.src.trim(); // Проверяем, что это нормальный URL картинки if ( src !== '' && src !== 'https://bro.usite.pro/' && !src.endsWith('/') ) { avatar = src; } } commentAvatars.forEach(img => { if (img.getAttribute('src') !== avatar) { img.setAttribute('src', avatar); } }); } document.addEventListener("DOMContentLoaded", () => { applyUserAvatar(); setTimeout(applyUserAvatar, 500); }); </script>
В этом участке необходимо просто заменить на свой сайт . Код
// Проверяем, что это нормальный URL картинки if ( src !== '' && src !== 'https://bro.usite.pro/' && !src.endsWith('/') ) { avatar = src; } }
При необходимости можно полностью заменить исходный код шаблона вида материалов обновлённой версией. Код
<!-- ЛЕНТА НОВОСТЕЙ --> <link rel="stylesheet" href="https://bro.usite.pro/css/bro-anon.css?v=2" media="all"> <div class="vk-modern-feed"> <div class="vk-modern-post"> <!-- HEADER --> <div class="vk-modern-header"> <div class="vk-modern-avatar"> <?if($AVATAR_URL$)?><img src="$AVATAR_URL$" alt="$USERNAME$"><?else?><img src="/.s/img/avatar.png"><?endif?> </div> <div class="vk-modern-author"> <div class="vk-modern-name"><a href="$PROFILE_URL$">$USERNAME$</a></div> <div class="vk-modern-time" title="$TIME$"> <img src="https://bro.usite.pro/icon/clock-icon.png" alt="Дата публикации" height="22"> <span>$DATE$</span> </div> </div> <?if($MODER_PANEL$)?><div class="entry-moder-container">$MODER_PANEL$</div><?endif?> <script> (function() { function initMPanels(root = document) { root.querySelectorAll('.u-mpanel').forEach(panel => { // если кнопка уже есть — не создаём вторую if (panel.querySelector('.custom-edit-btn')) return; const btn = document.createElement('div'); btn.className = 'custom-edit-btn'; btn.textContent = '•••'; panel.prepend(btn); btn.addEventListener('click', function(e) { e.stopPropagation(); const toggle = panel.querySelector('.u-mpanel-toggle'); if (toggle) toggle.click(); }); }); } // первый запуск document.addEventListener('DOMContentLoaded', () => initMPanels()); // наблюдатель за динамической подгрузкой const observer = new MutationObserver(mutations => { for (const m of mutations) { if (m.addedNodes.length) { m.addedNodes.forEach(node => { if (node.nodeType !== 1) return; // если сама панель добавилась if (node.classList?.contains('u-mpanel')) { initMPanels(node.parentNode); } // если внутри появились панели if (node.querySelectorAll) { const panels = node.querySelectorAll('.u-mpanel'); if (panels.length) initMPanels(node); } }); } } }); observer.observe(document.body, { childList: true, subtree: true }); })(); </script> </div> <!-- TEXT --> <?if($MESSAGE$)?><div class="vk-modern-text"> <div class="post" data-id="$ID$">$MESSAGE$</div> </div><?endif?> <!-- IMAGE --> <?if($COVER_IMAGE$)?><div class="vk-modern-attach"> <picture> <source srcset="$COVER_SMALL_URL$" media="(min-width:769px)"> <img src="$COVER_URL$" alt="$TITLE$" loading="lazy"> </picture> </div><?endif?> <!-- ACTIONS --> <div class="vk-modern-actions"> <div class="vk-actions-left"> <div class="vk-like" data-entryid="$ID$"> <span class="likeHeart" title="Поставить лайк"></span> <span class="uLikeCount">$RATED$</span> </div> <script src="/js/likeSystem.js" defer></script> <!-- COMMENTS --> <?if($COMMENTS_URL$)?> <a class="vk-action" href="$COMMENTS_URL$"> <svg viewBox="0 0 24 24"> <path d="M21 6h-18v10h4v4l4-4h10z"/> </svg> <span>$COMMENTS_NUM$</span> </a> <?endif?> <!-- READS --> <div class="vk-action"> <button class="vkShareBtn" onclick="vkShare(event)" aria-label="Поделиться" title="Поделиться"> <span class="vkShareRipple"></span> <svg viewBox="0 0 24 24" class="vkShareIcon"> <path d="M11.996 3.725A2.15 2.15 0 0 0 10 5.87l-.001 2.117-.02.005a9.904 9.904 0 0 0-7.827 10.721c.083.811 1.116 1.103 1.611.455l.187-.237a9.08 9.08 0 0 1 5.836-3.265l.213-.026.001 2.494a2.15 2.15 0 0 0 3.476 1.692l7.824-6.132a2.15 2.15 0 0 0 0-3.384l-7.824-6.132a2.15 2.15 0 0 0-1.326-.458z" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> <script> function vkShare(e){ const btn = e.currentTarget; const url = location.href; // ripple const rect = btn.getBoundingClientRect(); const ripple = btn.querySelector('.vkShareRipple'); ripple.style.left = (e.clientX - rect.left) + 'px'; ripple.style.top = (e.clientY - rect.top) + 'px'; ripple.classList.remove('show'); void ripple.offsetWidth; ripple.classList.add('show'); // share if (navigator.share) { navigator.share({ url }); } else { window.open('https://vk.com/share.php?url=' + encodeURIComponent(url),'_blank'); } } </script> </div> </div> <!-- Контейнер для просмотров --> <a class="vkViewBtn" href="$ENTRY_URL$" title="Перейти к новости"> <!-- Иконка глаза --> <svg viewBox="0 0 24 24" class="vkViewIcon" width="20" height="20"> <path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <circle cx="12" cy="12" r="3" fill="currentColor"/> </svg> <!-- Количество просмотров --> <span class="vkViewCount"> $READS$ </span> </a> </div> <!-- Форма комментариев --> <div class="vk-add-form"> <!-- Collapsed вид --> <div class="collapsed">Что у Вас нового?</div> <!-- Раскрытая форма --> <div class="expanded" style="display:none; position:relative;"> <!-- Аватар + поле + смайл --> <div class="vk-input-row" style="position:relative; display:flex; align-items:flex-start; gap:5px;"> <!-- Картинка для аватара --> <img class="vk-avatar commentUserAvatar" src="/.s/src/profile/img/profile_photo_thumbnail.png" alt="Аватарка" style="width:35px; height:35px; border-radius:50%; object-fit:cover; border:1px solid #cfd6e0;"> <script> function applyUserAvatar() { const userAvatarEl = document.querySelector('#userMenu .real-avatar'); const commentAvatars = document.querySelectorAll('.commentUserAvatar'); let avatar = '/.s/src/profile/img/profile_photo_thumbnail.png'; if (userAvatarEl && userAvatarEl.src) { const src = userAvatarEl.src.trim(); // Проверяем, что это нормальный URL картинки if ( src !== '' && src !== 'https://bro.usite.pro/' && !src.endsWith('/') ) { avatar = src; } } commentAvatars.forEach(img => { if (img.getAttribute('src') !== avatar) { img.setAttribute('src', avatar); } }); } document.addEventListener("DOMContentLoaded", () => { applyUserAvatar(); setTimeout(applyUserAvatar, 500); }); </script> <textarea class="vk-textarea" placeholder="Напишите комментарий..."></textarea> <!-- Кнопка смайлов --> <button type="button" class="vk-smile-btn" title="Вставить смайл"> <img src="https://bro.usite.pro/img/yksmile.webp" alt="смайл" style="width:20px; height:20px; display:block;"> </button> <!-- Popup со смайлами --> <div class="smiles smiles-grid" style="display:none;"> <a href="#" class="sml1" data-smile=">("><img src="/.s/sm/2/angry.gif" title="angry"></a> <a href="#" class="sml1" data-smile=":D"><img src="/.s/sm/2/biggrin.gif" title="biggrin"></a> <a href="#" class="sml1" data-smile="B)"><img src="/.s/sm/2/cool.gif" title="cool"></a> <a href="#" class="sml1" data-smile=":'("><img src="/.s/sm/2/cry.gif" title="cry"></a> <a href="#" class="sml1" data-smile="<_<"><img src="/.s/sm/2/dry.gif" title="dry"></a> <a href="#" class="sml1" data-smile="^_^"><img src="/.s/sm/2/happy.gif" title="happy"></a> <a href="#" class="sml1" data-smile=":("><img src="/.s/sm/2/sad.gif" title="sad"></a> <a href="#" class="sml1" data-smile=":)"><img src="/.s/sm/2/smile.gif" title="smile"></a> <a href="#" class="sml1" data-smile=":o"><img src="/.s/sm/2/surprised.gif" title="surprised"></a> <a href="#" class="sml1" data-smile=":p"><img src="/.s/sm/2/tongue.gif" title="tongue"></a> <a href="#" class="sml1" data-smile="%)"><img src="/.s/sm/2/wacko.gif" title="wacko"></a> <a href="#" class="sml1" data-smile=";)"><img src="/.s/sm/2/wink.gif" title="wink"></a> </div> </div> <!-- Действия --> <div class="vk-actions-row"> <div class="vk-left-group"> <button class="vkSendBtn">Отправить</button> <button type="button" class="vkAttachBtn" title="Прикрепить изображение"> <img src="https://www.svgrepo.com/show/278366/paper-clip.svg" alt="Прикрепить" width="24" height="24"> </button> <span class="vkStatus"></span> </div> <div class="vk-right-group"> <label class="vk-bell-wrapper" title="Подписаться на комментарии"> <svg class="vk-bell-icon"> <use xlink:href="/.s/t/2301/icons/icons.svg#bell_icon"></use> </svg> <input type="checkbox" class="vkBell" hidden> </label> <label class="vk-anon-wrapper" title="Анонимно"> <svg class="vk-anon-icon"> <use xlink:href="/.s/t/2301/icons/icons.svg#incognito_icon"></use> </svg> <input type="checkbox" class="vkAnon" hidden> </label> </div> </div> </div> </div> <script type="module" src="/js/vkCommentSmiles.js"></script> </div> </div> <iframe id="commentFrame" style="width:0;height:0;border:0;position:absolute;left:-9999px;"></iframe> <!-- Прокачанное уведомление --> <div id="vkSuccessMsg"> <div class="vk-tail"></div> <div class="vk-icon1">✓</div> <div class="vk-text"> Ваш комментарий успешно отправлен! Теперь он виден всем пользователям. </div> </div> <!-- Ставим перед скриптом модалку --> <div id="vkAttachModal" style="display:none;"> <div class="vkAttachOverlay"></div> <div class="vkAttachBox"> <div class="vkAttachHeader"> <img class="vkAttachIcon" src="https://www.svgrepo.com/show/509003/avatar-thinking-6.svg" alt="скрепка" width="16" height="16"> <span class="vkAttachTitle">Вставьте ссылку на изображение</span> </div> <input type="text" class="vkAttachInput" placeholder="https://"> <div class="vkAttachButtons"> <button class="vkAttachCancel">Отмена</button> <button class="vkAttachOk">OK</button> </div> </div> </div> <script src="/js/commentSystem.js"></script>
Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
Дата: Воскресенье, 22.02.2026, 10:08 | Сообщение # 7 |
|
Написал: Узнаваемый
Автор темы
Мурчанн
не в сети
Сообщений: 211
Обязательно в настройках установите Главная / Общие настройки/ Общие настройкиНастройки "HTML‑редактора" - обязательны иначе работать форма не будет.
Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.