«Продолжается развитие скрипта с добавлением новых возможностей. Реализована система двустороннего осмысленного подтверждения, включающая многоуровневые этапы верификации и контроля, что позволяет повысить надежность обработки данных и снизить вероятность ошибок.»
Модуль «Друзья» это современное решение для uCoz, превращающее стандартную систему добавления в друзья в полноценный социальный функционал. Вместо мгновенного добавления (как это было в старых версиях uCoz), скрипт реализует двухэтапную систему подтверждения через личные сообщения точно так же, как это работает в ВКонтакте, Facebook и других крупных социальных сетях.
Процесс добавления в друзья состоит из трёх логичных шагов:
Заявка. Пользователь нажимает кнопку «Добавить в друзья» на странице другого пользователя. Вместо мгновенного добавления система открывает красивое модальное окно, где можно выбрать группу друзей (Друг, Приятель, Знакомый, Семья, Коллега, Кумир) и при желании добавить личное сообщение. После нажатия «Отправить заявку» пользователю приходит личное сообщение со специальной ссылкой-приглашением.
Подтверждение
Получатель заявки переходит по ссылке и видит стильное окно подтверждения с аватаром отправителя. После нажатия «Подтвердить» он автоматически добавляет отправителя в свой список друзей и отправляет встречное сообщение со ссылкой на завершение.
Завершение. Отправитель первоначальной заявки получает ответное сообщение, переходит по ссылке и добавляет получателя к себе в друзья. Дружба становится взаимной.
Защита от дубликатов
Скрипт автоматически проверяет список друзей обеих сторон перед каждым действием. Если пользователь уже находится в списке, добавление блокируется с показом информативного уведомления. Более того, при попытке повторного добавления отображается точная дата, когда этот друг был добавлен ранее.
Двусторонняя синхронизация
Даже если один из пользователей удалил друга из своего списка, система корректно обработает повторную заявку не создаст дубликат, а отправит ссылку на завершение взаимного добавления.
Группы друзей
Шесть предустановленных категорий: Друг, Приятель, Знакомый, Семья, Коллега, Кумир. Выбор группы происходит в красивом выпадающем меню с синим градиентным фоном и белым текстом.
Личное сообщение к заявке
При отправке заявки можно прикрепить персональное сообщение , это делает процесс более живым и персонализированным, как в настоящих социальных сетях.
Красивые модальные окна
Все окна выполнены в современном стиле VK/Facebook:
Плавные анимации появления Градиентные заголовки с эффектом мерцания Пульсирующие иконки Аватары с объёмными тенями Стилизованные кнопки с hover-эффектами Информационные блоки с иконками
Информативные уведомления
При попытке добавить уже существующего друга пользователь видит:
1. Аватар пользователя 2. Имя 3. Статус «Уже в вашем списке друзей» 4. Дату добавления (извлекается из шаблона) 5. Описание ситуации
Безопасность и надёжность
Токены подтверждения
Каждая заявка получает уникальный токен, который сохраняется в localStorage после обработки. Это защищает от:
1. Повторного подтверждения одной и той же заявки 2. Перехвата ссылок третьими лицами 3. Случайного двойного клика
Защита от несанкционированного добавления
Скрипт перехватывает все AJAX-запросы на добавление в блог и блокирует их, пока пользователь не пройдёт через официальное окно подтверждения. Это исключает возможность добавления «в обход» системы.
Капча для ЛС
Если на сайте включена защита от спама в личных сообщениях, скрипт автоматически покажет окно ввода капчи , пользователю не нужно ни о чём беспокоиться.
Производительность
Минимальная нагрузка на сервер
Все запросы выполняются только по действию пользователя , никаких фоновых опросов За весь процесс дружбы происходит около 12 запросов (для сравнения: одна загрузка Facebook делает 50-100 запросов) Большинство запросов лёгкие GET-запросы
Умное кэширование
1. Аватары кэшируются в памяти и localStorage 2. Список друзей проверяется через AJAX только при необходимости 3. Профили пользователей загружаются по требованию
Быстрый отклик
Проверка локального кэша (localStorage) происходит мгновенно, до обращения к серверу. Это даёт пользователю ощущение мгновенной реакции интерфейса.
Дизайн
Интерфейс модуля выполнен в единой стилистике современных социальных сетей:
Модалка заявки — с аватаром получателя, выбором группы и возможностью добавить сообщение
Модалка подтверждения — с градиентной шапкой, пульсирующей иконкой и крупной аватаркой отправителя
Модалка завершения — компактная, с чётким призывом к действию
Модалка успеха — с анимированной синей галочкой в стиле VK
Alert-уведомления — компактные, с аватаром пользователя и детальной информацией
Все элементы адаптивны и корректно отображаются на мобильных устройствах.
Технические особенности
Работает на jQuery (совместим с uCoz)
Использует стандартный модуль «Блог» как хранилище записей о друзьях
Поддерживает все стандартные переменные uCoz
Код
($TITLE$, $OTHER1$, $OTHER3$, $DATE$ и др.)
Не требует установки дополнительных модулей или плагинов
Полностью изолирован — не конфликтует с другими скриптами на сайте
Поддерживает HTTPS и корректно работает с Mixed Content
Всё, что нужно для запуска установить скрипт, настроить шаблоны и наслаждаться.
html += '<div class="my-friend-card">'; html += '<div class="friend-avatar-friends" style="background-image:url(\''+f.ava+'\');" data-profile="'+f.profile+'"></div>'; html += '<div class="friend-nick-friends"><a href="'+f.profile+'" target="_blank">'+f.nick+'</a></div>'; if(f.group) html += '<div class="friend-group-friends">'+f.group+'</div>'; html += '</div>';
$.get(url).done(function(data){ var $data = $('<div>').append($.parseHTML(data)); var $items = $data.find(".friend, .fr, .друг, .friend-item, .fr-item"); if (!$items.length) $items = $data.find(".entry, .entry-card, .user-row");
var all = [];
$items.each(function(){ var $it = $(this);
// Пытаемся корректно достать аватар (несколько вариантов) var ava = ''; var $img = $it.find('img').first(); if ($img.length && ($img.attr('src') || '').match(/avatar/)) { ava = $img.attr('src'); if (ava && ava.indexOf('http') !== 0) ava = location.origin + ava; } else { var text = $it.text(); var avaMatch = text.match(/(\/avatar\/\d{2}\/\d{2}\/\d+\.(?:png|jpg))/); ava = avaMatch ? location.origin + avaMatch[0] : ''; }
// ← добавляем эту строку var DEFAULT_AVA = "/.s/src/profile/img/profile_photo_thumbnail.png"; if (!ava) ava = DEFAULT_AVA;
// ссылка на профиль var profileUrl = '#'; var hrefMatch = $it.html().match(/https?:\/\/[^\s"']+\/index\/8-(\d+)/); if (hrefMatch) { profileUrl = location.origin + '/index/8-' + parseInt(hrefMatch[1],10); } else { var $aProfile = $it.find('a[href*="/index/8-"]').first(); if ($aProfile.length) { profileUrl = $aProfile.attr('href'); if (profileUrl && profileUrl.indexOf('http') !== 0) profileUrl = location.origin + profileUrl; } }
// Ник и группы var textClean = $it.clone(); textClean.find('img, a, .ava, .del, .gr').remove(); var nick = (textClean.text() || '').trim().split('\n')[0] || 'Без имени'; nick = nick.replace(/\s{2,}/g,' ').trim(); var groupMatches = ($it.text().match(/(Кумир|Семья|Друг|Приятель|Коллега|Знакомый)/gi) || []); var groups = groupMatches;
// MODER_PANEL — ссылка удаления (если есть) var del = ''; var $delEl = $it.find('.del, .del-link').first(); if ($delEl.length) { del = ($delEl.text() || $delEl.attr('href') || '').trim(); } if (!del) { var delMatch = $it.html().match(/\/index\/92-3-\d+/); del = delMatch ? delMatch[0] : ''; }
// клик по аватару — открываем профиль $(document).on('click', '.friend-avatar-friends', function(){ var p = $(this).data('profile') || '#'; if (p && p !== '#') window.open(p, '_blank'); });
// Удаление крестиком — аккуратно формируем полный URL и шлём GET $(document).on('click', '.friend-delete-btn-friends', function(e){ e.preventDefault(); var $btn = $(this); var delUrl = decodeURIComponent($btn.data('del') || '');
if (!delUrl) { return alert('Ссылка удаления не найдена'); } if (!confirm('Вы уверены, что хотите удалить?')) return;
// если относительный — добавляем origin if (delUrl.indexOf('http') !== 0) { if (delUrl.charAt(0) !== '/') delUrl = '/' + delUrl; delUrl = location.origin + delUrl; }
<script type="text/javascript"> var othid = '$_USER_ID$'.trim(); var myid = '$USER_ID$'.trim();
$(document).ready(function(){
// Если мой ID = ID профиля, который смотрю → это я сам if (myid == othid) { $("#addFriendContainer").html(""); // делаем пустым, кнопка НЕ вставится return; // выходим и больше ничего не делаем }
// Иначе (это не я) → вставляем кнопку $("#addFriendContainer").html( '<a href="javascript:;" onclick="friends.sAdd(); return false;" class="btn-add">Добавить в друзья</a>' );
Подробную информацию об установке скрипта, а также о необходимых настройках системы для его корректной работы, вы можете найти в отдельной теме. В ней подробно описаны все этапы установки, требования к системе и параметры, которые необходимо настроить для стабильной работы скрипта.
Конечно, с точки зрения функционала скрипт уже достаточно далеко продвинулся вперёд. В дальнейшем смогу дорабатать дизайн, добавлять новые возможности для модальных окон, делать их более информативными.
К этому вопросу, скорее всего, вернусь ещё не скоро. Сейчас важно двигаться в другом направлении, поскольку есть и другие модули, которые также требуют доработки и улучшения.