403ab7c9c2b204f487bb2f86260ffdab355e9517 jcasper Wed Aug 19 05:49:25 2026 -0700 Faceted composites should apply the active sort order to the tracks being displayed; changing the sort changes the display order. We also preserve that order when returning to the page. refs #36320 diff --git src/hg/hgTrackUi/hgTrackUi.c src/hg/hgTrackUi/hgTrackUi.c index e664821afe3..32bafce637f 100644 --- src/hg/hgTrackUi/hgTrackUi.c +++ src/hg/hgTrackUi/hgTrackUi.c @@ -3268,30 +3268,54 @@ hashElFreeList(&elList); } jsonWriteListEnd(jw); jsonWriteString(jw, "mdid", (char *)metaDataId); jsonWriteString(jw, "primaryKey", (char *)primaryKey); // must exist if (maxCheckboxes) // only if present in trackDb.settings entry jsonWriteString(jw, "maxCheckboxes", (char *)maxCheckboxes); if (colorSettingsUrl) // only if present in trackDb.settings entry jsonWriteString(jw, "colorSettingsUrl", cgiEncode((char *)colorSettingsUrl)); jsonWriteString(jw, "metadataUrl", cgiEncode((char *)metaDataUrl)); jsonWriteString(jw, "track", tdb->track); char *defaultSortField = trackDbSetting(tdb, "defaultSortField"); if (isNotEmpty(defaultSortField)) jsonWriteString(jw, "defaultSortField", defaultSortField); +// How the user last sorted the faceted table, if they have. This overrides +// defaultSortField in the javascript, which is the only side that can act on it - +// turning field names into column positions needs the metadata file. The value +// comes back from the cart, so it's untrusted, and this JSON lands inside a +// <script> block: only pass through the characters "field=+ field2=-" needs. +char facetSortVar[1024]; +safef(facetSortVar, sizeof(facetSortVar), "%s.facetSortOrder", metaDataId); +char *facetSortOrder = cartOptionalString(cart, facetSortVar); +if (isNotEmpty(facetSortOrder)) + { + boolean clean = TRUE; + char *c = facetSortOrder; + for ( ; *c != '\0'; c++) + { + if (!isalnum((unsigned char)*c) && *c != '_' && *c != '.' && *c != '-' + && *c != '+' && *c != '=' && *c != ' ') + { + clean = FALSE; + break; + } + } + if (clean) + jsonWriteString(jw, "facetSortOrder", facetSortOrder); + } if (isNotEmpty(subtrackUrls)) { struct slPair *pairs = slPairListFromString((char *)subtrackUrls, TRUE); if (pairs) { jsonWriteObjectStart(jw, "subtrackUrls"); for (struct slPair *p = pairs; p != NULL; p = p->next) { char *encoded = htmlEncode((char *)p->val); jsonWriteString(jw, p->name, encoded); freeMem(encoded); } jsonWriteObjectEnd(jw); } slPairFreeValsAndList(&pairs);