mirror of https://github.com/zulip/zulip.git
actions_popover: Use tippyjs instead of bootstrap to display popover.
Fixes #23494 Popover now automatically displays on left when there is not enough space top or bottom of the reference element.
This commit is contained in:
parent
6a1ae465cc
commit
eb45925b1a
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue