diff --git a/server/public/home.html b/server/public/home.html index eac7b7d..81e42c7 100644 --- a/server/public/home.html +++ b/server/public/home.html @@ -3420,6 +3420,11 @@ let _openUnread=0; // set by selectChat (the unread count before it's reset) so function draftKey(kind,id){ return 'draft_'+((ME&&ME.id)||'')+'_'+kind+':'+id; } function getDraft(kind,id){ try{ return localStorage.getItem(draftKey(kind,id))||''; }catch(_){ return ''; } } function setDraft(kind,id,val){ try{ if(val&&val.trim()) localStorage.setItem(draftKey(kind,id), val); else localStorage.removeItem(draftKey(kind,id)); }catch(_){} } +// #14: GUARANTEED save of the currently-open chat's draft — called the instant we leave it (switching chats +// OR going back to the list). The per-keystroke 'input' save can be missed on mobile (predictive text / a +// fast tap-away fires no final input event), which lost the whole draft on switch-and-return. Snapshotting +// the composer value at leave-time makes it reliable regardless. Skipped while editing (that's not a draft). +function persistCurrentDraft(){ try{ if(selected && !editTarget){ const inp=document.getElementById('msgInput'); if(inp) setDraft(selected.kind, selected.id, inp.value); } }catch(_){} } // Compositor-only open slide (workflow-verified). armOpenSlide() runs AFTER openConvo's synchronous // render: it pins the pane off-screen (chat-opening), lets a frame paint it, then adds .chat-anim on a // double-rAF so the compositor runs the 300ms transform with the main thread idle. All scrollTop/innerHTML @@ -3810,6 +3815,7 @@ function openPollModal(gid){ } async function selectChat(kind,id){ ensureNotifyPermission(); + persistCurrentDraft(); // #14: snapshot the outgoing chat's draft BEFORE we swap (reliable across the switch) stopTyping(); // leaving the previous conversation → tell that peer we stopped if(_selMode) exitSelect(); // #1: leave forward-selection when changing chats selected={kind,id}; @@ -6045,6 +6051,7 @@ function switchTab(tab){ if(tab==='meeting' && meetState==='idle'){ renderMeetingLobby(); } } function showWelcome(skipAnim){ + persistCurrentDraft(); // #14: save the open chat's draft before we leave it for the list (back button) const finish=()=>{ selected=null; document.body.classList.remove('chat-open','chat-closing','chat-dragging'); renderChats(searchVal()); renderChatPanel(); updateRailUnread(); }; // Mobile: slide the outgoing conversation off to the right before swapping back to the chat list, so // "back" has a clear push/pop direction (like Teams/WhatsApp). Desktop just closes instantly.