message_scroll: Convert module to TypeScript.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg
2024-11-27 15:51:31 -08:00
committed by Anders Kaseorg
parent 93185dd7a6
commit 49f2d08006
4 changed files with 54 additions and 14 deletions

View File

@@ -150,7 +150,7 @@ EXEMPT_FILES = make_set(
"web/src/message_lists.ts",
"web/src/message_live_update.ts",
"web/src/message_notifications.ts",
"web/src/message_scroll.js",
"web/src/message_scroll.ts",
"web/src/message_scroll_state.ts",
"web/src/message_util.ts",
"web/src/message_view.ts",

View File

@@ -31,6 +31,40 @@ export type SelectIdOpts = {
from_rendering?: boolean;
};
export type MessageSelectedEventOpts = {
then_scroll: boolean;
target_scroll_offset: number | undefined;
use_closest: boolean;
empty_ok: boolean;
mark_read: boolean;
force_rerender: boolean;
from_scroll?: boolean;
from_rendering?: boolean;
id: number;
msg_list: MessageList;
previously_selected_id: number;
};
export type MessageSelectedEvent<TDelegateTarget, TData, TCurrentTarget, TTarget> =
JQuery.EventBase<TDelegateTarget, TData, TCurrentTarget, TTarget> & {
type: "message_selected.zulip";
} & MessageSelectedEventOpts;
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace JQuery {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface TypeToTriggeredEventMap<TDelegateTarget, TData, TCurrentTarget, TTarget> {
["message_selected.zulip"]: MessageSelectedEvent<
TDelegateTarget,
TData,
TCurrentTarget,
TTarget
>;
}
}
}
// A MessageList is the main interface for a message feed that is
// rendered in the DOM. Code outside the message feed rendering
// internals will directly call this module in order to manipulate
@@ -313,7 +347,7 @@ export class MessageList {
throw new TypeError("Bad message id " + id);
}
}
const opts = {
const opts: MessageSelectedEventOpts = {
then_scroll: false,
target_scroll_offset: undefined,
use_closest: false,

View File

@@ -1,5 +1,7 @@
import $ from "jquery";
import _ from "lodash";
import assert from "minimalistic-assert";
import type * as tippy from "tippy.js";
import * as compose_banner from "./compose_banner.ts";
import * as message_fetch from "./message_fetch.ts";
@@ -10,9 +12,10 @@ import * as narrow_state from "./narrow_state.ts";
import * as unread from "./unread.ts";
import * as unread_ops from "./unread_ops.ts";
import * as unread_ui from "./unread_ui.ts";
import {the} from "./util.ts";
let hide_scroll_to_bottom_timer;
export function hide_scroll_to_bottom() {
let hide_scroll_to_bottom_timer: ReturnType<typeof setTimeout> | undefined;
export function hide_scroll_to_bottom(): void {
const $show_scroll_to_bottom_button = $("#scroll-to-bottom-button-container");
if (message_lists.current === undefined) {
// Scroll to bottom button is not for non-message views.
@@ -35,14 +38,14 @@ export function hide_scroll_to_bottom() {
// Don't hide if user is hovered on it.
if (
!narrow_state.narrowed_by_topic_reply() &&
!$show_scroll_to_bottom_button.get(0).matches(":hover")
!the($show_scroll_to_bottom_button).matches(":hover")
) {
$show_scroll_to_bottom_button.removeClass("show");
}
}, 3000);
}
export function show_scroll_to_bottom_button() {
export function show_scroll_to_bottom_button(): void {
if (message_viewport.bottom_rendered_message_visible()) {
// Only show scroll to bottom button when
// last message is not visible in the
@@ -64,7 +67,7 @@ $(document).on("keydown", (e) => {
$("#scroll-to-bottom-button-container").removeClass("show");
});
export function scroll_finished() {
export function scroll_finished(): void {
message_scroll_state.set_actively_scrolling(false);
hide_scroll_to_bottom();
@@ -121,8 +124,8 @@ export function scroll_finished() {
}
}
let scroll_timer;
function scroll_finish() {
let scroll_timer: ReturnType<typeof setTimeout> | undefined;
function scroll_finish(): void {
message_scroll_state.set_actively_scrolling(true);
// Don't present the "scroll to bottom" widget if the current
@@ -136,7 +139,7 @@ function scroll_finish() {
scroll_timer = setTimeout(scroll_finished, 100);
}
export function initialize() {
export function initialize(): void {
$(document).on(
"scroll",
_.throttle(() => {
@@ -169,8 +172,8 @@ export function initialize() {
// This is likely the last message in the list. So, we loop through the messages
// in reverse order to find the message.
for (let i = messages.length - 1; i >= 0; i -= 1) {
if (messages[i].id === event.id && event.id !== event.msg_list.last()?.id) {
delete messages[i];
if (messages[i]!.id === event.id && event.id !== event.msg_list.last()?.id) {
messages.splice(i, 1);
break;
}
}
@@ -199,8 +202,11 @@ export function initialize() {
// this button is finished. This is necessary because the fading animation
// confuses Tippy's built-in `data-reference-hidden` feature.
$show_scroll_to_bottom_button.on("transitionend", (e) => {
assert(e.originalEvent instanceof TransitionEvent);
if (e.originalEvent.propertyName === "visibility") {
const tooltip = $("#scroll-to-bottom-button-clickable-area")[0]._tippy;
const tooltip = the(
$<tippy.ReferenceElement>("#scroll-to-bottom-button-clickable-area"),
)._tippy;
// make sure the tooltip exists and the class is not currently showing
if (tooltip && !$show_scroll_to_bottom_button.hasClass("show")) {
tooltip.destroy();

View File

@@ -65,7 +65,7 @@ import * as message_fetch from "./message_fetch.ts";
import * as message_list_hover from "./message_list_hover.ts";
import * as message_list_tooltips from "./message_list_tooltips.ts";
import * as message_lists from "./message_lists.ts";
import * as message_scroll from "./message_scroll.js";
import * as message_scroll from "./message_scroll.ts";
import * as message_view from "./message_view.ts";
import * as message_view_header from "./message_view_header.ts";
import * as message_viewport from "./message_viewport.ts";