perf(mobile): paginate threads to 40 (was 500) — kills the heavy-DOM jank at the source
User's insight: the jank/jumps come from rendering ALL ~500 messages on open. Load only the latest 40 (server + client PAGE), and the existing loadOlder() pages in older history on scroll-up with a scroll anchor (no jump). Whole-thread SEARCH is a separate endpoint, unaffected. Also #1: keyboard-show only pins to newest when already near the bottom, so replying to an OLD message no longer yanks to latest. Build marker -> 2026-07-18-batch120. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1134,7 +1134,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<script src="/icons.js?v=6"></script>
|
||||
<script>window.__BUILD='2026-07-18-batch119';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
||||
<script>window.__BUILD='2026-07-18-batch120';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
||||
// Emoji are rendered with the OS's own (colour) emoji font — instant, zero network.
|
||||
//
|
||||
// We used to run Twemoji over every emoji, which swapped each one for an <img> pulled INDIVIDUALLY from
|
||||
@@ -1155,7 +1155,7 @@ function twemojify(_el){ /* native emoji: nothing to do */ }</script>
|
||||
// gone (inputs are 16px), that height is clean, so we lift the composer by exactly it. keyboardWillShow
|
||||
// fires at the START of the animation, so the CSS bottom-transition slides the composer up WITH the
|
||||
// keyboard (smooth). raw>innerHeight guards the rare device-pixel unit.
|
||||
function setKb(px){ px=Math.max(0,Math.round(px)); r.style.setProperty('--kb',px+'px'); document.body.classList.toggle('kb-open',px>4); var b=document.getElementById('msgs'); if(b) b.scrollTop=b.scrollHeight; }
|
||||
function setKb(px){ px=Math.max(0,Math.round(px)); r.style.setProperty('--kb',px+'px'); document.body.classList.toggle('kb-open',px>4); var b=document.getElementById('msgs'); if(b && (b.scrollHeight-b.scrollTop-b.clientHeight)<400) b.scrollTop=b.scrollHeight; } /* #1: only keep pinned to newest when ALREADY near the bottom — replying to an OLD message must not yank to the latest */
|
||||
window.__bzResetKb=function(){ setKb(0); }; // called on composer blur as a safety net (#1: keyboard closed but lift stayed, leaving empty space after reply-cancel)
|
||||
var KB=C.Plugins&&C.Plugins.Keyboard;
|
||||
if(KB && KB.addListener){
|
||||
@@ -1500,7 +1500,7 @@ function enablePullRefresh(el, onRefresh){
|
||||
async function reloadThread(){ if(!selected) return; const kind=selected.kind, id=selected.id; const url=kind==='group'?('/api/messages/thread?group='+encodeURIComponent(id)):('/api/messages/thread?with='+encodeURIComponent(id)); try{ const msgs=await fetch(url).then(r=>r.json()); if(selected&&selected.kind===kind&&selected.id===id&&Array.isArray(msgs)){ THREAD=msgs; THREAD_CACHE.set(kind+':'+id, THREAD.slice()); renderThread(); } }catch(_){} }
|
||||
// ---- Older-history pagination: the thread loads the newest ~500; scrolling to the top fetches the
|
||||
// previous page (messages older than the oldest one loaded) and prepends them, preserving scroll. ----
|
||||
const PAGE=500;
|
||||
const PAGE=40; // load the latest 40 on open (fast render, no 500-node jank); loadOlder() pages in older history on scroll-up. MUST match the server thread limit.
|
||||
let _hasMoreOlder=false, _loadingOlder=false, _olderCd=0;
|
||||
function threadUrl(kind,id,before){ return (kind==='group'?'/api/messages/thread?group='+encodeURIComponent(id):'/api/messages/thread?with='+encodeURIComponent(id))+(before?('&before='+before):''); }
|
||||
async function loadOlder(){
|
||||
|
||||
Reference in New Issue
Block a user