ed65d23618ec85f58df1bc341199e904fab55929
lrnassar
Fri Sep 18 00:40:10 2026 -0700
hgTrackUi: substitute description page variables once, and in the container excerpt too. refs #38283
Removes the hVarSubstTrackDbHtml call in doMiddle. trackUi already calls it at each
of the two places that go on to print tdb->html, each after its own quickLift
getTrackHtml swap, so the doMiddle call was a second pass over the same text. That
second pass ate the escape in $$db, which reached the reader as hg38 in hgTrackUi
while hgc correctly showed $db. The plain ajax path returns before any html is
printed, so it loses nothing.
The Description panel at the top of a subtrack's settings page shows an excerpt of
its container's page, and nothing had substituted that one. A hub page using ${db}
or ${organism} in its opening paragraph showed the text raw there while the same
page rendered correctly further down the screen.
diff --git src/hg/hgTrackUi/hgTrackUi.c src/hg/hgTrackUi/hgTrackUi.c
index 566c540ee23..711f96846c5 100644
--- src/hg/hgTrackUi/hgTrackUi.c
+++ src/hg/hgTrackUi/hgTrackUi.c
@@ -3738,30 +3738,33 @@
// show super-track info
struct trackDb *tdbParent = tdb->parent;
printf("<b>Configure track container: "
"<img height=12 src='../images/ab_up.gif'>"
"<a href='%s?%s=%s&db=%s&c=%s&g=%s'>%s </a></b>",
hgTrackUiName(), cartSessionVarName(), cartSessionId(cart),
database, chromosome, cgiEncode(tdbParent->track), tdbParent->longLabel);
printf("<p>");
if (tdbIsFacetedComposite(tdb))
return;
if (tdbParent->html)
{
+ // the excerpt below is the container's own description page, so it needs the same
+ // substitution the track's page gets further down
+ hVarSubstTrackDbHtml(cart, tdbParent, database);
// collapsed panel for Description
printf("<p><table>"); // required by jsCollapsible
jsBeginCollapsibleSectionFontSize(cart, tdb->track, "superDescription", "Description", FALSE,
"medium");
// TODO: better done with regex
char *html = replaceChars(tdbParent->html, "<H", "<h");
html = replaceChars(html, "</H", "</h");
// remove Description header
html = replaceChars(html, "<h2>Description</h2>", "");
html = replaceChars(html, "<h3>Description</h3>", "");
html = replaceChars(html, "<h1>Description</h1>", "");
// remove everything after Description text
char *end = stringIn("<h2>", html);
@@ -4712,35 +4715,30 @@
if (tdb == NULL)
{
errAbort("Can't find %s in track database %s chromosome %s",
track, database, chromosome);
}
// Do little more dupe handling - make a tdb for dupe if any
if (isDup)
{
struct dupTrack *dup = dupTrackFindInList(dupList, dupWholeName);
if (dup == NULL)
errAbort("Can't find duplicate track %s", dupWholeName);
tdb = dupTdbFrom(tdb, dup);
}
-// resolve $hgsid, which hgTrackDb had no cart to resolve, and for a hub the rest of its
-// description page variables: a hub page never went through hgTrackDb at all. This is what
-// lets a hub page link to its container with $parentTrack.
-hVarSubstTrackDbHtml(cart, tdb, database);
-
if(cartOptionalString(cart, "ajax"))
{
// html is going to be used w/n a dialog in hgTracks.js so serve up stripped down html
// still need CSP2 header for security
printf("%s", getCspMetaHeader());
trackUi(tdb, tdbList, ct, TRUE);
cartRemove(cart,"ajax");
jsInlineFinish();
}
else
{
// htmlNoEscape() below lets the <span> through, so the labels themselves have to be
// escaped here - they come from trackDb, which a track hub controls
struct dyString *title = dyStringNew(0);
if (tdb->parent)