6859799d7f0ff85994452c04c2aa568d74e35476
chmalee
  Fri Sep 8 14:02:48 2023 -0700
Fix mouseovers not going away when moving away from them, refs #31365

diff --git src/hg/js/utils.js src/hg/js/utils.js
index ad09d68..d5e0d2c 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -3867,64 +3867,80 @@
     popUpEl.style.left = leftOffset + "px";
     popUpEl.style.top = topOffset + "px";
 }
 
 function replaceReserved(txt) {
     /* This should somehow be made more general so we can stop worrying about
      * user made tracks with whatever characters in it */
     if (!txt) {
         throw new Error("trying to replace null txt");
     }
     return txt.replace(/[^A-Za-z0-9_]/g, "_");
 }
 
 // the current mouseover timer, for showing the mouseover after a delay
 var mouseoverTimer;
+// the timer for when a user is moving the mouse after already bringing up
+// a pop up, there may be many items close together and we want the user
+// to bring up those mouseovers
+var mousemoveTimer;
+var showDiffMouseover = false;
 // signal handler for when mousemove has gone far enough away from the pop up
 // we can't use removeEventListener because the function call is hard to keep
 // track of because of a bounded this keyword
 var mousemoveSignal;
 // The div that moves around the users screen with the visible mouseover text
 var mouseoverContainer;
 
 function hideMouseoverText(ele) {
     /* Actually hides the tooltip text */
     let tooltipTarget = ele;
     tooltipTarget.classList.remove("isShown");
     tooltipTarget.style.opacity = "0";
     tooltipTarget.style.visibility = "hidden";
 }
 
+function mousemoveTimerHelper(e) {
+    showDiffMouseover = true;
+    clearTimeout(mousemoveTimer);
+    mousemoveTimer = undefined;
+}
+
 function mousemoveHelper(e) {
     /* Helper function for deciding whether to keep a tooltip visible upon a mousemove event */
-    if ($(".tooltip.isShown").length > 0) {
-        return;
+    if (mousemoveTimer === undefined) {
+        // if we are over another mouseable element we want to show that one instead
+        // use this timer to do so
+        showDiffMouseover = false;
+        mousemoveTimer = setTimeout(mousemoveTimerHelper, 100, e);
     }
     let targetBox = this.getBoundingClientRect();
     let mouseX = e.clientX;
     let mouseY = e.clientY;
     // currently allow the mouse to move in a 45 pixel box around the element
     if ( mouseX >= (targetBox.left - 45) && mouseX <= (targetBox.right + 45) &&
-            mouseY >= (targetBox.top - 45) && mouseY <= (targetBox.bottom + 45) ) {
-        // keep the mouseover showing
+            mouseY >= (targetBox.top - 45) && mouseY <= (targetBox.bottom + 45)
+            && !showDiffMouseover) {
         return;
     } else {
         // now that we are going to hide the pop up we can remove the event listener
         // for whether we wanted to keep the pop up or not
+        if ($(".tooltip.isShown").length > 0) {
             console.log("hiding mouseover in mousemove helper:");
             console.log(this);
             hideMouseoverText(this);
+        }
         mousemoveSignal.abort();
     }
 }
 
 function showMouseoverText(e) {
     // actually show the mouseover text
     e.preventDefault();
     referenceElement = e.target;
     if (!e.target.getAttribute("mouseoverid")) {
         // corner case: the side slice and grey control bar slice are weird, the td
         // container has the title tag, while the img or a element receives the mouseover
         // event, so we need to go back up the tree to find the mouseoverid for those elems
         while (referenceElement.parentElement && !referenceElement.getAttribute("mouseoverid")) {
             referenceElement = referenceElement.parentElement;
         }