diff --git a/web/src/condense.ts b/web/src/condense.ts index c80669402f..8426be11b1 100644 --- a/web/src/condense.ts +++ b/web/src/condense.ts @@ -4,6 +4,7 @@ import assert from "minimalistic-assert"; import render_message_length_toggle from "../templates/message_length_toggle.hbs"; import * as message_flags from "./message_flags.ts"; +import type {MessageList} from "./message_list.ts"; import * as message_lists from "./message_lists.ts"; import type {Message} from "./message_store.ts"; import * as message_viewport from "./message_viewport.ts"; @@ -23,6 +24,14 @@ This library implements two related, similar concepts: */ +const state: { + message_list: MessageList | undefined; + has_unread_cutoff_by_message_id: Set; +} = { + message_list: undefined, + has_unread_cutoff_by_message_id: new Set(), +}; + export function show_message_expander($row: JQuery): void { $row.find(".message_length_controller").html( render_message_length_toggle({toggle_type: "expander"}), @@ -170,6 +179,11 @@ export function condense_and_collapse(elems: JQuery): void { return; } + if (message_lists.current !== state.message_list) { + state.message_list = message_lists.current; + state.has_unread_cutoff_by_message_id = new Set(); + } + // For unread messages, we allow them to expand to most of a // desktop monitor's height, with stricter limits for mobile web // devices, especially in landscape mode. @@ -222,7 +236,14 @@ export function condense_and_collapse(elems: JQuery): void { // changing the layout of the page, which is more performanant. // More information here: https://web.dev/avoid-large-complex-layouts-and-layout-thrashing/#avoid-layout-thrashing for (const {elem, $content, message, message_height} of rows_to_resize) { - const height_cutoff = message.unread ? height_cutoff_unread : height_cutoff_read; + // Track which messages were unread when initially rendered so that subsequent + // re-renders don't collapse the message while user is reading it. + if (message.unread) { + state.has_unread_cutoff_by_message_id.add(message.id); + } + const height_cutoff = state.has_unread_cutoff_by_message_id.has(message.id) + ? height_cutoff_unread + : height_cutoff_read; const long_message = message_height > height_cutoff; if (long_message) { // All long messages are flagged as such.