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

1
Админ
Постов: 288
2
VIP
Постов: 75
3
Элита
Постов: 62
4
Проверенные
Постов: 46
5
Проверенные
Постов: 45
6
Проверенные
Постов: 39
7
VIP
Постов: 36
8
VIP
Постов: 35

  • Страница 1 из 1
  • 1
Скрипт друзей с функцией подтверждения V2.2 для uСoz
Дата: Вторник, 26.05.2026, 01:03 | Сообщение # 1 | | Написал: Известный
Автор темы
Мурчанн не в сети
        Сообщений:288
         Регистрация:20.10.2016
За уважение окружающих За уважение окружающих За хорошее поведение За преданность форуму За любовь народа

Продолжаем развитие системы добавления в друзья. На этот раз реализован расширенный механизм подтверждения, делающий процесс более осмысленным и двусторонним.



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

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

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

Дополнительно реализована система предварительной классификации. При отправке запроса инициатор может выбрать категорию например, «друзья», «кумир» и другие обозначения. Эта информация передаётся адресату, который, в свою очередь, получает возможность изменить предложенную категорию в соответствии со своим восприятием.

После выбора или подтверждения категории инициатор получает финальное уведомление для подтверждения. На этом этапе он уже не может вносить изменения остаётся лишь согласиться с предложенной классификацией. В случае отказа взаимная дружба не устанавливается.

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

Есть ещё один важный момент, но объясню проще.

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

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



Дополнительные поля:



Исходник

Код
<div id="vk_friends_block">
<h3>Братаны</h3>
<div id="vk_friends_list_custom"></div>

<div class="friends-count-box-custom">
$_BLOG_ENTRIES$
</div>
</div>

<link rel="stylesheet" href="https://bro.usite.pro/css/brother-friends.css?v=1">

<div id="friends-list" class="my-friends-list"></div>

<script type="text/javascript">
$(document).ready(function(){
var othid = '$_USER_ID$';
var storageKey = 'friends_' + othid;
var cacheTimeKey = storageKey + '_time';
var cacheTTL = 24 * 60 * 60 * 1000; // 24 часа

function renderFriends(friends){
var html = "";
var count = 0;
var seen = {};

friends.forEach(function(f){
if(count >= 4) return;
if(seen[f.profile]) return;
seen[f.profile] = true;

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>';

count++;
});

$("#friends-list").html(html);
$("#friends-count-box").text(count);
}

function fetchFriends(updateCache = true, compareCache = false){
$.get('/blog/0-0-0-0-17-' + othid, function(data){
var $items = $(data).find('.friend');
if(!$items.length){
$("#friends-list").html("<p>У этого пользователя нет друзей</p>");
$("#friends-count-box").text(0);
return;
}

var friends = [];
$items.each(function(){
var $el = $(this);
friends.push({
nick: $el.find('.nick').text().trim() || "Без имени",
ava: $el.find('.ava').text().trim() || '/.s/src/profile/img/profile_photo_thumbnail.png',
group: $el.find('.gr').text().trim() || "",
profile: $el.find('.url').text().trim() || '#'
});
});

if(compareCache){
var cached = localStorage.getItem(storageKey);
if(cached){
var cachedFriends = JSON.parse(cached);
var cachedProfiles = cachedFriends.map(f => f.profile).sort().join(',');
var newProfiles = friends.map(f => f.profile).sort().join(',');
if(cachedProfiles === newProfiles){
// Ничего не изменилось
return;
}
}
}

renderFriends(friends);

if(updateCache){
localStorage.setItem(storageKey, JSON.stringify(friends));
localStorage.setItem(cacheTimeKey, Date.now());
}
});
}

// Проверяем кэш
var cached = localStorage.getItem(storageKey);
var cacheTime = localStorage.getItem(cacheTimeKey);

if(cached && cacheTime && (Date.now() - cacheTime < cacheTTL)){
// Используем кэш
renderFriends(JSON.parse(cached));
// Параллельно тихая проверка на новые друзья
fetchFriends(false, true);
} else {
// Кэш устарел или нет
fetchFriends(true, false);
}
});
</script>

<script type="text/javascript">
if (typeof friends === 'undefined') window.friends = {}; // не перезаписываем, если уже есть

// Заполняем данные пользователя
friends.ucodes = {
homepage: '$HOME_PAGE_LINK$',
userid: '$USER_ID$',
username: '$USERNAME$',
_userid: '$_USER_ID$',
_username: '$_USERNAME$',
own: '$_IS_OWN_PROFILE$',
avatar: '<?if($_AVATAR$)?><?substr(substr($_AVATAR$, strpos($_AVATAR$, "src=\"")+5),0,strpos(substr($_AVATAR$, strpos($_AVATAR$, "src=\"")+5), "\""))?><?else?>/.s/src/profile/img/profile_photo_thumbnail.png<?endif?>',
_profurl: '$_PROFILE_URL$',
isuser: '$USER_LOGGED_IN$',
copyright: 'ucodes.ru'
};
</script>

<script>
if (typeof friends === 'undefined') window.friends = {};
(function($, friends){

friends.nowpage = 1;
friends.maxPage = false;

friends.fix = function() {
if (window._uWnd && _uWnd.getbyname('fr')) {
_uWnd.close('fr');
friends.nowpage = 1;
friends.maxPage = false;
setTimeout(friends.loadFr, 500);
} else friends.loadFr();
};

friends.loadFr = function(upd){
$("body").css("cursor", "wait");
var _upd = !!upd;
var targetId = (friends.ucodes && (friends.ucodes._userid || friends.ucodes.userid)) || '';
var url = '/blog/0-0-' + friends.nowpage + '-0-17-' + targetId + '?' + Math.random();

$.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] : '';
}

// собираем
all.push([ava, nick, groups, profileUrl, /*legacy action html*/ '', del]);
});

