6f7f5bac129d59cfb99d47a3f1de118c48e423cd
chmalee
  Wed Jul 23 15:25:01 2025 -0700
When mousing over a track, put a gear icon over the grey bar to hint that a context click is available. Put a 'x' icon to the right (or left in revCmp mode) to allow quick hiding of tracks. Both icons are enabled via hg.conf:greyBarIcons, refs #34420

diff --git src/hg/js/utils.js src/hg/js/utils.js
index d510cdd46cd..f4620ae5890 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -3832,34 +3832,119 @@
         if (jQuery.tableDnD) {
             var rows = dragReorder.getContiguousRowSet($(this).parents('tr.trDraggable')[0]);
             if (rows)
             $( rows ).removeClass("trDrag");
         }
     },
 
     trMouseOver: function (e)
     {   // Trying to make sure there is always a imageV2.lastTrack so that we know where we are
         var id = '';
         var a = /tr_(.*)/.exec($(this).attr('id'));  // voodoo
         if (a && a[1]) {
             id = a[1];
         }
         if (id.length > 0) {
-            if ( ! imageV2.lastTrack || imageV2.lastTrack.id !== id)
+            if ( ! imageV2.lastTrack || imageV2.lastTrack.id !== id) {
                 imageV2.lastTrack = rightClick.makeMapItem(id);
                 // currentMapItem gets set by mapItemMapOver.   This is just backup
             }
+
+            if (typeof greyBarIcons !== 'undefined' && greyBarIcons === true) {
+                // add a gear icon over the grey bar to bring up the context menu
+                let tdBtn = document.getElementById("td_btn_" + id);
+                if (tdBtn) {
+                    if (!document.getElementById("gear_btn_" + id)) {
+                        let span = document.createElement("span");
+                        span.id = "gear_btn_" + id;
+                        span.classList.add("hgTracksGearIcon", "ui-icon", "ui-icon-gear");
+                        span.title = "Configure track";
+                        tdBtn.appendChild(span);
+                        tdBtn.style.position = "relative";
+                        span.addEventListener("click", (e) => {
+                            // create a contextmenu event that the imgTbl will pick up
+                            e.preventDefault();
+                            e.stopPropagation();
+                            e.stopImmediatePropagation();
+                            const rightClickEvent = new MouseEvent("contextmenu", {
+                                bubbles: true,
+                                cancelable: true,
+                                view: window,
+                                clientX: tdBtn.getBoundingClientRect().left + 15,
+                                clientY: tdBtn.getBoundingClientRect().top,
+                                button: 2,
+                            });
+                            tdBtn.dispatchEvent(rightClickEvent);
+                        });
+                    }
+                }
+
+                // add an 'x' icon in the label area to hide the track
+                let tdSide = document.getElementById("td_side_" + id);
+                if (tdSide) {
+                    // mouseover event fires if you stop moving the mouse while still
+                    // hovering the element and then move it again, don't make
+                    // duplicate btns in that case
+                    if (!document.getElementById("close_btn_" + id)) {
+                        let btn = document.createElement("span");
+                        btn.id = "close_btn_" + id;
+                        btn.classList.add("hgTracksCloseIcon", "ui-icon", "ui-icon-close");
+                        btn.title = "Hide track";
+                        tdSide.appendChild(btn);
+                        tdSide.style.position = "relative";
+                        if (hgTracks && hgTracks.revCmplDisp) {
+                            // set up 'x' icon to the right
+                            btn.classList.add("hgTracksCloseIconRight");
+                        } else {
+                            // set up 'x' icon to the left
+                            btn.classList.add("hgTracksCloseIconLeft");
+                        }
+                        btn.addEventListener("click", (e) => {
+                           rightClick.hideTracks([id]);
+                        });
+                    }
+                }
+            }
+        }
+    },
+
+    trMouseLeave: function(e)
+    {
+        var id = '';
+        var a = /tr_(.*)/.exec($(this).attr('id'));  // voodoo
+        if (a && a[1]) {
+            id = a[1];
+        }
+        if (id.length > 0) {
+            // remove 'x' icon in the label area to hide the track
+            let tdSide = document.getElementById("td_side_" + id);
+            if (tdSide) {
+                let btn = document.getElementById("close_btn_" + id);
+                if (btn) {
+                    btn.remove();
+                }
+            }
+
+            // remove gear icon over the grey bar
+            let tdBtn = document.getElementById("td_btn_" + id);
+            if (tdBtn) {
+                let btn = document.getElementById("gear_btn_" + id);
+                if (btn) {
+                    btn.remove();
+                }
+            }
+        }
     },
 
     mapItemMouseOver: function ()
     {
         // Record data for current map area item
         var id = this.id;
         if (!id || id.length === 0) {
             id = '';
             var tr = $( this ).parents('tr.imgOrd');
             if ( $(tr).length === 1 ) {
                 var a = /tr_(.*)/.exec($(tr).attr('id'));  // voodoo
                 if (a && a[1]) {
                     id = a[1];
                 }
             }
@@ -3908,30 +3993,31 @@
         var btns = $("p.btn");
         if (btns.length > 0) {
             dragReorder.zipButtons($('#imgTbl'));
             $(btns).on("mouseenter", dragReorder.buttonMouseOver );
             $(btns).on("mouseleave", dragReorder.buttonMouseOut  );
             $(btns).show();
         }
         var handle = $("td.dragHandle");
         if (handle.length > 0) {
             $(handle).on("mouseenter", dragReorder.dragHandleMouseOver );
             $(handle).on("mouseleave", dragReorder.dragHandleMouseOut  );
         }
 
         // setup mouse callbacks for the area tags
         $("#imgTbl").find("tr").on("mouseover", dragReorder.trMouseOver );
+        $("#imgTbl").find("tr").on("mouseleave", dragReorder.trMouseLeave );
         $("#imgTbl").find("tr").each( function (i, row) {
             // save the original y positions of each row
             //if (row.id in dragReorder.originalHeights === false) {
                 dragReorder.originalHeights[row.id] = row.getBoundingClientRect().y + window.scrollY;
             //}
         });
 
 
         $(".area").each( function(t) {
                             this.onmouseover = dragReorder.mapItemMouseOver;
                             this.onmouseout = dragReorder.mapItemMouseOut;
                             this.onclick = posting.mapClk;
                         });
     }
 };