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("Configure track container: " "" "%s ", hgTrackUiName(), cartSessionVarName(), cartSessionId(cart), database, chromosome, cgiEncode(tdbParent->track), tdbParent->longLabel); printf("

"); 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("

"); // required by jsCollapsible jsBeginCollapsibleSectionFontSize(cart, tdb->track, "superDescription", "Description", FALSE, "medium"); // TODO: better done with regex char *html = replaceChars(tdbParent->html, "Description", ""); html = replaceChars(html, "

Description

", ""); html = replaceChars(html, "

Description

", ""); // remove everything after Description text char *end = stringIn("

", 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 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)