c32d6e08d19a0b8ad7ece12aab39d0ba0be7a9e1
chmalee
  Mon Dec 1 16:26:27 2025 -0800
hgTracks tooltips use the data-tooltip attribute on the area element if present, falling back to the title attribute. Makes title attributes for (hopefully all) tracks with special tooltips put the tooltip string into the data-tooltip attribute instead of the title attribute, refs #35756

diff --git src/hg/js/utils.js src/hg/js/utils.js
index c4c6a4a2192..2ccee7b046e 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -4201,31 +4201,31 @@
         mouseoverContainer.className = "tooltip";
         mouseoverContainer.style.position = "fixed";
         mouseoverContainer.style.display = "inline-block";
         mouseoverContainer.style.visibility = "hidden";
         mouseoverContainer.style.opacity = "0";
         mouseoverContainer.id = "mouseoverContainer";
         let tooltipTextSize = localStorage.getItem("tooltipTextSize");
         if (tooltipTextSize === null) {tooltipTextSize = window.browserTextSize;}
         mouseoverContainer.style.fontSize =  tooltipTextSize + "px";
         document.body.append(mouseoverContainer);
     }
 
     if (ele1) {
         ele1.setAttribute("mouseoverText", text);
         // Remove title attribute to prevent default browser tooltip
-        if (ele1.title) {
+        if (ele1.title || ele1.dataset.tooltip) {
             ele1.setAttribute("originalTitle", ele1.title);
             ele1.title = "";
         }
         // Remove previous listeners if any
         ele1.removeEventListener("mouseenter", ele1._mouseenterHandler);
         ele1.removeEventListener("mouseleave", ele1._mouseleaveHandler);
         // Show tooltip on mouseenter with delay
         ele1._mouseenterHandler = function(e) {
             // Clear any existing hide timeout
             if (ele1._tooltipHideTimeout) {
                 clearTimeout(ele1._tooltipHideTimeout);
                 ele1._tooltipHideTimeout = null;
             }
             // Determine delay based on tooltip type
             let isDelayedTooltip = ele1.getAttribute("tooltipDelay") === "delayed";
@@ -4284,30 +4284,33 @@
     mouseoverContainer.style.opacity = "1";
     mouseoverContainer.style.visibility = "visible";
     mouseoverContainer.setAttribute("origItemMouseoverId", ele.getAttribute("mouseoverid"));
 }
 
 function hideMouseoverText(ele) {
     /* Actually hides the tooltip text */
     ele.classList.remove("isShown");
     ele.style.opacity = "0";
     ele.style.visibility = "hidden";
 }
 
 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 */
+    if (mapEl.dataset.tooltip)
+        addMouseover(mapEl, mapEl.dataset.tooltip);
+    else
         addMouseover(mapEl, mapEl.title);
 }
 
 function convertTitleTagsToMouseovers() {
     /* make all the title tags in the document have mouseovers */
     document.querySelectorAll("[title]").forEach(function(a, i) {
         if (a.id !== "" && (a.id === "hotkeyHelp" || a.id.endsWith("Dialog") || a.id.endsWith("Popup"))) {
             // these divs are populated by ui-dialog, they should not have tooltips
             return;
         }
         if (a.title !== undefined &&
                 (a.title.startsWith("click & drag to scroll") || a.title.startsWith("drag select or click to zoom")))
             a.title = "";
         else if (a.title !== undefined && a.title.length > 0) {
             if (a.title.startsWith("Click to alter the display density")) {