From d5064fc7b2b4c221d80d04ce6ffdce498dc77971 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Thu, 5 Oct 2023 14:18:00 -0700 Subject: [PATCH] narrow: Extract narrow_title module. Signed-off-by: Anders Kaseorg --- tools/test-js-with-node | 1 + web/src/narrow.js | 77 +------------------- web/src/narrow_title.js | 117 ++++++++++++++++++++++++++++++ web/src/notifications.js | 41 ----------- web/src/server_events_dispatch.js | 3 +- web/src/ui_init.js | 3 +- web/src/views_util.js | 3 +- web/tests/dispatch.test.js | 3 +- web/tests/narrow.test.js | 23 +++--- web/tests/narrow_activate.test.js | 6 +- web/tests/recent_view.test.js | 4 +- 11 files changed, 146 insertions(+), 135 deletions(-) create mode 100644 web/src/narrow_title.js diff --git a/tools/test-js-with-node b/tools/test-js-with-node index ce6d429e6d..d8c06bf8fd 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -140,6 +140,7 @@ EXEMPT_FILES = make_set( "web/src/muted_users_ui.js", "web/src/narrow.js", "web/src/narrow_history.js", + "web/src/narrow_title.js", "web/src/navbar_alerts.js", "web/src/navigate.js", "web/src/notifications.js", diff --git a/web/src/narrow.js b/web/src/narrow.js index cd518d816e..37c413ad54 100644 --- a/web/src/narrow.js +++ b/web/src/narrow.js @@ -15,7 +15,6 @@ import * as condense from "./condense"; import {Filter} from "./filter"; import * as hash_parser from "./hash_parser"; import * as hashchange from "./hashchange"; -import {$t} from "./i18n"; import * as inbox_ui from "./inbox_ui"; import * as inbox_util from "./inbox_util"; import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area"; @@ -32,7 +31,7 @@ import * as message_view_header from "./message_view_header"; import * as narrow_banner from "./narrow_banner"; import * as narrow_history from "./narrow_history"; import * as narrow_state from "./narrow_state"; -import * as notifications from "./notifications"; +import * as narrow_title from "./narrow_title"; import {page_params} from "./page_params"; import * as people from "./people"; import * as pm_list from "./pm_list"; @@ -76,78 +75,6 @@ export function save_pre_narrow_offset_for_reload() { export let has_shown_message_list_view = false; -export function compute_narrow_title(filter) { - if (filter === undefined) { - // "All messages" and "Recent conversations" views have - // an `undefined` filter. - if (recent_view_util.is_visible()) { - return $t({defaultMessage: "Recent conversations"}); - } - - if (inbox_util.is_visible()) { - return $t({defaultMessage: "Inbox"}); - } - } - - const filter_title = filter.get_title(); - - if (filter_title === undefined) { - // Default result for uncommon narrow/search views. - return $t({defaultMessage: "Search results"}); - } - - if (filter.has_operator("stream")) { - if (!filter._sub) { - // The stream is not set because it does not currently - // exist (possibly due to a stream name change), or it - // is a private stream and the user is not subscribed. - return filter_title; - } - if (filter.has_operator("topic")) { - const topic_name = filter.operands("topic")[0]; - return "#" + filter_title + " > " + topic_name; - } - return "#" + filter_title; - } - - if (filter.has_operator("dm")) { - const emails = filter.operands("dm")[0]; - const user_ids = people.emails_strings_to_user_ids_string(emails); - - if (user_ids !== undefined) { - return people.get_recipients(user_ids); - } - if (emails.includes(",")) { - return $t({defaultMessage: "Invalid users"}); - } - return $t({defaultMessage: "Invalid user"}); - } - - if (filter.has_operator("sender")) { - const user = people.get_by_email(filter.operands("sender")[0]); - if (user) { - if (people.is_my_user_id(user.user_id)) { - return $t({defaultMessage: "Messages sent by you"}); - } - return $t( - {defaultMessage: "Messages sent by {sender}"}, - { - sender: user.full_name, - }, - ); - } - return $t({defaultMessage: "Invalid user"}); - } - - return filter_title; -} - -export let narrow_title = "home"; -export function update_narrow_title(filter) { - narrow_title = compute_narrow_title(filter); - notifications.redraw_title(); -} - export function reset_ui_state() { // Resets the state of various visual UI elements that are // a function of the current narrow. @@ -1015,7 +942,7 @@ function handle_post_view_change(msg_list) { compose_closed_ui.update_reply_recipient_label(); message_view_header.render_title_area(); - update_narrow_title(filter); + narrow_title.update_narrow_title(filter); left_sidebar_navigation_area.handle_narrow_activated(filter); stream_list.handle_narrow_activated(filter); pm_list.handle_narrow_activated(filter); diff --git a/web/src/narrow_title.js b/web/src/narrow_title.js new file mode 100644 index 0000000000..0ab2650a57 --- /dev/null +++ b/web/src/narrow_title.js @@ -0,0 +1,117 @@ +import * as favicon from "./favicon"; +import {$t} from "./i18n"; +import * as inbox_util from "./inbox_util"; +import {page_params} from "./page_params"; +import * as people from "./people"; +import * as recent_view_util from "./recent_view_util"; +import * as unread from "./unread"; + +export let unread_count = 0; +let pm_count = 0; +export let narrow_title = "home"; + +export function compute_narrow_title(filter) { + if (filter === undefined) { + // "All messages" and "Recent conversations" views have + // an `undefined` filter. + if (recent_view_util.is_visible()) { + return $t({defaultMessage: "Recent conversations"}); + } + + if (inbox_util.is_visible()) { + return $t({defaultMessage: "Inbox"}); + } + } + + const filter_title = filter.get_title(); + + if (filter_title === undefined) { + // Default result for uncommon narrow/search views. + return $t({defaultMessage: "Search results"}); + } + + if (filter.has_operator("stream")) { + if (!filter._sub) { + // The stream is not set because it does not currently + // exist (possibly due to a stream name change), or it + // is a private stream and the user is not subscribed. + return filter_title; + } + if (filter.has_operator("topic")) { + const topic_name = filter.operands("topic")[0]; + return "#" + filter_title + " > " + topic_name; + } + return "#" + filter_title; + } + + if (filter.has_operator("dm")) { + const emails = filter.operands("dm")[0]; + const user_ids = people.emails_strings_to_user_ids_string(emails); + + if (user_ids !== undefined) { + return people.get_recipients(user_ids); + } + if (emails.includes(",")) { + return $t({defaultMessage: "Invalid users"}); + } + return $t({defaultMessage: "Invalid user"}); + } + + if (filter.has_operator("sender")) { + const user = people.get_by_email(filter.operands("sender")[0]); + if (user) { + if (people.is_my_user_id(user.user_id)) { + return $t({defaultMessage: "Messages sent by you"}); + } + return $t( + {defaultMessage: "Messages sent by {sender}"}, + { + sender: user.full_name, + }, + ); + } + return $t({defaultMessage: "Invalid user"}); + } + + return filter_title; +} + +export function redraw_title() { + // Update window title to reflect unread messages in current view + const new_title = + (unread_count ? "(" + unread_count + ") " : "") + + narrow_title + + " - " + + page_params.realm_name + + " - " + + "Zulip"; + + document.title = new_title; +} + +export function update_unread_counts(counts) { + const new_unread_count = unread.calculate_notifiable_count(counts); + const new_pm_count = counts.direct_message_count; + if (new_unread_count === unread_count && new_pm_count === pm_count) { + return; + } + + unread_count = new_unread_count; + pm_count = new_pm_count; + + // Indicate the message count in the favicon + favicon.update_favicon(unread_count, pm_count); + + // Notify the current desktop app's UI about the new unread count. + if (window.electron_bridge !== undefined) { + window.electron_bridge.send_event("total_unread_count", unread_count); + } + + // TODO: Add a `window.electron_bridge.updateDirectMessageCount(new_pm_count);` call? + redraw_title(); +} + +export function update_narrow_title(filter) { + narrow_title = compute_narrow_title(filter); + redraw_title(); +} diff --git a/web/src/notifications.js b/web/src/notifications.js index cf2471b671..6c993b1c5a 100644 --- a/web/src/notifications.js +++ b/web/src/notifications.js @@ -6,14 +6,12 @@ import render_unmute_topic_banner from "../templates/compose_banner/unmute_topic import * as alert_words from "./alert_words"; import * as blueslip from "./blueslip"; import * as compose_banner from "./compose_banner"; -import * as favicon from "./favicon"; import * as hash_util from "./hash_util"; import {$t} from "./i18n"; import * as message_lists from "./message_lists"; import * as message_parser from "./message_parser"; import * as narrow from "./narrow"; import * as narrow_state from "./narrow_state"; -import {page_params} from "./page_params"; import * as people from "./people"; import * as spoilers from "./spoilers"; import * as stream_data from "./stream_data"; @@ -102,45 +100,6 @@ export function permission_state() { return NotificationAPI.permission; } -let unread_count = 0; -let pm_count = 0; - -export function redraw_title() { - // Update window title to reflect unread messages in current view - const new_title = - (unread_count ? "(" + unread_count + ") " : "") + - narrow.narrow_title + - " - " + - page_params.realm_name + - " - " + - "Zulip"; - - document.title = new_title; -} - -export function update_unread_counts(counts) { - const new_unread_count = unread.calculate_notifiable_count(counts); - const new_pm_count = counts.direct_message_count; - if (new_unread_count === unread_count && new_pm_count === pm_count) { - return; - } - - unread_count = new_unread_count; - pm_count = new_pm_count; - - // Indicate the message count in the favicon - favicon.update_favicon(unread_count, pm_count); - - // Notify the current desktop app's UI about the new unread count. - if (window.electron_bridge !== undefined) { - window.electron_bridge.send_event("total_unread_count", unread_count); - } - - // TODO: Add a `window.electron_bridge.updateDirectMessageCount(new_pm_count);` call? - - redraw_title(); -} - function notify_unmute(muted_narrow, stream_id, topic_name) { const $unmute_notification = $( render_unmute_topic_banner({ diff --git a/web/src/server_events_dispatch.js b/web/src/server_events_dispatch.js index d51862de41..582fd9d08d 100644 --- a/web/src/server_events_dispatch.js +++ b/web/src/server_events_dispatch.js @@ -28,6 +28,7 @@ import * as message_lists from "./message_lists"; import * as message_live_update from "./message_live_update"; import * as muted_users_ui from "./muted_users_ui"; import * as narrow_state from "./narrow_state"; +import * as narrow_title from "./narrow_title"; import * as navbar_alerts from "./navbar_alerts"; import * as notifications from "./notifications"; import * as overlays from "./overlays"; @@ -224,7 +225,7 @@ export function dispatch_normal_event(event) { move_messages_within_stream_limit_seconds: message_edit.update_inline_topic_edit_ui, message_retention_days: noop, move_messages_between_streams_policy: noop, - name: notifications.redraw_title, + name: narrow_title.redraw_title, name_changes_disabled: settings_account.update_name_change_display, notifications_stream_id: stream_ui_updates.update_announce_stream_option, org_type: noop, diff --git a/web/src/ui_init.js b/web/src/ui_init.js index da14748c60..f1e5e08dde 100644 --- a/web/src/ui_init.js +++ b/web/src/ui_init.js @@ -67,6 +67,7 @@ import * as muted_users from "./muted_users"; import * as narrow from "./narrow"; import * as narrow_history from "./narrow_history"; import * as narrow_state from "./narrow_state"; +import * as narrow_title from "./narrow_title"; import * as navbar_alerts from "./navbar_alerts"; import * as navigate from "./navigate"; import * as notifications from "./notifications"; @@ -383,7 +384,7 @@ function initialize_unread_ui() { ); unread_ui.register_update_unread_counts_hook(() => topic_list.update()); unread_ui.register_update_unread_counts_hook((counts) => - notifications.update_unread_counts(counts), + narrow_title.update_unread_counts(counts), ); unread_ui.register_update_unread_counts_hook(inbox_ui.update); diff --git a/web/src/views_util.js b/web/src/views_util.js index 2f6193cfa6..4d76013f39 100644 --- a/web/src/views_util.js +++ b/web/src/views_util.js @@ -3,6 +3,7 @@ import $ from "jquery"; import * as message_view_header from "./message_view_header"; import * as narrow from "./narrow"; import * as narrow_state from "./narrow_state"; +import * as narrow_title from "./narrow_title"; import * as navigate from "./navigate"; import * as pm_list from "./pm_list"; import * as resize from "./resize"; @@ -35,7 +36,7 @@ export function show(opts) { unread_ui.hide_unread_banner(); opts.update_compose(); narrow_state.reset_current_filter(); - narrow.update_narrow_title(narrow_state.filter()); + narrow_title.update_narrow_title(narrow_state.filter()); message_view_header.render_title_area(); narrow.handle_middle_pane_transition(); search.clear_search_form(); diff --git a/web/tests/dispatch.test.js b/web/tests/dispatch.test.js index 04a258a5d1..17f02e8ecb 100644 --- a/web/tests/dispatch.test.js +++ b/web/tests/dispatch.test.js @@ -34,6 +34,7 @@ const message_events = mock_esm("../src/message_events"); const message_lists = mock_esm("../src/message_lists"); const user_topics_ui = mock_esm("../src/user_topics_ui"); const muted_users_ui = mock_esm("../src/muted_users_ui"); +const narrow_title = mock_esm("../src/narrow_title"); const notifications = mock_esm("../src/notifications"); const pm_list = mock_esm("../src/pm_list"); const reactions = mock_esm("../src/reactions"); @@ -420,7 +421,7 @@ run_test("realm settings", ({override}) => { override(settings_invites, "update_invite_user_panel", noop); override(sidebar_ui, "update_invite_user_option", noop); override(gear_menu, "initialize", noop); - override(notifications, "redraw_title", noop); + override(narrow_title, "redraw_title", noop); function test_electron_dispatch(event, fake_send_event) { with_overrides(({override}) => { diff --git a/web/tests/narrow.test.js b/web/tests/narrow.test.js index 6ff569aed8..928eda64ec 100644 --- a/web/tests/narrow.test.js +++ b/web/tests/narrow.test.js @@ -16,6 +16,7 @@ const people = zrequire("people"); const stream_data = zrequire("stream_data"); const {Filter} = zrequire("../src/filter"); const narrow = zrequire("narrow"); +const narrow_title = zrequire("narrow_title"); const settings_config = zrequire("settings_config"); const recent_view_util = zrequire("recent_view_util"); const inbox_util = zrequire("inbox_util"); @@ -773,22 +774,22 @@ run_test("narrow_compute_title", () => { filter = undefined; recent_view_util.set_visible(true); inbox_util.set_visible(false); - assert.equal(narrow.compute_narrow_title(filter), "translated: Recent conversations"); + assert.equal(narrow_title.compute_narrow_title(filter), "translated: Recent conversations"); recent_view_util.set_visible(false); inbox_util.set_visible(true); - assert.equal(narrow.compute_narrow_title(filter), "translated: Inbox"); + assert.equal(narrow_title.compute_narrow_title(filter), "translated: Inbox"); inbox_util.set_visible(false); filter = new Filter([{operator: "in", operand: "home"}]); - assert.equal(narrow.compute_narrow_title(filter), "translated: All messages"); + assert.equal(narrow_title.compute_narrow_title(filter), "translated: All messages"); // Search & uncommon narrows filter = new Filter([{operator: "search", operand: "potato"}]); - assert.equal(narrow.compute_narrow_title(filter), "translated: Search results"); + assert.equal(narrow_title.compute_narrow_title(filter), "translated: Search results"); filter = new Filter([{operator: "sender", operand: "me"}]); - assert.equal(narrow.compute_narrow_title(filter), "translated: Messages sent by you"); + assert.equal(narrow_title.compute_narrow_title(filter), "translated: Messages sent by you"); // Stream narrows const sub = { @@ -801,13 +802,13 @@ run_test("narrow_compute_title", () => { {operator: "stream", operand: "foo"}, {operator: "topic", operand: "bar"}, ]); - assert.equal(narrow.compute_narrow_title(filter), "#Foo > bar"); + assert.equal(narrow_title.compute_narrow_title(filter), "#Foo > bar"); filter = new Filter([{operator: "stream", operand: "foo"}]); - assert.equal(narrow.compute_narrow_title(filter), "#Foo"); + assert.equal(narrow_title.compute_narrow_title(filter), "#Foo"); filter = new Filter([{operator: "stream", operand: "Elephant"}]); - assert.equal(narrow.compute_narrow_title(filter), "translated: Unknown stream #Elephant"); + assert.equal(narrow_title.compute_narrow_title(filter), "translated: Unknown stream #Elephant"); // Direct messages with narrows const joe = { @@ -818,14 +819,14 @@ run_test("narrow_compute_title", () => { people.add_active_user(joe); filter = new Filter([{operator: "dm", operand: "joe@example.com"}]); - assert.equal(narrow.compute_narrow_title(filter), "joe"); + assert.equal(narrow_title.compute_narrow_title(filter), "joe"); filter = new Filter([{operator: "dm", operand: "joe@example.com,sally@doesnotexist.com"}]); blueslip.expect("warn", "Unknown emails"); - assert.equal(narrow.compute_narrow_title(filter), "translated: Invalid users"); + assert.equal(narrow_title.compute_narrow_title(filter), "translated: Invalid users"); blueslip.reset(); filter = new Filter([{operator: "dm", operand: "sally@doesnotexist.com"}]); blueslip.expect("warn", "Unknown emails"); - assert.equal(narrow.compute_narrow_title(filter), "translated: Invalid user"); + assert.equal(narrow_title.compute_narrow_title(filter), "translated: Invalid user"); }); diff --git a/web/tests/narrow_activate.test.js b/web/tests/narrow_activate.test.js index 39edb8643e..532ae729cd 100644 --- a/web/tests/narrow_activate.test.js +++ b/web/tests/narrow_activate.test.js @@ -29,7 +29,7 @@ const message_feed_top_notices = mock_esm("../src/message_feed_top_notices"); const message_feed_loading = mock_esm("../src/message_feed_loading"); const message_view_header = mock_esm("../src/message_view_header"); const narrow_history = mock_esm("../src/narrow_history"); -const notifications = mock_esm("../src/notifications"); +const narrow_title = mock_esm("../src/narrow_title"); const stream_list = mock_esm("../src/stream_list"); const left_sidebar_navigation_area = mock_esm("../src/left_sidebar_navigation_area"); const typing_events = mock_esm("../src/typing_events"); @@ -86,7 +86,7 @@ function test_helper({override}) { stub(hashchange, "save_narrow"); stub(message_feed_loading, "hide_indicators"); stub(message_feed_top_notices, "hide_top_of_narrow_notices"); - stub(notifications, "redraw_title"); + stub(narrow_title, "update_narrow_title"); stub(stream_list, "handle_narrow_activated"); stub(message_view_header, "render_title_area"); stub(left_sidebar_navigation_area, "handle_narrow_activated"); @@ -193,7 +193,7 @@ run_test("basics", ({override}) => { [compose_closed_ui, "update_buttons_for_stream"], [compose_closed_ui, "update_reply_recipient_label"], [message_view_header, "render_title_area"], - [notifications, "redraw_title"], + [narrow_title, "update_narrow_title"], [left_sidebar_navigation_area, "handle_narrow_activated"], [stream_list, "handle_narrow_activated"], [compose_actions, "on_narrow"], diff --git a/web/tests/recent_view.test.js b/web/tests/recent_view.test.js index d93e44b908..f4b8ff1b94 100644 --- a/web/tests/recent_view.test.js +++ b/web/tests/recent_view.test.js @@ -142,11 +142,13 @@ mock_esm("../src/user_topics", { all_visibility_policies, }); const narrow = mock_esm("../src/narrow", { - update_narrow_title: noop, hide_unread_banner: noop, handle_middle_pane_transition: noop, has_shown_message_list_view: true, }); +mock_esm("../src/narrow_title", { + update_narrow_title() {}, +}); mock_esm("../src/pm_list", { update_private_messages: noop, handle_message_view_deactivated: noop,