2eb14fc0378432977d83366a3211c67f8913018d
max
  Mon Sep 21 06:21:51 2026 -0700
hgc and hgTrackUi: open off-site links in a new tab, with rel="noopener noreferrer"

offsiteLinksToNewTab() in utils.js runs over the rendered page alongside
addHgsidToLinks() and gives every http(s) link whose host is not ours a
target=_blank it does not already have, plus rel="noopener noreferrer".  Without
noopener the page that opens keeps a handle on the tab it came from and can
navigate it; without noreferrer the Referer header carries our own URL, which has
the session id in it.  The href on a track description page is written by whoever
wrote the track or the hub, so neither is theoretical.  A mailto: or an ftp: link
is left alone, and so is every link that stays on this server.

jsAddHgsidToLinks() now emits both calls and is renamed jsFixUpPageLinks().
hgTracks.js runs the same pass over the track description popup: the replace it
does before that already puts a target on every link in there, so what this adds
is the rel on the ones that leave.

refs #38380

diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c
index d117c9271d6..6bfb7c2ea42 100644
--- src/hg/hgc/hgc.c
+++ src/hg/hgc/hgc.c
@@ -3813,31 +3813,31 @@
 char *html = getHtmlFromSelfOrParent(tdb, liftDb);
 if (html != NULL && html[0] != 0)
     {
     htmlHorizontalLine();
 
     // Add pennantIcon
     printPennantIconNote(tdb);
 
     // Wrap description html in div with limited width, so when the page is very wide
     // due to long details, the user doesn't have to scroll right to read the description.
     puts("<div class='readableWidth'>");
     puts(html);
     puts("</div>");
     }
 hPrintf("<BR>\n");
-jsAddHgsidToLinks();
+jsFixUpPageLinks();
 }
 
 static struct chain *quickLiftChainInRange(struct trackDb *tdb, int id)
 /* Load one chain out of the assembly the track came from and map it onto the reference.
  * Every chain in the window is loaded and then matched on id, rather than asking for the
  * one id:  the chain's sequence name in the other assembly is not known here, and the
  * by-id loaders abort when the id is not in the range they were given. */
 {
 char *liftDb = trackDbSetting(tdb, "quickLiftDb");
 char *table = NULL;
 quickLiftResolveTable(tdb, trackHubSkipHubName(tdb->table), &table, &liftDb);
 char *quickLiftFile = trackDbSetting(tdb, "quickLiftUrl");
 
 char *chainFile = NULL, *linkFile = NULL;
 if (startsWith("big", tdb->type))