18125243f8a0d219285fe081ed3f1eb8cd558ff2
max
  Sat Sep 26 17:59:16 2026 -0700
hgTracks: GenBank as a fourth format in the "Download Current Track Data" dialog

The file holds the DNA of the region in view plus the selected track items
as a GenBank feature table, so a region opens in the sequence editors people
already use: SnapGene, Benchling, ApE and the rest. Blocks become join()
locations, thickStart..thickEnd a CDS for the types that really carry a gene
model, and an item running off the edge of the view gets the partial markers.
Written in javascript beside the existing JSON/CSV/TSV converters, because
the dialog is entirely client side: it adds one getData/sequence call to the
getData/track call it already makes.

Behind showGenbankDownload in hg.conf, default off, registered as a release
gate in hgConfCatalog.py. Wiggle-type tracks have no GenBank equivalent and
are greyed out while the format is selected, and the region is capped at
100 Mbp because the web browser has to build the whole file in memory.

The dialog itself is reworked at the same time, for every format: the output
format comes first, then the file name, the track list and the check-all
buttons; it uses the page's font size and normal-height buttons instead of
jquery-ui's smaller ones; and the position sits on its own line with the
strand the Reverse button is showing. hgTracks.c adds organism and
scientificName to jsonForClient, which the GenBank header needs.

refs #38433

diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index 5a50d3c050b..bb2d6ae79ae 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -9129,30 +9129,34 @@
     else if (loginSystemEnabled() || wikiLinkEnabled())
         {
         // Hand the JS dialog a login URL that returns to this hgTracks page.
         char *retUrl = wikiLinkEncodeReturnUrl(cartSessionId(cart), "hgTracks", "");
         char *loginUrl = wikiLinkUserLoginUrlReturning(cartSessionId(cart), retUrl);
         jsInlineF("var myVariantsLoginUrl = \"%s\";\n", loginUrl);
         freez(&retUrl);
         freez(&loginUrl);
         }
     }
 
 // put the track download interface behind hg.conf control
 if (cfgOptionBooleanDefault("showDownloadUi", TRUE))
     jsInline("var showDownloadButton = true;\n");
 
+// remove the hg.conf option once this feature is released
+if (cfgOptionBooleanDefault("showGenbankDownload", FALSE))
+    jsInline("var showGenbankDownload = true;\n");
+
 // remove the hg.conf option once this feature is released
 if (cfgOptionBooleanDefault("showIgv", FALSE))
     {
     puts(" <button id='hgtIgv' type='button' "
             "title='Add an IGV.js window below the UCSC Browser, to open files from "
             "your local harddisk or server' >Add IGV Tracks</button>");
     //jsInline("document.getElementById('hgtIgv').addEventListener('click', onIgvClick);");
     }
 
 }
 
 static void printAliases(char *nativeName, char *displayName)
 /* Print out the alternative names for this sequence next to the position. */
 {
 struct slName *aliases = chromAliasFindAliases(nativeName);
@@ -12347,30 +12351,36 @@
 
 /* Do main display. */
 
 if (cartUsualBoolean(cart, "hgt.trackImgOnly", FALSE))
     {
     trackImgOnly = TRUE;
     ideogramToo = cartUsualBoolean(cart, "hgt.ideogramToo", FALSE);
     hideControls = TRUE;
     withNextItemArrows = FALSE;
     withNextExonArrows = FALSE;
     hgFindMatchesShowHighlight = FALSE;
     }
 
 jsonForClient = newJsonObject(newHash(8));
 jsonObjectAdd(jsonForClient, "cgiVersion", newJsonString(CGI_VERSION));
+// the javascript track data download needs these for the GenBank output
+if (isNotEmpty(organism))
+    jsonObjectAdd(jsonForClient, "organism", newJsonString(trackHubSkipHubName(organism)));
+char *sciName = hScientificName(database);
+if (isNotEmpty(sciName))
+    jsonObjectAdd(jsonForClient, "scientificName", newJsonString(sciName));
 boolean searching = differentString(cartUsualString(cart, TRACK_SEARCH,"0"), "0");
 
 if(!trackImgOnly)
     {
     // Write out includes for css and js files
     hWrites(commonCssStyles());
     jsIncludeFile("mousetrap.min.js", NULL);
     jsIncludeFile("jquery.js", NULL);
     jsIncludeFile("jquery-ui.js", NULL);
     jsIncludeFile("utils.js", NULL);
     jsIncludeFile("ajax.js", NULL);
     jsIncludeFile("jquery.watermarkinput.js", NULL);
     if(!searching)
         {
         jsIncludeFile("jquery.history.js", NULL);