9a6f8e36d8af2950b88c9613c0003f1dc298507e
max
  Mon Sep 30 03:07:22 2024 -0700
adding right click options: hide all others, move to top/bottom, refs #23793

diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js
index a0416eb..e0acd37 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -2114,30 +2114,83 @@
 
 };
 
   ///////////////////////////////////////
  //// rightClick (aka context menu) ////
 ///////////////////////////////////////
 var rightClick = {
 
     menu: null,
     selectedMenuItem: null,   // currently choosen context menu item (via context menu).
     floatingMenuItem: null,
     currentMapItem:   null,
     supportZoomCodon: true,  // add zoom to exon and zoom to codon to right click menu
     clickedHighlightIdx : null,  // the index (0,1,...) of the highlight item that overlaps the last right-click
 
+    moveTo : function(id, topOrBottom) {
+        /* move a track to either "top" or "bottom" position */
+        let newPos = "-1";
+        if (topOrBottom==="bottom") {
+            //newPos = String(parseInt($(".trDraggable").last().attr("abbr"))+1);
+            newPos = 9999;
+        }
+
+        let trEl = $(document.getElementById('tr_' + id));
+        trEl.attr('abbr', newPos);
+
+        dragReorder.sort($("#imgTbl"));
+        //cart.setVarsObj({},null,false);
+
+        // The C code seems to assume that the track order is linearly increasing, so fix that up now
+
+        dragReorder.setOrder($("#imgTbl"));
+    },
+    hideTracks: function (ids) 
+    {
+        var cartVars = [];
+        var cartVals = [];
+
+        for (var i = 0; i<ids.length; i++) {
+            var id = ids[i];
+            var rec = hgTracks.trackDb[id];
+            if (tdbIsSubtrack(rec)) {
+                // Remove subtrack level vis and explicitly uncheck.
+                //cart.setVars( [ id, id+"_sel" ], [ '[]', 0 ] ); 
+                cartVars.push(id);
+                cartVals.push('[]');
+
+                cartVars.push(id+"_sel");
+                cartVals.push(0);
+            } else if (tdbIsFolderContent(rec)) {
+                // supertrack children need to have _sel set to trigger superttrack reshaping
+                //cart.setVars( [ id, id+"_sel" ], [ 'hide', 0 ] ); 
+                cartVars.push(id);
+                cartVals.push('hide');
+
+                cartVars.push(id+"_sel");
+                cartVals.push(0);
+            } else {
+                //cart.setVars([id], ['hide']);  // Others, just set vis hide.
+                cartVars.push(id);
+                cartVals.push('hide');
+            }
+            $(document.getElementById('tr_' + id)).remove();
+        }
+        imageV2.afterImgChange(true);
+        cart.setVars( cartVars, cartVals );
+    },
+
     makeMapItem: function (id)
     {   // Create a dummy mapItem on the fly
         // (for objects that don't have corresponding entry in the map).
         if (id && id.length > 0 && hgTracks.trackDb) {
             var title;
             var rec = hgTracks.trackDb[id];
             if (rec) {
                 title = rec.shortLabel;
             } else {
                 title = id;
             }
             return {id: id, title: "configure " + title};
         } else {
             return null;
         }
@@ -2419,30 +2472,41 @@
                     break;
                 }
             }
 
             $.ajax({
                 type: "PUT",
                 async: false,
                 url: "../cgi-bin/hgCollection",
                 data: "cmd=addTrack&track=" + id + "&collection=" + collectionName + "&hgsid=" + getHgsid(),
                 trueSuccess: mySuccess,
                 success: catchErrorOrDispatch,
                 error: errorHandler,
             });
 
             imageV2.fullReload();
