Список пользователей

1
Админ
Постов: 211
2
VIP
Постов: 72
3
Элита
Постов: 50
4
Проверенные
Постов: 35
5
VIP
Постов: 35
6
Проверенные
Постов: 32
7
Пользователи
Постов: 31
8
Проверенные
Постов: 29

  • Страница 1 из 1
  • 1
Форма комментариев -VK социальная сеть V 1.0 uCoz функционал
Дата: Понедельник, 16.02.2026, 04:27 | Сообщение # 1 | | Написал: Узнаваемый
Автор темы
Мурчанн не в сети
        Сообщений:211
         Регистрация:20.10.2016

Здравствуйте, уважаемый читатель.

Как вы уже, вероятно, догадались, я публикую открытые исходные коды. Делается это с одной целью чтобы как можно больше людей могли подхватить идею, развить её, улучшить под свои задачи и создать нечто более продвинутое. Только через открытость, практику и совместное развитие можно добиться реального прогресса и вывести проект на новый уровень.

А теперь давайте начнём по порядку. Ниже я подробно опишу, какие изменения и обновления были внесены.

Данная форма комментариев была изначально разработана для каталога статей сайта на платформе uCoz. Однако это не должно вас ограничивать форму можно легко адаптировать под любой модуль, и она будет корректно работать практически везде.



Основные возможности формы:

Отправка комментариев непосредственно к материалу и в систему комментариев модуля «Страница материала».

Стилистика интерфейса выполнена в духе классических социальных сетей: можно заметить лёгкое сходство, однако дизайн полностью авторский и переработан.

Несколько режимов работы:

Режим «Невидимка» возможность оставлять комментарии скрытно.

Подписка на комментарии получение уведомлений о новых ответах и обновлениях обсуждения.

Встроенный набор смайлов для выражения эмоций.

Реализовано компактное всплывающее окно для быстрой отправки эмоций и реакций.

Добавлена функция прикрепления изображения (в стиле классического VK): при нажатии на значок скрепки открывается всплывающее окно, где можно указать ссылку на изображение без загрузки файла на сервер.

Описание скрипта

Скрипт структурирован и разбит на логические секции, что значительно упрощает его расширение и добавление нового функционала. Открытый исходный код остаётся понятным и удобным для навигации даже при первом знакомстве с ним сложно «заблудиться».

Каждая часть оформлена отдельными блоками, благодаря чему дополнительный функционал можно внедрять прямо секциями, без необходимости перерабатывать весь код. Такой подход делает систему гибкой и удобной для модификации.

При значительном увеличении объёма скрипта его можно без проблем вынести в отдельный файл, что позволит сохранить читаемость, упростит поддержку и дальнейшее развитие проекта.

Описание работы скрипта формы комментариев

Данный скрипт реализует современную интерактивную форму комментариев с расширенным функционалом, ориентированную на удобство пользователя и работу без перезагрузки страницы. Скрипт построен на чистом JavaScript и активируется после полной загрузки DOM-структуры страницы.

Общий принцип работы

После загрузки страницы скрипт находит все блоки публикаций с классом .vk-modern-post и инициализирует для каждого из них систему формы комментариев. Архитектура построена модульно, что позволяет легко расширять функционал и адаптировать скрипт под различные задачи.

Основные функции скрипта

1. Переключение формы (свернутая / развернутая)

По умолчанию отображается компактная (свернутая) форма.

При клике форма раскрывается и активируется поле ввода текста.

При клике вне формы она автоматически сворачивается обратно.

Это создаёт поведение, аналогичное современным социальным сетям.

Режим «Аноним»

Позволяет отправлять комментарий без указания пользователя.

При активации:

В оригинальной форме включается флаг anonymous

Очищаются поля user_id и email

Визуально кнопка подсвечивается

Режим переключается без перезагрузки страницы.

Подписка на комментарии (колокольчик)

При включении пользователь автоматически подписывается на ответы и новые комментарии к материалу.

В основной форме устанавливается флаг subscribe

Состояние кнопки отображается визуально

Прикрепление изображения (скрепка + модальное окно)

Реализован механизм добавления изображения по прямой ссылке:

1. При нажатии на кнопку скрепки открывается модальное окно.

2. Пользователь вводит прямую ссылку на изображение.

3.Скрипт проверяет:

....ссылка не пустая

........начинается с http или https

4. В текст комментария автоматически вставляется BB-код:

Код
[img]ссылка[/img]


Изображение не загружается на сервер ,используется внешняя ссылка.

Отправка комментария без перезагрузки

Отправка реализована через скрытый 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
         Регистрация:20.10.2016

На Юкозе нет переменных в виде материала, которые позволяют взять аватар авторизованного пользователя и автоматически подставить его в форму комментариев. Поэтому был написан скрипт, который вытаскивает аватар прямо из блока профиля и подставляет его туда, куда мне нужно.

Внесены изменения в интерфейс формы:

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>




Пока писал текст, выявился ещё один баг: после прогрузки следующего материала скрипт не видит аватарку и автоматически подставляет дефолтную. Скрипт будет дорабатываться, и уже продумывается решение этой задачи. Как только появится рабочий способ, я внесу соответствующие изменения. alik

Мурчанн

Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
Дата: Вторник, 17.02.2026, 05:59 | Сообщение # 3 | | Написал: Узнаваемый
Автор темы
Мурчанн не в сети
        Сообщений:211
         Регистрация:20.10.2016

Скрипт работал только при первой загрузке страницы, потому что был привязан к событию 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
         Регистрация:20.10.2016

Упаковал скрипты, чтобы они занимали меньше места и были максимально компактными.

Работа с формой завершена , она функционирует стабильно.

Если у вас есть идеи, предложения или пожелания по улучшению скриптов пишите в тему.

Рассмотрим ваши предложения, если они будут интересными или полезными, внесём изменения или добавим новые функции.

Код
<!-- ЛЕНТА НОВОСТЕЙ -->
<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
         Регистрация:20.10.2016

Обнаружен баг в скрипте: после подгрузки материалов форма редактирования (три точки) пропадает. Скрипт был переписан, логика изменена. Нужно просто заменить старый скрипт на новый.

Код
<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
         Регистрация:20.10.2016

В режиме тестирования всё работает корректно, однако в процессе реальной эксплуатации постепенно выявляются мелкие недочёты.

В этот раз было замечено, что в форме комментария не подставлялась дефолтная аватарка. Скрипт постоянно пытался установить изображение по умолчанию, но из-за некорректной логики проверки выполнял это действие повторно при каждом изменении 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
         Регистрация:20.10.2016

Обязательно в настройках установите

Главная / Общие настройки/ Общие настройки

Настройки "HTML‑редактора" - обязательны иначе работать форма не будет.

Мурчанн

Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
  • Страница 1 из 1
  • 1
Поиск: