compose_actions: Convert module to typescript.

This commit is contained in:
evykassirer 2024-04-03 18:48:12 -07:00 committed by Tim Abbott
parent 55cf08c4e6
commit d6f4424102
3 changed files with 83 additions and 32 deletions

View File

@ -66,7 +66,7 @@ EXEMPT_FILES = make_set(
"web/src/buddy_list.ts",
"web/src/click_handlers.js",
"web/src/compose.js",
"web/src/compose_actions.js",
"web/src/compose_actions.ts",
"web/src/compose_banner.ts",
"web/src/compose_call_ui.js",
"web/src/compose_closed_ui.js",

View File

@ -10,9 +10,11 @@ import * as compose_pm_pill from "./compose_pm_pill";
import * as compose_recipient from "./compose_recipient";
import * as compose_state from "./compose_state";
import * as compose_ui from "./compose_ui";
import type {ComposeTriggeredOptions} from "./compose_ui";
import * as compose_validate from "./compose_validate";
import * as drafts from "./drafts";
import * as message_lists from "./message_lists";
import type {Message} from "./message_store";
import * as message_viewport from "./message_viewport";
import * as narrow_state from "./narrow_state";
import {page_params} from "./page_params";
@ -25,28 +27,53 @@ import * as spectators from "./spectators";
import {realm} from "./state_data";
import * as stream_data from "./stream_data";
const compose_clear_box_hooks = [];
const compose_cancel_hooks = [];
// Opts sent to `compose_actions.start`.
type ComposeActionsStartOpts = {
message_type: "private" | "stream";
force_close?: boolean;
trigger?: string;
private_message_recipient?: string;
message?: Message;
stream_id?: number;
topic?: string;
content?: string;
draft_id?: string;
skip_scrolling_selected_message?: boolean;
is_reply?: boolean;
};
export function register_compose_box_clear_hook(hook) {
// An iteration on `ComposeActionsStartOpts` that enforces that
// some values are present.
type ComposeActionsOpts = ComposeActionsStartOpts & {
topic: string;
private_message_recipient: string;
trigger: string;
};
type ComposeHook = () => void;
const compose_clear_box_hooks: ComposeHook[] = [];
const compose_cancel_hooks: ComposeHook[] = [];
export function register_compose_box_clear_hook(hook: ComposeHook): void {
compose_clear_box_hooks.push(hook);
}
export function register_compose_cancel_hook(hook) {
export function register_compose_cancel_hook(hook: ComposeHook): void {
compose_cancel_hooks.push(hook);
}
function call_hooks(hooks) {
function call_hooks(hooks: ComposeHook[]): void {
for (const f of hooks) {
f();
}
}
export function blur_compose_inputs() {
export function blur_compose_inputs(): void {
$(".message_comp").find("input, textarea, button, #private_message_recipient").trigger("blur");
}
function hide_box() {
function hide_box(): void {
// This is the main hook for saving drafts when closing the compose box.
drafts.update_draft();
blur_compose_inputs();
@ -58,19 +85,34 @@ function hide_box() {
$("#compose_controls").show();
}
function show_compose_box(opts) {
compose_recipient.update_compose_for_message_type(opts);
function show_compose_box(opts: ComposeActionsOpts): void {
let opts_by_message_type: ComposeTriggeredOptions;
if (opts.message_type === "private") {
opts_by_message_type = {
trigger: opts.trigger,
message_type: "private",
private_message_recipient: opts.private_message_recipient,
};
} else {
opts_by_message_type = {
trigger: opts.trigger,
message_type: "stream",
stream_id: opts.stream_id,
topic: opts.topic,
};
}
compose_recipient.update_compose_for_message_type(opts_by_message_type);
$("#compose").css({visibility: "visible"});
// When changing this, edit the 42px in _maybe_autoscroll
$(".new_message_textarea").css("min-height", "3em");
compose_ui.set_focus(opts);
compose_ui.set_focus(opts_by_message_type);
}
export function clear_textarea() {
export function clear_textarea(): void {
$("#compose").find("input[type=text], textarea").val("");
}
function clear_box() {
function clear_box(): void {
call_hooks(compose_clear_box_hooks);
// TODO: Better encapsulate at-mention warnings.
@ -90,8 +132,8 @@ function clear_box() {
$(".compose_control_button_container:has(.add-poll)").removeClass("disabled-on-hover");
}
let autosize_callback_opts;
export function autosize_message_content(opts) {
let autosize_callback_opts: ComposeActionsStartOpts;
export function autosize_message_content(opts: ComposeActionsStartOpts): void {
if (!compose_ui.is_full_size()) {
autosize_callback_opts = opts;
$("textarea#compose-textarea")
@ -103,14 +145,14 @@ export function autosize_message_content(opts) {
}
}
export function expand_compose_box() {
export function expand_compose_box(): void {
$("#compose_close").attr("data-tooltip-template-id", "compose_close_tooltip_template");
$("#compose_close").show();
$("#compose_controls").hide();
$(".message_comp").show();
}
export function complete_starting_tasks(opts) {
export function complete_starting_tasks(opts: ComposeActionsOpts): void {
// This is sort of a kitchen sink function, and it's called only
// by compose.start() for now. Having this as a separate function
// makes testing a bit easier.
@ -122,7 +164,7 @@ export function complete_starting_tasks(opts) {
compose_recipient.update_narrow_to_recipient_visibility();
}
export function maybe_scroll_up_selected_message(opts) {
export function maybe_scroll_up_selected_message(opts: ComposeActionsStartOpts): void {
if (opts.skip_scrolling_selected_message) {
return;
}
@ -140,7 +182,7 @@ export function maybe_scroll_up_selected_message(opts) {
}
const $selected_row = message_lists.current.selected_row();
if ($selected_row.height() > message_viewport.height() - 100) {
if ($selected_row.height()! > message_viewport.height() - 100) {
// For very tall messages whose height is close to the entire
// height of the viewport, don't auto-scroll the viewport to
// the end of the message (since that makes it feel annoying
@ -155,7 +197,9 @@ export function maybe_scroll_up_selected_message(opts) {
}
}
export function fill_in_opts_from_current_narrowed_view(opts) {
export function fill_in_opts_from_current_narrowed_view(
opts: ComposeActionsStartOpts,
): ComposeActionsOpts {
return {
stream_id: undefined,
topic: "",
@ -171,7 +215,7 @@ export function fill_in_opts_from_current_narrowed_view(opts) {
};
}
function same_recipient_as_before(opts) {
function same_recipient_as_before(opts: ComposeActionsOpts): boolean {
return (
compose_state.get_message_type() === opts.message_type &&
((opts.message_type === "stream" &&
@ -182,23 +226,23 @@ function same_recipient_as_before(opts) {
);
}
export function start(opts) {
export function start(raw_opts: ComposeActionsStartOpts): void {
if (page_params.is_spectator) {
spectators.login_to_access();
return;
}
if (!opts.message_type) {
if (!raw_opts.message_type) {
// We prefer callers to be explicit about the message type, but
// we if we don't know, we open a stream compose box by default,
// which opens stream selection dropdown.
// Also, message_type is used to check if compose box is open in compose_state.composing().
opts.message_type = "stream";
raw_opts.message_type = "stream";
blueslip.warn("Empty message type in compose.start");
}
popovers.hide_all();
autosize_message_content(opts);
autosize_message_content(raw_opts);
if (reload_state.is_in_progress()) {
return;
@ -206,7 +250,7 @@ export function start(opts) {
compose_banner.clear_message_sent_banners();
expand_compose_box();
opts = fill_in_opts_from_current_narrowed_view(opts);
const opts = fill_in_opts_from_current_narrowed_view(raw_opts);
const is_clear_topic_button_triggered = opts.trigger === "clear topic button";
// If we are invoked by a compose hotkey (c or x) or new topic
@ -306,7 +350,7 @@ export function start(opts) {
complete_starting_tasks(opts);
}
export function cancel() {
export function cancel(): void {
// As user closes the compose box, restore the compose box max height
if (compose_ui.is_full_size()) {
compose_ui.make_compose_box_original_size();
@ -335,7 +379,7 @@ export function cancel() {
$(document).trigger("compose_canceled.zulip");
}
export function on_show_navigation_view() {
export function on_show_navigation_view(): void {
/* This function dictates the behavior of the compose box
* when navigating to a view, as opposed to a narrow. */
@ -353,7 +397,7 @@ export function on_show_navigation_view() {
cancel();
}
export function on_topic_narrow() {
export function on_topic_narrow(): void {
if (!compose_state.composing()) {
// If our compose box is closed, then just
// leave it closed, assuming that the user is
@ -403,7 +447,14 @@ export function on_topic_narrow() {
$("textarea#compose-textarea").trigger("focus");
}
export function on_narrow(opts) {
// TODO/typescript: Fill this in when converting narrow.js to typescripot.
type NarrowActivateOpts = {
trigger?: string;
force_close?: boolean;
private_message_recipient?: string;
};
export function on_narrow(opts: NarrowActivateOpts): void {
// We use force_close when jumping between direct message narrows with
// the "p" key, so that we don't have an open compose box that makes
// it difficult to cycle quickly through unread messages.
@ -449,7 +500,7 @@ export function on_narrow(opts) {
opts.private_message_recipient
) {
const emails = opts.private_message_recipient.split(",");
if (emails.length !== 1 || !people.get_by_email(emails[0]).is_bot) {
if (emails.length !== 1 || !people.get_by_email(emails[0])!.is_bot) {
// If we are navigating between direct message conversations,
// we want the compose box to close for non-bot users.
if (compose_state.composing()) {

View File

@ -32,7 +32,7 @@ export function get_recipient_label(message) {
};
} else if (narrow_state.pm_ids_string()) {
// TODO: This is a total hack. Ideally, we'd rework
// this to not duplicate the actual compose_actions.js
// this to not duplicate the actual compose_actions.ts
// logic for what happens when you click the button,
// and not call into random modules with hacky fake
// "message" objects.