Fix Emoji Popover being leaked in certain circumstances.

Fixes the leaked popover issue where a popover for a dead element was
unable to be removed because it wasn’t connected to a parent that
existed in the DOM. Now they are cleaned up on every call to
popovers.hide_all().

Fixes: #3077.
This commit is contained in:
Brock Whittaker 2017-01-03 17:44:49 -08:00 committed by Tim Abbott
parent c2ca4cb1bb
commit de6c7ad360
1 changed files with 34 additions and 0 deletions

View File

@ -9,6 +9,33 @@ var emoji_map_is_open = false;
var userlist_placement = "right"; var userlist_placement = "right";
var list_of_popovers = [];
// this utilizes the proxy pattern to intercept all calls to $.fn.popover
// and push the $.fn.data($o, "popover") results to an array.
// this is needed so that when we try to unload popovers, we can kill all dead
// ones that no longer have valid parents in the DOM.
(function (popover) {
$.fn.popover = function () {
// apply the jQuery object as `this`, and popover function arguments.
popover.apply(this, arguments);
// if there is a valid "popover" key in the jQuery data object then
// push it to the array.
if (this.data("popover")) {
list_of_popovers.push(this.data("popover"));
}
};
// add back all shallow properties of $.fn.popover to the new proxied version.
for (var x in popover) {
if (popover.hasOwnProperty(x)) {
$.fn.popover[x] = popover[x];
}
}
}($.fn.popover));
function show_message_info_popover(element, id) { function show_message_info_popover(element, id) {
var last_popover_elem = current_message_info_popover_elem; var last_popover_elem = current_message_info_popover_elem;
popovers.hide_all(); popovers.hide_all();
@ -845,6 +872,13 @@ exports.hide_all = function () {
popovers.hide_userlist_sidebar(); popovers.hide_userlist_sidebar();
popovers.hide_streamlist_sidebar(); popovers.hide_streamlist_sidebar();
popovers.hide_emoji_map_popover(); popovers.hide_emoji_map_popover();
// look through all the popovers that have been added and removed.
list_of_popovers.forEach(function ($o) {
if (!document.body.contains($o.$element[0]) && $o.$tip) {
$o.$tip.remove();
}
});
}; };
exports.set_userlist_placement = function (placement) { exports.set_userlist_placement = function (placement) {