7e32381bc2152e0bdf4e5be2f46fe033e80cb5d5
jrobinso
  Mon Sep 15 17:41:54 2025 -0700
(1) Broadcast a "filePickerReady" message on filePicker.html mode.  (2) Make special input mode optional with a config parameter.

diff --git src/hg/js/igvFileHelper.js src/hg/js/igvFileHelper.js
index 852c5dfa13c..6794987c226 100644
--- src/hg/js/igvFileHelper.js
+++ src/hg/js/igvFileHelper.js
@@ -460,30 +460,31 @@
             }
             const igvRow = insertIGVRow();
 
             // Ammend the 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,
                 showAxis: false,
                 showTrackDragHandles: false,
                 showAxisColumn: false,
                 gearColumnPosition: 'left',
                 showGearColumn: false,
                 showTrackLabels: false,
+                formEmbedMode: true,  // triggers key capture in input dialogs
                 disableZoom: true,
                 minimumBases: 0
             });
 
             const div = document.getElementById("igv_div");
             igvBrowser = await igv.createBrowser(div, config);
             updateTrackNames();
 
             // Add event handler to remove IGV row from table if all IGV tracks are removed.
             igvBrowser.on('trackremoved', function (track) {
 
                 channel.postMessage({type: "removedTrack", config: track.config});
 
                 const allTracks = igvBrowser.findTracks(t => "sequence" !== t.type);   // ignore sequence track
                 if (allTracks.length === 0) {
@@ -639,29 +640,44 @@
          *
          * Eventually expand or reimplement this function to support all UCSC browser genomes.
          *
          * @param genomeID
          * @returns {{id: string, twoBitURL: string}}
          */
         async function getMinimalReference(genomeID) {
             const currentURL = window.location.href;
             const upOneDirURL = currentURL.substring(0, currentURL.lastIndexOf('/'));
             const apiUrl = upOneDirURL+`/hubApi?cmd=/list/files;genome=${genomeID};format=text;skipContext=1;fileType=2bit`;
             try {
                 const twoBitURL = await getLine(apiUrl);
                 return {
                     "id": genomeID,
                     "twoBitURL": twoBitURL,
-                }
+                };
             } catch (e) {
                 console.error(e);
                 alert("Internal Error: Cannot get 2bit file from "+ apiUrl);
                 return null;
             }
         }
 
+        function parseLocusString(locusString) {
+            const locusRegex = /^([^:]+)(?::(\d+)(?:-(\d+))?)?$/;
+            const match = locusString.match(locusRegex);
+            if (!match) {
+                throw new Error(`Invalid locus string: ${locusString}`);
+            }
+            const chr = match[1];
+            let start = match[2] ? parseInt(match[2].replace(",", ""), 10) - 1 : 0; // Convert to 0-based
+            let end = match[3] ? parseInt(match[3].replace(",", ""), 10) : start + 100; // Default to 100bp if no end provided
+            if (isNaN(start) || isNaN(end) || start < 0 || end <= start) {
+                throw new Error(`Invalid start or end in locus string: ${locusString}`);
+            }
+            return {chr, start, end};
+        }
+
         // Attach helper functions to the igv object
         igv.initIgvUcsc = initIgvUcsc;
         igv.updateIgvStartPosition = updateIgvStartPosition;
 
     }
 )();