diff --git a/tools/test-js-with-node b/tools/test-js-with-node index d5ba0487c8..f68f9d0e62 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -160,7 +160,7 @@ EXEMPT_FILES = make_set( "web/src/navbar_alerts.ts", "web/src/navbar_help_menu.ts", "web/src/navbar_menus.js", - "web/src/navigate.js", + "web/src/navigate.ts", "web/src/onboarding_steps.ts", "web/src/overlay_util.ts", "web/src/overlays.ts", diff --git a/web/src/message_lists.ts b/web/src/message_lists.ts index 792e65a5e8..621da34996 100644 --- a/web/src/message_lists.ts +++ b/web/src/message_lists.ts @@ -12,6 +12,9 @@ type MessageListView = { update_recipient_bar_background_color: () => void; rerender_messages: (messages: Message[], message_content_edited?: boolean) => void; is_fetched_end_rendered: () => boolean; + is_fetched_start_rendered: () => boolean; + first_rendered_message: () => Message | undefined; + last_rendered_message: () => Message | undefined; show_message_as_read: (message: Message, options: {from?: "pointer" | "server"}) => void; show_messages_as_unread: (message_ids: number[]) => void; _render_win_start: number; @@ -46,6 +49,9 @@ export type MessageList = { can_mark_messages_read_without_setting: () => boolean; rerender_view: () => void; update_muting_and_rerender: () => void; + prev: () => number | undefined; + next: () => number | undefined; + is_at_end: () => boolean; prevent_reading: () => void; resume_reading: () => void; data: MessageListData; @@ -55,6 +61,7 @@ export type MessageList = { messages: Message[], append_opts: {messages_are_new: boolean}, ) => RenderInfo | undefined; + first: () => Message | undefined; last: () => Message | undefined; visibly_empty: () => boolean; selected_message: () => Message; diff --git a/web/src/navigate.js b/web/src/navigate.ts similarity index 68% rename from web/src/navigate.js rename to web/src/navigate.ts index eb877e3652..7be88cc1b2 100644 --- a/web/src/navigate.js +++ b/web/src/navigate.ts @@ -4,12 +4,12 @@ import * as message_lists from "./message_lists"; import * as message_viewport from "./message_viewport"; import * as unread_ops from "./unread_ops"; -function go_to_row(msg_id) { +function go_to_row(msg_id: number): void { assert(message_lists.current !== undefined); message_lists.current.select_id(msg_id, {then_scroll: true, from_scroll: true}); } -export function up() { +export function up(): void { assert(message_lists.current !== undefined); message_viewport.set_last_movement_direction(-1); const msg_id = message_lists.current.prev(); @@ -19,7 +19,7 @@ export function up() { go_to_row(msg_id); } -export function down(with_centering) { +export function down(with_centering = false): void { assert(message_lists.current !== undefined); message_viewport.set_last_movement_direction(1); @@ -45,22 +45,24 @@ export function down(with_centering) { go_to_row(msg_id); } -export function to_home() { +export function to_home(): void { assert(message_lists.current !== undefined); message_viewport.set_last_movement_direction(-1); - const first_id = message_lists.current.first().id; - message_lists.current.select_id(first_id, {then_scroll: true, from_scroll: true}); + const first_message = message_lists.current.first(); + assert(first_message !== undefined); + message_lists.current.select_id(first_message.id, {then_scroll: true, from_scroll: true}); } -export function to_end() { +export function to_end(): void { assert(message_lists.current !== undefined); - const next_id = message_lists.current.last().id; + const last_message = message_lists.current.last(); + assert(last_message !== undefined); message_viewport.set_last_movement_direction(1); - message_lists.current.select_id(next_id, {then_scroll: true, from_scroll: true}); + message_lists.current.select_id(last_message.id, {then_scroll: true, from_scroll: true}); unread_ops.process_visible(); } -function amount_to_paginate() { +function amount_to_paginate(): number { // Some day we might have separate versions of this function // for Page Up vs. Page Down, but for now it's the same // strategy in either direction. @@ -71,7 +73,7 @@ function amount_to_paginate() { // are especially worried about missing messages, so we want // a little bit of the old page to stay on the screen. The // value chosen here is roughly 2 or 3 lines of text, but there - // is nothing sacred about it, and somebody more anal than me + // is nothing sacred about it, and somebody more anal than we // might wish to tie this to the size of some particular DOM // element. const overlap_amount = 55; @@ -88,7 +90,7 @@ function amount_to_paginate() { return delta; } -export function page_up_the_right_amount() { +export function page_up_the_right_amount(): void { // This function's job is to scroll up the right amount, // after the user hits Page Up. We do this ourselves // because we can't rely on the browser to account for certain @@ -100,37 +102,42 @@ export function page_up_the_right_amount() { message_viewport.scrollTop(message_viewport.scrollTop() - delta); } -export function page_down_the_right_amount() { +export function page_down_the_right_amount(): void { // see also: page_up_the_right_amount const delta = amount_to_paginate(); message_viewport.scrollTop(message_viewport.scrollTop() + delta); } -export function page_up() { +export function page_up(): void { assert(message_lists.current !== undefined); if (message_viewport.at_rendered_top() && !message_lists.current.visibly_empty()) { if (message_lists.current.view.is_fetched_start_rendered()) { - message_lists.current.select_id(message_lists.current.first().id, {then_scroll: false}); + const first_message = message_lists.current.first(); + assert(first_message !== undefined); + message_lists.current.select_id(first_message.id, {then_scroll: false}); } else { - message_lists.current.select_id( - message_lists.current.view.first_rendered_message().id, - { - then_scroll: false, - }, - ); + const first_rendered_message = message_lists.current.view.first_rendered_message(); + assert(first_rendered_message !== undefined); + message_lists.current.select_id(first_rendered_message.id, { + then_scroll: false, + }); } } else { page_up_the_right_amount(); } } -export function page_down() { +export function page_down(): void { assert(message_lists.current !== undefined); if (message_viewport.at_rendered_bottom() && !message_lists.current.visibly_empty()) { if (message_lists.current.view.is_fetched_end_rendered()) { - message_lists.current.select_id(message_lists.current.last().id, {then_scroll: false}); + const last_message = message_lists.current.last(); + assert(last_message !== undefined); + message_lists.current.select_id(last_message.id, {then_scroll: false}); } else { - message_lists.current.select_id(message_lists.current.view.last_rendered_message().id, { + const last_rendered_message = message_lists.current.view.last_rendered_message(); + assert(last_rendered_message !== undefined); + message_lists.current.select_id(last_rendered_message.id, { then_scroll: false, }); }