tippy: Add message_list_tooltip helper to clear tooltips on rerender.

We've had a series of bugs where tooltips get leaked when a message list
is rerendered. For some tooltips, we used a 'mutation observer' to remove the tooltip
in this situation, but this was expensive and messy. We replace this with a Tippy
plugin to keep track of this class of tooltips, with a central hook to remove them
during rendering.

Message lists are rerendered in the background in a variety of situations;
a simple way to trigger it is clicking the mute/unmute topic/stream button in
the topic menu/stream menu and the clickable area overlaps with the
message list tooltips area. If a tooltip was visible at the time, the tooltip loses its
reference due to the re-rendering removing its DOM element, appearing at the top-left corner.

To prevent this behavior for all message list tooltips, we need to
store all instances of the message list tooltips and then destroy
them if the instances does refer to something else then document.body
using the 'destroy_all_message_list_instances' function just
before re-rendering.

Whenever the message list is rendered, all the message list tooltips
will be destroyed if they do not refer to document.body. This
prevents the double appearance of those tooltips if the reference
is removed from the DOM.

This plugin allows us to remove the mutation observers and net delete code
while hopefully fixing this bug for the whole app.
This commit is contained in:
PALASH BADERIA
2023-05-01 11:03:14 +05:30
committed by GitHub
parent 368d2aa27d
commit 341f3a1ce2
3 changed files with 67 additions and 84 deletions

View File

@@ -33,6 +33,7 @@ import * as stream_data from "./stream_data";
import * as sub_store from "./sub_store";
import * as submessage from "./submessage";
import * as timerender from "./timerender";
import * as tippyjs from "./tippyjs";
import * as user_topics from "./user_topics";
import * as util from "./util";
@@ -1275,6 +1276,9 @@ export class MessageListView {
}
rerender_messages(messages, message_content_edited) {
// We need to destroy all the tippy instances from the DOM before re-rendering to
// prevent the appearance of tooltips whose reference has been removed.
tippyjs.destroy_all_message_list_tooltips();
// Convert messages to list messages
let message_containers = messages.map((message) => this.message_containers.get(message.id));
// We may not have the message_container if the stream or topic was muted