From 1818ce1e470ae7b91be60334e6cacbcaaa5af1b3 Mon Sep 17 00:00:00 2001 From: Evy Kassirer Date: Thu, 11 Sep 2025 15:31:39 -0700 Subject: [PATCH] compose_send_menu_popover: Convert module to typescript. --- tools/test-js-with-node | 2 +- ...opover.js => compose_send_menu_popover.ts} | 64 +++++++++++-------- web/src/compose_setup.js | 2 +- web/src/hotkey.js | 2 +- web/src/popover_menus.ts | 4 +- web/src/ui_init.js | 2 +- 6 files changed, 43 insertions(+), 33 deletions(-) rename web/src/{compose_send_menu_popover.js => compose_send_menu_popover.ts} (86%) diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 2717695a31..d524f9dfc4 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -79,7 +79,7 @@ EXEMPT_FILES = make_set( "web/src/compose_paste.ts", "web/src/compose_recipient.ts", "web/src/compose_reply.ts", - "web/src/compose_send_menu_popover.js", + "web/src/compose_send_menu_popover.ts", "web/src/compose_setup.js", "web/src/compose_state.ts", "web/src/compose_textarea.ts", diff --git a/web/src/compose_send_menu_popover.js b/web/src/compose_send_menu_popover.ts similarity index 86% rename from web/src/compose_send_menu_popover.js rename to web/src/compose_send_menu_popover.ts index 079454fd09..82550b499c 100644 --- a/web/src/compose_send_menu_popover.js +++ b/web/src/compose_send_menu_popover.ts @@ -1,4 +1,5 @@ import $ from "jquery"; +import assert from "minimalistic-assert"; import * as tippy from "tippy.js"; import render_schedule_message_popover from "../templates/popovers/schedule_message_popover.hbs"; @@ -16,25 +17,27 @@ import * as popover_menus from "./popover_menus.ts"; import * as scheduled_messages from "./scheduled_messages.ts"; import {parse_html} from "./ui_util.ts"; import {user_settings} from "./user_settings.ts"; +import * as util from "./util.ts"; export const SCHEDULING_MODAL_UPDATE_INTERVAL_IN_MILLISECONDS = 60 * 1000; const ENTER_SENDS_SELECTION_DELAY = 600; let send_later_popover_keyboard_toggle = false; -function set_compose_box_schedule(element) { - const selected_send_at_time = element.dataset.sendStamp / 1000; +function set_compose_box_schedule(element: HTMLElement): number { + assert(element.dataset.sendStamp !== undefined); + const selected_send_at_time = Number.parseInt(element.dataset.sendStamp, 10) / 1000; return selected_send_at_time; } export function open_schedule_message_menu( - remind_message_id = undefined, - target = "#send_later i", -) { + remind_message_id: number | undefined = undefined, + target: tippy.ReferenceElement = util.the($("#send_later i")), +): void { if (remind_message_id === undefined && !compose_validate.validate(true)) { return; } - let interval; + let interval: ReturnType; popover_menus.toggle_popover_menu(target, { theme: "popover-menu", @@ -79,12 +82,12 @@ export function open_schedule_message_menu( ); } const $popper = $(instance.popper); - const message_schedule_callback = (time) => { + const message_schedule_callback = (time: string | number): void => { if (remind_message_id !== undefined) { do_schedule_reminder( time, remind_message_id, - $popper.find(".schedule-reminder-note").val(), + $popper.find("textarea.schedule-reminder-note").val()!, ); } else { do_schedule_message(time); @@ -94,7 +97,7 @@ export function open_schedule_message_menu( const $send_later_options_content = $popper.find(".popover-menu-list"); const current_time = new Date(); flatpickr.show_flatpickr( - $(".send_later_custom")[0], + util.the($(".send_later_custom")), (send_at_time) => { message_schedule_callback(send_at_time); popover_menus.hide_current_popover_if_visible(instance); @@ -109,7 +112,7 @@ export function open_schedule_message_menu( // Return to normal state. $send_later_options_content.css("pointer-events", "all"); const selected_date = selectedDates[0]; - + assert(instance.config.minDate !== undefined); if (selected_date && selected_date < instance.config.minDate) { scheduled_messages.set_minimum_scheduled_message_delay_minutes_note( true, @@ -130,8 +133,8 @@ export function open_schedule_message_menu( $popper.one( "click", ".send_later_today, .send_later_tomorrow, .send_later_monday", - (e) => { - const send_at_time = set_compose_box_schedule(e.currentTarget); + function (this: HTMLElement, e) { + const send_at_time = set_compose_box_schedule(this); message_schedule_callback(send_at_time); e.preventDefault(); e.stopPropagation(); @@ -146,31 +149,35 @@ export function open_schedule_message_menu( } clearInterval(interval); instance.destroy(); - popover_menus.popover_instances.send_later_options = undefined; + popover_menus.popover_instances.send_later_options = null; }, }); } -function parse_sent_at_time(send_at_time) { - if (!Number.isInteger(send_at_time)) { +function parse_sent_at_time(send_at_time: string | number): number { + if (typeof send_at_time !== "number") { // Convert to timestamp if this is not a timestamp. return Math.floor(Date.parse(send_at_time) / 1000); } return send_at_time; } -export function do_schedule_message(send_at_time) { +export function do_schedule_message(send_at_time: string | number): void { send_at_time = parse_sent_at_time(send_at_time); scheduled_messages.set_selected_schedule_timestamp(send_at_time); compose.finish(true); } -export function do_schedule_reminder(send_at_time, remind_message_id, note_text) { +export function do_schedule_reminder( + send_at_time: string | number, + remind_message_id: number, + note_text: string, +): void { send_at_time = parse_sent_at_time(send_at_time); message_reminder.set_message_reminder(send_at_time, remind_message_id, note_text); } -function get_send_later_menu_items() { +function get_send_later_menu_items(): JQuery | undefined { const $send_later_options = $("#send_later_popover"); if ($send_later_options.length === 0) { blueslip.error("Trying to get menu items when schedule popover is closed."); @@ -180,19 +187,19 @@ function get_send_later_menu_items() { return $send_later_options.find("[tabindex='0']"); } -function focus_first_send_later_popover_item() { +function focus_first_send_later_popover_item(): void { // It is recommended to only call this when the user opens the menu with a hotkey. // Our popup menus act kind of funny when you mix keyboard and mouse. const $items = get_send_later_menu_items(); popover_menus.focus_first_popover_item($items); } -export function toggle() { +export function toggle(): void { send_later_popover_keyboard_toggle = true; $("#send_later i").trigger("click"); } -export function initialize() { +export function initialize(): void { tippy.delegate("body", { ...popover_menus.default_popover_props, theme: "popover-menu", @@ -228,20 +235,21 @@ export function initialize() { const $popper = $(instance.popper); $popper.one("click", ".send_later_selected_send_later_time", () => { const send_at_timestamp = scheduled_messages.get_selected_send_later_timestamp(); + assert(send_at_timestamp !== undefined); do_schedule_message(send_at_timestamp); popover_menus.hide_current_popover_if_visible(instance); }); // Handle clicks on Enter-to-send settings $popper.one("click", ".enter_sends_choice", (e) => { - let selected_behaviour = $(e.currentTarget) + const selected_behaviour = $(e.currentTarget) .find("input[type='radio']") .attr("value"); - selected_behaviour = selected_behaviour === "true"; // Convert to bool - user_settings.enter_sends = selected_behaviour; + const selected_behaviour_bool = selected_behaviour === "true"; + user_settings.enter_sends = selected_behaviour_bool; channel.patch({ url: "/json/settings", - data: {enter_sends: selected_behaviour}, + data: {enter_sends: selected_behaviour_bool}, }); e.stopPropagation(); setTimeout(() => { @@ -273,14 +281,14 @@ export function initialize() { }, onHidden(instance) { instance.destroy(); - popover_menus.popover_instances.send_later = undefined; + popover_menus.popover_instances.send_later = null; send_later_popover_keyboard_toggle = false; }, }); } // This function is exported for unit testing purposes. -export function should_update_send_later_options(date) { +export function should_update_send_later_options(date: Date): boolean { const current_minute = date.getMinutes(); const current_hour = date.getHours(); @@ -295,7 +303,7 @@ export function should_update_send_later_options(date) { return current_minute === 60 - scheduled_messages.MINIMUM_SCHEDULED_MESSAGE_DELAY_SECONDS / 60; } -export function update_send_later_options() { +export function update_send_later_options(): void { const now = new Date(); if (should_update_send_later_options(now)) { const filtered_send_opts = scheduled_messages.get_filtered_send_opts(now); diff --git a/web/src/compose_setup.js b/web/src/compose_setup.js index cb68723f54..25d1c38e95 100644 --- a/web/src/compose_setup.js +++ b/web/src/compose_setup.js @@ -13,7 +13,7 @@ import * as compose_call_ui from "./compose_call_ui.ts"; import * as compose_fade from "./compose_fade.ts"; import * as compose_notifications from "./compose_notifications.ts"; import * as compose_recipient from "./compose_recipient.ts"; -import * as compose_send_menu_popover from "./compose_send_menu_popover.js"; +import * as compose_send_menu_popover from "./compose_send_menu_popover.ts"; import * as compose_state from "./compose_state.ts"; import * as compose_ui from "./compose_ui.ts"; import * as compose_validate from "./compose_validate.ts"; diff --git a/web/src/hotkey.js b/web/src/hotkey.js index c4d643affb..9e14ab3f99 100644 --- a/web/src/hotkey.js +++ b/web/src/hotkey.js @@ -11,7 +11,7 @@ import * as compose_actions from "./compose_actions.ts"; import * as compose_banner from "./compose_banner.ts"; import * as compose_recipient from "./compose_recipient.ts"; import * as compose_reply from "./compose_reply.ts"; -import * as compose_send_menu_popover from "./compose_send_menu_popover.js"; +import * as compose_send_menu_popover from "./compose_send_menu_popover.ts"; import * as compose_state from "./compose_state.ts"; import * as compose_textarea from "./compose_textarea.ts"; import * as condense from "./condense.ts"; diff --git a/web/src/popover_menus.ts b/web/src/popover_menus.ts index 1732df02f4..bdaa03968b 100644 --- a/web/src/popover_menus.ts +++ b/web/src/popover_menus.ts @@ -33,7 +33,8 @@ type PopoverName = | "buddy_list" | "stream_actions_popover" | "color_picker_popover" - | "show_channels_sidebar"; + | "show_channels_sidebar" + | "send_later_options"; export const popover_instances: Record = { compose_control_buttons: null, @@ -56,6 +57,7 @@ export const popover_instances: Record = { stream_actions_popover: null, color_picker_popover: null, show_channels_sidebar: null, + send_later_options: null, }; // Font size in em for popover derived from popover font size being diff --git a/web/src/ui_init.js b/web/src/ui_init.js index cc158bcbcc..3a92488620 100644 --- a/web/src/ui_init.js +++ b/web/src/ui_init.js @@ -33,7 +33,7 @@ import * as compose_paste from "./compose_paste.ts"; import * as compose_pm_pill from "./compose_pm_pill.ts"; import * as compose_recipient from "./compose_recipient.ts"; import * as compose_reply from "./compose_reply.ts"; -import * as compose_send_menu_popover from "./compose_send_menu_popover.js"; +import * as compose_send_menu_popover from "./compose_send_menu_popover.ts"; import * as compose_setup from "./compose_setup.js"; import * as compose_textarea from "./compose_textarea.ts"; import * as compose_tooltips from "./compose_tooltips.ts";