6ae582f5103a8b27420c44a8f92f210969f65f4c
max
  Sat Jul 25 21:36:18 2026 -0700
hgc BLAT alignment viewer: table-free page, share dialog, chromAlias, block-count fix

refs #37893

Modern base-alignment page (showSomeAlignmentModern):
- Switch page chrome to webStartGbNoBanner()/webEndGb() (menubar + <main>, no legacy
nested section tables) and draw the gold title bar + grey Back/Share buttons in plain
HTML instead of injecting them with JS.
- Full-height "jump to" sidebar; its links are position:sticky so they stay visible while
scrolling the long alignment. The per-block "Block N" links use the block count the
renderer returns, not psl->blockCount. The DNA path (ffShAliPart) merges blocks
separated by gaps <= 8 bases, so raw psl->blockCount over-counted and produced links to
#N anchors that did not exist; the returned count matches the emitted anchors.
- Show the genomic sequence's chromAlias names ("Genome sequence chr7 is also known as:
..."), de-duplicated. Friendly assembly label (organism + accession) for hub databases
instead of the internal hub_NNN_ name.

Durable "Share a link":
- Opens the shared topLinks.js "Share a link" modal and hands it a durable
hgc?g=htcBlatAlign link. The link carries only the hit selectors (c/o/i) plus u=l&s=;
db and the browser window come from the saved session. htcBlatAlign rebuilds the one
alignment from the session's durable bigPsl custom track (no BLAT re-run).
- Restore the per-hit "Alignment" links on shared-session results tables (hgBlat.c).

lib/cart.c:
- cartWriteHeaderAndCont() is now idempotent (guards on cartDidContentType). hgc writes
the CGI header early, so a later webStartGb* would otherwise write a second
Set-Cookie/Content-Type into the page body.

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index 4b35a71452f..12d9b70b15f 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -2771,30 +2771,35 @@
  * headers. This allows, for example, to prevent web browser caching of hgTracks
  * responses, but implicitly allow web browser caching everywhere else */
 {
 struct slPair *h;
 for (h = httpHeaders; h != NULL; h = h->next)
     {
     printf("%s: %s\n", h->name, (char *)h->val);
     }
 }
 
 void cartWriteHeaderAndCont(struct cart* cart, char *cookieName, char *contType)
 /* write http headers including cookie and content type line.
  * contType defaults to text/html when NULL.
  * cookieName defaults to hUserCookie() when NULL */
 {
+/* The CGI header must be written exactly once; a second write lands in the page body.  Some flows
+ * (e.g. hgc) emit it early via cartAndCookieWithHtml before a later webStart also asks for it, so
+ * guard here rather than trusting every caller to check cartDidContentType first. */
+if (cartDidContentType)
+    return;
 if (!contType)
     contType = "text/html";
 if (!cookieName)
     cookieName = hUserCookie();
 
 addHttpHeaders();
 cartWriteCookie(cart, cookieName);
 printf("Content-Type: %s\n\n", contType);
 cartDidContentType = TRUE;
 }
 
 struct cart *cartAndCookieWithHtml(char *cookieName, char **exclude,
                                    struct hash *oldVars, boolean doContentType)
 /* Load cart from cookie and session cgi variable.  Write cookie
  * and optionally content-type part HTTP preamble to web page.  Don't