af3a143571e5aa064eab75c34f9444b35413b562
chmalee
  Tue Nov 30 15:28:15 2021 -0800
Add snippet support to trix searching. Required changing the
wordPos from the first highest matching wordIndex to the
wordIndex of the actual span. Have trixContextIndex create a
second level index for fast retrieval of line offsets in
original text file used by ixIxx. Create a simple UI for navigating
hgFind search results.

diff --git src/hg/js/hgGateway.js src/hg/js/hgGateway.js
index e9c5bbd..974cb51 100644
--- src/hg/js/hgGateway.js
+++ src/hg/js/hgGateway.js
@@ -1484,53 +1484,69 @@
             cart.flush();
             uiState.db = db;
             clearPositionInput();
         }
     }
 
     function onClickCopyPosition() {
         // Copy the displayed position into the position input:
         var posDisplay = $('#positionDisplay').text();
         $('#positionInput').val(posDisplay).focus();
     }
 
     function goToHgTracks() {
         // Create and submit a form for hgTracks with hidden inputs for org, db and position.
         var position = $('#positionInput').val();
+        var searchTerm = position;
         var posDisplay = $('#positionDisplay').text();
         var pix = uiState.pix || calculateHgTracksWidth();
         var $form;
         if (! position || position === '' || position === positionWatermark ||
             position === selectedGene) {
             position = posDisplay;
         } else {
             position = position.replace(/\u2013|\u2014/g, "-");  // replace en-dash and em-dash with hyphen
         }
-
+        var canonMatch = position.match(canonicalRangeExp);
+        var gbrowserMatch = position.match(gbrowserRangeExp);
+        var lengthMatch = position.match(lengthRangeExp);
+        var bedMatch = position.match(bedRangeExp);
+        var sqlMatch = position.match(sqlRangeExp);
+        var singleMatch = position.match(singleBaseExp);
+        var positionMatch = canonMatch || gbrowserMatch || lengthMatch || bedMatch || sqlMatch || singleMatch;
+        if (positionMatch !== null) {
+            // We already have a position from either selecting a suggestion or the user just typed a regular
+            // old position, so go to hgTracks at that location
             // Show a spinner -- sometimes it takes a while for hgTracks to start displaying.
             $('.jwGoIcon').removeClass('fa-play').addClass('fa-spinner fa-spin');
             // Make a form and submit it.  In order for this to work in IE, the form
             // must be appended to the body.
             $form = $('<form action="hgTracks" method=GET id="mainForm">' +
                       '<input type=hidden name="hgsid" value="' + window.hgsid + '">' +
                       '<input type=hidden name="org" value="' + uiState.genome + '">' +
                       '<input type=hidden name="db" value="' + uiState.db + '">' +
                       '<input type=hidden name="position" value="' + position + '">' +
                       '<input type=hidden name="pix" value="' + pix + '">' +
                       '</form>');
             $('body').append($form);
             $form.submit();
+        } else {
+            // User has entered a search term with no suggestion, go to the disambiguation
+            // page so the user can choose a position
+            $('.jwGoIcon').removeClass('fa-play').addClass('fa-spinner fa-spin');
+            window.location.assign("../cgi-bin/searchExample?hgsid="+ window.hgsid + "&search=" + searchTerm);
+        }
     }
 
     function replaceHgsidInLinks() {
         // Substitute '$hgsid' with real hgsid in <a> href's.
         $('a').each(function(ix, aEl) {
             var href = aEl.getAttribute('href');
             if (href && href.indexOf('$hgsid') >= 0) {
                 aEl.setAttribute('href', href.replace('$hgsid', window.hgsid));
             }
         });
     }
 
     function displaySurvey() {
         // If hg.conf specifies a survey link, then hgGateway.c has set corresponding global vars.
         // Use those to display a labeled link (possibly an <img>) in the otherwise empty