friends.open(all, _upd);

}).fail(function(){ console.error("Ошибка загрузки друзей."); })
.always(function(){ $("body").css("cursor", "default"); });
};

friends.table = function(arr){
if(!arr.length) return '<div class="no-friends">Друзей нет</div>';
var html = '';
$.each(arr, function(i, item){
// item = [ava, nick, groups, profileUrl, actionHtml, del]
var avaUrl = item[0] || '';
var nick = escapeHtml(item[1] || 'Без имени');
var profile = item[3] || '#';
var groupsHtml = '';
if (item[2] && item[2].length) {
groupsHtml = item[2].map(function(cat){
return '<a class="friend-group-friends" href="'+ profile +'" target="_blank">'+ escapeHtml(cat.trim()) +'</a>';
}).join(' ');
}

// крестик — показываем только если есть ссылка на MODER_PANEL и юзер владелец
var delBtnHtml = '';
var hasDel = item[5] && item[5].length;
if (hasDel && friends.ucodes && friends.ucodes.own == 1) {
delBtnHtml = '<button class="friend-delete-btn-friends" data-del="'+ encodeURIComponent(item[5]) +'" title="Удалить"></button>';
}

html += `
<div class="friend-card-friends">
<div class="friend-avatar-friends" style="background-image:url('${avaUrl}'); cursor:pointer;" data-profile="${profile}"></div>
<div class="friend-info-friends">
<div class="friend-nick-friends"><a class="friend-profile-link" href="${profile}" target="_blank" rel="noopener">${nick}</a></div>
${groupsHtml}
</div>
${delBtnHtml}
</div>`;
});
return html;
};

friends.open = function(frnds, isUpdate){
var cards = friends.table(frnds);
var moreHtml = (friends.maxPage && friends.nowpage < friends.maxPage)
? '<div class="moreFr" style="text-align:right;"><a href="javascript:void(0)" onclick="friends.more();">Остальные друзья</a></div>' : '';

if(isUpdate){
if(!$('#frr').length) $('#fr').after('<div id="frr"></div>');
$('#frr').append(cards + moreHtml);
} else {
var contentHtml = '<div id="frr">' + cards + moreHtml + '</div>';
if(window._uWnd){
new _uWnd('fr', 'Друзья '+(friends.ucodes && friends.ucodes._username ? friends.ucodes._username : ''), 500, 800, {
minw:500, maxw:500, maxh:800,
onbeforeclose: function(){ friends.nowpage=1; friends.maxPage=false; }
}, contentHtml);
} else {
if(!$('#fr').length) $('body').append('<div id="fr" style="margin-top:10px;"></div>');
$('#fr').html(contentHtml);
}
}
};

friends.more = function(){
friends.nowpage++;
$(".moreFr").remove();
friends.loadFr(true);
};

// клик по аватару — открываем профиль
$(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;
}

// Убираем карточку визуально
$btn.closest('.friend-card-friends').fadeOut(220, function(){ $(this).remove(); });

// Отправляем запрос
$.get(delUrl)
.done(function(){ console.log('Удаление отправлено: ' + delUrl); })
.fail(function(){ alert('Ошибка при удалении'); });
});

// Вспомогательная
function escapeHtml(str){
return String(str || '').replace(/[&<>"'`=\/]/g, function(s){ return ({'&':'&','<':'<','>':'>','"':'"',"'":''',"/":'/','`':'`','=':'='})[s]; });
}

$(document).on("click", ".openFriends", function(){ friends.fix(); });

})(jQuery, friends);
</script>

<div class="udtb">

<!-- Контейнер для обеих кнопок -->
<div class="buttons-row">
<!-- Левая кнопка -->
<div id="addFriendContainer"></div>

<!-- Правая кнопка -->
<a href="#" id="lookfr" class="btn-look" onclick="friends.fix();return false;">Посмотреть друзей</a>
</div>
</div>

<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>'
);

});
</script>

<script type="text/javascript" src="https://bro.usite.pro/js/friends.03.js"></script>


Видео



Пока у меня не было возможности полноценно протестировать скрипт например, на повторные клики, защиту от дублирующего добавления в друзья и другие ситуации, которые могут проявиться со временем. Проще говоря, я пока не могу точно сказать, насколько он надёжен и завершён.

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

В целом, чем выше уровень продуманности функционала, тем более качественным и привлекательным будет выглядеть проект. Хотя, конечно, есть ограничения самой платформы uCoz , там особо не развернёшься.

Но я стараюсь находить нестандартные решения и добавлять интересные фишки.

Появилась ещё одна идея, довольно интересная, но при этом сложная в реализации. Насколько я знаю, многие пытались сделать нечто подобное на uCoz, но ни у кого не получилось. Посмотрим, может, я смогу что-то изменить.

Это предпоследняя версия другого скрипта, который просто добавляет в друзья без каких-либо проверок простой, но рабочий.

Мурчанн

Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
Дата: Вторник, 26.05.2026, 01:16 | Сообщение # 2 | | Написал: Известный
Автор темы
Мурчанн не в сети
        Сообщений:288
         Регистрация:20.10.2016
За уважение окружающих За уважение окружающих За хорошее поведение За преданность форуму За любовь народа

Исходный код слишком длинный, система его не пропускает из-за ограничений.

Просто кликните по ссылке и он откроется.

Ссылка на скрипт

Мурчанн

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