modals: Convert schedule message modal to popover.

Fixes: #35003
This commit is contained in:
Maneesh Shukla
2025-06-24 20:42:37 +05:30
committed by Tim Abbott
parent 3d3f7b3782
commit 3b874c3dfa
10 changed files with 118 additions and 130 deletions

View File

@@ -1,9 +1,8 @@
import $ from "jquery";
import * as tippy from "tippy.js";
import render_schedule_message_popover from "../templates/popovers/schedule_message_popover.hbs";
import render_send_later_popover from "../templates/popovers/send_later_popover.hbs";
import render_send_later_modal from "../templates/send_later_modal.hbs";
import render_send_later_modal_options from "../templates/send_later_modal_options.hbs";
import * as blueslip from "./blueslip.ts";
import * as channel from "./channel.ts";
@@ -13,7 +12,6 @@ import * as compose_validate from "./compose_validate.ts";
import * as drafts from "./drafts.ts";
import * as flatpickr from "./flatpickr.ts";
import * as message_reminder from "./message_reminder.ts";
import * as modals from "./modals.ts";
import * as popover_menus from "./popover_menus.ts";
import * as scheduled_messages from "./scheduled_messages.ts";
import {parse_html} from "./ui_util.ts";
@@ -29,22 +27,13 @@ function set_compose_box_schedule(element) {
return selected_send_at_time;
}
export function open_send_later_menu(remind_message_id = undefined) {
export function open_schedule_message_menu(
remind_message_id = undefined,
target = "#send_later i",
) {
if (remind_message_id === undefined && !compose_validate.validate(true)) {
return;
}
// Only show send later options that are possible today.
const date = new Date();
const filtered_send_opts = scheduled_messages.get_filtered_send_opts(date);
$("body").append(
$(
render_send_later_modal({
...filtered_send_opts,
is_reminder: remind_message_id !== undefined,
}),
),
);
let interval;
const message_schedule_callback = (time) => {
if (remind_message_id !== undefined) {
@@ -54,35 +43,50 @@ export function open_send_later_menu(remind_message_id = undefined) {
}
};
modals.open("send_later_modal", {
autoremove: true,
on_show() {
popover_menus.toggle_popover_menu(target, {
theme: "popover-menu",
placement: remind_message_id !== undefined ? "bottom" : "top",
popperOptions: {
modifiers: [
{
name: "flip",
options: {
fallbackPlacements:
remind_message_id !== undefined ? ["top", "left"] : ["bottom", "left"],
},
},
],
},
onShow(instance) {
// Only show send later options that are possible today.
const date = new Date();
const filtered_send_opts = scheduled_messages.get_filtered_send_opts(date);
instance.setContent(
parse_html(
render_schedule_message_popover({
...filtered_send_opts,
is_reminder: remind_message_id !== undefined,
}),
),
);
popover_menus.popover_instances.send_later_options = instance;
interval = setInterval(
update_send_later_options,
SCHEDULING_MODAL_UPDATE_INTERVAL_IN_MILLISECONDS,
);
const $send_later_modal = $("#send_later_modal");
// Upon the first keydown event, we focus on the first element in the list,
// enabling keyboard navigation that is handled by `hotkey.js` and `list_util.ts`.
$send_later_modal.one("keydown", () => {
const $options = $send_later_modal.find("a");
$options[0].focus();
$send_later_modal.on("keydown", (e) => {
if (e.key === "Enter") {
e.target.click();
}
});
});
$send_later_modal.on("click", ".send_later_custom", (e) => {
const $send_later_modal_content = $send_later_modal.find(".modal__content");
},
onMount(instance) {
const $popper = $(instance.popper);
$popper.on("click", ".send_later_custom", (e) => {
const $send_later_options_content = $popper.find(".popover-menu-list");
const current_time = new Date();
flatpickr.show_flatpickr(
$(".send_later_custom")[0],
message_schedule_callback,
(send_at_time) => {
message_schedule_callback(send_at_time);
popover_menus.hide_current_popover_if_visible(instance);
},
new Date(current_time.getTime() + 60 * 60 * 1000),
{
minDate: new Date(
@@ -91,7 +95,7 @@ export function open_send_later_menu(remind_message_id = undefined) {
),
onClose(selectedDates, _dateStr, instance) {
// Return to normal state.
$send_later_modal_content.css("pointer-events", "all");
$send_later_options_content.css("pointer-events", "all");
const selected_date = selectedDates[0];
if (selected_date && selected_date < instance.config.minDate) {
@@ -106,12 +110,12 @@ export function open_send_later_menu(remind_message_id = undefined) {
},
},
);
// Disable interaction with rest of the options in the modal.
$send_later_modal_content.css("pointer-events", "none");
// Disable interaction with rest of the options in the popover.
$send_later_options_content.css("pointer-events", "none");
e.preventDefault();
e.stopPropagation();
});
$send_later_modal.one(
$popper.one(
"click",
".send_later_today, .send_later_tomorrow, .send_later_monday",
(e) => {
@@ -119,16 +123,14 @@ export function open_send_later_menu(remind_message_id = undefined) {
message_schedule_callback(send_at_time);
e.preventDefault();
e.stopPropagation();
popover_menus.hide_current_popover_if_visible(instance);
},
);
},
on_shown() {
// When shown, we should give the modal focus to correctly handle keyboard events.
const $send_later_modal_overlay = $("#send_later_modal .modal__overlay");
$send_later_modal_overlay.trigger("focus");
},
on_hide() {
onHidden(instance) {
clearInterval(interval);
instance.destroy();
popover_menus.popover_instances.send_later_options = undefined;
},
});
}
@@ -142,14 +144,12 @@ function parse_sent_at_time(send_at_time) {
}
export function do_schedule_message(send_at_time) {
modals.close_if_open("send_later_modal");
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) {
modals.close_if_open("send_later_modal");
send_at_time = parse_sent_at_time(send_at_time);
message_reminder.set_message_reminder(send_at_time, remind_message_id);
}
@@ -237,8 +237,8 @@ export function initialize() {
});
// Handle Send later clicks
$popper.one("click", ".open_send_later_modal", () => {
open_send_later_menu();
popover_menus.hide_current_popover_if_visible(instance);
open_schedule_message_menu();
});
$popper.one("click", ".compose_new_message", () => {
drafts.update_draft();
@@ -283,8 +283,8 @@ export function update_send_later_options() {
const now = new Date();
if (should_update_send_later_options(now)) {
const filtered_send_opts = scheduled_messages.get_filtered_send_opts(now);
$("#send_later_options").replaceWith(
$(render_send_later_modal_options(filtered_send_opts)),
$("#send-later-options").replaceWith(
$(render_schedule_message_popover(filtered_send_opts)),
);
}
}

View File

@@ -137,9 +137,9 @@ export function initialize() {
if (is_edit_input) {
message_edit.save_message_row_edit($row);
} else if (event.target.dataset.validationTrigger === "schedule") {
compose_send_menu_popover.open_send_later_menu();
compose_send_menu_popover.open_schedule_message_menu();
// We need to set this flag to true here because `open_send_later_menu` validates the message and sets
// We need to set this flag to true here because `open_schedule_message_menu` validates the message and sets
// the user acknowledged wildcard flag back to 'false' and we don't want that to happen because then it
// would again show the wildcard warning banner when we actually send the message from 'send-later' modal.
compose_validate.set_user_acknowledged_stream_wildcard_flag(true);

View File

@@ -6,7 +6,6 @@ const list_selectors = [
"#buddy-list-users-matching-view",
"#buddy-list-other-users",
"#buddy-list-participants",
"#send_later_options",
];
export function inside_list(e: JQuery.KeyDownEvent): boolean {

View File

@@ -1,5 +1,6 @@
import $ from "jquery";
import assert from "minimalistic-assert";
import type * as tippy from "tippy.js";
import render_message_actions_popover from "../templates/popovers/message_actions_popover.hbs";
@@ -67,7 +68,10 @@ export function toggle_message_actions_menu(message: Message): boolean {
export function initialize({
message_reminder_click_handler,
}: {
message_reminder_click_handler: (remind_message_id: number) => void;
message_reminder_click_handler: (
remind_message_id: number,
target: tippy.ReferenceElement,
) => void;
}): void {
popover_menus.register_popover_menu(".actions_hover .message-actions-menu-button", {
theme: "popover-menu",
@@ -147,10 +151,10 @@ export function initialize({
$popper.one("click", ".message-reminder", (e) => {
const remind_message_id = Number($(e.currentTarget).attr("data-message-id"));
message_reminder_click_handler(remind_message_id);
popover_menus.hide_current_popover_if_visible(instance);
message_reminder_click_handler(remind_message_id, instance.reference);
e.preventDefault();
e.stopPropagation();
popover_menus.hide_current_popover_if_visible(instance);
});
$popper.one("click", ".popover_move_message", (e) => {

View File

@@ -457,8 +457,8 @@ export async function initialize_everything(state_data) {
left_sidebar_navigation_area_popovers.initialize();
user_topic_popover.initialize();
topic_popover.initialize();
const message_reminder_click_handler = (remind_message_id) => {
compose_send_menu_popover.open_send_later_menu(remind_message_id);
const message_reminder_click_handler = (remind_message_id, target) => {
compose_send_menu_popover.open_schedule_message_menu(remind_message_id, target);
};
message_actions_popover.initialize({message_reminder_click_handler});
compose_send_menu_popover.initialize();

View File

@@ -647,24 +647,6 @@
margin-bottom: 20px;
}
#send_later_options {
.send_later_list {
margin: 0;
list-style: none;
.send_later_option {
display: flex;
padding: 3px 15px;
&:focus,
&:hover {
text-decoration: none;
background-color: hsl(0deg 0% 0% / 20%);
}
}
}
}
.dialog-widget-footer-minor-text {
font-size: smaller;
font-style: italic;

View File

@@ -256,6 +256,13 @@
}
}
.popover-header-name {
font-weight: 600;
color: var(--color-text-popover-menu);
line-height: 1.1;
margin-top: 4px;
}
.popover-group-menu-info {
display: flex;
flex-direction: column;
@@ -974,12 +981,6 @@ ul.popover-group-menu-member-list {
}
}
#send_later_modal {
.modal__content {
padding-bottom: 16px;
}
}
.visibility-policy-popover {
.popover-menu-list {
padding: 2px;

View File

@@ -0,0 +1,47 @@
<div class="popover-menu" id="send-later-options" data-simplebar data-simplebar-tab-index="-1">
<ul role="menu" class="popover-menu-list">
<li role="none" class="text-item popover-menu-list-item">
<span class="popover-header-name">
{{#if is_reminder}}
{{t "Schedule reminder" }}
{{else}}
{{t "Schedule message" }}
{{/if}}
</span>
</li>
{{#if possible_send_later_today}}
<li role="separator" class="popover-menu-separator"></li>
{{#each possible_send_later_today}}
<li role="none" class="link-item popover-menu-list-item">
<a role="menuitem" id="{{@key}}" class="send_later_today send_later_option popover-menu-link" data-send-stamp="{{this.stamp}}" tabindex="0">
<span class="popover-menu-label">{{this.text}}</span>
</a>
</li>
{{/each}}
{{/if}}
<li role="separator" class="popover-menu-separator"></li>
{{#each send_later_tomorrow}}
<li role="none" class="link-item popover-menu-list-item">
<a role="menuitem" id="{{@key}}" class="send_later_tomorrow send_later_option popover-menu-link" data-send-stamp="{{this.stamp}}" tabindex="0">
<span class="popover-menu-label">{{this.text}}</span>
</a>
</li>
{{/each}}
{{#if possible_send_later_monday}}
<li role="separator" class="popover-menu-separator"></li>
{{#each possible_send_later_monday}}
<li role="none" class="link-item popover-menu-list-item">
<a role="menuitem" id="{{@key}}" class="send_later_monday send_later_option popover-menu-link" data-send-stamp="{{this.stamp}}" tabindex="0">
<span class="popover-menu-label">{{this.text}}</span>
</a>
</li>
{{/each}}
{{/if}}
<li role="separator" class="popover-menu-separator"></li>
<li role="none" class="link-item popover-menu-list-item">
<a role="menuitem" class="send_later_custom send_later_option popover-menu-link" tabindex="0">
<span class="popover-menu-label">{{t 'Custom time'}}</span>
</a>
</li>
</ul>
</div>

View File

@@ -1,19 +0,0 @@
<div class="micromodal" id="send_later_modal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1">
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="send_later_modal_label">
<header class="modal__header">
<h1 class="modal__title" id="send_later_modal_label">
{{#if is_reminder}}
{{t "Schedule reminder" }}
{{else}}
{{t "Schedule message" }}
{{/if}}
</h1>
<button class="modal__close" aria-label="{{t 'Close modal' }}" data-micromodal-close></button>
</header>
<main class="modal__content">
{{> send_later_modal_options . }}
</main>
</div>
</div>
</div>

View File

@@ -1,26 +0,0 @@
<div id="send_later_options">
<ul class="send_later_list">
{{#if possible_send_later_today}}
{{#each possible_send_later_today}}
<li>
<a id="{{@key}}" class="send_later_today send_later_option" data-send-stamp="{{this.stamp}}" tabindex="0">{{this.text}}</a>
</li>
{{/each}}
{{/if}}
{{#each send_later_tomorrow}}
<li>
<a id="{{@key}}" class="send_later_tomorrow send_later_option" data-send-stamp="{{this.stamp}}" tabindex="0">{{this.text}}</a>
</li>
{{/each}}
{{#if possible_send_later_monday }}
{{#each possible_send_later_monday}}
<li>
<a id="{{@key}}" class="send_later_monday send_later_option" data-send-stamp="{{this.stamp}}" tabindex="0">{{this.text}}</a>
</li>
{{/each}}
{{/if}}
<li>
<a class="send_later_custom send_later_option" tabindex="0">{{t 'Custom time'}}</a>
</li>
</ul>
</div>