narrow: Open compose box before rendering main message feed.

As discussed in the new comments, we had a bug where the
system-initiated animated scroll that happens when the compose box
opens as a result of narrowing would race with the internal
rerendering that occurs when the message_fetch request asking the
server for additional data returns.

The correct fix for this is just to open the compose box, if we're
going to do so, before setting the user's scroll position in the
narrowing/rendering process.

This ends up being a UI improvement (in that the compose box is
available for typing a bit earlier) as well as avoiding both the risk
of this race as well as the bad UX of adjusting the user's scroll
position multiple times as part of entering the view.

This does not address an as-yet-unknown bug wherein the animated
scroll that occurs when opening the compose box, when racing with a
background rerender, results in a bogus ending scroll position, though
it's easy to see how that might occur given that rerendering does
clear the DOM briefly.
This commit is contained in:
Tim Abbott 2024-01-31 09:50:51 -08:00
parent 07234f6a31
commit 7d4ec1f93b
3 changed files with 25 additions and 8 deletions

View File

@ -90,11 +90,11 @@ function clear_box() {
$(".compose_control_button_container:has(.add-poll)").removeClass("disabled-on-hover"); $(".compose_control_button_container:has(.add-poll)").removeClass("disabled-on-hover");
} }
export function autosize_message_content() { export function autosize_message_content(opts) {
if (!compose_ui.is_full_size()) { if (!compose_ui.is_full_size()) {
autosize($("textarea#compose-textarea"), { autosize($("textarea#compose-textarea"), {
callback() { callback() {
maybe_scroll_up_selected_message(); maybe_scroll_up_selected_message(opts);
}, },
}); });
} }
@ -112,7 +112,7 @@ export function complete_starting_tasks(msg_type, opts) {
// by compose.start() for now. Having this as a separate function // by compose.start() for now. Having this as a separate function
// makes testing a bit easier. // makes testing a bit easier.
maybe_scroll_up_selected_message(); maybe_scroll_up_selected_message(opts);
compose_fade.start_compose(msg_type); compose_fade.start_compose(msg_type);
if (msg_type === "stream") { if (msg_type === "stream") {
stream_bar.decorate( stream_bar.decorate(
@ -125,7 +125,11 @@ export function complete_starting_tasks(msg_type, opts) {
compose_recipient.update_narrow_to_recipient_visibility(); compose_recipient.update_narrow_to_recipient_visibility();
} }
export function maybe_scroll_up_selected_message() { export function maybe_scroll_up_selected_message(opts) {
if (!opts.skip_scrolling_selected_message) {
return;
}
// If the compose box is obscuring the currently selected message, // If the compose box is obscuring the currently selected message,
// scroll up until the message is no longer occluded. // scroll up until the message is no longer occluded.
if (message_lists.current.selected_id() === -1) { if (message_lists.current.selected_id() === -1) {
@ -194,7 +198,7 @@ export function start(msg_type, opts) {
} }
popovers.hide_all(); popovers.hide_all();
autosize_message_content(); autosize_message_content(opts);
if (reload_state.is_in_progress()) { if (reload_state.is_in_progress()) {
return; return;
@ -456,7 +460,14 @@ export function on_narrow(opts) {
return; return;
} }
} }
start("private");
// Open the compose box, passing the option to skip attempting
// an animated adjustment to scroll position, which is useless
// because we are called before the narrowing process has set
// the view's scroll position. recenter_view is responsible
// for taking the open compose box into account when placing
// the selecting message.
start("private", {skip_scrolling_selected_message: true});
return; return;
} }

View File

@ -508,6 +508,13 @@ export function activate(raw_terms, opts) {
}); });
} }
// Important: We need to consider opening the compose box
// before calling update_selection, so that the logic in
// recenter_view for positioning the currently selected
// message can take into account the space consumed by the
// open compose box.
compose_actions.on_narrow(opts);
if (select_immediately) { if (select_immediately) {
update_selection({ update_selection({
id_info, id_info,
@ -525,7 +532,6 @@ export function activate(raw_terms, opts) {
handle_post_view_change(msg_list); handle_post_view_change(msg_list);
compose_actions.on_narrow(opts);
unread_ui.update_unread_banner(); unread_ui.update_unread_banner();

View File

@ -215,6 +215,7 @@ run_test("basics", ({override}) => {
[message_feed_loading, "hide_indicators"], [message_feed_loading, "hide_indicators"],
[message_lists, "save_pre_narrow_offset_for_reload"], [message_lists, "save_pre_narrow_offset_for_reload"],
[compose_banner, "clear_message_sent_banners"], [compose_banner, "clear_message_sent_banners"],
[compose_actions, "on_narrow"],
[unread_ops, "process_visible"], [unread_ops, "process_visible"],
[narrow_history, "save_narrow_state_and_flush"], [narrow_history, "save_narrow_state_and_flush"],
[message_viewport, "stop_auto_scrolling"], [message_viewport, "stop_auto_scrolling"],
@ -226,7 +227,6 @@ run_test("basics", ({override}) => {
[narrow_title, "update_narrow_title"], [narrow_title, "update_narrow_title"],
[left_sidebar_navigation_area, "handle_narrow_activated"], [left_sidebar_navigation_area, "handle_narrow_activated"],
[stream_list, "handle_narrow_activated"], [stream_list, "handle_narrow_activated"],
[compose_actions, "on_narrow"],
[compose_recipient, "handle_middle_pane_transition"], [compose_recipient, "handle_middle_pane_transition"],
]); ]);