3f45623e433942768d54a474f0e66709c1fad529
chmalee
  Fri Dec 1 11:18:12 2023 -0800
Make tooltips go away when moving the mouse outside the window

diff --git src/hg/js/utils.js src/hg/js/utils.js
index 1c3500b..ad3634f 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -4115,62 +4115,78 @@
 
 function titleTagToMouseover(mapEl) {
     /* for a given area tag, extract the title text into a div that can be positioned
     * like a standard tooltip mouseover next to the item */
     addMouseover(mapEl, mapEl.title);
 }
 
 function convertTitleTagsToMouseovers() {
     /* make all the title tags in the document have mouseovers */
     $("[[title]").each(function(i, a) {
         if (a.title !== undefined && a.title.length > 0) {
             titleTagToMouseover(a);
         }
     });
 
+    /* Mouseover should clear if you leave the document window altogether */
+    document.body.addEventListener("mouseleave", (ev) => {
+        clearTimeout(mouseoverTimer);
+        mousemoveController.abort();
+        hideMouseoverText(mouseoverContainer);
+        canShowNewMouseover = false;
+        // let mouseovers show up again upon moving back in to the window
+        // but only need the event once
+        document.body.addEventListener("mouseenter", (ev) => {
+            canShowNewMousoever = true;
+        }, {once: true});
+    });
+
     /* make the above mouseovers go away if we are in an input or select menu */
     const inps = document.getElementsByTagName("input");
     const sels = document.getElementsByTagName("select");
     for (let inp of inps) {
         if (!(inp.type == "hidden" || inp.type == "HIDDEN")) {
             inp.addEventListener("focus", (ev) => {
-                hideMouseoverText(mouseoverContainer);
+                clearTimeout(mouseoverTimer);
                 mousemoveController.abort();
+                hideMouseoverText(mouseoverContainer);
                 canShowNewMouseover = false;
             });
             inp.addEventListener("blur", (evt) => {
                 canShowNewMouseover = true;
             });
         }
     }
     for (let sel of sels) {
         sel.addEventListener("focus", (ev) => {
-            hideMouseoverText(mouseoverContainer);
+            clearTimeout(mouseoverTimer);
             mousemoveController.abort();
+            hideMouseoverText(mouseoverContainer);
             canShowNewMouseover = false;
         });
         sel.addEventListener("blur", (evt) => {
             canShowNewMouseover = true;
         });
     }
 
     /* for hgTracks specifically, we also need to deal with the special contextmenu */
     let imgTbl = document.getElementById("imgTbl");
     if (imgTbl) {
         imgTbl.addEventListener("contextmenu", function(e) {
-            hideMouseoverText(mouseoverContainer);
+            clearTimeout(mouseoverTimer);
             mousemoveController.abort();
+            hideMouseoverText(mouseoverContainer);
             canShowNewMouseover = false;
             // right-click menu doesn't capture focus so manually catch it
             document.addEventListener("click", function(ev) {
                 // there is a race condition where the close happens after an inputs
                 // focus happens, which means mouseovers get re-enabled when the focus
                 // on the input should prevent them, catch that here:
                 if (!(document.activeElement.tagName === "INPUT" ||
                         document.activeElement === "SELECT")) {
                     canShowNewMouseover = true;
                 }
             }, {once: true});
             document.addEventListener("keyup", function(ev) {
                 if (ev.keyCode == 27) {
                     // there is a race condition where the close happens after an inputs
                     // focus happens, which means mouseovers get re-enabled when the focus