user_group_popover: Migrate popover to Tippy.

Fixes part of #23632.
This commit is contained in:
Daniil Fadeev 2023-09-15 13:59:38 +04:00 committed by Tim Abbott
parent e52188bd41
commit 91d2b5ed81
4 changed files with 104 additions and 88 deletions

View File

@ -1,44 +1,46 @@
import $ from "jquery";
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 * as blueslip from "./blueslip";
import * as buddy_data from "./buddy_data";
import {media_breakpoints_num} from "./css_variables";
import * as message_lists from "./message_lists";
import * as message_viewport from "./message_viewport";
import * as people from "./people";
import {hide_all, popover_items_handle_keyboard} from "./popovers";
import * as popover_menus from "./popover_menus";
import * as popovers from "./popovers";
import {popover_items_handle_keyboard} from "./popovers";
import * as rows from "./rows";
import * as ui_util from "./ui_util";
import * as user_groups from "./user_groups";
import * as util from "./util";
let $current_user_group_popover_elem;
let user_group_popover_instance;
export function hide() {
if (is_open()) {
$current_user_group_popover_elem.popover("destroy");
$current_user_group_popover_elem = undefined;
user_group_popover_instance.destroy();
user_group_popover_instance = undefined;
}
}
export function is_open() {
return $current_user_group_popover_elem !== undefined;
return Boolean(user_group_popover_instance);
}
function get_user_group_popover_items() {
if (!$current_user_group_popover_elem) {
if (!is_open()) {
blueslip.error("Trying to get menu items when user group popover is closed.");
return undefined;
}
const popover_data = $current_user_group_popover_elem.data("popover");
if (!popover_data) {
const $popover = $(user_group_popover_instance.popper);
if (!$popover) {
blueslip.error("Cannot find user group popover data");
return undefined;
}
return $("li:not(.divider):visible a", popover_data.$tip);
return $("li:not(.divider):visible a", $popover);
}
export function handle_keyboard(key) {
@ -49,40 +51,58 @@ export function handle_keyboard(key) {
// element is the target element to pop off of;
// message_id is the message id containing it, which should be selected;
export function toggle_user_group_info_popover(element, message_id) {
const $last_popover_elem = $current_user_group_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.
if (is_open()) {
hide();
return;
}
// hardcoded pixel height of the popover
// note that the actual size varies (in group size), but this is about as big as it gets
const popover_size = 390;
const $elt = $(element);
const user_group_id = Number.parseInt($elt.attr("data-user-group-id"), 10);
const group = user_groups.get_user_group_from_id(user_group_id);
message_lists.current.select_id(message_id);
let show_as_overlay = false;
if ($elt.data("popover") === undefined) {
const args = {
group_name: group.name,
group_description: group.description,
members: sort_group_members(fetch_group_members([...group.members])),
};
$elt.popover({
placement: calculate_info_popover_placement(popover_size, $elt),
template: render_user_group_info_popover(),
content: render_user_group_info_popover_content(args),
html: true,
trigger: "manual",
fixed: true,
});
$elt.popover("show");
$current_user_group_popover_elem = $elt;
// If the window is mobile-sized, we will render the
// user group popover centered on the screen with the overlay.
if (window.innerWidth <= media_breakpoints_num.md) {
show_as_overlay = true;
}
popover_menus.toggle_popover_menu(
element,
{
placement: "right",
arrow: false,
popperOptions: {
modifiers: [
{
name: "flip",
options: {
fallbackPlacements: ["left", "top", "bottom"],
},
},
],
},
onCreate(instance) {
popovers.hide_all_except_sidebars();
if (message_id) {
message_lists.current.select_id(message_id);
}
user_group_popover_instance = instance;
const $popover = $(instance.popper);
$popover.addClass("user-group-popover-root");
const args = {
group_name: group.name,
group_description: group.description,
members: sort_group_members(fetch_group_members([...group.members])),
};
instance.setContent(ui_util.parse_html(render_user_group_info_popover(args)));
},
onHidden() {
hide();
},
},
{show_as_overlay},
);
}
export function register_click_handlers() {
@ -118,27 +138,11 @@ function sort_group_members(members) {
return members.sort((a, b) => util.strcmp(a.full_name, b.fullname));
}
function calculate_info_popover_placement(size, $elt) {
const ypos = $elt.get_offset_to_window().top;
if (!(ypos + size / 2 < message_viewport.height() && ypos > size / 2)) {
if (ypos + size < message_viewport.height()) {
return "bottom";
} else if (ypos > size) {
return "top";
}
}
return undefined;
}
// exporting these functions for testing purposes
export const _test_fetch_group_members = fetch_group_members;
export const _test_sort_group_members = sort_group_members;
export const _test_calculate_info_popover_placement = calculate_info_popover_placement;
export function initialize() {
register_click_handlers();
}

View File

@ -303,6 +303,7 @@ ul {
}
}
.group-info-popover,
.message-user-card-popover,
.user-card-popover {
width: 240px;
@ -669,7 +670,6 @@ ul {
}
@media (width < $md_min) {
.message-user-card-popover,
.user-card-popover {
display: flex !important;
justify-content: center;
@ -787,7 +787,8 @@ ul {
}
.giphy-popover,
.emoji-popover-root {
.emoji-popover-root,
.user-group-popover-root {
.tippy-content {
/* We remove the default padding from this container
as it is not necessary for the Giphy popover. */
@ -799,6 +800,19 @@ ul {
}
}
.user-group-popover-root {
& .popover-content ul.nav {
/* TODO: Clean this logic up after drop Bootstrap styling */
margin: 0;
}
& .tippy-box {
box-shadow: 0 5px 10px hsl(0deg 0% 0% / 20%);
/* User group popover has a bigger border-radius than our usual popovers. */
border-radius: 6px;
}
}
.emoji-popover-root {
/* The emoji popover has a different background color for the
header and footer, so we customize the arrow to match this color. */

View File

@ -1,7 +1,36 @@
<div class="popover message-user-card-popover group-info-popover">
<div class="group-info-popover">
<div class="popover-inner">
<div class="popover-content">
<div></div>
<div class="group-info">
<div class="group-name"> {{group_name}} </div>
<div class="group-description">
{{group_description}}
</div>
</div>
<hr />
<ul class="nav nav-list member-list" data-simplebar data-simplebar-auto-hide="false">
{{#each members}}
<li>
{{#if is_active }}
{{#if is_bot}}
<i class="zulip-icon zulip-icon-bot" aria-hidden="true"></i>
{{else}}
<span class="user_circle {{user_circle_class}} popover_user_presence" title="{{user_last_seen_time_status}}"></span>
{{/if}}
{{/if}}
<span>{{full_name}}</span>
</li>
{{/each}}
</ul>
<hr />
<ul class="nav nav-list manage-group">
<li>
<a href="#organization/user-groups-admin">
<i class="fa fa-cog" aria-hidden="true"></i>
{{t 'Manage user groups' }}
</a>
</li>
</ul>
</div>
</div>
</div>

View File

@ -1,31 +0,0 @@
{{! Contents of the "user group info" popup }}
<div class="group-info">
<div class="group-name"> {{group_name}} </div>
<div class="group-description">
{{group_description}}
</div>
</div>
<hr />
<ul class="nav nav-list member-list" data-simplebar data-simplebar-auto-hide="false">
{{#each members}}
<li>
{{#if is_active }}
{{#if is_bot}}
<i class="zulip-icon zulip-icon-bot" aria-hidden="true"></i>
{{else}}
<span class="user_circle {{user_circle_class}} popover_user_presence" title="{{user_last_seen_time_status}}"></span>
{{/if}}
{{/if}}
<span>{{full_name}}</span>
</li>
{{/each}}
</ul>
<hr />
<ul class="nav nav-list manage-group">
<li>
<a href="#organization/user-groups-admin">
<i class="fa fa-cog" aria-hidden="true"></i>
{{t 'Manage user groups' }}
</a>
</li>
</ul>