Spaces:
Running
Running
Update static/script.js
Browse files- static/script.js +65 -11
static/script.js
CHANGED
|
@@ -539,6 +539,12 @@
|
|
| 539 |
}
|
| 540 |
}, 20000);
|
| 541 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 542 |
function wsOpen() {
|
| 543 |
return State.ws && State.ws.readyState === WebSocket.OPEN;
|
| 544 |
}
|
|
@@ -770,8 +776,8 @@
|
|
| 770 |
DOM.convAvatarPh.className = 'conv-avatar-ph';
|
| 771 |
DOM.convAvatarPh.innerHTML = '<i class="fas fa-globe"></i>';
|
| 772 |
DOM.convPresenceDot.classList.add('hidden');
|
| 773 |
-
const meCount =
|
| 774 |
-
DOM.convSubtitle.innerHTML = `<span class="status-dot online"></span> ${
|
| 775 |
DOM.onlineBtn.style.display = '';
|
| 776 |
}
|
| 777 |
}
|
|
@@ -818,7 +824,10 @@
|
|
| 818 |
document.addEventListener('visibilitychange', () => {
|
| 819 |
if (document.visibilityState === 'visible') {
|
| 820 |
markActiveRead(true);
|
|
|
|
|
|
|
| 821 |
if (State.activeConvId) renderConversationHeader(State.activeConvId);
|
|
|
|
| 822 |
} else {
|
| 823 |
updateTitleUnread();
|
| 824 |
}
|
|
@@ -909,6 +918,8 @@
|
|
| 909 |
(msg.online_users || []).forEach(u => State.onlineUsers.set(u.id, u));
|
| 910 |
updateSidebarMe();
|
| 911 |
updateOnlineBadge();
|
|
|
|
|
|
|
| 912 |
|
| 913 |
// fresh session: adopt server conversation list, drop old caches
|
| 914 |
State.conversations.clear();
|
|
@@ -1026,16 +1037,19 @@
|
|
| 1026 |
}
|
| 1027 |
|
| 1028 |
case 'user_status': {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1029 |
if (msg.status === 'online') {
|
| 1030 |
-
State.onlineUsers.set(msg.user_id,
|
| 1031 |
-
|
| 1032 |
-
display_name: msg.display_name, avatar_path: msg.avatar_path
|
| 1033 |
-
});
|
| 1034 |
} else {
|
| 1035 |
State.onlineUsers.delete(msg.user_id);
|
| 1036 |
}
|
| 1037 |
updateOnlineBadge();
|
| 1038 |
updatePeerPresence(msg.user_id, msg.status === 'online');
|
|
|
|
| 1039 |
if (State.activeConvId) renderConversationHeader(State.activeConvId);
|
| 1040 |
break;
|
| 1041 |
}
|
|
@@ -1049,6 +1063,28 @@
|
|
| 1049 |
break;
|
| 1050 |
}
|
| 1051 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1052 |
case 'message_edited': {
|
| 1053 |
const mid = msg.message_id;
|
| 1054 |
if (State.messages.has(mid)) {
|
|
@@ -1128,6 +1164,17 @@
|
|
| 1128 |
if (ts) ts.delete(mid);
|
| 1129 |
}
|
| 1130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1131 |
function updatePeerPresence(userId, online) {
|
| 1132 |
let changed = false;
|
| 1133 |
State.conversations.forEach(c => {
|
|
@@ -2252,14 +2299,21 @@
|
|
| 2252 |
if (wsOpen()) wsSend({ type: 'get_online_users' });
|
| 2253 |
}
|
| 2254 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2255 |
function updateOnlineBadge() {
|
| 2256 |
-
|
| 2257 |
-
DOM.onlineBadge.
|
|
|
|
| 2258 |
}
|
| 2259 |
|
| 2260 |
function renderOnlineUsers() {
|
| 2261 |
DOM.onlineUsersList.innerHTML = '';
|
| 2262 |
-
|
|
|
|
| 2263 |
DOM.onlineUsersList.innerHTML = '<div class="loading-state"><span>No users online</span></div>';
|
| 2264 |
DOM.onlineTotal.textContent = '0 users online';
|
| 2265 |
return;
|
|
@@ -2279,7 +2333,7 @@
|
|
| 2279 |
</div>`;
|
| 2280 |
DOM.onlineUsersList.appendChild(div);
|
| 2281 |
});
|
| 2282 |
-
DOM.onlineTotal.textContent = `${
|
| 2283 |
}
|
| 2284 |
|
| 2285 |
// ============================================================
|
|
@@ -2601,4 +2655,4 @@
|
|
| 2601 |
// Go
|
| 2602 |
// ============================================================
|
| 2603 |
init();
|
| 2604 |
-
})();
|
|
|
|
| 539 |
}
|
| 540 |
}, 20000);
|
| 541 |
|
| 542 |
+
// periodic presence refresh so a missed status event can't leave the
|
| 543 |
+
// online list/badge stale (e.g. after a background tab is throttled)
|
| 544 |
+
setInterval(() => {
|
| 545 |
+
if (wsOpen()) wsSend({ type: 'get_online_users' });
|
| 546 |
+
}, 60000);
|
| 547 |
+
|
| 548 |
function wsOpen() {
|
| 549 |
return State.ws && State.ws.readyState === WebSocket.OPEN;
|
| 550 |
}
|
|
|
|
| 776 |
DOM.convAvatarPh.className = 'conv-avatar-ph';
|
| 777 |
DOM.convAvatarPh.innerHTML = '<i class="fas fa-globe"></i>';
|
| 778 |
DOM.convPresenceDot.classList.add('hidden');
|
| 779 |
+
const meCount = onlineCountExcludingSelf();
|
| 780 |
+
DOM.convSubtitle.innerHTML = `<span class="status-dot online"></span> ${meCount} online`;
|
| 781 |
DOM.onlineBtn.style.display = '';
|
| 782 |
}
|
| 783 |
}
|
|
|
|
| 824 |
document.addEventListener('visibilitychange', () => {
|
| 825 |
if (document.visibilityState === 'visible') {
|
| 826 |
markActiveRead(true);
|
| 827 |
+
updateAllPeerPresence();
|
| 828 |
+
requestOnlineUsers();
|
| 829 |
if (State.activeConvId) renderConversationHeader(State.activeConvId);
|
| 830 |
+
if (!DOM.onlineModal.classList.contains('hidden')) renderOnlineUsers();
|
| 831 |
} else {
|
| 832 |
updateTitleUnread();
|
| 833 |
}
|
|
|
|
| 918 |
(msg.online_users || []).forEach(u => State.onlineUsers.set(u.id, u));
|
| 919 |
updateSidebarMe();
|
| 920 |
updateOnlineBadge();
|
| 921 |
+
updateAllPeerPresence();
|
| 922 |
+
if (!DOM.onlineModal.classList.contains('hidden')) renderOnlineUsers();
|
| 923 |
|
| 924 |
// fresh session: adopt server conversation list, drop old caches
|
| 925 |
State.conversations.clear();
|
|
|
|
| 1037 |
}
|
| 1038 |
|
| 1039 |
case 'user_status': {
|
| 1040 |
+
const updated = {
|
| 1041 |
+
id: msg.user_id, username: msg.username,
|
| 1042 |
+
display_name: msg.display_name, avatar_path: msg.avatar_path
|
| 1043 |
+
};
|
| 1044 |
if (msg.status === 'online') {
|
| 1045 |
+
State.onlineUsers.set(msg.user_id, updated);
|
| 1046 |
+
applyUserProfileToConversations(updated);
|
|
|
|
|
|
|
| 1047 |
} else {
|
| 1048 |
State.onlineUsers.delete(msg.user_id);
|
| 1049 |
}
|
| 1050 |
updateOnlineBadge();
|
| 1051 |
updatePeerPresence(msg.user_id, msg.status === 'online');
|
| 1052 |
+
renderSidebar();
|
| 1053 |
if (State.activeConvId) renderConversationHeader(State.activeConvId);
|
| 1054 |
break;
|
| 1055 |
}
|
|
|
|
| 1063 |
break;
|
| 1064 |
}
|
| 1065 |
|
| 1066 |
+
case 'profile_updated': {
|
| 1067 |
+
const updated = {
|
| 1068 |
+
id: msg.user_id,
|
| 1069 |
+
username: msg.username,
|
| 1070 |
+
display_name: msg.display_name,
|
| 1071 |
+
avatar_path: msg.avatar_path,
|
| 1072 |
+
};
|
| 1073 |
+
if (updated.id === State.user?.id) {
|
| 1074 |
+
State.user.display_name = updated.display_name;
|
| 1075 |
+
State.user.avatar_path = updated.avatar_path;
|
| 1076 |
+
updateSidebarMe();
|
| 1077 |
+
}
|
| 1078 |
+
State.onlineUsers.set(updated.id, updated);
|
| 1079 |
+
updateOnlineBadge();
|
| 1080 |
+
applyUserProfileToConversations(updated);
|
| 1081 |
+
updateAllPeerPresence();
|
| 1082 |
+
renderSidebar();
|
| 1083 |
+
if (State.activeConvId) renderConversationHeader(State.activeConvId);
|
| 1084 |
+
if (!DOM.onlineModal.classList.contains('hidden')) renderOnlineUsers();
|
| 1085 |
+
break;
|
| 1086 |
+
}
|
| 1087 |
+
|
| 1088 |
case 'message_edited': {
|
| 1089 |
const mid = msg.message_id;
|
| 1090 |
if (State.messages.has(mid)) {
|
|
|
|
| 1164 |
if (ts) ts.delete(mid);
|
| 1165 |
}
|
| 1166 |
|
| 1167 |
+
function applyUserProfileToConversations(user) {
|
| 1168 |
+
if (!user || !user.id) return;
|
| 1169 |
+
State.conversations.forEach(c => {
|
| 1170 |
+
if (c.type === 'dm' && c.peer && c.peer.id === user.id) {
|
| 1171 |
+
if (user.username) c.peer.username = user.username;
|
| 1172 |
+
if (user.display_name) c.peer.display_name = user.display_name;
|
| 1173 |
+
if ('avatar_path' in user) c.peer.avatar_path = user.avatar_path;
|
| 1174 |
+
}
|
| 1175 |
+
});
|
| 1176 |
+
}
|
| 1177 |
+
|
| 1178 |
function updatePeerPresence(userId, online) {
|
| 1179 |
let changed = false;
|
| 1180 |
State.conversations.forEach(c => {
|
|
|
|
| 2299 |
if (wsOpen()) wsSend({ type: 'get_online_users' });
|
| 2300 |
}
|
| 2301 |
|
| 2302 |
+
function onlineCountExcludingSelf() {
|
| 2303 |
+
const hasSelf = State.onlineUsers.has(State.user?.id);
|
| 2304 |
+
return hasSelf ? Math.max(0, State.onlineUsers.size - 1) : State.onlineUsers.size;
|
| 2305 |
+
}
|
| 2306 |
+
|
| 2307 |
function updateOnlineBadge() {
|
| 2308 |
+
const count = onlineCountExcludingSelf();
|
| 2309 |
+
DOM.onlineBadge.textContent = count;
|
| 2310 |
+
DOM.onlineBadge.classList.toggle('hidden', count === 0);
|
| 2311 |
}
|
| 2312 |
|
| 2313 |
function renderOnlineUsers() {
|
| 2314 |
DOM.onlineUsersList.innerHTML = '';
|
| 2315 |
+
const count = onlineCountExcludingSelf();
|
| 2316 |
+
if (count === 0) {
|
| 2317 |
DOM.onlineUsersList.innerHTML = '<div class="loading-state"><span>No users online</span></div>';
|
| 2318 |
DOM.onlineTotal.textContent = '0 users online';
|
| 2319 |
return;
|
|
|
|
| 2333 |
</div>`;
|
| 2334 |
DOM.onlineUsersList.appendChild(div);
|
| 2335 |
});
|
| 2336 |
+
DOM.onlineTotal.textContent = `${count} user${count === 1 ? '' : 's'} online`;
|
| 2337 |
}
|
| 2338 |
|
| 2339 |
// ============================================================
|
|
|
|
| 2655 |
// Go
|
| 2656 |
// ============================================================
|
| 2657 |
init();
|
| 2658 |
+
})();
|