narrow: Add 'more topics' state to browser history.

When navigating "back" or "forward", the left sidebar state
should be restored.

Earlier, "more topics" expanded was not considered a distinct
state.

This commit makes it possible to correctly place you in the
"more topics" view or not, depending on where you were.

Fixes #29548.
This commit is contained in:
Prakhar Pratyush 2024-04-30 19:58:32 +05:30 committed by Tim Abbott
parent 549f4fe00b
commit 95be5db08b
6 changed files with 51 additions and 10 deletions

View File

@ -154,3 +154,21 @@ export function set_hash(hash: string): void {
window.location.hash = hash;
}
}
type StateData = {
narrow_pointer?: number;
narrow_offset?: number;
show_more_topics?: boolean;
};
export function update_current_history_state_data(new_data: StateData): void {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const current_state = history.state as StateData | null;
const current_state_data = {
narrow_pointer: current_state?.narrow_pointer,
narrow_offset: current_state?.narrow_offset,
show_more_topics: current_state?.show_more_topics,
};
const state_data = {...current_state_data, ...new_data};
history.replaceState(state_data, "", window.location.href);
}

View File

@ -182,6 +182,7 @@ function do_hashchange_normal(from_reload) {
const narrow_opts = {
change_hash: false, // already set
trigger: "hash change",
show_more_topics: false,
};
if (from_reload) {
blueslip.debug("We are narrowing as part of a reload.");
@ -191,10 +192,11 @@ function do_hashchange_normal(from_reload) {
}
}
const location_data_for_hash = history.state;
if (location_data_for_hash) {
narrow_opts.then_select_id = location_data_for_hash.narrow_pointer;
narrow_opts.then_select_offset = location_data_for_hash.narrow_offset;
const data_for_hash = history.state;
if (data_for_hash) {
narrow_opts.then_select_id = data_for_hash.narrow_pointer;
narrow_opts.then_select_offset = data_for_hash.narrow_offset;
narrow_opts.show_more_topics = data_for_hash.show_more_topics ?? false;
}
narrow.activate(terms, narrow_opts);
return true;

View File

@ -92,6 +92,10 @@ export function update_hash_to_match_filter(filter, trigger) {
}
const new_hash = hash_util.search_terms_to_hash(filter.terms());
changehash(new_hash, trigger);
if (stream_list.is_zoomed_in()) {
browser_history.update_current_history_state_data({show_more_topics: true});
}
}
function create_and_update_message_list(filter, id_info, opts) {
@ -166,6 +170,7 @@ function create_and_update_message_list(filter, id_info, opts) {
// workflow we have which calls `narrow.activate` after hash is updated.
if (opts.change_hash) {
update_hash_to_match_filter(filter, opts.trigger);
opts.show_more_topics = history.state?.show_more_topics ?? false;
}
// Show the new set of messages. It is important to set message_lists.current to
@ -263,6 +268,7 @@ export function activate(raw_terms, opts) {
then_select_offset: undefined,
change_hash: true,
trigger: "unknown",
show_more_topics: false,
...opts,
};
@ -606,7 +612,7 @@ export function activate(raw_terms, opts) {
});
}
handle_post_view_change(msg_list);
handle_post_view_change(msg_list, opts);
unread_ui.update_unread_banner();
@ -1086,7 +1092,7 @@ export function to_compose_target() {
}
}
function handle_post_view_change(msg_list) {
function handle_post_view_change(msg_list, opts) {
const filter = msg_list.data.filter;
scheduled_messages_feed_ui.update_schedule_message_indicator();
typing_events.render_notifications_for_narrow();
@ -1103,7 +1109,7 @@ function handle_post_view_change(msg_list) {
message_view_header.render_title_area();
narrow_title.update_narrow_title(filter);
left_sidebar_navigation_area.handle_narrow_activated(filter);
stream_list.handle_narrow_activated(filter);
stream_list.handle_narrow_activated(filter, opts.change_hash, opts.show_more_topics);
pm_list.handle_narrow_activated(filter);
activity_ui.build_user_sidebar();
}

View File

@ -34,7 +34,7 @@ function _save_narrow_state(): void {
narrow_pointer,
narrow_offset,
};
history.replaceState(narrow_data, "", window.location.href);
browser_history.update_current_history_state_data(narrow_data);
}
// Safari limits you to 100 replaceState calls in 30 seconds.

View File

@ -9,6 +9,7 @@ import render_stream_subheader from "../templates/streams_subheader.hbs";
import render_subscribe_to_more_streams from "../templates/subscribe_to_more_streams.hbs";
import * as blueslip from "./blueslip";
import * as browser_history from "./browser_history";
import type {Filter} from "./filter";
import * as hash_util from "./hash_util";
import {$t} from "./i18n";
@ -746,10 +747,21 @@ export function update_stream_sidebar_for_narrow(filter: Filter): JQuery | undef
return $stream_li;
}
export function handle_narrow_activated(filter: Filter): void {
export function handle_narrow_activated(
filter: Filter,
change_hash: boolean,
show_more_topics: boolean,
): void {
const $stream_li = update_stream_sidebar_for_narrow(filter);
if ($stream_li) {
scroll_stream_into_view($stream_li);
if (!change_hash) {
if (!is_zoomed_in() && show_more_topics) {
zoom_in();
} else if (is_zoomed_in() && !show_more_topics) {
zoom_out();
}
}
}
}
@ -805,6 +817,7 @@ export function initialize({
$("#stream_filters").on("click", ".show-more-topics", (e) => {
zoom_in();
browser_history.update_current_history_state_data({show_more_topics: true});
e.preventDefault();
e.stopPropagation();
@ -812,6 +825,7 @@ export function initialize({
$(".show-all-streams").on("click", (e) => {
zoom_out();
browser_history.update_current_history_state_data({show_more_topics: false});
e.preventDefault();
e.stopPropagation();

View File

@ -6,6 +6,7 @@ const {mock_esm, set_global, zrequire} = require("./lib/namespace");
const {run_test, noop} = require("./lib/test");
const $ = require("./lib/zjquery");
set_global("history", {});
mock_esm("../src/resize", {
resize_stream_filters_container() {},
});
@ -46,7 +47,7 @@ const message_view_header = mock_esm("../src/message_view_header");
const message_viewport = mock_esm("../src/message_viewport");
const narrow_history = mock_esm("../src/narrow_history");
const narrow_title = mock_esm("../src/narrow_title");
const stream_list = mock_esm("../src/stream_list");
const stream_list = mock_esm("../src/stream_list", {is_zoomed_in: () => false});
const left_sidebar_navigation_area = mock_esm("../src/left_sidebar_navigation_area");
const typing_events = mock_esm("../src/typing_events");
const unread_ops = mock_esm("../src/unread_ops");