diff --git a/frontend_tests/node_tests/hotkey.js b/frontend_tests/node_tests/hotkey.js index 1d0b81247a..e441e3b0d4 100644 --- a/frontend_tests/node_tests/hotkey.js +++ b/frontend_tests/node_tests/hotkey.js @@ -59,12 +59,14 @@ const overlays = mock_esm("../../static/js/overlays", { is_overlay_or_modal_open: () => overlays.is_modal_open() || overlays.is_active(), }); const popovers = mock_esm("../../static/js/popovers", { - actions_popped: () => false, user_info_manage_menu_popped: () => false, message_info_popped: () => false, user_sidebar_popped: () => false, user_info_popped: () => false, }); +const popover_menus = mock_esm("../../static/js/popover_menus", { + actions_popped: () => false, +}); const reactions = mock_esm("../../static/js/reactions"); const search = mock_esm("../../static/js/search"); const settings_data = mock_esm("../../static/js/settings_data"); @@ -366,7 +368,7 @@ run_test("misc", ({override}) => { assert_mapping("s", narrow, "by_recipient"); assert_mapping("S", narrow, "by_topic"); assert_mapping("u", popovers, "show_sender_info"); - assert_mapping("i", popovers, "open_message_menu"); + assert_mapping("i", popover_menus, "toggle_message_actions_menu"); assert_mapping(":", reactions, "open_reactions_popover", true); assert_mapping(">", compose_actions, "quote_and_reply"); assert_mapping("e", message_edit, "start"); diff --git a/frontend_tests/node_tests/popovers.js b/frontend_tests/node_tests/popovers.js index af724ac432..5119bf49d9 100644 --- a/frontend_tests/node_tests/popovers.js +++ b/frontend_tests/node_tests/popovers.js @@ -29,9 +29,6 @@ const message_lists = mock_esm("../../static/js/message_lists", { }, }, }); -mock_esm("../../static/js/message_viewport", { - height: () => 500, -}); mock_esm("../../static/js/stream_popover", { hide_stream_popover: noop, hide_topic_popover: noop, @@ -43,7 +40,6 @@ mock_esm("../../static/js/stream_popover", { const people = zrequire("people"); const user_status = zrequire("user_status"); -const message_edit = zrequire("message_edit"); const popovers = zrequire("popovers"); const alice = { @@ -218,54 +214,3 @@ test_ui("sender_hover", ({override, mock_template}) => { // todo: load image }); - -test_ui("actions_popover", ({override, mock_template}) => { - override($.fn, "popover", noop); - - const $target = $.create("click target"); - - const handler = $("#main_div").get_on_handler("click", ".actions_hover"); - - const message = { - id: 999, - topic: "Actions (1)", - type: "stream", - stream_id: 123, - sent_by_me: true, - }; - - message_lists.current.get = (msg_id) => { - assert.equal(msg_id, message.id); - return message; - }; - - message_lists.current.view.message_containers.get = (msg_id) => { - assert.equal(msg_id, message.id); - return { - is_hidden: false, - }; - }; - - override(page_params, "realm_allow_message_editing", true); - override(page_params, "realm_message_content_edit_limit_seconds", null); - assert.equal(message_edit.get_editability(message), message_edit.editability_types.FULL); - - $target.closest = (sel) => { - assert.equal(sel, ".message_row"); - return { - toggleClass: noop, - }; - }; - - mock_template("actions_popover_template.hbs", false, () => "actions-template"); - mock_template("actions_popover_content.hbs", false, (opts) => { - // TODO: Test all the properties of the popover - assert.equal( - opts.conversation_time_uri, - "http://zulip.zulipdev.com/#narrow/stream/123-unknown/topic/Actions.20.281.29/near/999", - ); - return "actions-content"; - }); - - handler.call($target, e); -}); diff --git a/static/js/click_handlers.js b/static/js/click_handlers.js index af53c3e6eb..eb4f0ca532 100644 --- a/static/js/click_handlers.js +++ b/static/js/click_handlers.js @@ -242,11 +242,6 @@ export function initialize() { }); $("body").on("click", ".reveal_hidden_message", (e) => { - // Hide actions popover to keep its options - // in sync with revealed/hidden state of - // muted user's message. - popovers.hide_actions_popover(); - const message_id = rows.id($(e.currentTarget).closest(".message_row")); message_lists.current.view.reveal_hidden_message(message_id); e.stopPropagation(); diff --git a/static/js/emoji_picker.js b/static/js/emoji_picker.js index ea6f5ac287..216fcf4c11 100644 --- a/static/js/emoji_picker.js +++ b/static/js/emoji_picker.js @@ -666,7 +666,7 @@ export function build_emoji_popover($elt, id) { register_popover_events($popover); } -export function toggle_emoji_popover(element, id) { +export function toggle_emoji_popover(element, id, coming_from_actions_popover) { const $last_popover_elem = $current_message_emoji_popover_elem; popovers.hide_all(); if ($last_popover_elem !== undefined && $last_popover_elem.get()[0] === element) { @@ -683,7 +683,7 @@ export function toggle_emoji_popover(element, id) { if (user_status_ui.user_status_picker_open()) { build_emoji_popover($elt, id, true); - } else if ($elt.data("popover") === undefined) { + } else if ($elt.data("popover") === undefined || coming_from_actions_popover) { // Keep the element over which the popover is based off visible. $elt.addClass("reaction_button_visible"); build_emoji_popover($elt, id); @@ -748,19 +748,6 @@ export function register_click_handlers() { toggle_emoji_popover(this, message_id); }); - $("body").on("click", ".actions_popover .reaction_button", (e) => { - const message_id = $(e.currentTarget).data("message-id"); - e.preventDefault(); - e.stopPropagation(); - // HACK: Because we need the popover to be based off an - // element that definitely exists in the page even if the - // message wasn't sent by us and thus the .reaction_hover - // element is not present, we use the message's - // .fa-chevron-down element as the base for the popover. - const elem = $(".selected_message .actions_hover")[0]; - toggle_emoji_popover(elem, message_id); - }); - $("body").on("click", ".emoji-popover-tab-item", function (e) { e.stopPropagation(); e.preventDefault(); diff --git a/static/js/hotkey.js b/static/js/hotkey.js index 38257a5799..d02dc3c3f5 100644 --- a/static/js/hotkey.js +++ b/static/js/hotkey.js @@ -29,6 +29,7 @@ import * as narrow from "./narrow"; import * as navigate from "./navigate"; import * as overlays from "./overlays"; import {page_params} from "./page_params"; +import * as popover_menus from "./popover_menus"; import * as popovers from "./popovers"; import * as reactions from "./reactions"; import * as recent_topics_ui from "./recent_topics_ui"; @@ -351,7 +352,7 @@ export function process_escape_key(e) { } function handle_popover_events(event_name) { - if (popovers.actions_popped()) { + if (popover_menus.actions_popped()) { popovers.actions_menu_handle_keyboard(event_name); return true; } @@ -938,7 +939,7 @@ export function process_hotkey(e, hotkey) { // Shortcuts that operate on a message switch (event_name) { case "message_actions": - return popovers.open_message_menu(msg); + return popover_menus.toggle_message_actions_menu(msg); case "star_message": message_flags.toggle_starred_and_update_server(msg); return true; diff --git a/static/js/popover_menus.js b/static/js/popover_menus.js index 0854d8a1fe..0da6126faa 100644 --- a/static/js/popover_menus.js +++ b/static/js/popover_menus.js @@ -2,9 +2,11 @@ TippyJS/Popper popover library from the legacy Bootstrap popovers system in popovers.js. */ +import ClipboardJS from "clipboard"; import $ from "jquery"; import tippy, {delegate} from "tippy.js"; +import render_actions_popover_content from "../templates/actions_popover_content.hbs"; import render_compose_control_buttons_popover from "../templates/compose_control_buttons_popover.hbs"; import render_compose_select_enter_behaviour_popover from "../templates/compose_select_enter_behaviour_popover.hbs"; import render_left_sidebar_stream_setting_popover from "../templates/left_sidebar_stream_setting_popover.hbs"; @@ -13,17 +15,34 @@ import render_mobile_message_buttons_popover_content from "../templates/mobile_m import * as channel from "./channel"; import * as common from "./common"; import * as compose_actions from "./compose_actions"; +import * as condense from "./condense"; +import * as emoji_picker from "./emoji_picker"; import * as giphy from "./giphy"; +import {$t} from "./i18n"; +import * as message_edit from "./message_edit"; +import * as message_edit_history from "./message_edit_history"; +import * as message_lists from "./message_lists"; import * as narrow_state from "./narrow_state"; +import * as popover_menus_data from "./popover_menus_data"; import * as popovers from "./popovers"; +import * as read_receipts from "./read_receipts"; +import * as rows from "./rows"; import * as settings_data from "./settings_data"; +import * as stream_popover from "./stream_popover"; import {parse_html} from "./ui_util"; +import * as unread_ops from "./unread_ops"; import {user_settings} from "./user_settings"; let left_sidebar_stream_setting_popover_displayed = false; let compose_mobile_button_popover_displayed = false; export let compose_enter_sends_popover_displayed = false; let compose_control_buttons_popover_instance; +let message_actions_popover_displayed = false; +let message_actions_popover_keyboard_toggle = false; + +export function actions_popped() { + return message_actions_popover_displayed; +} export function get_compose_control_buttons_popover() { return compose_control_buttons_popover_instance; @@ -47,7 +66,8 @@ export function any_active() { left_sidebar_stream_setting_popover_displayed || compose_mobile_button_popover_displayed || compose_control_buttons_popover_instance || - compose_enter_sends_popover_displayed + compose_enter_sends_popover_displayed || + message_actions_popover_displayed ); } @@ -98,6 +118,20 @@ function tippy_no_propagation(target, popover_props) { }); } +export function toggle_message_actions_menu(message) { + if (message.locally_echoed) { + // Don't open the popup for locally echoed messages for now. + // It creates bugs with things like keyboard handlers when + // we get the server response. + return true; + } + + const $popover_reference = $(".selected_message .actions_hover .zulip-icon-ellipsis-v-solid"); + message_actions_popover_keyboard_toggle = true; + $popover_reference.trigger("click"); + return true; +} + export function initialize() { tippy_no_propagation("#streams_inline_icon", { onShow(instance) { @@ -228,4 +262,183 @@ export function initialize() { compose_enter_sends_popover_displayed = false; }, }); + + tippy_no_propagation(".actions_hover .zulip-icon-ellipsis-v-solid", { + // The is our minimum supported width for mobile. We shouldn't + // make the popover wider than this. + maxWidth: "320px", + placement: "bottom", + popperOptions: { + modifiers: [ + { + // The placement is set to bottom, but if that placement does not fit, + // the opposite top placement will be used. + name: "flip", + options: { + fallbackPlacements: ["top", "left"], + }, + }, + ], + }, + onShow(instance) { + on_show_prep(instance); + const $row = $(instance.reference).closest(".message_row"); + const message_id = rows.id($row); + message_lists.current.select_id(message_id); + const args = popover_menus_data.get_actions_popover_content_context(message_id); + instance.setContent(parse_html(render_actions_popover_content(args))); + $row.addClass("has_popover has_actions_popover"); + message_actions_popover_displayed = true; + }, + onMount(instance) { + if (message_actions_popover_keyboard_toggle) { + popovers.focus_first_action_popover_item(); + } + message_actions_popover_keyboard_toggle = false; + + // We want click events to propagate to `instance` so that + // instance.hide gets called. + const $popper = $(instance.popper); + $popper.one("click", ".respond_button", (e) => { + // Arguably, we should fetch the message ID to respond to from + // e.target, but that should always be the current selected + // message in the current message list (and + // compose_actions.respond_to_message doesn't take a message + // argument). + compose_actions.quote_and_reply({trigger: "popover respond"}); + e.preventDefault(); + e.stopPropagation(); + instance.hide(); + }); + + $popper.one("click", ".popover_edit_message, .popover_view_source", (e) => { + const message_id = $(e.currentTarget).data("message-id"); + const $row = message_lists.current.get_row(message_id); + message_edit.start($row); + e.preventDefault(); + e.stopPropagation(); + instance.hide(); + }); + + $popper.one("click", ".popover_move_message", (e) => { + const message_id = $(e.currentTarget).data("message-id"); + const message = message_lists.current.get(message_id); + stream_popover.build_move_topic_to_stream_popover( + message.stream_id, + message.topic, + message, + ); + e.preventDefault(); + e.stopPropagation(); + instance.hide(); + }); + + $popper.one("click", ".mark_as_unread", (e) => { + const message_id = $(e.currentTarget).data("message-id"); + unread_ops.mark_as_unread_from_here(message_id); + e.preventDefault(); + e.stopPropagation(); + instance.hide(); + }); + + $popper.one("click", ".popover_toggle_collapse", (e) => { + const message_id = $(e.currentTarget).data("message-id"); + const $row = message_lists.current.get_row(message_id); + const message = message_lists.current.get(rows.id($row)); + if ($row) { + if (message.collapsed) { + condense.uncollapse($row); + } else { + condense.collapse($row); + } + } + e.preventDefault(); + e.stopPropagation(); + instance.hide(); + }); + + $popper.one("click", ".rehide_muted_user_message", (e) => { + const message_id = $(e.currentTarget).data("message-id"); + const $row = message_lists.current.get_row(message_id); + const message = message_lists.current.get(rows.id($row)); + const message_container = message_lists.current.view.message_containers.get( + message.id, + ); + if ($row && !message_container.is_hidden) { + message_lists.current.view.hide_revealed_message(message_id); + } + e.preventDefault(); + e.stopPropagation(); + instance.hide(); + }); + + $popper.one("click", ".view_edit_history", (e) => { + const message_id = $(e.currentTarget).data("message-id"); + const $row = message_lists.current.get_row(message_id); + const message = message_lists.current.get(rows.id($row)); + message_edit_history.show_history(message); + $("#message-history-cancel").trigger("focus"); + e.preventDefault(); + e.stopPropagation(); + instance.hide(); + }); + + $popper.one("click", ".view_read_receipts", (e) => { + const message_id = $(e.currentTarget).data("message-id"); + read_receipts.show_user_list(message_id); + e.preventDefault(); + e.stopPropagation(); + instance.hide(); + }); + + $popper.one("click", ".delete_message", (e) => { + const message_id = $(e.currentTarget).data("message-id"); + message_edit.delete_message(message_id); + e.preventDefault(); + e.stopPropagation(); + instance.hide(); + }); + + $popper.one("click", ".reaction_button", (e) => { + const message_id = $(e.currentTarget).data("message-id"); + // Don't propagate the click event since `toggle_emoji_popover` opens a + // emoji_picker which we don't want to hide after actions popover is hidden. + e.stopPropagation(); + e.preventDefault(); + // HACK: Because we need the popover to be based off an + // element that definitely exists in the page even if the + // message wasn't sent by us and thus the .reaction_hover + // element is not present, we use the message's + // .fa-chevron-down element as the base for the popover. + const elem = $(".selected_message .actions_hover")[0]; + emoji_picker.toggle_emoji_popover(elem, message_id, true); + instance.hide(); + }); + + new ClipboardJS($popper.find(".copy_link")[0]).on("success", (e) => { + // e.trigger returns the DOM element triggering the copy action + const message_id = e.trigger.dataset.messageId; + const $row = $(`[zid='${CSS.escape(message_id)}']`); + $row.find(".alert-msg") + .text($t({defaultMessage: "Copied!"})) + .css("display", "block") + .delay(1000) + .fadeOut(300); + + setTimeout(() => { + // The Clipboard library works by focusing to a hidden textarea. + // We unfocus this so keyboard shortcuts, etc., will work again. + $(":focus").trigger("blur"); + }, 0); + instance.hide(); + }); + }, + onHidden(instance) { + const $row = $(instance.reference).closest(".message_row"); + $row.removeClass("has_popover has_actions_popover"); + instance.destroy(); + message_actions_popover_displayed = false; + message_actions_popover_keyboard_toggle = false; + }, + }); } diff --git a/static/js/popovers.js b/static/js/popovers.js index 594132d756..191c728bad 100644 --- a/static/js/popovers.js +++ b/static/js/popovers.js @@ -1,14 +1,10 @@ import ClipboardJS from "clipboard"; import {add, formatISO, parseISO, set} from "date-fns"; -import ConfirmDatePlugin from "flatpickr/dist/plugins/confirmDate/confirmDate"; import $ from "jquery"; import tippy, {hideAll} from "tippy.js"; -import render_actions_popover_content from "../templates/actions_popover_content.hbs"; -import render_actions_popover_template from "../templates/actions_popover_template.hbs"; import render_no_arrow_popover from "../templates/no_arrow_popover.hbs"; import render_playground_links_popover_content from "../templates/playground_links_popover_content.hbs"; -import render_remind_me_popover_content from "../templates/remind_me_popover_content.hbs"; import render_user_group_info_popover from "../templates/user_group_info_popover.hbs"; import render_user_group_info_popover_content from "../templates/user_group_info_popover_content.hbs"; import render_user_info_popover_content from "../templates/user_info_popover_content.hbs"; @@ -21,15 +17,11 @@ import * as channel from "./channel"; import * as compose_actions from "./compose_actions"; import * as compose_state from "./compose_state"; import * as compose_ui from "./compose_ui"; -import * as condense from "./condense"; -import {media_breakpoints_num} from "./css_variables"; import * as dialog_widget from "./dialog_widget"; import * as emoji_picker from "./emoji_picker"; import * as giphy from "./giphy"; import * as hash_util from "./hash_util"; import {$t, $t_html} from "./i18n"; -import * as message_edit from "./message_edit"; -import * as message_edit_history from "./message_edit_history"; import * as message_lists from "./message_lists"; import * as message_viewport from "./message_viewport"; import * as muted_users from "./muted_users"; @@ -39,8 +31,6 @@ import * as overlays from "./overlays"; import {page_params} from "./page_params"; import * as people from "./people"; import * as popover_menus from "./popover_menus"; -import * as popover_menus_data from "./popover_menus_data"; -import * as read_receipts from "./read_receipts"; import * as realm_playground from "./realm_playground"; import * as reminder from "./reminder"; import * as resize from "./resize"; @@ -51,7 +41,6 @@ import * as settings_data from "./settings_data"; import * as settings_users from "./settings_users"; import * as stream_popover from "./stream_popover"; import * as ui_report from "./ui_report"; -import * as unread_ops from "./unread_ops"; import * as user_groups from "./user_groups"; import * as user_profile from "./user_profile"; import {user_settings} from "./user_settings"; @@ -59,8 +48,6 @@ import * as user_status from "./user_status"; import * as user_status_ui from "./user_status_ui"; import * as util from "./util"; -let $current_actions_popover_elem; -let current_flatpickr_instance; let $current_message_info_popover_elem; let $current_user_info_popover_elem; let $current_user_info_popover_manage_menu; @@ -70,8 +57,6 @@ let userlist_placement = "right"; let list_of_popovers = []; export function clear_for_testing() { - $current_actions_popover_elem = undefined; - current_flatpickr_instance = undefined; $current_message_info_popover_elem = undefined; $current_user_info_popover_elem = undefined; $current_user_info_popover_manage_menu = undefined; @@ -519,55 +504,14 @@ function show_user_group_info_popover(element, group, message) { } } -export function toggle_actions_popover(element, id) { - const $last_popover_elem = $current_actions_popover_elem; - hide_all(); - if ($last_popover_elem !== undefined && $last_popover_elem.get()[0] === element) { - // We want it to be the case that a user can dismiss a popover - // by clicking on the same element that caused the popover. - return; - } - - $(element).closest(".message_row").toggleClass("has_popover has_actions_popover"); - message_lists.current.select_id(id); - const $elt = $(element); - if ($elt.data("popover") === undefined) { - const args = popover_menus_data.get_actions_popover_content_context(id); - - const ypos = $elt.offset().top; - $elt.popover({ - // Popover height with 7 items in it is ~190 px - placement: message_viewport.height() - ypos < 220 ? "top" : "bottom", - title: "", - content: render_actions_popover_content(args), - template: render_actions_popover_template(), - html: true, - trigger: "manual", - }); - $elt.popover("show"); - $current_actions_popover_elem = $elt; - } - - if (window.innerWidth < media_breakpoints_num.xl) { - // This ensures that the popover doesn't overflow to the right of the window. - const actions_popover_left = window.innerWidth - $(".actions_popover_wrapper").outerWidth(); - $(".actions_popover_wrapper").css("left", actions_popover_left); - } -} - function get_action_menu_menu_items() { + const $current_actions_popover_elem = $("[data-tippy-root] .actions_popover"); if (!$current_actions_popover_elem) { blueslip.error("Trying to get menu items when action popover is closed."); return undefined; } - const popover_data = $current_actions_popover_elem.data("popover"); - if (!popover_data) { - blueslip.error("Cannot find popover data for actions menu."); - return undefined; - } - - return $("li:not(.divider):visible a", popover_data.$tip); + return $current_actions_popover_elem.find("li:not(.divider):visible a"); } export function focus_first_popover_item($items, index = 0) { @@ -607,50 +551,18 @@ export function popover_items_handle_keyboard(key, $items) { $items.eq(index).trigger("focus"); } -function focus_first_action_popover_item() { +export function focus_first_action_popover_item() { // For now I recommend only calling 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_action_menu_menu_items(); focus_first_popover_item($items); } -export function open_message_menu(message) { - if (message.locally_echoed) { - // Don't open the popup for locally echoed messages for now. - // It creates bugs with things like keyboard handlers when - // we get the server response. - return true; - } - - const message_id = message.id; - toggle_actions_popover($(".selected_message .actions_hover")[0], message_id); - if ($current_actions_popover_elem) { - focus_first_action_popover_item(); - } - return true; -} - export function actions_menu_handle_keyboard(key) { const $items = get_action_menu_menu_items(); popover_items_handle_keyboard(key, $items); } -export function actions_popped() { - return $current_actions_popover_elem !== undefined; -} - -export function hide_actions_popover() { - if (actions_popped()) { - $(".has_popover").removeClass("has_popover has_actions_popover"); - $current_actions_popover_elem.popover("destroy"); - $current_actions_popover_elem = undefined; - } - if (current_flatpickr_instance !== undefined) { - current_flatpickr_instance.destroy(); - current_flatpickr_instance = undefined; - } -} - export function message_info_popped() { return $current_message_info_popover_elem !== undefined; } @@ -818,12 +730,6 @@ export function hide_playground_links_popover() { } export function register_click_handlers() { - $("#main_div").on("click", ".actions_hover", function (e) { - const $row = $(this).closest(".message_row"); - e.stopPropagation(); - toggle_actions_popover(this, rows.id($row)); - }); - $("#main_div").on( "click", ".sender_name, .sender_name-in-status, .inline_profile_picture", @@ -1086,28 +992,6 @@ export function register_click_handlers() { current_user_sidebar_popover = $target.data("popover"); }); - $("body").on("click", ".mark_as_unread", (e) => { - hide_actions_popover(); - const message_id = $(e.currentTarget).data("message-id"); - - unread_ops.mark_as_unread_from_here(message_id); - - e.stopPropagation(); - e.preventDefault(); - }); - - $("body").on("click", ".respond_button", (e) => { - // Arguably, we should fetch the message ID to respond to from - // e.target, but that should always be the current selected - // message in the current message list (and - // compose_actions.respond_to_message doesn't take a message - // argument). - compose_actions.quote_and_reply({trigger: "popover respond"}); - hide_actions_popover(); - e.stopPropagation(); - e.preventDefault(); - }); - $("body").on("click", ".remind.custom", (e) => { $(e.currentTarget)[0]._flatpickr.toggle(); e.stopPropagation(); @@ -1177,104 +1061,6 @@ export function register_click_handlers() { e.stopPropagation(); e.preventDefault(); }); - $("body").on("click", ".popover_toggle_collapse", (e) => { - const message_id = $(e.currentTarget).data("message-id"); - const $row = message_lists.current.get_row(message_id); - const message = message_lists.current.get(rows.id($row)); - - hide_actions_popover(); - - if ($row) { - if (message.collapsed) { - condense.uncollapse($row); - } else { - condense.collapse($row); - } - } - - e.stopPropagation(); - e.preventDefault(); - }); - $("body").on("click", ".popover_edit_message, .popover_view_source", (e) => { - const message_id = $(e.currentTarget).data("message-id"); - const $row = message_lists.current.get_row(message_id); - hide_actions_popover(); - message_edit.start($row); - e.stopPropagation(); - e.preventDefault(); - }); - $("body").on("click", ".popover_move_message", (e) => { - const message_id = $(e.currentTarget).data("message-id"); - const message = message_lists.current.get(message_id); - hide_actions_popover(); - stream_popover.build_move_topic_to_stream_popover( - message.stream_id, - message.topic, - message, - ); - e.stopPropagation(); - e.preventDefault(); - }); - $("body").on("click", ".rehide_muted_user_message", (e) => { - const message_id = $(e.currentTarget).data("message-id"); - const $row = message_lists.current.get_row(message_id); - const message = message_lists.current.get(rows.id($row)); - const message_container = message_lists.current.view.message_containers.get(message.id); - - hide_actions_popover(); - - if ($row && !message_container.is_hidden) { - message_lists.current.view.hide_revealed_message(message_id); - } - - e.stopPropagation(); - e.preventDefault(); - }); - $("body").on("click", ".view_edit_history", (e) => { - const message_id = $(e.currentTarget).data("message-id"); - const $row = message_lists.current.get_row(message_id); - const message = message_lists.current.get(rows.id($row)); - - hide_actions_popover(); - message_edit_history.show_history(message); - $("#message-history-cancel").trigger("focus"); - e.stopPropagation(); - e.preventDefault(); - }); - - $("body").on("click", ".view_read_receipts", (e) => { - const message_id = $(e.currentTarget).data("message-id"); - hide_actions_popover(); - read_receipts.show_user_list(message_id); - e.stopPropagation(); - e.preventDefault(); - }); - - $("body").on("click", ".delete_message", (e) => { - const message_id = $(e.currentTarget).data("message-id"); - hide_actions_popover(); - message_edit.delete_message(message_id); - e.stopPropagation(); - e.preventDefault(); - }); - - clipboard_enable(".copy_link").on("success", (e) => { - hide_actions_popover(); - // e.trigger returns the DOM element triggering the copy action - const message_id = e.trigger.dataset.messageId; - const $row = $(`[zid='${CSS.escape(message_id)}']`); - $row.find(".alert-msg") - .text($t({defaultMessage: "Copied!"})) - .css("display", "block") - .delay(1000) - .fadeOut(300); - - setTimeout(() => { - // The Clipboard library works by focusing to a hidden textarea. - // We unfocus this so keyboard shortcuts, etc., will work again. - $(":focus").trigger("blur"); - }, 0); - }); clipboard_enable(".copy_mention_syntax"); @@ -1332,7 +1118,6 @@ export function any_active() { // Expanded sidebars on mobile view count as popovers as well. return ( popover_menus.any_active() || - actions_popped() || user_sidebar_popped() || stream_popover.stream_popped() || stream_popover.topic_popped() || @@ -1353,7 +1138,6 @@ export function hide_all_except_sidebars(opts) { } else if (opts.exclude_tippy_instance) { hideAll({exclude: opts.exclude_tippy_instance}); } - hide_actions_popover(); emoji_picker.hide_emoji_popover(); giphy.hide_giphy_popover(); stream_popover.hide_stream_popover(); diff --git a/static/styles/popovers.css b/static/styles/popovers.css index 27d345c9b6..3e32466780 100644 --- a/static/styles/popovers.css +++ b/static/styles/popovers.css @@ -205,21 +205,20 @@ ul { } } -.actions_popover_wrapper { - .arrow { - position: absolute; - } - - @media (width < $xl_min) { - width: max-content; - } - - @media (width <= $mm_min) { - width: auto; - } -} - .actions_popover { + /* Override default padding of tippyjs */ + margin: 0 -9px; + + /* Override bootstrap defaults */ + .nav-list > li > a { + padding: 3px 15px; + } + + /* Override bootstrap defaults */ + hr { + margin: 5px 0; + } + .mark_as_unread { .unread_count { /* The icon for this menu item is in the form of an unread count from diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 86e70e4a56..ce2250efca 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -71,6 +71,7 @@ EXEMPT_FILES = make_set( "static/js/confirm_dialog.js", "static/js/copy_and_paste.js", "static/js/csrf.ts", + "static/js/css_variables.js", "static/js/dark_theme.js", "static/js/debug.js", "static/js/deprecated_feature_notice.js", @@ -82,6 +83,7 @@ EXEMPT_FILES = make_set( "static/js/emoji_picker.js", "static/js/emojisets.js", "static/js/favicon.js", + "static/js/feature_flags.ts", "static/js/feedback_widget.js", "static/js/flatpickr.js", "static/js/floating_recipient_bar.js",