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

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

  • Страница 1 из 1
  • 1
Модуль ВК «Подарки» для Ucoz v 15.2 продвинутая версия
Дата: Понедельник, 06.04.2026, 21:30 | Сообщение # 1 | | Написал: Узнаваемый
Автор темы
Мурчанн не в сети
        Сообщений:232
         Регистрация:20.10.2016

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



Была переписана логика скрипта она стала проще, чище и быстрее. Теперь скрипт загружает только 4 подарка по умолчанию, а для остальных реализована отдельная кнопка «Загрузить подарки». Это решение позволило обеспечить мгновенную загрузку основной части контента, а дополнительные элементы подгружаются по запросу, скрытым способом.

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

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

Остаётся лишь довести логику до более совершенного и быстрого состояния, после чего на этом этапе можно будет остановиться.



Код
<!-- ======= Блок подарков ======= -->

<div class="gifts-block">
<div class="gifts-header">Подарки</div>
<div class="gifts-footer" id="gifts-count">Загрузка…</div>
<div class="gifts-container" id="gifts-container"></div>
</div>

<link rel="stylesheet" href="https://bro.usite.pro/css/parser-gifts2.css" media="all">

<script>
window.GIFTS_CONFIG = {
userId: $USER_ID$,
container: "gifts-container",
counter: "gifts-count"
};
</script>

<div id="uc-online-list" style="display:none;">
$ONLINE_USERS_LIST$
</div>

<script src="https://bro.usite.pro/js/parser-gifts2.js"></script>


Этот вариант без кнопки подгрузить