+        } else if (cmd === "hideOthers") {
+            var hideIds = [];
+            for (var otherId in hgTracks.trackDb) {
+                if (otherId!==id) 
+                    hideIds.push(otherId);
+            }
+            rightClick.hideTracks(hideIds);
+        } else if (cmd === "moveTop") {
+            rightClick.moveTo(id, "top");
+        } else if (cmd === "moveBottom") {
+            rightClick.moveTo(id, "bottom");
         } else if ((cmd === 'sortExp') || (cmd === 'sortSim')) {
             url = "hgTracks?hgsid=" + getHgsid() + "&" + cmd + "=";
             rec = hgTracks.trackDb[id];
             if (tdbHasParent(rec) && tdbIsLeaf(rec))
                 url += rec.parentTrack;
             else {
                 // The button already has the ref
                 var link2 = normed($( 'td#td_btn_'+ rightClick.selectedMenuItem.id ).children('a')); 
                 if (link2)
                     url = $(link2).attr('href');
                 else
                     url += rightClick.selectedMenuItem.id;
             }
             location.assign(url);
 
@@ -2586,41 +2650,31 @@
                 updateObj[key] = 1;
                 cart.setVarsObj(updateObj,null,false);
                 imageV2.requestImgUpdate(id, id + ".doMergeItems=1");
             }
         } else {   // if ( cmd in 'hide','dense','squish','pack','full','show' )
             // Change visibility settings:
             //
             // First change the select on our form:
             rec = hgTracks.trackDb[id];
             selectUpdated = vis.update(id, cmd);
 
             // Now change the track image
             if (imageV2.enabled && cmd === 'hide') {
                 // Hide local display of this track and update server side cart.
                 // Subtracks controlled by 2 settings so del vis and set sel=0.
-                if (tdbIsSubtrack(rec)) {
-                    // Remove subtrack level vis and explicitly uncheck.
-                    cart.setVars( [ id, id+"_sel" ], [ '[]', 0 ] ); 
-                } else if (tdbIsFolderContent(rec)) {
-                    // supertrack children need to have _sel set to trigger superttrack reshaping
-                    cart.setVars( [ id, id+"_sel" ], [ 'hide', 0 ] ); 
-                } else {
-                    cart.setVars([id], ['hide']);  // Others, just set vis hide.
-                }
-                $(document.getElementById('tr_' + id)).remove();
-                imageV2.afterImgChange(true);
+                rightClick.hideTracks([id]);
             } else if (!imageV2.mapIsUpdateable) {
                 jQuery('body').css('cursor', 'wait');
                 if (selectUpdated) {
                     // assert(document.TrackForm);
                     document.TrackForm.submit();
                 } else {
                         // Add vis update to queue then submit
                         cart.setVars([id], [cmd], null, false); // synchronous
                         document.TrackHeaderForm.submit();
                 }
             } else {
                 imageV2.requestImgUpdate(id, id + "=" + cmd, "", cmd);
             }
         }
     },
@@ -2930,30 +2984,56 @@
                                        title + "...";
                             o[item] = {onclick: function(menuItemClicked, menuObject) {
                                        rightClick.hit(menuItemClicked,menuObject,"followLink");
                                        return true; }
                             };
                             any = true;
                         }
                     }
                     if (any) {
                         menu.push($.contextMenu.separator);
                         menu.push(o);
                     }
                 }
             }
 
+
+            menu.push($.contextMenu.separator);
+            o = {};
+            o[" Hide all other tracks "] = {
+                onclick: function(menuItemClicked, menuObject) {
+                    rightClick.hit(menuItemClicked, menuObject, "hideOthers");
+                    return true; }
+            };  
+            menu.push(o);
+
+            o = {};
+            o[" Move to top "] = {
+                onclick: function(menuItemClicked, menuObject) {
+                    rightClick.hit(menuItemClicked, menuObject, "moveTop");
+                    return true; }
+            };  
+            menu.push(o);
+
+            o = {};
+            o[" Move to bottom "] = {
+                onclick: function(menuItemClicked, menuObject) {
+                    rightClick.hit(menuItemClicked, menuObject, "moveBottom");
+                    return true; }
+            };  
+            menu.push(o);
+
             if (rightClick.selectedMenuItem && rec) {
                 // Add cfg options at just shy of end...
                 o = {};
                 if (tdbIsLeaf(rec)) {
 
                     if (rec.configureBy !== 'none'
                     && (!tdbIsCompositeSubtrack(rec) || rec.configureBy !== 'clickThrough')) {
                         // Note that subtracks never do clickThrough because
                         // parentTrack cfg is the desired clickThrough
                         o[rightClick.makeImgTag("wrench.png")+" Configure "+rec.shortLabel] = {
                             onclick: function(menuItemClicked, menuObject) {
                                 rightClick.hit(menuItemClicked, menuObject, "hgTrackUi_popup");
                                 return true; }
                         };
                     }
@@ -5832,17 +5912,16 @@
         return;
 
     var skipNotification = localStorage.getItem("hgTracks.hideSpeedNotification");
     dumpCart(loadSeconds, skipNotification);
         
     if (skipNotification)
         return;
 
     msg = "This page took "+loadSeconds+" seconds to load. We strive to keep "+
         "the UCSC Genome Browser quick and responsive. See our "+
         "<b><a href='../FAQ/FAQtracks.html#speed' target='_blank'>display speed FAQ</a></b> for "+
         "common causes and solutions to slow performance. If this problem continues, you can create a  "+
         "session link via <b>My Data</b> &gt; <b>My Sessions</b> and send the link to <b>genome-www@soe.ucsc.edu</b>.";
     notifBoxSetup("hgTracks", "hideSpeedNotification", msg);
     notifBoxShow("hgTracks", "hideSpeedNotification");
-
 }