popover_menus: Stop propagating click events when opening a popover.

This could result in things like compose box being opened by the click
that opens the popover.
This commit is contained in:
Aman Agrawal 2022-11-29 08:04:27 +00:00 committed by Tim Abbott
parent 223dca65b2
commit 8b6dc955f1
1 changed files with 41 additions and 12 deletions

View File

@ -3,7 +3,7 @@
popovers system in popovers.js. */
import $ from "jquery";
import {delegate} from "tippy.js";
import tippy, {delegate} from "tippy.js";
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";
@ -67,10 +67,39 @@ function on_show_prep(instance) {
popovers.hide_all_except_sidebars(instance);
}
function tippy_no_propagation(target, popover_props) {
// For some elements, such as the click target to open the message
// actions menu, we want to avoid propagating the click event to
// parent elements. Tippy's built-in `delegate` method does not
// have an option to do stopPropagation, so we use this method to
// open the Tippy popovers associated with such elements.
//
// A click on the click target will close the menu; for this to
// work correctly without leaking, all callers need call
// `instance.destroy()` inside their `onHidden` handler.
//
// TODO: Should we instead we wrap the caller's `onHidden` hook,
// if any, to add `instance.destroy()`?
$("body").on("click", target, (e) => {
e.preventDefault();
e.stopPropagation();
const instance = e.currentTarget._tippy;
if (instance) {
instance.hide();
return;
}
tippy(e.currentTarget, {
...default_popover_props,
showOnCreate: true,
...popover_props,
});
});
}
export function initialize() {
delegate("body", {
...default_popover_props,
target: "#streams_inline_icon",
tippy_no_propagation("#streams_inline_icon", {
onShow(instance) {
const can_create_streams =
settings_data.user_can_create_private_streams() ||
@ -90,12 +119,15 @@ export function initialize() {
left_sidebar_stream_setting_popover_displayed = true;
return true;
},
onHidden() {
onHidden(instance) {
instance.destroy();
left_sidebar_stream_setting_popover_displayed = false;
},
});
// compose box buttons popover shown on mobile widths.
// We want this click event to propagate and hide other popovers
// that could possibly obstruct user from using this popover.
delegate("body", {
...default_popover_props,
target: ".compose_mobile_button",
@ -135,9 +167,7 @@ export function initialize() {
// Click event handlers for it are handled in `compose_ui` and
// we don't want to close this popover on click inside it but
// only if user clicked outside it.
delegate("body", {
...default_popover_props,
target: ".compose_control_menu_wrapper",
tippy_no_propagation(".compose_control_menu_wrapper", {
placement: "top",
onShow(instance) {
instance.setContent(
@ -150,14 +180,13 @@ export function initialize() {
compose_control_buttons_popover_instance = instance;
popovers.hide_all_except_sidebars(instance);
},
onHidden() {
onHidden(instance) {
instance.destroy();
compose_control_buttons_popover_instance = undefined;
},
});
delegate("body", {
...default_popover_props,
target: ".enter_sends",
tippy_no_propagation(".enter_sends", {
placement: "top",
onShow(instance) {
on_show_prep(instance);