94041c12e043016875ebd340568bda0ccaf122f6
lrnassar
Wed Jul 8 13:53:22 2026 -0700
Add db= to cross-CGI hgTracks/hgTrackUi/hgc links to prevent wrong-assembly errors. refs #37840
Completes the incomplete work from #26892: links from the browser to a different
CGI omitted db=, so the target CGI fell back to the cart's db (often wrong),
producing "Can't find
This track is generated on-the-fly by the browser as needed.\n"
"There is no existing data file for this track. To obtain the data for this track\n"
"use the following kent command line program hgGcPercent:
Maximum Interval to Interpolate Across: ");
cgiMakeIntVar(&options[6][0], thisLineGap, 10 );
printf(" bases");
}
}
void affyTranscriptomeUi(struct trackDb *tdb)
/* put up UI for the GC percent track (a sample track)*/
{
int affyTranscriptomeHeightPer = atoi(cartUsualString(cart, "affyTranscriptome.heightPer", "100"));
char *fill = cartUsualString(cart, "affyTranscriptome.fill", "1");
printf("
");
printf(" Fill Blocks: ");
cgiMakeRadioButton("affyTranscriptome.fill", "1", sameString(fill, "1"));
printf(" on ");
cgiMakeRadioButton("affyTranscriptome.fill", "0", sameString(fill, "0"));
printf(" off ");
printf("
Track Height: ");
cgiMakeIntVar("affyTranscriptome.heightPer", affyTranscriptomeHeightPer, 5 );
printf(" pixels");
}
void ancientRUi(struct trackDb *tdb)
/* put up UI for the ancient repeats track to let user enter an
* integer to filter out those repeats with less aligned bases.*/
{
int ancientRMinLength = atoi(cartUsualString(cart, "ancientR.minLength", "50"));
printf("
Length Filter Exclude aligned repeats with less than ");
cgiMakeIntVar("ancientR.minLength", ancientRMinLength, 4 );
printf("aligned bases (not necessarily identical). Enter 0 for no filtering.");
}
void affyTransfragUi(struct trackDb *tdb)
/* Options for filtering affymetrix transfrag track based on score. */
{
boolean skipPseudos = cartUsualBoolean(cart, "affyTransfrags.skipPseudos", TRUE);
boolean skipDups = cartUsualBoolean(cart, "affyTransfrags.skipDups", FALSE);
printf(" ");
cgiMakeCheckBox("affyTransfrags.skipPseudos", skipPseudos);
printf(" Remove transfrags that overlap pseudogenes from display. ");
cgiMakeCheckBox("affyTransfrags.skipDups", skipDups);
printf(" Remove transfrags that have a BLAT match elsewhere in the genome from display. ");
}
void ucsfdemoUi(struct trackDb *tdb)
{
char **menu;
int menuSize = 0;
int menuPos = 0;
puts(" ER filter: ");
menuSize = 3;
menu = needMem((size_t)(menuSize * sizeof(char *)));
menuPos = 0;
menu[menuPos++] = "no filter";
menu[menuPos++] = "pos";
menu[menuPos++] = "neg";
cgiMakeDropList(UCSF_DEMO_ER, menu, menuSize,
cartCgiUsualString(cart, UCSF_DEMO_ER, UCSF_DEMO_ER_DEFAULT));
freez(&menu);
puts(" PR filter: ");
menuSize = 3;
menu = needMem((size_t)(menuSize * sizeof(char *)));
menuPos = 0;
menu[menuPos++] = "no filter";
menu[menuPos++] = "pos";
menu[menuPos++] = "neg";
cgiMakeDropList(UCSF_DEMO_PR, menu, menuSize,
cartCgiUsualString(cart, UCSF_DEMO_PR, UCSF_DEMO_PR_DEFAULT));
freez(&menu);
}
void hapmapSnpsUi(struct trackDb *tdb)
/* Options for filtering hapmap snps */
/* Default is always to not filter (include all data) */
/* snp track puts the menu options in kent/src/hg/lib/snp125Ui.h */
/* snp track also sets global variables, don't actually need this? */
/* Consider using radio buttons */
{
struct sqlConnection *conn = hAllocConn(database);
boolean isPhaseIII = sameString(trackDbSettingOrDefault(tdb, "hapmapPhase", "II"), "III");
if ((isPhaseIII && !sqlTableExists(conn, "hapmapPhaseIIISummary")) ||
(!isPhaseIII & !sqlTableExists(conn, "hapmapAllelesSummary")))
return;
puts("
");
puts("Display filters (applied to all subtracks):");
puts(" \n");
puts(" Population availability: ");
static char *popAvailMenuPhaseIII[] =
{ "no filter",
"all 11 Phase III populations",
"all 4 Phase II populations" };
static char *popAvailMenuPhaseII[] =
{ "no filter",
"all 4 populations",
"1-3 populations" };
char **menu = isPhaseIII ? popAvailMenuPhaseIII : popAvailMenuPhaseII;
cgiMakeDropList(HAP_POP_COUNT, menu, 3,
cartUsualString(cart, HAP_POP_COUNT, HAP_FILTER_DEFAULT));
puts(" Major allele mixture between populations: ");
static char *mixedMenu[] = { "no filter", "mixed", "not mixed" };
cgiMakeDropList(HAP_POP_MIXED, mixedMenu, 3,
cartUsualString(cart, HAP_POP_MIXED, HAP_FILTER_DEFAULT));
puts(" Monomorphism: ");
static char *noYesNoMenu[] = { "no filter", "yes", "no" };
char **pops = isPhaseIII ? hapmapPhaseIIIPops : hapmapPhaseIIPops;
int popCount = isPhaseIII ? HAP_PHASEIII_POPCOUNT : HAP_PHASEII_POPCOUNT;
puts("
");
int cellCount = 0, i;
char cartVar[128];
for (i = 0; i < popCount; i++)
{
char table[HDB_MAX_TABLE_STRING];
if (endsWith(tdb->track, "PhaseII"))
safef(table, sizeof(table), "hapmapSnps%sPhaseII", pops[i]);
else
safef(table, sizeof(table), "hapmapSnps%s", pops[i]);
if (sqlTableExists(conn, table))
{
if (cellCount == 0)
puts("
");
hFreeConn(&conn);
}
#ifdef UNUSED
static boolean isInTrackList(struct trackDb *tdbList, struct trackDb *target)
/* Return TRUE if target is in tdbList. */
{
struct trackDb *tdb;
for (tdb = tdbList; tdb != NULL; tdb = tdb->next)
if (tdb == target)
return TRUE;
return FALSE;
}
#endif /* UNUSED */
void superTrackUi(struct trackDb *superTdb, struct trackDb *tdbList)
/* List tracks in this collection, with visibility controls and UI links */
{
jsIncludeFile("hui.js",NULL);
printf("
");
printf("Tracks that are part of this container are listed below. Use the buttons below to set their visibility. The grey button shows each track's current visibility.
");
printf("\n
");
tdbRefSortPrioritiesFromCart(cart, &superTdb->children);
struct slRef *childRef;
char javascript[1024];
for (childRef = superTdb->children; childRef != NULL; childRef = childRef->next)
{
struct trackDb *tdb = childRef->val;
if (childRef == superTdb->children) // first time through
{
printf("
\n");
printf("Apply visibility: \n");
printf("\n");
printInfoIcon("The 'Apply to all visible tracks' button sets the visibility selected in this dropdown on all tracks below that are not hidden. "
"The 'Apply to all tracks' button sets the visibility selected in this dropdown on all tracks below, including hidden ones.");
// First button: set all selectors that are not on 'hide' to the current value of the top select
printf("\n");
jsOnEventById("click", "superVizApplyButton", "superUiSetAllTracks(true)");
// Second button: set all selectors to the current value of the top select
printf(" \n");
jsOnEventById("click", "superVizApplyAllButton", "superUiSetAllTracks()");
printf("
\n");
}
printf("
");
if (!tdbIsDownloadsOnly(tdb))
{
char id[256];
enum trackVisibility tv =
hTvFromString(cartUsualString(cart, tdb->track,hStringFromTv(tdb->visibility)));
safef(id, sizeof id, "%s_check", tdb->track);
printf("",
id, (tv != tvHide?" CHECKED":""));
safef(javascript, sizeof(javascript), "superT.selChanged(this)");
struct slPair *event = slPairNew("change", cloneString(javascript));
char *onlyVis = trackDbSetting(tdb, "onlyVisibility");
hTvDropDownClassVisOnlyAndExtra(tdb->track, tv, tdb->canPack,
(tv == tvHide ? "vizSelect hiddenText":"vizSelect normalText"),
onlyVis,
event);
// print a group of buttons that act like radiobuttons (see javascript lines below)
printf("
", tdb->track);
char *trackVizStr = hStringFromTv(tv);
// vizList is e.g. {"hide", "dense", "squish", "pack", "full"}, but can be shorter, e.g. when canPack=false
char **vizList = hTvGetVizArr(tv, tdb->canPack, onlyVis);
int vizListLen = arrNullLen(vizList);
for (int i = 0; i < vizListLen; i++) {
char *buttonViz = vizList[i];
// the currently active viz mode is an 'active' button = pressed
if (strcasecmp(buttonViz, trackVizStr) == 0)
printf("
");
printf("
\n
");
hPrintIcons(tdb);
safef(id, sizeof id, "%s_link", tdb->track);
// the
");
// Now configure the elements above with Javascript:
// * Clicking a button sets the dropdown to the button's text and triggers change
// so superT.selChanged() runs (handles checkbox sync, hiddenText class, auto-show/hide superTrack)
jsOnEventBySelector("click", ".seg-btn-group > button",
"let dropdown = $('[name=\"' + $(this).parent().data('trackname')+'\"]'); " // cannot use #id, . has special meaning
"let buttonText=$(this).text().toLowerCase(); "
"dropdown.val(buttonText).trigger('change');"
);
// * Clicking buttons does not submit the form (default action of is to submit, unless type=button)
jsInline("$('.seg-btn-group button').attr('type', 'button');");
// * Clicking buttons makes them pressed
jsInline("$('.seg-btn-group').on('click', 'button', function() {"
"$(this).addClass('seg-active').siblings().removeClass('seg-active');"
"});");
// * Changing the dropdown updates the buttons
jsInline("$('#superTrackTable .vizSelect').on('change', function() {"
"$(this).next().children().removeClass('seg-active');"
"let labelToFind = capitalizeFirstLetter($(this).val());"
"$(this).next().find('button').filter(function() { return $(this).text().trim() === labelToFind; }).addClass('seg-active');"
"});");
// * Grey out the superTrack dropdown when manually set to hide
jsInline("$('.superDropdown').on('change', function() {"
"if ($(this).val() === 'hide') {"
"$(this).removeClass('normalText').addClass('hiddenText');"
"} else {"
"$(this).removeClass('hiddenText').addClass('normalText');"
"}"
"});");
// * Hide all subtrack dropdowns from the user. They are used so the CGI arguments
// are sent to hgTracks, but are not necessary as UI elements anymore
jsInline("$('#superTrackTable .vizSelect').hide();");
// --- Supertrack-level filters ---
// If the supertrack's trackDb declares any filter.*, filterValues.*,
// filterByRange.*, etc. settings, render the standard filter UI here.
// The cart variables are stored under the supertrack's name
// (e.g. "lrSv.filter.svLen.min"). Subtracks inherit these values via
// cartOptionalStringClosestToHome() during hgTracks rendering; a cart
// value set on a subtrack always overrides the supertrack's.
if (bedHasFilters(superTdb))
{
// scoreCfgUi (called below with title==NULL) emits a and an empty
// before the filter table; the wrapper + scoped style below hides them
// without touching shared code other callers rely on.
puts("
");
puts("");
puts("
Filters: ");
printInfoIcon("Filter values set here apply to every track in this "
"container. A filter set directly on an individual track "
"overrides the value here for that track only.");
puts("
");
// Pass title=NULL so scoreCfgUi does not emit its "
title"
// banner. The container
above is already the section label.
scoreCfgUi(database, cart, superTdb, superTdb->track,
NULL, 1000, /*boxed=*/FALSE);
puts("
");
}
}
#ifdef USE_HAL
static void cfgHalSnake(struct trackDb *tdb, char *name)
{
boolean parentLevel = isNameAtParentLevel(tdb, name);
if (parentLevel)
return;
char *fileName = trackDbSetting(tdb, "bigDataUrl");
if (fileName == NULL)
return;
char *errString;
int handle = halOpenLOD(fileName, &errString);
if (handle < 0)
errAbort("can't open HAL file: %s", fileName);
struct hal_species_t *speciesList, *sp;
char *otherSpecies = trackDbSetting(tdb, "otherSpecies");
extern char *database;
speciesList = halGetPossibleCoalescenceLimits(handle, otherSpecies,
trackHubSkipHubName(database), &errString);
int count = 0;
for(sp=speciesList; sp; sp = sp->next)
count++;
if (count == 0)
return;
char codeVarName[1024];
safef(codeVarName, sizeof codeVarName, "%s.coalescent", tdb->track);
char **ancestors;
AllocArray(ancestors, count);
count = 0;
for(sp=speciesList; sp; sp = sp->next)
{
ancestors[count] = sp->name;
count++;
}
char *coalescent = cartOptionalString(cart, codeVarName);
printf("Set Coalescent Ancestor to:");
cgiMakeDropListFull(codeVarName, ancestors, ancestors,
count, coalescent, NULL, NULL);
}
#endif
static struct slPair *parseDataTypes(struct trackDb *tdb)
{
/* Parse the 'dataTypes' trackDb setting into an slName list.
* 'dataTypes' is a space separated list of words, each indicating a
* data type. Return value is NULL on error.
*/
char *tdbDataTypes = cloneString(trackDbSetting(tdb, "dataTypes"));
if (tdbDataTypes == NULL)
return NULL;
// A bit awkward to go through chopByWhite into slNameListFromStringArray, but
// the slNameList family of functions doesn't have a chopByWhite equivalent.
int n_datatypes = chopByWhiteRespectDoubleQuotes(tdbDataTypes, NULL, 0);
char **datatypes = calloc(n_datatypes, sizeof(char *));
chopByWhiteRespectDoubleQuotes(tdbDataTypes, datatypes, n_datatypes);
struct slPair *list = NULL;
// At this point, each row in datatypes is the string for one data type.
// Either a (possibly quoted) label, or else that followed by | followed
// by (possibly quoted) text to display with the data type checkox.
for (int i = 0; i < n_datatypes; i++)
{
// If it's just a name, use that for the name and the display title.
// But if it's of the form , then split them apart.
char *dtParts[2];
int partCount = chopByCharRespectDoubleQuotes(datatypes[i], '|',
dtParts, 2);
char *name, *title;
name = title = dtParts[0];
if (partCount > 1)
title = dtParts[1];
slPairAdd(&list, name, cloneString(title));
}
freeMem(tdbDataTypes);
return list;
}
unsigned long cartDbParseId(char *, char **); // ADS: avoid extra include
static void facetedCompositeUi(struct trackDb *tdb)
{
/* ADS: How facetedComposite differs from other track types
* - compositeTrack track setting is "faceted"
* - Required fields in the 'settings' longblob for the trackDb entry:
* - 'metaDataUrl': a non-blocked URL (can be server-local) with
* metadata to generate the table. This might change to an existing metadata
* setting in the future.
* - 'dataTypes': the names of the data types, ordered and space separated.
*
* This function will embed sessionDb.settings/cart data in the
* generated HTML. Instead of embedding all relevant tracks, it
* parses the tracks named like:
*
* facetedCompositeName_dataElementName_dataTypeName_sel=1
*
* And only sends unique dataElement and dataTypes, which might be
* much smaller. The faceted composite assumes that selection of
* dataTypes applies to all dataElements, but within the cart, these
* are separate tracks, and each must be present to be drawn. But
* the JS doesn't need the product {dataType} x {dataElement}, just
* the union {datType} U {dataElement}. These are put in two arrays
* in a JSON section of the HTML.
*/
const int token_size = 1024;
// html elements for the controls page (from singleCellMerged)
const char pageStyle[] =
"";
const char placeholderDiv[] = "\n";
// --- Get data from 'settings' field in 'trackDb' entry ---
// required
const char *metaDataUrl = trackDbSetting(tdb, "metaDataUrl");
const char *primaryKey = trackDbSetting(tdb, "primaryKey");
struct slPair *dataTypes = parseDataTypes(tdb);
boolean hasDataTypes = (dataTypes != NULL);
// optional
const char *colorSettingsUrl = (const char *)hashFindVal(tdb->settingsHash, "colorSettingsUrl");
const char *maxCheckboxes = (const char *)hashFindVal(tdb->settingsHash, "maxCheckboxes");
const char *subtrackUrls = trackDbSetting(tdb, "subtrackUrls");
// --- done parsing values from trackDb.settings ---
const char *metaDataId = tdb->track;
const int metaDataIdLen = strlen(metaDataId);
printf(pageStyle); // css
printf(placeholderDiv); // placholder
// start by figuring out what's on by default and hasn't been overridden
struct hash *defaultOn = hashNew(0);
for (struct trackDb *st = tdb->subtracks; st != NULL; st = st->next)
{
char *setting = NULL;
char *words[2];
boolean enabled = TRUE;
if ((setting = trackDbLocalSetting(st, "parent")) != NULL)
{
char *clone = NULL;
if (chopLine(clone = cloneString(setting), words) >= 2)
if (sameString(words[1], "off"))
enabled = FALSE;
freeMem(clone);
}
if (enabled)
{
char val[1024];
safef(val, sizeof(val), "%s_sel", st->track);
if (!cartVarExists(cart, val))
hashAdd(defaultOn, val, NULL);
}
}
/* --- START embedded JSON data --- */
struct jsonWrite *jw = jsonWriteNew();
jsonWriteObjectStart(jw, NULL);
// find selected data types
jsonWriteObjectStart(jw, "dataTypes");
struct slName *selectedDataTypes = NULL; // non-null val will be used as flag
if (hasDataTypes)
{
for (struct slPair *thisType = dataTypes; thisType != NULL; thisType = thisType->next)
{
char toMatch[token_size];
boolean selected = FALSE;
safef(toMatch, token_size, "%s_*_%s_sel", metaDataId, thisType->name);
// Easy case - check if there's a defaultOn track still active with this track type
if (hashItemExistsLike(defaultOn, toMatch))
{
slNameAddHead(&selectedDataTypes, thisType->name);
selected = TRUE;
}
else
{
// Now we have to check for any cart variables that turn on a track with this data type
struct slPair *dt_vars = cartVarsLike(cart, toMatch);
struct slPair *this_var = dt_vars;
while (this_var != NULL)
{
if (cartBoolean(cart, this_var->name))
{
slNameAddHead(&selectedDataTypes, thisType->name);
selected = TRUE;
break;
}
this_var = this_var->next;
}
slPairFreeList(&dt_vars);
}
char *label = htmlEncode(stripEnclosingDoubleQuotes(thisType->val));
jsonWriteObjectStart(jw, thisType->name);
jsonWriteNumber(jw, "active", selected ? 1 : 0);
jsonWriteString(jw, "title", label);
jsonWriteObjectEnd(jw);
freeMem(label);
}
}
// else: dataTypes dict is empty - JS will detect this
jsonWriteObjectEnd(jw);
// find selected data sets
jsonWriteListStart(jw, "dataElements");
if (hasDataTypes)
{
char toMatch[token_size];
safef(toMatch, token_size, "%s_*_*_sel", metaDataId);
struct slPair *mdidVars = cartVarsLike(cart, toMatch);
for (struct slPair *le = mdidVars; le != NULL; le = le->next)
{
if (cartBoolean(cart, le->name))
{
const char *nameStart = le->name + metaDataIdLen + 1;
const char *nameEnd = strchr(nameStart, '_');
if (nameEnd && nameEnd > nameStart)
{
char *name = cloneStringZ(nameStart, nameEnd - nameStart);
jsonWriteString(jw, NULL, name);
freeMem(name);
}
}
}
slPairFreeList(&mdidVars);
// Now add data elements on by default that haven't been modified
struct hashEl *el, *elList = hashElListHash(defaultOn);
for (el = elList; el != NULL; el = el->next)
{
if (!cartVarExistsLike(cart, el->name))
{
const char *nameStart = el->name + metaDataIdLen + 1;
const char *nameEnd = strchr(nameStart, '_');
if (nameEnd && nameEnd > nameStart)
{
char *name = cloneStringZ(nameStart, nameEnd - nameStart);
jsonWriteString(jw, NULL, name);
freeMem(name);
}
}
}
hashElFreeList(&elList);
}
else
{
// No data types - look for {mdid}_{de}_sel pattern (no dataType component)
char toMatch[token_size];
safef(toMatch, token_size, "%s_*_sel", metaDataId);
struct slPair *mdidVars = cartVarsLike(cart, toMatch);
for (struct slPair *le = mdidVars; le != NULL; le = le->next)
{
if (cartBoolean(cart, le->name))
{
// Extract data element name: between mdid_ and _sel
const char *nameStart = le->name + metaDataIdLen + 1;
const char *nameEnd = strstr(nameStart, "_sel");
if (nameEnd && nameEnd > nameStart)
{
char *name = cloneStringZ(nameStart, nameEnd - nameStart);
jsonWriteString(jw, NULL, name);
freeMem(name);
}
}
}
slPairFreeList(&mdidVars);
// Now add data elements on by default that haven't been modified
struct hashEl *el, *elList = hashElListHash(defaultOn);
for (el = elList; el != NULL; el = el->next)
{
if (!cartVarExistsLike(cart, el->name))
{
const char *nameStart = el->name + metaDataIdLen + 1;
const char *nameEnd = strstr(nameStart, "_sel");
if (nameEnd && nameEnd > nameStart)
{
char *name = cloneStringZ(nameStart, nameEnd - nameStart);
jsonWriteString(jw, NULL, name);
freeMem(name);
}
}
}
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);
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);
}
if (isNotEmpty(cartOptionalString(cart, "udcTimeout")))
jsonWriteBoolean(jw, "udcTimeout", TRUE);
jsonWriteObjectEnd(jw);
printf("\n", jw->dy->string);
jsonWriteFree(&jw);
/* --- END embedded JSON data --- */
jsIncludeFile("dataTables-2.2.2.min.js", NULL);
jsIncludeFile("dataTables.select-3.0.0.min.js", NULL);
jsIncludeFile("facetedComposite.js", NULL);
webIncludeResourceFile("dataTables-2.2.2.min.css");
webIncludeResourceFile("dataTables.select-3.0.0.min.css");
webIncludeResourceFile("facetedComposite.css");
// cleanup
slPairFreeValsAndList(&dataTypes);
hashFree(&defaultOn);
}
static void myVariantsShareUi(struct trackDb *tdb)
/* Render the inline share management section on hgTrackUi for a user's own
* myVariants track. Emits HTML + calls into hui.js via jsInline to wire up
* the create/list/revoke API calls. */
{
char *userName = getUserName();
if (userName == NULL)
{
printf("
\n");
jsInline("if (typeof myVariantsShareInit === 'function') myVariantsShareInit();\n");
}
void specificUi(struct trackDb *tdb, struct trackDb *tdbList, struct customTrack *ct, boolean ajax)
/* Draw track specific parts of UI. */
{
char *track = tdb->track;
char *db = database;
char *liftDb = cloneString(trackDbSetting(tdb, "quickLiftDb"));
if (liftDb != NULL)
db = liftDb;
// Ideally check cfgTypeFromTdb()/cfgByCfgType() first, but with all these special cases already in
// place, lets be cautious at this time.
// NOTE: Developer, please try to use cfgTypeFromTdb()/cfgByCfgType().
boolean boxed = trackDbSettingClosestToHomeOn(tdb, "boxedCfg");
boolean isGencode3 = trackDbSettingOn(tdb, "isGencode3");
// UI precedence:
// 1) supers to get them out of the way: they have no controls
// 2) special cases based upon track name (developer please avoid)
// 3) cfgTypeFromTdb()/cfgByCfgType() <== prefered method
// 4) special cases falling through the cracks but based upon type
if (tdbIsSuperTrack(tdb))
superTrackUi(tdb, tdbList);
else if (tdbIsComposite(tdb) && sameOk(trackDbLocalSetting(tdb, "compositeTrack"), "faceted"))
facetedCompositeUi(tdb);
else if (sameString(track, "stsMap"))
stsMapUi(tdb);
else if (sameString(track, "affyTxnPhase2"))
affyTxnPhase2Ui(tdb);
else if (sameString(track, "cgapSage"))
cgapSageUi(tdb);
else if (sameString(track, "stsMapMouseNew"))
stsMapMouseUi(tdb);
else if (sameString(track, "stsMapRat"))
stsMapRatUi(tdb);
else if (sameString(track, "snpMap"))
snpMapUi(tdb);
else if (sameString(track, "snp"))
snpUi(tdb);
else if (snpVersion(track) >= 125)
snp125Ui(tdb);
else if (sameString(track, "rertyHumanDiversityLd")
|| startsWith("hapmapLd", track)
|| sameString(tdb->type, "ld2"))
ldUi(tdb);
else if (sameString(track, "cbr_waba"))
cbrWabaUi(tdb);
else if (sameString(track, "fishClones"))
fishClonesUi(tdb);
else if (sameString(track, "recombRate"))
recombRateUi(tdb);
else if (sameString(track, "recombRateRat"))
recombRateRatUi(tdb);
else if (sameString(track, "recombRateMouse"))
recombRateMouseUi(tdb);
else if (sameString(track, "cghNci60"))
cghNci60Ui(tdb);
else if (sameString(track, "xenoRefGene")
|| sameString(track, "ncbiGene")
|| sameString(track, "refGene"))
refGeneUI(tdb);
else if (startsWith("transMapAln", track) && (trackDbSetting(tdb, "bigDataUrl") == NULL))
transMapUI(tdb);
else if (sameString(track, "rgdGene2"))
rgdGene2UI(tdb);
else if (sameString(track, "knownGene") && !isGencode3)
knownGeneUI(tdb);
else if (sameString(track, "omimLocation"))
omimLocationUI(tdb);
else if (sameString(track, "omimGene2"))
omimGene2UI(tdb);
else if (sameString(track, "omimGene"))
omimGeneUI(tdb);
else if (sameString(track, "hg17Kg"))
hg17KgUI(tdb);
else if (startsWith("ucscRetro", track)
|| startsWith("retroMrnaInfo", track))
retroGeneUI(tdb);
else if (sameString(track, "ensGeneNonCoding"))
ensemblNonCodingUI(tdb);
else if (startsWith("refSeqComposite", track))
ncbiRefSeqUI(tdb);
else if (sameString(track, "ensGene"))
ensGeneUI(tdb);
else if (sameString(track, "vegaGeneComposite"))
vegaGeneUI(tdb);
else if (sameString(track, "rosetta"))
rosettaUi(tdb);
else if (startsWith("pubs", track))
pubsUi(tdb);
else if (startsWith("blastDm", track))
blastFBUi(tdb);
else if (sameString(track, "blastSacCer1SG"))
blastSGUi(tdb);
else if (sameString(track, "blastHg17KG")
|| sameString(track, "blastHg16KG")
|| sameString(track, "blastCe3WB")
|| sameString(track, "blastHg18KG")
|| sameString(track, "blatzHg17KG")
|| startsWith("mrnaMap", track)
|| startsWith("mrnaXeno", track))
blastUi(tdb);
else if (sameString(track, "hgPcrResult"))
pcrResultUi(tdb);
else if (sameString(track, "ancientR"))
ancientRUi(tdb);
else if (sameString(track, "zoo")
|| sameString(track, "zooNew" ))
zooWiggleUi(tdb);
else if (sameString(track, "humMusL")
|| sameString(track, "musHumL")
|| sameString(track, "regpotent")
|| sameString(track, "mm3Rn2L" )
|| sameString(track, "mm3Hg15L" )
|| sameString(track, "hg15Mm3L" ))
humMusUi(tdb,7);
else if (startsWith("chain", track)
|| endsWith("chainSelf", track))
chainColorUi(tdb);
else if (sameString(track, "orthoTop4") // still used ??
|| sameString(track, "mouseOrtho")
|| sameString(track, "mouseSyn"))
// NOTE: type psl xeno tracks use crossSpeciesCfgUi, so
// add explicitly here only if track has another type (bed, chain).
// For crossSpeciesCfgUi, the
// default for chrom coloring is "on", unless track setting
// colorChromDefault is set to "off"
crossSpeciesCfgUi(cart,tdb);
else if (sameString(track, "affyTranscriptome"))
affyTranscriptomeUi(tdb);
else if (sameString(track, WIKI_TRACK_TABLE))
wikiTrackUi(tdb);
else if (sameString(track, RULER_TRACK_NAME))
rulerUi(tdb);
else if (sameString(trackHubSkipHubName(track), "quickLiftChain"))
quickLiftUi(tdb);
else if (sameString(track, OLIGO_MATCH_TRACK_NAME))
oligoMatchUi(tdb);
else if (sameString(track, GC_ON_FLY_TRACK_NAME))
gcOnFlyUi(tdb);
else if (sameString(track, CUTTERS_TRACK_NAME))
cutterUi(tdb);
else if(sameString(track, "affyTransfrags"))
affyTransfragUi(tdb);
else if (sameString(track, "gvPos"))
gvUi(tdb);
else if (sameString(track, "oreganno"))
oregannoUi(tdb);
else if (startsWith("retroposons", track))
retroposonsUi(tdb);
else if (sameString(track, "tfbsConsSites"))
tfbsConsSitesUi(tdb);
else if (sameString(track, "CGHBreastCancerUCSF"))
ucsfdemoUi(tdb);
else if (startsWith("hapmapSnps", track))
hapmapSnpsUi(tdb);
else if (sameString(track, "switchDbTss"))
switchDbScoreUi(tdb);
else if (sameString(track, "dgv")
|| (startsWith("dgvV", track) && isdigit(track[4])))
dgvUi(tdb);
else if (sameString(track, "all_mrna")
|| sameString(track, "mrna")
|| sameString(track, "all_est")
|| sameString(track, "est")
|| sameString(track, "tightMrna")
|| sameString(track, "tightEst")
|| sameString(track, "intronEst")
|| sameString(track, "xenoMrna")
|| sameString(track, "xenoEst"))
mrnaCfgUi(cart, tdb, tdb->track, NULL, boxed);
else if (sameString(track, "lrg"))
lrgCfgUi(cart, tdb, tdb->track, NULL, boxed);
else if (startsWithWord("hic", tdb->type) && tdbIsComposite(tdb))
hicCfgUiComposite(cart, tdb, tdb->track, NULL, boxed); // Some hic options aren't available at this level
else if (tdb->type != NULL)
{ // NOTE for developers: please avoid special cases and use cfgTypeFromTdb//cfgByCfgType()
// When you do, then multi-view cfg and subtrack cfg will work.
eCfgType cType = cfgTypeFromTdb(tdb,FALSE);
if (cType != cfgNone)
{
cfgByCfgType(cType,db, cart, tdb,tdb->track, NULL, boxed);
if (startsWith("gtexGene", track))
gtexGeneUi(cart, tdb, tdb->track, NULL, TRUE);
else if (startsWith("gtexEqtlCluster", track))
gtexEqtlClusterUi(cart, tdb, tdb->track, NULL, TRUE);
#ifdef USE_HAL
if (cType == cfgSnake)
cfgHalSnake(tdb, tdb->track);
#endif
}
// NOTE: these cases that fall through the cracks should probably get folded into cfgByCfgType()
else if (startsWithWord("expRatio", tdb->type))
expRatioUi(tdb);
else if (startsWith("chromGraph", tdb->type))
chromGraphUi(tdb);
else if (startsWith("sample", tdb->type))
genericWiggleUi(tdb,7);
else if (startsWithWord("array",tdb->type)) // not quite the same as "expRatio" (custom tracks)
expRatioCtUi(tdb);
else if (startsWithWord("factorSource",tdb->type))
factorSourceUi(db,tdb);
else if (startsWithWord("bigBed",tdb->type))
labelCfgUi(db, cart, tdb, tdb->track);
}
if (tdbSupportsColorOverride(tdb))
colorTrackOption(cart, tdb->track, tdb);
/* myVariants own track: render inline share management. Skip shared tracks
* (myVariants_shared_*) - you can't re-share someone else's data. */
if (cfgOptionBooleanDefault("doMyVariants", FALSE)
&& isMyVariantsTrack(tdb->track)
&& !isMyVariantsSharedTrack(tdb->track))
myVariantsShareUi(tdb);
if (!ajax) // ajax asks for a simple cfg dialog for right-click popup or hgTrackUi subtrack cfg
{
// Composites *might* have had their top level controls just printed,
// but almost certainly have additional controls
boolean isLogo = (trackDbSetting(tdb, "logo") != NULL);
// It'd be nice to handle faceted composites as a separate container type, but practically so much
// of the display features we want are identical to composites - it's easier to special case the UI.
if (tdbIsComposite(tdb) && !isLogo) // for the moment generalizing this to include other containers...
if (!sameOk(trackDbLocalSetting(tdb, "compositeTrack"), "faceted")) // but not faceted containers ...
hCompositeUi(db, cart, tdb, NULL, NULL, MAIN_FORM);
// Additional special case navigation links may be added
extraUiLinks(db, tdb, cart);
}
}
#ifdef UNUSED
static void findSuperChildrenAndSettings(struct trackDb *tdbList, struct trackDb *super)
/* Find the tracks that have super as a parent and stuff references to them on
* super's children list. Also do some visibility and parentName futzing. */
{
struct trackDb *tdb;
for (tdb = tdbList; tdb != NULL; tdb = tdb->next)
{
if (tdb->parent == super)
{
trackDbSuperMemberSettings(tdb); /* This adds tdb to tdb->parent->children. */
}
}
}
#endif /* UNUSED */
struct jsonElement *jsonGlobalsHash = NULL;
void jsonPrintGlobals()
// prints out the "common" globals json hash
// This hash is the one utils.js and therefore all CGIs know about
{
if (jsonGlobalsHash != NULL)
{
struct dyString *dy = dyStringNew(1024);
jsonDyStringPrint(dy, jsonGlobalsHash, "common", 0);
jsInline(dy->string);
dyStringFree(&dy);
}
}
void jsonObjectAddGlobal(char *name, struct jsonElement *ele)
/* Add json object to global hash */
{
if (jsonGlobalsHash == NULL)
jsonGlobalsHash = newJsonObject(newHash(5));
jsonObjectAdd(jsonGlobalsHash, name, ele);
}
void showSupertrackInfo(struct trackDb *tdb)
{
// A bit of context when we're in hierarchy: parent description and sibling track list
if (!tdb->parent)
return;
// show super-track info
struct trackDb *tdbParent = tdb->parent;
printf("Configure track container: "
""
"%s ",
hgTrackUiName(), cartSessionVarName(), cartSessionId(cart),
chromosome, cgiEncode(tdbParent->track), tdbParent->longLabel);
printf("
");
if (tdbIsComposite(tdb) && sameOk(trackDbLocalSetting(tdb, "compositeTrack"), "faceted"))
return;
if (tdbParent->html)
{
// 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);
if (!end)
end = stringIn("
", html);
if (!end)
end = stringIn("
", html);
if (end)
*end = '\0';
printf("%s", html);
printf("
To view the full description, click "
"here.\n",
hgTrackUiName(), cartSessionVarName(), cartSessionId(cart),
chromosome, cgiEncode(tdbParent->track));
jsEndCollapsibleSection();
printf("
\n"); // required by jsCollapsible
}
// collapsed panel for list of other tracks in the supertrack
char listTitle[1000];
safef(listTitle, sizeof listTitle, "All tracks in this collection (%d)",
slCount(tdbParent->children));
printf("
",tdbParent?tdbParent->track:tdb->track);
}
cartRemove(cart,"descriptionOnly"); // This is a once only request and should be deleted
return;
}
if (tdbIsContainer(tdb) || tdbIsSuperTrack(tdb))
{
safef(setting,sizeof(setting),"%s.%s",tdb->track,RESET_TO_DEFAULTS);
// NOTE: if you want track vis to not be reset, move to after vis dropdown
if (1 == cartUsualInt(cart, setting, 0))
{
if (tdbIsSuperTrack(tdb))
{
// SuperTrack children live in tdb->children (slRef list), not in
// the subtracks tree that cartRemoveAllForTdbAndChildren walks.
// Clear the supertrack's own cart vars (filters, visibility) and
// each child's vars by hand.
cartRemoveAllForTdb(cart, tdb);
struct slRef *childRef;
for (childRef = tdb->children; childRef != NULL; childRef = childRef->next)
cartRemoveAllForTdb(cart, (struct trackDb *)childRef->val);
}
else
cartRemoveAllForTdbAndChildren(cart,tdb);
}
else if (!ajax) // Overkill on !ajax, because ajax shouldn't be called for a composite
cartTdbTreeReshapeIfNeeded(cart,tdb);
}
/* track configuration form */
printf("");
if (ajax)
return;
if (ct)
{
/* hidden form for custom tracks CGI */
printf("\n");
if (ct->bbiFile)
{
time_t timep = bbiUpdateTime(ct->bbiFile);
printBbiUpdateTime(&timep);
}
else
printUpdateTime(CUSTOM_TRASH, ct->tdb, ct);
}
if (!ct)
{
/* Print data version setting, if any */
cgiDown(0.7);
printRelatedTracks(database,trackHash,tdb,cart);
printDataVersion(database, tdb);
char *genome = hGenome(database);
char *desc = hFreezeDateOpt(database);
printf("Assembly: %s %s ", genome, desc);
/* Print lift information from trackDb, if any */
trackDbPrintOrigAssembly(tdb, database);
printUpdateTime(database, tdb, NULL);
}
char *liftDb = cloneString(trackDbSetting(tdb, "quickLiftDb"));
// quickLiftChain has static html
if (liftDb && differentString(trackHubSkipHubName(tdb->track), "quickLiftChain"))
tdb->html = getTrackHtml(liftDb, tdb->table);
if (tdb->html != NULL && tdb->html[0] != 0)
{
char *browserVersion;
if (btIE == cgiClientBrowser(&browserVersion, NULL, NULL) && *browserVersion < '8')
htmlHorizontalLine();
else // Move line down, since
Description (in ->html) is proceded by too much space
printf("");
printf("
");
puts(""); // include anchor for Description link
// Add pennantIcon
printPennantIconNote(tdb);
char *html = tdb->html;
if (trackDbSetting(tdb, "wgEncode"))
{
// add anchor to Credits section of ENCODE HTML page so lab contacts are easily found (on top menu)
html = replaceChars(tdb->html, "2>Credits", "2>\n
Credits
");
}
puts("
");
puts(html);
puts("
");
printf("
");
cgiDown(0.7); // positions top link below line
makeTopLink(tdb);
printf("
");
makeTopLink(tdb);
printf("
");
}
} /* void trackUi(struct trackDb *tdb) */
struct trackDb *trackDbForPseudoTrack(char *tableName, char *shortLabel,
char *longLabel, int defaultVis, boolean canPack)
/* Create trackDb for a track without a corresponding table. */
{
struct trackDb *tdb;
AllocVar(tdb);
tdb->track = tableName;
tdb->table = tableName;
tdb->shortLabel = shortLabel;
tdb->longLabel = longLabel;
tdb->visibility = defaultVis;
tdb->priority = 1.0;
tdb->html = hFileContentsOrWarning(hHelpFile(tableName));
tdb->type = "none";
tdb->grp = "map";
tdb->canPack = canPack;
return tdb;
}
struct trackDb *trackDbForWikiTrack()
/* Create a trackDb entry for the wikiTrack.
It is not a real track, so doesn't appear in trackDb */
{
return trackDbForPseudoTrack(WIKI_TRACK_TABLE,
WIKI_TRACK_LABEL, WIKI_TRACK_LONGLABEL, tvFull, FALSE);
}
struct trackDb *trackDbForRuler()
/* Create a trackDb entry for the base position ruler.
It is not (yet?) a real track, so doesn't appear in trackDb */
{
return trackDbForPseudoTrack(RULER_TRACK_NAME,
RULER_TRACK_LABEL, RULER_TRACK_LONGLABEL, tvFull, FALSE);
}
struct trackDb *trackDbForOligoMatch()
/* Create a trackDb entry for the oligo matcher pseudo-track. */
{
return trackDbForPseudoTrack(OLIGO_MATCH_TRACK_NAME,
OLIGO_MATCH_TRACK_LABEL, OLIGO_MATCH_TRACK_LONGLABEL, tvHide, TRUE);
}
static char *handleDupOp(char *track, struct hash *trackHash)
/* Handle the duplication operation in the URL if any. Return dupe name if
* a dupe has happened. The trackHash is keyed by track name and has
* struct trackDb values. */
{
char *newTrack = NULL;
/* Handle duplicate, and possible in the future other operations on tracks. */
char *opVar = "hgTrackUi_op";
char *operation = cartUsualString(cart, opVar, NULL);
if (operation != NULL)
{
if (sameString(operation, "dupe"))
{
struct trackDb *tdb = hashFindVal(trackHash, dupTrackSkipToSourceName(track));
newTrack = dupTrackInCartAndTrash(track, cart, tdb);
}
else if (sameString(operation, "undupe"))
{
newTrack = dupTrackSkipToSourceName(track);
undupTrackInCartAndTrash(track, cart);
}
else
{
internalErr();
}
cartRemove(cart, opVar);
}
return newTrack;
}
/* Setting names whose file contents are safe to serve via hgFetch.
* Only admin-configured (native track) values are checked -- never hub or custom tracks.
* Do NOT add bigDataUrl or bigDataIndex here -- those may be restricted (we
* might change this later to instead respect the tableBrowser setting in trackDb). */
static char *fetchableSettings[] = {"metaDataUrl", "colorSettingsUrl", NULL};
boolean fileUrlMatchesHub(char *fileUrl, struct hubConnectStatus *hubStatus)
/* Ignores fetchableSettings for now, whitelisting anything that sits inside
* the hub.txt directory structure. Assumes fileUrl has been canonicalized. */
{
char baseDir[2048];
splitPath(hubStatus->hubUrl, baseDir, NULL, NULL);
return startsWith(baseDir, fileUrl);
}
static boolean fileUrlMatchesTrackSetting(char *fileUrl, struct trackDb *tdb)
/* Check if fileUrl matches any whitelisted setting in this trackDb.
* Assumes fileUrl has been canonicalized. */
{
char **p;
for (p = fetchableSettings; *p != NULL; p++)
{
char *val = trackDbSetting(tdb, *p);
if (val != NULL && sameString(val, fileUrl))
return TRUE;
}
return FALSE;
}
void handleFileFetch(struct cart *cart)
/* Checks if a requested file is a legal request based on an attached cart or
* native track. If so, retrieves the file content via UDC and retransmits
* it as the page content. */
{
char *genome = NULL;
getDbAndGenome(cart, &database, &genome, NULL);
initGenbankTableNames(database);
char *fileUrl = cartOptionalString(cart, "fileUrl");
char *urlClone = cloneString(fileUrl);
cgiDecode(urlClone, urlClone, strlen(urlClone));
fileUrl = resolveDotDots(urlClone);
freeMem(urlClone);
boolean matchFound = FALSE;
// Check if fileUrl falls under a connected hub's base directory
struct slName *hubIds = hubConnectHubsInCart(cart);
struct slName *thisHubId = hubIds;
while (thisHubId != NULL)
{
struct hubConnectStatus *hubStatus = hubFromIdNoAbort(sqlUnsigned(thisHubId->name));
if (hubStatus != NULL)
{
if (isEmpty(hubStatus->errorMessage) && fileUrlMatchesHub(fileUrl, hubStatus))
{
matchFound = TRUE;
break;
}
}
thisHubId = thisHubId->next;
}
// For native database tracks (not hub or custom tracks), check if fileUrl matches
// a whitelisted trackDb setting. Only native tracks are checked here because their
// settings are admin-configured and trusted. Hub and custom track settings are
// user-controlled and could be used for SSRF attacks.
if (!matchFound)
{
char *track = cartOptionalString(cart, "track");
char *sourceDb = cartOptionalString(cart, "sourceDb"); // for future quickLift use
if (sourceDb == NULL)
sourceDb = database;
if (track != NULL && !isHubTrack(track) && !isCustomTrack(track))
{
struct trackDb *tdb = tdbForTrack(sourceDb, track, NULL);
if (tdb != NULL)
matchFound = fileUrlMatchesTrackSetting(fileUrl, tdb);
}
}
if (!matchFound)
{
puts("Status: 400 Bad Request");
errAbort("Supplied fileUrl does not match any connected hubs or track settings.");
}
// By now we know that fileUrl points to something valid to fetch and return to the user.
// Now we just have to fetch the file contents and retransmit it.
int timeout = cartUsualInt(cart, "udcTimeout", 300);
if (udcCacheTimeout() < timeout)
udcSetCacheTimeout(timeout);
struct udcFile *udc = udcFileMayOpen(fileUrl, NULL);
if (udc == NULL)
{
puts("Status: 404 Not Found");
puts("Content-Type: text/plain\n");
printf("Error: could not open %s\n", fileUrl);
freeMem(fileUrl);
return;
}
char maxAge[1024];
safef(maxAge, sizeof(maxAge), "max-age=%d", timeout);
printf("Cache-Control: %s\n", maxAge);
// See if we're getting a "has it changed" request.
// If so, return a 304 if nothing changed.
char etag[1024];
time_t mtime = udcUpdateTime(udc);
safef(etag, sizeof(etag), "\"%ld\"", mtime);
printf("ETag: %s\n", etag);
udcFileClose(&udc);
char *ifNone = getenv("HTTP_IF_NONE_MATCH");
if (isNotEmpty(ifNone))
{
if (sameStringN(etag, ifNone, strlen(etag)-1)) // Apache can add -gzip to etags during transmission
{
puts("Status: 304 Not Modified\n");
freeMem(fileUrl);
return;
}
}
puts("Content-Type: text/plain\n");
char *content = udcFileReadAll(fileUrl, NULL, 0, NULL);
puts(content);
freeMem(content);
freeMem(fileUrl);
}
void doMiddle(struct cart *theCart)
/* Write body of web page. */
{
boolean isFileFetch = isNotEmpty(cartOptionalString(theCart, "fileUrl"));
if (isFileFetch)
{
handleFileFetch(theCart); // file fetch workaround for CORS issues
return;
}
char *earlyOp = cartOptionalString(theCart, "hgTrackUi_op");
if (earlyOp != NULL && sameString(earlyOp, "quickLiftRemove"))
{
char *opTrack = cloneString(cartOptionalString(theCart, "g"));
char *opSourceDb = cloneString(cartOptionalString(theCart, "qlSourceDb"));
char *opDb = cloneString(cartUsualString(theCart, "db", ""));
cartRemove(theCart, "hgTrackUi_op");
cartRemove(theCart, "qlSourceDb");
if (opTrack != NULL && opSourceDb != NULL)
{
quickLiftHubRemoveTrack(theCart, opSourceDb, opTrack);
cartSetString(theCart, opTrack, "hide");
}
printf("Location: %s?db=%s&%s\r\n\r\n",
hgTracksName(), opDb, cartSidUrlString(theCart));
return;
}
cartWriteHeaderAndCont(theCart, NULL, NULL); // "normal" hgTrackUi
struct trackDb *tdbList = NULL;
struct trackDb *tdb = NULL;
char *track;
struct customTrack *ct = NULL, *ctList = NULL;
char *ignored;
/* used to have hgBotDelayFrac(0.25) here, replaced with earlyBotCheck()
* at the beginning of main() to output message here if in delay time
* 2021-06-21 - Hiram
*/
if (issueBotWarning)
{
char *ip = getenv("REMOTE_ADDR");
botDelayMessage(ip, botDelayMillis);
}
cart = theCart;
track = cartString(cart, "g");
getDbAndGenome(cart, &database, &ignored, NULL);
initGenbankTableNames(database);
chromosome = cartUsualString(cart, "c", hDefaultChrom(database));
trackHash = trackHashMakeWithComposites(database,chromosome,&tdbList,FALSE);
/* Handle dup of track related stuff */
char *dupeName = handleDupOp(track, trackHash);
if (dupeName != NULL)
track = dupeName;
struct dupTrack *dupList = dupTrackListFromCart(cart);
char *dupWholeName = NULL;
boolean isDup = isDupTrack(track);
if (isDup)
{
dupWholeName = track;
track = dupTrackSkipToSourceName(track);
}
/* Add in duplicate tracks. */
struct dupTrack *dup;
for (dup = dupList; dup != NULL; dup = dup->next)
{
struct trackDb *sourceTdb = hashFindVal(trackHash, dup->source);
if (sourceTdb != NULL)
{
struct trackDb *dupTdb = dupTdbFrom(sourceTdb, dup);
hashAdd(trackHash, dupTdb->track, dupTdb);
if (sourceTdb->parent != NULL)
{
struct trackDb *parent = sourceTdb->parent;
// Add to parent here depending on whether composite or something else?
if (tdbIsFolder(parent))
{
refAdd(&parent->children, dupTdb);
}
else
{
slAddHead(&parent->subtracks, dupTdb);
dupTdb = NULL; /* We use it! */
}
}
if (dupTdb != NULL)
slAddHead(&tdbList, dupTdb);
}
}
if (sameWord(track, WIKI_TRACK_TABLE))
tdb = trackDbForWikiTrack();
else if (sameWord(track, RULER_TRACK_NAME))
/* special handling -- it's not a full-fledged track */
tdb = trackDbForRuler();
else if (sameWord(track, OLIGO_MATCH_TRACK_NAME))
tdb = trackDbForOligoMatch();
else if (sameWord(track, CUTTERS_TRACK_NAME))
tdb = trackDbForPseudoTrack(CUTTERS_TRACK_NAME, CUTTERS_TRACK_LABEL, CUTTERS_TRACK_LONGLABEL, tvHide, TRUE);
else if (isCustomTrack(track)
|| (cfgOptionBooleanDefault("doMyVariants", FALSE) && isMyVariantsTrack(track)))
{
/* myVariants tracks (own and shared) are built dynamically and live in
* the CT list rather than the SQL trackDb table, but their names don't
* carry the ct_ prefix, so we need to look them up alongside regular
* custom tracks. */
ctList = customTracksParseCart(database, cart, NULL, NULL);
for (ct = ctList; ct != NULL; ct = ct->next)
{
if (sameString(track, ct->tdb->track))
{
tdb = ct->tdb;
break;
}
}
/* Fallback for direct hgTrackUi navigation without hgTracks: regenerate
* the myVariants CT file and re-parse. Normally the CT file was written
* during the preceding hgTracks visit, so this branch only fires for
* bookmarked URLs or direct links. */
if (tdb == NULL && isMyVariantsTrack(track))
{
char *userName = getUserName();
char *ctFile = myVariantsWriteCtFile(userName, database, cart);
if (isNotEmpty(ctFile))
{
char mvVarName[256];
safef(mvVarName, sizeof mvVarName, MYVARIANTS_FILE_VAR_PREFIX "%s", database);
cartSetString(cart, mvVarName, ctFile);
freeMem(ctFile);
ctList = customTracksParseCart(database, cart, NULL, NULL);
for (ct = ctList; ct != NULL; ct = ct->next)
{
if (sameString(track, ct->tdb->track))
{
tdb = ct->tdb;
break;
}
}
}
}
}
else if (isHubTrack(track))
{
tdb = hubConnectAddHubForTrackAndFindTdb(database, track, &tdbList, trackHash);
}
else if (sameString(track, "hgPcrResult"))
tdb = pcrResultFakeTdb();
else
{
tdb = tdbForTrack(database, track,&tdbList);
}
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);
}
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
{
char title[1000];
if (tdb->parent)
{
safef(title, sizeof title,
// TODO: replace in-line styling with class
""
"%s %s",
tdb->parent->shortLabel, tdb->shortLabel);
}
else
safef(title, sizeof title, "%s", tdb->shortLabel);
char *titleEnd = (tdbIsSuper(tdb) ? "Tracks" :
tdbIsDownloadsOnly(tdb) ? DOWNLOADS_ONLY_TITLE : "Track Settings");
htmlNoEscape(); // allow HTML tags to format title blue bar (using short label)
cartWebStart(cart, database, "%s %s", title, titleEnd);
htmlDoEscape();
trackUi(tdb, tdbList, ct, FALSE);
printf(" \n");
jsonPrintGlobals();
webEnd();
}
}
char *excludeVars[] = { "submit", "Submit", "g", "fileUrl", "track", "sourceDb", NULL, "ajax", NULL,};
int main(int argc, char *argv[])
/* Process command line. */
{
long enteredMainTime = clock1000();
/* 0, 0, == use default 10 second for warning, 20 second for immediate exit */
issueBotWarning = earlyBotCheck(enteredMainTime, "hgTrackUi", delayFraction, 0, 0, "html");
cgiSpoof(&argc, argv);
cartEmptyShellNoContent(doMiddle, hUserCookie(), excludeVars, NULL);
cgiExitTime("hgTrackUi", enteredMainTime);
return 0;
}