hotfix jointlist
This commit is contained in:
@@ -315,6 +315,53 @@
|
||||
letter-spacing: .08em;
|
||||
}
|
||||
|
||||
|
||||
.app-ws-status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: .38rem;
|
||||
min-height: 2rem;
|
||||
padding: .34rem .58rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(255,255,255,.10);
|
||||
background: rgba(255,255,255,.05);
|
||||
color: var(--app-text-muted);
|
||||
font-size: .7rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: .05em;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.app-ws-status__dot {
|
||||
width: .58rem;
|
||||
height: .58rem;
|
||||
flex: 0 0 .58rem;
|
||||
border-radius: 50%;
|
||||
background: #f5b942;
|
||||
box-shadow: 0 0 0 .18rem rgba(245,185,66,.13);
|
||||
transition: background-color .15s ease, box-shadow .15s ease;
|
||||
}
|
||||
|
||||
.app-ws-status[data-state="connected"] .app-ws-status__dot {
|
||||
background: #27d17f;
|
||||
box-shadow: 0 0 0 .18rem rgba(39,209,127,.14);
|
||||
}
|
||||
|
||||
.app-ws-status[data-state="connecting"] .app-ws-status__dot,
|
||||
.app-ws-status[data-state="syncing"] .app-ws-status__dot,
|
||||
.app-ws-status[data-state="reconnecting"] .app-ws-status__dot {
|
||||
background: #f5b942;
|
||||
box-shadow: 0 0 0 .18rem rgba(245,185,66,.13);
|
||||
}
|
||||
|
||||
.app-ws-status[data-state="offline"] .app-ws-status__dot,
|
||||
.app-ws-status[data-state="error"] .app-ws-status__dot {
|
||||
background: #ef6461;
|
||||
box-shadow: 0 0 0 .18rem rgba(239,100,97,.14);
|
||||
}
|
||||
|
||||
.app-navbar-toggler {
|
||||
border-color: rgba(255,255,255,.28);
|
||||
padding: .3rem .55rem;
|
||||
|
||||
@@ -64,6 +64,25 @@
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.app-ws-status--mobile {
|
||||
width: 2.15rem;
|
||||
min-width: 2.15rem;
|
||||
height: 2.15rem;
|
||||
min-height: 2.15rem;
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.app-ws-status--mobile .app-ws-status__label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.app-ws-status--mobile .app-ws-status__dot {
|
||||
width: .68rem;
|
||||
height: .68rem;
|
||||
flex-basis: .68rem;
|
||||
}
|
||||
|
||||
.app-mobile-menu {
|
||||
grid-column: 3;
|
||||
justify-self: end;
|
||||
@@ -919,3 +938,18 @@
|
||||
padding: .85rem .9rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.endpoint-view_list .app-navbar__meta--mobile,
|
||||
.endpoint-shared_list .app-navbar__meta--mobile {
|
||||
max-width: min(50vw, 14rem);
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.endpoint-view_list .app-navbar__meta--mobile,
|
||||
.endpoint-shared_list .app-navbar__meta--mobile {
|
||||
max-width: min(46vw, 10rem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
const socket = io({
|
||||
reconnection: true,
|
||||
reconnectionAttempts: Infinity,
|
||||
reconnectionDelay: 500,
|
||||
reconnectionDelayMax: 5000,
|
||||
timeout: 8000
|
||||
reconnectionDelay: 350,
|
||||
reconnectionDelayMax: 2000,
|
||||
randomizationFactor: 0.2,
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
/*──────────────── placeholder pustej listy ────────────────*/
|
||||
@@ -38,6 +39,9 @@ function setupList(listId, username) {
|
||||
if (typeof window.ensureCurrentListJoined === 'function') {
|
||||
window.ensureCurrentListJoined();
|
||||
}
|
||||
if (typeof window.refreshListSocketStatus === 'function') {
|
||||
window.refreshListSocketStatus();
|
||||
}
|
||||
|
||||
const newItemInput = document.getElementById('newItem');
|
||||
|
||||
|
||||
@@ -14,17 +14,74 @@ let currentRoomUsers = [];
|
||||
// wbudowanemu mechanizmowi Socket.IO zestawić nowe połączenie. Nie wywołujemy
|
||||
// socket.disconnect(), bo jest to ręczne rozłączenie i może wejść w konflikt
|
||||
// z automatycznym reconnectem.
|
||||
const WAKE_CHECK_DEBOUNCE_MS = 250;
|
||||
const WAKE_ACK_TIMEOUT_MS = 4000;
|
||||
const WAKE_WATCHDOG_INTERVAL_MS = 5000;
|
||||
const WAKE_WATCHDOG_GAP_MS = 15000;
|
||||
const WAKE_RETRY_CONNECT_MS = 1200;
|
||||
const WAKE_CHECK_DEBOUNCE_MS = 80;
|
||||
const WAKE_ACK_TIMEOUT_MS = 1800;
|
||||
const WAKE_WATCHDOG_INTERVAL_MS = 3000;
|
||||
const WAKE_WATCHDOG_GAP_MS = 9000;
|
||||
const WAKE_RETRY_CONNECT_MS = 500;
|
||||
|
||||
let wakeCheckTimer = null;
|
||||
let wakeCheckInProgress = false;
|
||||
let reconnectFallbackTimer = null;
|
||||
let lastWatchdogTick = Date.now();
|
||||
|
||||
|
||||
const LIST_SOCKET_STATUS_LABELS = {
|
||||
connected: 'WebSocket: połączono i zsynchronizowano',
|
||||
connecting: 'WebSocket: łączenie',
|
||||
syncing: 'WebSocket: synchronizacja listy',
|
||||
reconnecting: 'WebSocket: ponowne łączenie',
|
||||
offline: 'WebSocket: brak połączenia z internetem',
|
||||
error: 'WebSocket: błąd połączenia'
|
||||
};
|
||||
|
||||
let listSocketStatus = 'connecting';
|
||||
|
||||
function setListSocketStatus(state, detail = '') {
|
||||
listSocketStatus = state;
|
||||
const baseLabel = LIST_SOCKET_STATUS_LABELS[state] || LIST_SOCKET_STATUS_LABELS.connecting;
|
||||
const label = detail ? `${baseLabel} (${detail})` : baseLabel;
|
||||
|
||||
document.querySelectorAll('[data-ws-status]').forEach(el => {
|
||||
el.dataset.state = state;
|
||||
el.setAttribute('title', label);
|
||||
el.setAttribute('aria-label', label);
|
||||
});
|
||||
}
|
||||
|
||||
function currentSocketTransportName() {
|
||||
try {
|
||||
return socket.io && socket.io.engine && socket.io.engine.transport
|
||||
? socket.io.engine.transport.name
|
||||
: '';
|
||||
} catch (_) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function refreshListSocketStatus() {
|
||||
if (!hasActiveListRoom()) return;
|
||||
|
||||
if (typeof navigator !== 'undefined' && navigator.onLine === false) {
|
||||
setListSocketStatus('offline');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!socket.connected) {
|
||||
setListSocketStatus('reconnecting');
|
||||
return;
|
||||
}
|
||||
|
||||
if (joinedSocketId === socket.id && joinedRoomId === String(window.LIST_ID) && didReceiveFirstFullList) {
|
||||
setListSocketStatus('connected', currentSocketTransportName());
|
||||
return;
|
||||
}
|
||||
|
||||
setListSocketStatus('syncing');
|
||||
}
|
||||
|
||||
window.refreshListSocketStatus = refreshListSocketStatus;
|
||||
|
||||
function hasActiveListRoom() {
|
||||
return Boolean(window.LIST_ID && window.usernameForReconnect);
|
||||
}
|
||||
@@ -56,6 +113,7 @@ function ensureCurrentListJoined() {
|
||||
|
||||
joinedSocketId = socketId;
|
||||
joinedRoomId = roomId;
|
||||
setListSocketStatus('syncing');
|
||||
|
||||
socket.emit('join_list', {
|
||||
room: window.LIST_ID,
|
||||
@@ -77,6 +135,7 @@ function forceCloseStaleTransport() {
|
||||
wakeCheckInProgress = false;
|
||||
joinedSocketId = null;
|
||||
joinedRoomId = null;
|
||||
setListSocketStatus('reconnecting');
|
||||
|
||||
if (window.LIST_ID) disableCheckboxes(true);
|
||||
|
||||
@@ -106,9 +165,14 @@ function forceCloseStaleTransport() {
|
||||
|
||||
function runWakeCheck() {
|
||||
if (document.hidden || !hasActiveListRoom()) return;
|
||||
if (typeof navigator !== 'undefined' && navigator.onLine === false) return;
|
||||
if (typeof navigator !== 'undefined' && navigator.onLine === false) {
|
||||
setListSocketStatus('offline');
|
||||
disableCheckboxes(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!socket.connected) {
|
||||
setListSocketStatus('reconnecting');
|
||||
disableCheckboxes(true);
|
||||
socket.connect();
|
||||
return;
|
||||
@@ -122,6 +186,7 @@ function runWakeCheck() {
|
||||
|
||||
if (wakeCheckInProgress) return;
|
||||
wakeCheckInProgress = true;
|
||||
setListSocketStatus('syncing');
|
||||
|
||||
// request_full_list pełni jednocześnie rolę health-checka i synchronizacji.
|
||||
socket.timeout(WAKE_ACK_TIMEOUT_MS).emit(
|
||||
@@ -133,6 +198,7 @@ function runWakeCheck() {
|
||||
if (!err && response && response.ok === true) {
|
||||
// Jeśli połączenie jest zdrowe, nie wykonujemy reconnectu i nie emitujemy
|
||||
// ponownego join_list. Samo przełączenie karty pozostaje więc całkowicie ciche.
|
||||
setListSocketStatus('connected', currentSocketTransportName());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -159,7 +225,20 @@ window.addEventListener('pageshow', event => {
|
||||
if (event.persisted) recoverListSocket();
|
||||
});
|
||||
|
||||
window.addEventListener('online', recoverListSocket);
|
||||
window.addEventListener('focus', () => {
|
||||
if (!document.hidden) recoverListSocket();
|
||||
});
|
||||
|
||||
window.addEventListener('online', () => {
|
||||
if (hasActiveListRoom()) setListSocketStatus('reconnecting');
|
||||
recoverListSocket();
|
||||
});
|
||||
|
||||
window.addEventListener('offline', () => {
|
||||
if (!hasActiveListRoom()) return;
|
||||
setListSocketStatus('offline');
|
||||
disableCheckboxes(true);
|
||||
});
|
||||
|
||||
// Dla środowisk emitujących zdarzenie resume (np. webview/PWA wrapper).
|
||||
document.addEventListener('resume', recoverListSocket);
|
||||
@@ -182,6 +261,7 @@ socket.on('connect', function () {
|
||||
joinedRoomId = null;
|
||||
|
||||
if (hasActiveListRoom()) {
|
||||
setListSocketStatus('syncing');
|
||||
disableCheckboxes(true);
|
||||
ensureCurrentListJoined();
|
||||
}
|
||||
@@ -191,18 +271,35 @@ socket.on('disconnect', function () {
|
||||
wakeCheckInProgress = false;
|
||||
joinedSocketId = null;
|
||||
joinedRoomId = null;
|
||||
if (window.LIST_ID) disableCheckboxes(true);
|
||||
if (window.LIST_ID) {
|
||||
setListSocketStatus(
|
||||
typeof navigator !== 'undefined' && navigator.onLine === false ? 'offline' : 'reconnecting'
|
||||
);
|
||||
disableCheckboxes(true);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('connect_error', function () {
|
||||
wakeCheckInProgress = false;
|
||||
if (window.LIST_ID) disableCheckboxes(true);
|
||||
if (window.LIST_ID) {
|
||||
setListSocketStatus(
|
||||
typeof navigator !== 'undefined' && navigator.onLine === false ? 'offline' : 'error'
|
||||
);
|
||||
disableCheckboxes(true);
|
||||
}
|
||||
});
|
||||
|
||||
if (socket.io && typeof socket.io.on === 'function') {
|
||||
socket.io.on('reconnect_attempt', () => {
|
||||
if (hasActiveListRoom()) setListSocketStatus('reconnecting');
|
||||
});
|
||||
}
|
||||
|
||||
socket.off('joined_confirmation');
|
||||
socket.on('joined_confirmation', function (data) {
|
||||
const isInitialVisibleJoin = !didCompleteInitialJoin && !data.silent;
|
||||
didCompleteInitialJoin = true;
|
||||
setListSocketStatus('syncing');
|
||||
|
||||
if (Array.isArray(data.users)) {
|
||||
currentRoomUsers = data.users;
|
||||
@@ -289,6 +386,7 @@ socket.on('full_list', function (data) {
|
||||
updateListSmoothly(data.items);
|
||||
disableCheckboxes(false);
|
||||
wakeCheckInProgress = false;
|
||||
setListSocketStatus('connected', currentSocketTransportName());
|
||||
if (typeof window.syncSortModeUI === 'function') {
|
||||
window.syncSortModeUI();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<link rel="stylesheet" href="{{ static_asset_url('static_bp.serve_css', 'split/pages.css') }}">
|
||||
|
||||
{% set hide_login_ui = request.path == '/system-auth' %}
|
||||
{% set is_live_list_view = request.endpoint in ['view_list', 'shared_list'] %}
|
||||
|
||||
{% set exclude_paths = ['/system-auth'] %}
|
||||
{% if (exclude_paths | select("in", request.path) | list | length == 0)
|
||||
@@ -68,6 +69,12 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if is_live_list_view %}
|
||||
<div class="app-ws-status" data-ws-status data-state="connecting" role="status" aria-label="WebSocket: łączenie" title="WebSocket: łączenie">
|
||||
<span class="app-ws-status__dot" aria-hidden="true"></span>
|
||||
<span class="app-ws-status__label" aria-hidden="true">WS</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="d-lg-none app-navbar__meta app-navbar__meta--mobile ms-auto">
|
||||
@@ -84,6 +91,12 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if is_live_list_view %}
|
||||
<div class="app-ws-status app-ws-status--mobile" data-ws-status data-state="connecting" role="status" aria-label="WebSocket: łączenie" title="WebSocket: łączenie">
|
||||
<span class="app-ws-status__dot" aria-hidden="true"></span>
|
||||
<span class="app-ws-status__label" aria-hidden="true">WS</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="dropdown d-lg-none app-mobile-menu">
|
||||
|
||||
Reference in New Issue
Block a user