d99ea622f4024a17ea2cb5dbb4a4d81fd14395c7
jcasper
Mon Mar 16 10:05:34 2026 -0700
Moving cartDump vis adjustments for faceted tracks into its own function, per request. refs #37090
diff --git src/hg/cartDump/cartDump.c src/hg/cartDump/cartDump.c
index 43fde324e08..f959fb22f23 100644
--- src/hg/cartDump/cartDump.c
+++ src/hg/cartDump/cartDump.c
@@ -1,250 +1,266 @@
/* cartDump - Dump contents of cart. */
/* Copyright (C) 2014 The Regents of the University of California
* See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
#include "common.h"
#include "linefile.h"
#include "hash.h"
#include "cheapcgi.h"
#include "cart.h"
#include "hdb.h"
#include "jsHelper.h"
#include "hui.h"
#include "botDelay.h"
/* for earlyBotCheck() function at the beginning of main() */
#define delayFraction 1.0 /* standard penalty for most CGIs */
static boolean issueBotWarning = FALSE;
#define CART_DUMP_REMOVE_VAR "n/a"
struct hash *oldVars = NULL;
-void doMiddle(struct cart *cart)
-/* cartDump - Dump contents of cart. */
+void handleFacets(struct cart *cart)
+/* Process track vis updates for a faceted composite. This uses information about
+ * which data types (dt) and data elements (de) were on before and after the
+ * user made UI changes. If data types are used by the track, they're usually
+ * things like "reads" and "signals". Data elements are generally either sample
+ * IDs (if data types are also used) or just the ends of track names.
+ *
+ * If the user adds a new data element, we turn on all associated tracks for the
+ * active data types. If a user adds a new data type, we turn on all associated
+ * tracks for the active data elements. But if a data element/type combo was already
+ * checked, we don't re-enable that track because the user might have hidden it
+ * manually.
+ */
{
-#define MATCH_VAR "match"
-
-char *vName = "cartDump.varName";
-char *vVal = "cartDump.newValue";
char *mName = "cartDump.metaDataId";
-char *wildcard;
-boolean asTable = cartVarExists(cart,CART_DUMP_AS_TABLE);
-
-if (cgiVarExists("submit"))
- {
- char *varName = cgiOptionalString(vName);
- char *newValue = cgiOptionalString(vVal);
- if (isNotEmpty(varName) && isNotEmpty(newValue))
- {
- varName = skipLeadingSpaces(varName);
- eraseTrailingSpaces(varName);
- if (sameString(newValue, CART_DUMP_REMOVE_VAR) || sameString(newValue, CART_VAR_EMPTY))
- cartRemove(cart, varName);
- else
- cartSetString(cart, varName, newValue);
- }
- cartRemove(cart, vVal);
- cartRemove(cart, "submit");
- }
-if (cgiVarExists("noDisplay"))
- {
- // update cart vars for a track, called by hgTracks.js and ajax.js
- // not useful to hackers, so there is no need to call bottleneck.
- char *trackName = cgiOptionalString("g");
- if (trackName != NULL && hashNumEntries(oldVars) > 0)
- {
- char *db = cartString(cart, "db");
- struct trackDb *tdb = hTrackDbForTrack(db, trackName);
- if (tdb != NULL && tdbIsComposite(tdb))
- {
- struct lm *lm = lmInit(0);
- cartTdbTreeCleanupOverrides(tdb,cart,oldVars,lm);
- lmCleanup(&lm);
- }
- }
+if (!cgiVarExists(mName))
+ return;
- if (cgiVarExists(mName))
- {
char *mdid = cgiOptionalString(mName);
char mdid_de_was[1024], mdid_de_now[1024], mdid_dt_was[1024], mdid_dt_now[1024];
safef(mdid_de_was, sizeof(mdid_de_was), "%s.de_was", mdid);
safef(mdid_de_now, sizeof(mdid_de_now), "%s.de_now", mdid);
safef(mdid_dt_was, sizeof(mdid_dt_was), "%s.dt_was", mdid);
safef(mdid_dt_now, sizeof(mdid_dt_now), "%s.dt_now", mdid);
// Grab the lists of which de/dt elements were on before and after the user
// changed settings around
struct slName *de_was_list = cgiStringList(mdid_de_was);
struct slName *de_now_list = cgiStringList(mdid_de_now);
struct slName *dt_was_list = cgiStringList(mdid_dt_was);
struct slName *dt_now_list = cgiStringList(mdid_dt_now);
// For faster lookup
struct hash *de_was_hash = hashFromSlNameList(de_was_list);
struct hash *de_now_hash = hashFromSlNameList(de_now_list);
struct hash *dt_was_hash = hashFromSlNameList(dt_was_list);
struct hash *dt_now_hash = hashFromSlNameList(dt_now_list);
// Check if we sent dt_was/now variables, indicating that this composite has data types
boolean hasDataTypes = (dt_was_list != NULL || dt_now_list != NULL);
char subtrackSetting[1024];
if (hasDataTypes)
{
// Cross-product mode: tracks are identified by mdid_de_dt
// Turn ON: (de_on x dt_now), (de_now x dt_on)
// where de_on = de_now - de_was, dt_on = dt_now - dt_was
for (struct slName *de = de_now_list; de != NULL; de = de->next)
{
boolean de_is_new = (hashLookup(de_was_hash, de->name) == NULL);
for (struct slName *dt = dt_now_list; dt != NULL; dt = dt->next)
{
boolean dt_is_new = (hashLookup(dt_was_hash, dt->name) == NULL);
if (de_is_new || dt_is_new)
{
safef(subtrackSetting, sizeof(subtrackSetting),
"%s_%s_%s_sel", mdid, de->name, dt->name);
cartSetString(cart, subtrackSetting, "1");
}
}
}
// Turn OFF: (de_off x dt_was), (de_was x dt_off)
// where de_off = de_was - de_now, dt_off = dt_was - dt_now
for (struct slName *de = de_was_list; de != NULL; de = de->next)
{
boolean de_is_off = (hashLookup(de_now_hash, de->name) == NULL);
for (struct slName *dt = dt_was_list; dt != NULL; dt = dt->next)
{
boolean dt_is_off = (hashLookup(dt_now_hash, dt->name) == NULL);
if (de_is_off || dt_is_off)
{
safef(subtrackSetting, sizeof(subtrackSetting),
"%s_%s_%s_sel", mdid, de->name, dt->name);
cartSetString(cart, subtrackSetting, "0");
}
}
}
}
else
{
// Data elements only mode: tracks are identified by mdid_de
// Turn ON: de_now - de_was
for (struct slName *de = de_now_list; de != NULL; de = de->next)
{
if (hashLookup(de_was_hash, de->name) == NULL)
{
safef(subtrackSetting, sizeof(subtrackSetting),
"%s_%s_sel", mdid, de->name);
cartSetString(cart, subtrackSetting, "1");
}
}
// Turn OFF: de_was - de_now
for (struct slName *de = de_was_list; de != NULL; de = de->next)
{
if (hashLookup(de_now_hash, de->name) == NULL)
{
safef(subtrackSetting, sizeof(subtrackSetting),
"%s_%s_sel", mdid, de->name);
cartSetString(cart, subtrackSetting, "0");
}
}
}
hashFree(&de_was_hash);
hashFree(&de_now_hash);
hashFree(&dt_was_hash);
hashFree(&dt_now_hash);
slFreeList(&de_was_list);
slFreeList(&de_now_list);
slFreeList(&dt_was_list);
slFreeList(&dt_now_list);
cartRemove(cart, mName);
cartRemove(cart, mdid_de_was);
cartRemove(cart, mdid_de_now);
cartRemove(cart, mdid_dt_was);
cartRemove(cart, mdid_dt_now);
}
+
+void doMiddle(struct cart *cart)
+/* cartDump - Dump contents of cart. */
+{
+#define MATCH_VAR "match"
+
+char *vName = "cartDump.varName";
+char *vVal = "cartDump.newValue";
+char *wildcard;
+boolean asTable = cartVarExists(cart,CART_DUMP_AS_TABLE);
+
+if (cgiVarExists("submit"))
+ {
+ char *varName = cgiOptionalString(vName);
+ char *newValue = cgiOptionalString(vVal);
+ if (isNotEmpty(varName) && isNotEmpty(newValue))
+ {
+ varName = skipLeadingSpaces(varName);
+ eraseTrailingSpaces(varName);
+ if (sameString(newValue, CART_DUMP_REMOVE_VAR) || sameString(newValue, CART_VAR_EMPTY))
+ cartRemove(cart, varName);
+ else
+ cartSetString(cart, varName, newValue);
+ }
+ cartRemove(cart, vVal);
+ cartRemove(cart, "submit");
+ }
+if (cgiVarExists("noDisplay"))
+ {
+ // update cart vars for a track, called by hgTracks.js and ajax.js
+ // not useful to hackers, so there is no need to call bottleneck.
+ char *trackName = cgiOptionalString("g");
+ if (trackName != NULL && hashNumEntries(oldVars) > 0)
+ {
+ char *db = cartString(cart, "db");
+ struct trackDb *tdb = hTrackDbForTrack(db, trackName);
+ if (tdb != NULL && tdbIsComposite(tdb))
+ {
+ struct lm *lm = lmInit(0);
+ cartTdbTreeCleanupOverrides(tdb,cart,oldVars,lm);
+ lmCleanup(&lm);
+ }
+ }
+ handleFacets(cart);
return;
}
// To discourage hacking, call bottleneck
if (issueBotWarning)
{
char *ip = getenv("REMOTE_ADDR");
botDelayMessage(ip, botDelayMillis);
}
if (asTable)
{
jsIncludeFile("jquery.js",NULL); // required by utils.js
jsIncludeFile("utils.js",NULL);
jsIncludeFile("ajax.js",NULL);
printf("Show as plain text.
",CART_DUMP_AS_TABLE);
printf("
");
wildcard = cgiOptionalString(MATCH_VAR);
if (wildcard)
cartDumpLike(cart, wildcard);
else
cartDump(cart);
printf("");
if (!asTable)
{
printf("\n");
}
printf("Cookies passed to %s:
\n%s\n