0aba57c06e4263f91f5b1e20eafca36946b4649b
jrobinso
  Sat Sep 20 21:31:02 2025 -0700
remove local igvBrowser variable for clarity.  igvBrowser is a global

diff --git src/hg/js/igvFileHelper.js src/hg/js/igvFileHelper.js
index e924a60937c..a2421d09671 100644
--- src/hg/js/igvFileHelper.js
+++ src/hg/js/igvFileHelper.js
@@ -1,30 +1,30 @@
 // Helper functions for using igv.js with local files in the UCSC genome browser
 //
 // The UCSC browser does not use modules, so wrap code in a self-executing function to limit
 // scope of variables to this file.
 
 (function () {
     const indexExtensions = new Set(['bai', 'csi', 'tbi', 'idx', 'crai']);
     const requireIndex = new Set(['bam', 'cram']);
 
     // File scope variables
     const IGV_STORAGE_KEY = "igvSession";
     let filePicker = null;
-    let igvBrowser = null;
     let isDragging = false;
     let sessionAutoSaveTimer = null;
+    window.igvBrowser = undefined;  // The gloal igv.js browser object, TODO -- perhaps this should be attached to "igv"
 
     // Create a BroadcastChannel for communication between the UCSC browser page and the file picker page.
     const channel = new BroadcastChannel('igv_file_channel');
 
     // Message types for communication between browser page and file picker page
     const MSG = {
         SELECTED_FILES: 'selectedFiles',
         RESTORE_FILES: 'restoreFiles',
         REMOVED_TRACK: 'removedTrack',
         LOAD_URL: 'loadURL',
         FILE_PICKER_READY: 'filePickerReady',
         PING: 'ping',
         PONG: 'pong'
     };
 
@@ -424,31 +424,31 @@
     function openFilePicker() {
         filePicker = window.open('../admin/filePicker.html', 'igvFilePicker', 'width=600,height=1000');
         if (!filePicker) {
             showDialog("Unable to open file picker window.  Please disable your popup blocker for this site and try again.");
         }
         return filePicker;
     }
 
     /**
      * Update the track names in the left hand column of the IGV row in the image table.
      */
     function updateTrackNames() {
 
 
         // Add track names to the left hand column.
-        if (!igvBrowser) return;
+        if (typeof igvBrowser === "undefined") return;
 
         const gearIconSize = 10;
         const leftSidebar = document.getElementById('igv_leftsidebar');
         const nameDiv = document.getElementById('igv_namediv');
 
         // Clear any existing content
         nameDiv.innerHTML = "";
         leftSidebar.innerHTML = "";
 
         const allTracks = igvBrowser.findTracks(t => t.type);  // ignore tracks with no type
         let top = 0;
         for (let track of allTracks) {
 
             const gearDiv = document.createElement('div');
             gearDiv.style.position = 'absolute';
@@ -537,30 +537,31 @@
         igvRow.appendChild(td1);
 
         const leftSidebarDiv = document.createElement('div');
         leftSidebarDiv.id = 'igv_leftsidebar';
         leftSidebarDiv.style.position = "absolute";
         leftSidebarDiv.style.top = "0px";
         leftSidebarDiv.style.bottom = "0px";
         leftSidebarDiv.style.left = "0px";
         leftSidebarDiv.style.right = "0px";
         leftSidebarDiv.style.background = "rgb(193,193,193)";
         td1.appendChild(leftSidebarDiv);
 
         // Second cell for track names
         const td2 = document.createElement('td');
         td2.style.position = 'relative';
+        td2.className = 'dragHandle tdLeft';
         igvRow.appendChild(td2);
 
         const nameDiv = document.createElement('div');
         nameDiv.id = 'igv_namediv';
         nameDiv.style.position = 'absolute';
         nameDiv.style.top = '0';
         nameDiv.style.bottom = '0';
         nameDiv.style.left = '0';
         nameDiv.style.right = '0';
         td2.appendChild(nameDiv);
 
         // Third cell for the IGV browser div
         const td3 = document.createElement('td');
         igvRow.appendChild(td3);
 
@@ -607,35 +608,36 @@
      *
      * @param config -- The IGV browser configuration object.  Must include a reference genome, but might also include
      *                  an initial locus or tracks.
      * @returns {Promise<Browser>}
      */
     async function createIGVBrowser(config) {
 
         // Override locus  in the IGV session with the UCSC locus
         // TODO -- should we use genomePos here?
         const ucscImageWidth = document.getElementById("td_data_ruler").clientWidth;
         const resolution = (hgTracks.winEnd - hgTracks.winStart) / ucscImageWidth;
         config.locus = {chr: hgTracks.chromName, start: hgTracks.winStart, bpPerPixel: resolution};
 
         console.log("Creating IGV browser with config: ", config);
 
-        if (document.getElementById("tr_igv")) {
-            console.warn("IGV track row already exists ???");   // TODO -- how can this happen?
-            return;
+        let igvRow = document.getElementById("tr_igv")
+        if (!igvRow) {
+            // No existing igv row, insert one
+            igvRow = insertIGVRow();
         }
-        const igvRow = insertIGVRow();
+
 
         // Ammend the igv config to remove most of the IGV widgets.  We only want the track display area.
         Object.assign(config, {
             showNavigation: false,
             showIdeogram: false,
             showRuler: false,
             //showSequence: false,   // Uncomment this to hide igv sequence track
             showAxis: false,
             showTrackDragHandles: false,
             showAxisColumn: false,
             gearColumnPosition: 'left',
             showGearColumn: false,
             showTrackLabels: false,   // Uncomment this to hide the "floating div" igv track labels
             formEmbedMode: true,  // works around hotkey issues affecting igv input elements
             disableZoom: true,   // disable zooming in igv, use UCSC zoom controls