Дата: Понедельник, 06.04.2026, 21:30 | Сообщение # 1 |
|
Написал: Узнаваемый
Автор темы
Мурчанн
не в сети
Сообщений: 232
В процессе работы я получил больше опыта и знаний, что позволило мне улучшить реализацию модуля. Воспользовавшись моментом, я полностью переработал модуль подарков и восстановил корректное отображение онлайн-статуса. Была переписана логика скрипта она стала проще, чище и быстрее. Теперь скрипт загружает только 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); })();
Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.