47ea57080b515e5dad5f658c58feb8944a7e7d61
chmalee
  Thu Jan 29 15:30:26 2026 -0800
Replace clade/assembly dropdowns with a search bar on most CGIs. Add a recents list to hgGateway and to the species bar and to the 'Genomes' dropdown menu. Track recently selected species in localStorage. Add toGenome and fromGenome arguemnts to hubApi/liftOver in order to find appropriate liftover assemblies, refs #36232

diff --git src/hg/hgBlat/hgBlat.c src/hg/hgBlat/hgBlat.c
index 1b88fed8be9..fd83a10746a 100644
--- src/hg/hgBlat/hgBlat.c
+++ src/hg/hgBlat/hgBlat.c
@@ -23,30 +23,31 @@
 #include "web.h"
 #include "hash.h"
 #include "botDelay.h"
 #include "trashDir.h"
 #include "trackHub.h"
 #include "hgConfig.h"
 #include "errCatch.h"
 #include "portable.h"
 #include "portable.h"
 #include "dystring.h"
 #include "chromInfo.h"
 #include "net.h"
 #include "fuzzyFind.h"
 #include "chromAlias.h"
 #include "subText.h"
+#include "jsHelper.h"
 
 struct cart *cart;	/* The user's ui state. */
 struct hash *oldVars = NULL;
 boolean orgChange = FALSE;
 boolean dbChange = FALSE;
 boolean allGenomes = FALSE;
 boolean allResults = FALSE;
 boolean autoRearr = FALSE;
 static long enteredMainTime = 0;
 
 
 boolean autoBigPsl = FALSE;  // DEFAULT VALUE change to TRUE in future
 
 /* for earlyBotCheck() function at the beginning of main() */
 #define delayFraction   0.5    /* standard penalty is 1.0 for most CGIs */
@@ -2052,69 +2053,79 @@
     }
 
 if ((!feelingLucky && !allGenomes) || (autoBigPsl && feelingLucky))
     cartWebEnd();
 
 gfFileCacheFree(&tFileCache);
 }
 
 void askForSeq(char *organism, char *db)
 /* Put up a little form that asks for sequence.
  * Call self.... */
 {
 /* ignore struct serverTable* return, but can error out if not found */
 findServer(db, FALSE);
 
-/* JavaScript to update form when org changes */
-char *onChangeText = ""
-    "document.mainForm.changeInfo.value='orgChange';"
-    "document.mainForm.submit();";
-
 char *userSeq = NULL;
 char *type = NULL;
 
 printf( 
 "<FORM ACTION=\"../cgi-bin/hgBlat\" METHOD=\"POST\" ENCTYPE=\"multipart/form-data\" NAME=\"mainForm\">\n"
 "<H2>BLAT Search Genome</H2>\n");
 cartSaveSession(cart);
 puts("\n");
 puts("<INPUT TYPE=HIDDEN NAME=changeInfo VALUE=\"\">\n");
 puts("<TABLE class='hgBlatTable' BORDER=0 WIDTH=80>\n");
 printf("<TR>\n");
 printf("<TD ALIGN=CENTER style='overflow:hidden;white-space:nowrap;'>Genome:");
 printf(" <INPUT TYPE=CHECKBOX id=allGenomes NAME=allGenomes VALUE=\"\">");
 printf(" <span id=searchAllText> Search all genomes</span>");
 printf("</TD>");
 // clicking on the Search ALL text clicks the checkbox.
 jsOnEventById("click", "searchAllText", 
     "document.mainForm.allGenomes.click();"
     "return false;"   // cancel the default
     );
 
 printf("<TD ALIGN=CENTER>Assembly:</TD>");
 printf("<TD ALIGN=CENTER>Query type:</TD>");
 printf("<TD ALIGN=CENTER>Sort output:</TD>");
 printf("<TD ALIGN=CENTER>Output type:</TD>");
 printf("<TD ALIGN=CENTER>&nbsp;</TD>");
 printf("</TR>\n");
 
 printf("<TR>\n");
-printf("<TD ALIGN=CENTER>\n");
-printBlatGenomeListHtml(db, "change", onChangeText);
+printf("<TD class='searchCell' ALIGN=CENTER>\n");
+// hgBlat requires this <input> be created to go along with form submission, we
+// will change it when a genome is selected in the search bar
+printf("<input name='db' value='%s' type='hidden'></input>\n", db);
+jsIncludeAutoCompleteLibs();
+char *searchBarId = "genomeSearch";
+printGenomeSearchBar(searchBarId, "Search any species, genome or assembly name", NULL, TRUE, NULL, NULL);
+jsInlineF(
+    "setupGenomeSearchBar({\n"
+    "    inputId: '%s',\n"
+    "    onSelect: function(item) {\n"
+    "        document.mainForm.db.value = item.genome;\n"
+    "    }\n"
+    "});\n"
+    , searchBarId
+);
 printf("</TD>\n");
-printf("<TD ALIGN=CENTER>\n");
-printBlatAssemblyListHtml(db);
+printf("<TD id='genomeLabel' class='searchCell' ALIGN=CENTER>\n");
+char *dbLabel = getCurrentGenomeLabel(db);
+printf("%s\n", dbLabel);
 printf("</TD>\n");
 printf("<TD ALIGN=CENTER>\n");
 if (orgChange)
     type = cartOptionalString(cart, "type");
 cgiMakeDropList("type", typeList, ArraySize(typeList), type);
 printf("</TD>\n");
 printf("<TD ALIGN=CENTER>\n");
 cgiMakeDropList("sort", pslSortList, ArraySize(pslSortList), cartOptionalString(cart, "sort"));
 printf("</TD>\n");
 printf("<TD ALIGN=CENTER>\n");
 cgiMakeDropList("output", outputList, ArraySize(outputList), cartOptionalString(cart, "output"));
 printf("</TD>\n");
 printf("</TR>\n<TR>\n");
 userSeq = cartUsualString(cart, "userSeq", "");
 printf("<TD COLSPAN=5 ALIGN=CENTER>\n");