Код
(async function () {
'use strict';

const CONFIG = window.GIFTS_CONFIG || {};

const container = document.getElementById(CONFIG.container || 'gifts-container');
const counter = document.getElementById(CONFIG.counter || 'gifts-count');
const userId = CONFIG.userId || 0;

if (!container || !counter || !userId) return;

const STORAGE_KEY = `giftsData_${userId}`;

let allGifts = [];
let cachedCount = -1;

const onlineListText = (document.getElementById('uc-online-list')?.textContent || '').toLowerCase();

/* ----------------------------- */
//  Проверка онлайна
function isUserOnline(userId){
  const container = document.getElementById('uc-online-list');
  if(!container) return false;

  const links = container.querySelectorAll('a');

  for(const link of links){
    if(link.href.includes('uid=' + userId)){
      return true;
    }
  }

  return false;
}
  

/* ----------------------------- */
async function getGiftCount() {
try {

const res = await fetch(`/index/54-${userId}-`);
const text = await res.text();

const xml = new DOMParser().parseFromString(text,'application/xml');
const cmd = xml.querySelector('cmd[p="content"]');

if (!cmd) return 0;

const temp = document.createElement('div');
temp.innerHTML = cmd.textContent;

let total = 0;

temp.querySelectorAll('td[onclick*="_uWnd.reload"]').forEach(td=>{

const b = td.querySelector('b');
total += b ? (+b.textContent.trim() || 1) : 1;

});

return total;

}catch(e){

console.error(e);
return -1;

}
}

/* ----------------------------- */
async function fullRefresh(){

try{

const res = await fetch(`/index/54-${userId}-`);
const text = await res.text();

const xml = new DOMParser().parseFromString(text,'application/xml');
const cmd = xml.querySelector('cmd[p="content"]');

if(!cmd) return;

const temp = document.createElement('div');
temp.innerHTML = cmd.textContent;

const tds = [...temp.querySelectorAll('td[onclick*="_uWnd.reload"]')];

let total = 0;
const newGifts = [];

for(const td of tds){

const img = td.querySelector('img');

if(!img) continue;

const count = td.querySelector('b')
? +td.querySelector('b').textContent.trim() || 1
: 1;

const onclick = td.getAttribute('onclick');

total += count;

for(let i=0;i<count;i++){

newGifts.push({

img: img.src,
onclick,
nick:'Загрузка...',
avatar:'/.s/src/profile/img/profile_photo_thumbnail.png',
date:'',
comment:'',
profile:'#',
recipientId:null

});

}

}

cachedCount = total;
allGifts = newGifts;

/* обогащаем первые 30 (быстрее чем 40) */

for(let i=0;i<Math.min(allGifts.length,30);i++){

allGifts[i] = await enrichGift(allGifts[i]);

if(i%5===4)
await new Promise(r=>setTimeout(r,200));

}

allGifts.sort((a,b)=> new Date(b.date||0)-new Date(a.date||0));

localStorage.setItem(STORAGE_KEY,JSON.stringify({

count:cachedCount,
gifts:allGifts

}));

renderCounter();
renderPreview();
updateShowAllButton();

}catch(e){

console.error(e);
counter.textContent='Ошибка';

}

}

/* ----------------------------- */
async function enrichGift(g){

try{

const m = g.onclick.match(/url:'([^']+)'/);

if(!m) return g;

const page = await fetch(m[1]).then(r=>r.text());
const doc = new DOMParser().parseFromString(page,'text/html');

const legend = doc.querySelector('legend a');

if(legend){

g.nick = legend.textContent.trim();
g.profile = legend.href;

}

g.comment = doc.querySelector('[id^="mtx"]')?.textContent.trim() || '';
g.date = doc.querySelector('div[style*="text-align:right"], .date')?.textContent.trim() || '';

if(g.profile && g.profile!=='#'){

const prof = await fetch(g.profile).then(r=>r.text());
const pdoc = new DOMParser().parseFromString(prof,'text/html');

const photo = pdoc.querySelector('.profile-photo');

if(photo?.style.backgroundImage){

g.avatar = photo.style.backgroundImage.replace(/^url\(["']?|["']?\)$/g,'');

}

const idMatch =
g.profile.match(/-(\d+)(?:-|$)/) ||
g.profile.match(/\/(\d+)$/);

if (idMatch) {
g.recipientId = idMatch[1];
}

}

return g;

}catch(e){

return g;

}

}

/* ----------------------------- */

function renderCounter(){

const word =
cachedCount === 1 ? 'подарок'
: cachedCount < 5 ? 'подарка'
: 'подарков';

counter.textContent = `${cachedCount} ${word}`;

}

/* ----------------------------- */

function renderPreview(){
    container.innerHTML='';

    if(allGifts.length === 0){
        const emptyDiv = document.createElement('div');
        emptyDiv.className = 'gifts-empty';
        emptyDiv.innerHTML = `
            <p>Похоже, у вас пока нет подарков. 🎁</p>
            <p>Когда друзья вручат вам подарки, они появятся здесь. Следите за новыми сюрпризами!</p>
        `;
        emptyDiv.style.textAlign = 'center';
        emptyDiv.style.padding = '10px';
        emptyDiv.style.color = '#555';
        emptyDiv.style.fontStyle = 'italic';
        emptyDiv.style.background = '#f9f9f9';
        emptyDiv.style.borderRadius = '8px';
        container.appendChild(emptyDiv);
        return;
    }

    allGifts.slice(0,3).forEach(g=>{
        const div = document.createElement('div');
        div.className='gift-card';
        div.title=g.nick;
        div.innerHTML=`<img src="${g.img}" alt="">`;
        container.appendChild(div);
    });
}

/* ----------------------------- */

function updateShowAllButton(){

document.querySelectorAll('.show-all-btn').forEach(b=>b.remove());

if(allGifts.length>3){

const btn=document.createElement('button');

btn.className='show-all-btn';
btn.textContent='Все подарки';

btn.onclick=showPopup;

container.appendChild(btn);

}

}

/* ----------------------------- */

function showPopup(){

if(!allGifts?.length){
    alert('Нет подарков');
    return;
}

/* ============================= */
/* 🟢 ОНЛАЙН СПИСОК uCoz */
const onlineRaw = document.getElementById('uc-online-list')?.innerHTML || '';

function isOnline(userId){
    if(!userId) return false;
    const id = String(userId);

    // uCoz формат иногда: -123 или /123
    return onlineRaw.includes(`-${id}`) || onlineRaw.includes(`/${id}`);
}
/* ============================= */

const overlay=document.createElement('div');
overlay.className='gifts-popup-overlay';

const popup=document.createElement('div');
popup.className='gifts-popup';

popup.innerHTML=`
<div class="gifts-popup-header">
  <strong>🎁 Мои подарки</strong>
  <small>${allGifts.length}</small>
  <span>×</span>
</div>
<div class="gifts-popup-list"></div>
`;

overlay.appendChild(popup);
document.body.appendChild(overlay);

// закрытие
popup.querySelector('span').onclick=()=>overlay.remove();
overlay.addEventListener('click',e=>{
    if(e.target===overlay) overlay.remove();
});

const list=popup.querySelector('.gifts-popup-list');

allGifts.forEach(gift=>{

    const nick = gift.nick || 'Пользователь';
    const avatar = gift.avatar || '/.s/src/profile/img/profile_photo_thumbnail.png';
    const profile = gift.profile || '#';

    const isUserOnline = isOnline(gift.recipientId);

    const row=document.createElement('div');
    row.className='vk-gift';

    row.innerHTML=`
<div class="vk-user">
    <div class="avatar-wrap">
        <img src="${avatar}" alt="">
        <span class="giftsOnlineDot ${isUserOnline ? 'giftsOnlineDot--on' : 'giftsOnlineDot--off'}"></span>
    </div>

    <div>
        <div class="name">
            <a href="${profile}" target="_blank">${nick}</a>
        </div>
        <div class="date">${gift.date || ''}</div>
        ${gift.comment ? `<div class="vk-comment">${gift.comment}</div>`:''}
    </div>
</div>

<div class="vk-gift-img">
    <img src="${gift.img}">
</div>

<div class="vk-reply"></div>
`;

    const replyBlock = row.querySelector('.vk-reply');

    //  кнопка "вручить подарок"
    if(gift.recipientId && String(gift.recipientId)!==String(userId)){
        const giftBtn=document.createElement('a');
        giftBtn.href='javascript:;';
        giftBtn.textContent='🎁 Вручить подарок';

        giftBtn.onclick=()=>{
            new _uWnd(
                'AwD',
                'Вручить награду',
                380,
                200,
                {maxh:300,minh:100,closeonesc:1},
                {url:'/index/55-'+gift.recipientId}
            );
        };

        replyBlock.appendChild(giftBtn);
    }

    list.appendChild(row);
});

}

/* ----------------------------- */

counter.onclick = showPopup;
counter.style.cursor='pointer';

/* мгновенный кэш */

const saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');

if(saved.gifts){

allGifts = saved.gifts;
cachedCount = saved.count;

renderCounter();
renderPreview();
updateShowAllButton();

}

/* фоновая проверка */

(async ()=>{

const liveCount = await getGiftCount();

if(liveCount<0) return;

if(cachedCount!==-1 && liveCount===cachedCount)
return;

await fullRefresh();

})();

/* ----------------------------- */
//  запуск статуса при загрузке
renderOnlineStatus();

/* ----------------------------- */
//  автообновление онлайна (раз в 30 сек)
setInterval(()=>{
  renderOnlineStatus();
},30000);

})();


Мурчанн

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