ca7d5327e325b074ce65c86f9ef7fea5be47ab25 tdreszer Wed Jul 20 11:13:05 2011 -0700 Initial check-in of not yet comple subtrack configuration module. diff --git src/hg/lib/hui.c src/hg/lib/hui.c index e3ffd74..1a680c9 100644 --- src/hg/lib/hui.c +++ src/hg/lib/hui.c @@ -16,53 +16,54 @@ #include "chainDb.h" #include "netCart.h" #include "obscure.h" #include "wiggle.h" #include "phyloTree.h" #include "hgMaf.h" #include "udc.h" #include "customTrack.h" #include "encode/encodePeak.h" #include "mdb.h" #include "web.h" #include "hPrint.h" #include "fileUi.h" #include "bigBed.h" #include "bigWig.h" +#include "regexHelper.h" static char const rcsid[] = "$Id: hui.c,v 1.297 2010/06/02 19:27:51 tdreszer Exp $"; #define SMALLBUF 128 #define MAX_SUBGROUP 9 #define ADD_BUTTON_LABEL "add" #define CLEAR_BUTTON_LABEL "clear" #define JBUFSIZE 2048 //#define PM_BUTTON "\"%s\"\n" //#define DEF_BUTTON "\"%s\"\n" //#define DEFAULT_BUTTON(nameOrId,anc,beg,contains) printf(DEF_BUTTON,(anc),(anc),(nameOrId), (beg),(contains),(nameOrId),(beg),(contains),(anc),"defaults_sm.png","default") //#define PLUS_BUTTON(nameOrId,anc,beg,contains) printf(PM_BUTTON, (anc),(anc),(nameOrId),"true", (beg),(contains),(anc),"add_sm.gif", "+") //#define MINUS_BUTTON(nameOrId,anc,beg,contains) printf(PM_BUTTON, (anc),(anc),(nameOrId),"false",(beg),(contains),(anc),"remove_sm.gif","-") #define PM_BUTTON "\"%s\"\n" #define DEF_BUTTON "\"%s\"\n" #define DEFAULT_BUTTON(nameOrId,anc,beg,contains) printf(DEF_BUTTON,(nameOrId), (beg),(contains),(nameOrId),(beg),(contains),(anc),"defaults_sm.png","default") #define PLUS_BUTTON(nameOrId,anc,beg,contains) printf(PM_BUTTON, (nameOrId),"true", (beg),(contains),(anc),"add_sm.gif", "+") #define MINUS_BUTTON(nameOrId,anc,beg,contains) printf(PM_BUTTON, (nameOrId),"false",(beg),(contains),(anc),"remove_sm.gif","-") #define ENCODE_DCC_DOWNLOADS "encodeDCC" -//#define SUBTRACK_CFG_POPUP +#define SUBTRACK_CFG struct trackDb *wgEncodeDownloadDirKeeper(char *db, struct trackDb *tdb, struct hash *trackHash) /* Look up through self and parents, looking for someone responsible for handling * where the downloads are. */ { if (!tdbIsDownloadsOnly(tdb) && !sameString(tdb->table, tdb->track) && trackHash) { tdb = hashFindVal(trackHash, tdb->table); if (tdb == NULL) errAbort("Can't find track for table %s in wgEncodeDownloadDirKeeper", tdb->table); } return trackDbTopLevelSelfOrParent(tdb); } static char *htmlStringForDownloadsLink(char *database, struct trackDb *tdb,char *name,boolean nameIsFile, @@ -3489,49 +3490,53 @@ if(notFirst) dyStringPrintf(dyClause, " AND "); dyStringAppend(dyClause, clause); freeMem(clause); notFirst = TRUE; } } if(dyStringLen(dyClause) == 0) { dyStringFree(&dyClause); return NULL; } return dyStringCannibalize(&dyClause); } -void filterBySetCfgUi(struct trackDb *tdb, filterBy_t *filterBySet, boolean onOneLine) +void filterBySetCfgUi(struct cart *cart, struct trackDb *tdb, + filterBy_t *filterBySet, boolean onOneLine) /* Does the UI for a list of filterBy structure */ { if(filterBySet == NULL) return; #define FILTERBY_HELP_LINK "help" int count = slCount(filterBySet); if(count == 1) puts(""); else printf("Filter items by: (select multiple categories and items - %s)
\n",FILTERBY_HELP_LINK); filterBy_t *filterBy = NULL; +if(cartOptionalString(cart, "ajax") == NULL) + { webIncludeResourceFile("ui.dropdownchecklist.css"); jsIncludeFile("ui.dropdownchecklist.js",NULL); #ifdef NEW_JQUERY jsIncludeFile("ddcl.js",NULL); #endif///def NEW_JQUERY + } int ix=0; for(filterBy = filterBySet;filterBy != NULL; filterBy = filterBy->next) { puts(""); } // Finally the big "for loop" to list each subtrack as a table row. for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) { subtrack = subtrackRef->val; int ix; // Determine whether subtrack is checked, visible, configurable, has group membership, etc. int fourState = subtrackFourStateChecked(subtrack,cart); boolean checkedCB = fourStateChecked(fourState); boolean enabledCB = fourStateEnabled(fourState); eCfgType cType = cfgTypeFromTdb(subtrack,FALSE); -#ifdef SUBTRACK_CFG_POPUP - // Turn this off only if configurable explicitly set to off - if (trackDbSettingClosestToHome(subtrack, "configurable") && trackDbSettingClosestToHomeOn(subtrack, "configurable") == FALSE) -#else///ifndef SUBTRACK_CFG_POPUP + if (cType != cfgNone) + { + #ifdef SUBTRACK_CFG + // Turn off configuring for certain track type or if explicitly turned off + if (regexMatch(subtrack->track, "^snp[0-9]+") // Special cases to be removed + || regexMatch(subtrack->track, "^cons[0-9]+way") // (matches logic in json setup in imageV2.c) + || regexMatch(subtrack->track, "^multiz") + || SETTING_IS_OFF(trackDbSettingClosestToHome(subtrack, "configureByPopup"))) + #else///ifndef SUBTRACK_CFG if (trackDbSettingClosestToHomeOn(subtrack, "configurable") == FALSE) -#endif///ndef SUBTRACK_CFG_POPUP + #endif///ndef SUBTRACK_CFG cType = cfgNone; + } membership_t *membership = subgroupMembershipGet(subtrack); if (sortOrder == NULL && !useDragAndDrop) { if ( divisionIfNeeded(lastDivide,dividers,membership) ) colorIx = (colorIx == COLOR_BG_DEFAULT_IX ? COLOR_BG_ALTDEFAULT_IX : COLOR_BG_DEFAULT_IX); } // Start the TR which must have an id that is directly related to the checkBox id char *id = checkBoxIdMakeForTrack(subtrack,membersForAll->members,membersForAll->dimMax,membership); // view is known tag printf("\n",id,(!displayAll?" style='display:none'":"")); // Now the TD that holds the checkbox printf("", @@ -4055,132 +4064,130 @@ for(di=dimX;didimMax;di++) { if (membersForAll->members[di] && -1 != (ix = stringArrayIx(membersForAll->members[di]->groupTag, membership->subgroups, membership->count))) dyStringPrintf(dyHtml," %s",membership->membership[ix]); } if (membersForAll->members[dimV] && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count))) dyStringPrintf(dyHtml, " %s",membership->membership[ix]); // Saved view for last // And finally the checkBox is made! char htmlIdentifier[SMALLBUF]; safef(htmlIdentifier, sizeof(htmlIdentifier), "%s_sel", subtrack->track); cgiMakeCheckBoxFourWay(htmlIdentifier,checkedCB,enabledCB,id,dyStringContents(dyHtml),"onclick='matSubCbClick(this);' style='cursor:pointer'"); if (useDragAndDrop) printf(" "); - // TODO: make a "view" dropdown (fake to save rendering time) and a configurable wrench here right after the checkbox +#ifdef SUBTRACK_CFG + if (cType != cfgNone) // make a wrench + { + // TODO: make vis dd or vis text inp or vis img. Alternatively, make '*' to denote there are subtrack level differences. + enum trackVisibility vis = tdbVisLimitedByAncestry(cart, subtrack, TRUE); + #define SUBTRACK_CFG_WRENCH "\n" + printf(SUBTRACK_CFG_WRENCH,subtrack->track,hStringFromTv(vis)); + //#define SUBTRACK_CFG_WRENCH "\n" + //printf(SUBTRACK_CFG_WRENCH,subtrack->track); + } +#endif///def SUBTRACK_CFG // A hidden field to keep track of subtrack order if it could change if (sortOrder != NULL || useDragAndDrop) { safef(htmlIdentifier, sizeof(htmlIdentifier), "%s.priority", subtrack->track); float priority = (float)cartUsualDouble(cart, htmlIdentifier, subtrack->priority); printf("", htmlIdentifier, priority); // keeing track of priority } // A color patch which helps distinguish subtracks in some types of composites if (doColorPatch) { printf("", subtrack->colorR, subtrack->colorG, subtrack->colorB); } - // Subtrack configuration requires a field that is a link to an embedded (or popup) dialog -#ifdef SUBTRACK_CFG_POPUP - #define CFG_SUBTRACK_LINK "%s" - #define MAKE_CFG_SUBTRACK_LINK(table,label,title) printf(CFG_SUBTRACK_LINK, (table),(table),(label),(label),(title)) - struct dyString *dyLabel = newDyString(128); -#else///ifndef SUBTRACK_CFG_POPUP - #define CFG_SUBTRACK_LINK "%s" - #define MAKE_CFG_SUBTRACK_LINK(table,title) printf(CFG_SUBTRACK_LINK, (table),(table),(title)) -#endif///ndef SUBTRACK_CFG_POPUP - // If sortable, then there must be a column per sortable dimension if (sortOrder != NULL) { int sIx=0; for(sIx=0;sIxcount;sIx++) { ix = stringArrayIx(sortOrder->column[sIx], membership->subgroups, membership->count); // TODO: Sort needs to expand from subGroups to labels as well if (ix >= 0) { char *titleRoot=NULL; if (cvTermIsEmpty(sortOrder->column[sIx],membership->titles[ix])) titleRoot = cloneString("  "); else titleRoot = labelRoot(membership->titles[ix],NULL); // Each sortable column requires hidden goop (in the "abbr" field currently) which is the actual sort on value printf (""); freeMem(titleRoot); } } } else // Non-sortable tables do not have sort by columns but will display a short label (which may be a configurable link) { printf (""); } -#ifdef SUBTRACK_CFG_POPUP - dyStringFree(&dyLabel); -#endif///def SUBTRACK_CFG_POPUP // The long label column (note that it may have a "..." that allows getting at all the metadata) printf ("\n\n\n"); } puts("
"); if(count == 1) printf("Filter by %s (select multiple items - %s)",filterBy->title,FILTERBY_HELP_LINK); else printf("%s",filterBy->title); printf("
\n"); // TODO: columnCount (Number of filterBoxes per row) should be configurable through tdb setting #ifdef NEW_JQUERY #define FILTER_BY_FORMAT "
     ",subtrack->track,sortOrder->column[sIx],membership->membership[ix]); - #ifdef SUBTRACK_CFG_POPUP - dyStringPrintf(dyLabel,"%s ",titleRoot); - if (cType != cfgNone && sameString("view",sortOrder->column[sIx])) // configure link is on view currenntly TODO: make a wrench next to check box/view - { - dyStringAppend(dyLabel,"Configuration"); - MAKE_CFG_SUBTRACK_LINK(subtrack->track,dyStringContents(dyLabel),titleRoot); - } - #else///ifndef SUBTRACK_CFG_POPUP - if (cType != cfgNone && sameString("view",sortOrder->column[sIx])) - MAKE_CFG_SUBTRACK_LINK(subtrack->track,titleRoot); // FIXME: Currently configurable under sort only supported when multiview - #endif///ndef SUBTRACK_CFG_POPUP + #ifndef SUBTRACK_CFG + #define CFG_SUBTRACK_LINK "%s" + #define MAKE_CFG_SUBTRACK_LINK(table,title) printf(CFG_SUBTRACK_LINK, (table),(table),(title)) + if (cType != cfgNone && sameString("view",sortOrder->column[sIx])) // configure link is on view currently + MAKE_CFG_SUBTRACK_LINK(subtrack->track,titleRoot); else + #endif///ndef SUBTRACK_CFG printf("%s",titleRoot); puts (" "); indentIfNeeded(hierarchy,membership); - #ifdef SUBTRACK_CFG_POPUP - if (cType != cfgNone && cType != cfgWigMaf) // FIXME: wigMaf restriction is temporary until configureByPopup off is set - MAKE_CFG_SUBTRACK_LINK(subtrack->track,subtrack->shortLabel,subtrack->shortLabel); - #else///ifndef SUBTRACK_CFG_POPUP + #ifndef SUBTRACK_CFG if (cType != cfgNone) MAKE_CFG_SUBTRACK_LINK(subtrack->track,subtrack->shortLabel); - #endif///ndef SUBTRACK_CFG_POPUP else + #endif///ndef SUBTRACK_CFG printf("%s",subtrack->shortLabel); puts (" %s", subtrack->longLabel); if (trackDbSetting(parentTdb, "wgEncode") && trackDbSetting(subtrack, "accession")) printf (" [GEO:%s]", trackDbSetting(subtrack, "accession")); compositeMetadataToggle(db,subtrack,NULL,TRUE,FALSE, trackHash); printf(" "); -#ifndef SUBTRACK_CFG_POPUP // Embedded cfg dialogs are within the TD that contains the longLabel. This allows a wide item to be embedded in the table if (cType != cfgNone) { + #ifdef SUBTRACK_CFG + // How to make this thing float to the left? Container is overflow:visible + // and contained (made in js) is position:relative; left: -{some pixels} + #define CFG_SUBTRACK_DIV "" + #define MAKE_CFG_SUBTRACK_DIV(table,view) printf(CFG_SUBTRACK_DIV,(table),(view)?(view):"noView") + char * view = NULL; + if (membersForAll->members[dimV] && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count))) + view = membership->membership[ix]; + MAKE_CFG_SUBTRACK_DIV(subtrack->track,view); + #else///ifndef SUBTRACK_CFG dependentCfgsNeedBinding = TRUE; // configurable subtrack needs to be bound to composite settings #define CFG_SUBTRACK_DIV "
\n" #define MAKE_CFG_SUBTRACK_DIV(table,cfgVar,open) printf(CFG_SUBTRACK_DIV,(table),((open)?"":" style='display:none'"),(cfgVar),((open)?"on":"off")) safef(htmlIdentifier,sizeof(htmlIdentifier),"%s.childShowCfg",subtrack->track); boolean open = cartUsualBoolean(cart, htmlIdentifier,FALSE); MAKE_CFG_SUBTRACK_DIV(subtrack->track,htmlIdentifier,open); safef(htmlIdentifier,sizeof(htmlIdentifier),"%s",subtrack->track); cfgByCfgType(cType,db,cart,subtrack,htmlIdentifier,"Subtrack",TRUE); printf("
"); + #endif///ndef SUBTRACK_CFG } -#endif///ndef SUBTRACK_CFG_POPUP // A schema link for each track printf("
 "); makeSchemaLink(db,subtrack,"schema"); printf(" "); // Do we have a restricted until date? if (restrictions) { char *dateDisplay = encodeRestrictionDateDisplay(db,subtrack); if (dateDisplay) { if (dateIsOld(dateDisplay,"%F")) printf(" %s ", dateDisplay); else @@ -4205,34 +4212,34 @@ if (slCount(subtrackRefList) > 5) printf("\n"); // Restruction policy needs a link if (restrictions && sortOrder != NULL) printf("Restriction Policy", ENCODE_DATA_RELEASE_POLICY); printf("
"); if (sortOrder == NULL) printf(""); // Tying subtracks with matrix and subtrack cfgs with views requires javascript help puts(""); -#ifndef SUBTRACK_CFG_POPUP +#ifndef SUBTRACK_CFG if (dependentCfgsNeedBinding) cfgLinkToDependentCfgs(cart,parentTdb,parentTdb->track); -#endif//ndef SUBTRACK_CFG_POPUP +#endif//ndef SUBTRACK_CFG // Finally we are free of all this membersForAllSubGroupsFree(parentTdb,&membersForAll); dyStringFree(&dyHtml) sortOrderFree(&sortOrder); dividersFree(÷rs); hierarchyFree(&hierarchy); } static void compositeUiSubtracksMatchingPrimary(char *db, struct cart *cart, struct trackDb *parentTdb,char *primarySubtrack) /* Display list of subtracks associated with a primary subtrack for the hgTables merge function */ { assert(primarySubtrack != NULL); char *primaryType = getPrimaryType(primarySubtrack, parentTdb); char htmlIdentifier[SMALLBUF]; @@ -4874,31 +4881,31 @@ #ifdef ALL_SCORE_FILTERS_LOGIC // Numeric filters are first boolean isBoxOpened = FALSE; if (numericFiltersShowAll(cart, tdb, &isBoxOpened, boxed, compositeLevel, name, title) > 0) skipScoreFilter = TRUE; #endif///def ALL_SCORE_FILTERS_LOGIC // Add any multi-selects next if(filterBySet != NULL) { if(!tdbIsComposite(tdb) && cartOptionalString(cart, "ajax") == NULL) jsIncludeFile("hui.js",NULL); if (!isBoxOpened) // Note filterBy boxes are not double "boxed", if there are no other filters printf("
"); - filterBySetCfgUi(tdb,filterBySet,TRUE); + filterBySetCfgUi(cart,tdb,filterBySet,TRUE); filterBySetFree(&filterBySet); skipScoreFilter = TRUE; } // For no good reason scoreFilter is incompatible with filterBy and or numericFilters // FIXME scoreFilter should be implemented inside numericFilters and is currently specificly excluded to avoid unexpected changes if (skipScoreFilter) { #ifdef ALL_SCORE_FILTERS_LOGIC if (isBoxOpened) cfgEndBox(boxed); #endif///def ALL_SCORE_FILTERS_LOGIC return; // Cannot have both '*filter' and 'scoreFilter' } @@ -5356,31 +5363,31 @@ printf("

Filter out NMD targets."); cgiMakeCheckBox(varName, nmdDefault); } if(!sameString(tdb->track, "tigrGeneIndex") && !sameString(tdb->track, "ensGeneNonCoding") && !sameString(tdb->track, "encodeGencodeRaceFrags")) baseColorDropLists(cart, tdb, name); if (cartOptionalString(cart, "ajax") == NULL) { filterBy_t *filterBySet = filterBySetGet(tdb,cart,name); if(filterBySet != NULL) { printf("
"); - filterBySetCfgUi(tdb,filterBySet,FALSE); + filterBySetCfgUi(cart,tdb,filterBySet,FALSE); filterBySetFree(&filterBySet); } } cfgEndBox(boxed); } static boolean isSpeciesOn(struct cart *cart, struct trackDb *tdb, char *species, char *option, int optionSize, boolean defaultState) /* check the cart to see if species is turned off or on (default is defaultState) */ { boolean ret = defaultState; safef(option, optionSize, "%s.%s", tdb->track, species); /* see if this is a simple multiz (not composite track) */ char *s = cartOptionalString(cart, option); if (s != NULL) @@ -6093,31 +6100,33 @@ char *viewName = membersOfView->tags[ix]; printf("tags[ix],NULL)) || (firstOpened != -1 && firstOpened != ix)) printf(" style=\"display:none\""); printf("> "); int ix2=ix; while(0 < ix2--) printf(" "); printf("",membersOfView->count+1); safef(varName, sizeof(varName), "%s", view->track); if(configurable[ix] != cfgNone) { cfgByCfgType(configurable[ix],db,cart,view->subtracks,varName, membersOfView->titles[ix],TRUE); + #ifndef SUBTRACK_CFG cfgLinkToDependentCfgs(cart,parentTdb,varName); + #endif///ndef SUBTRACK_CFG } } } } puts(""); subgroupMembersFree(&membersOfView); freeMem(matchedSubtracks); return TRUE; } char *compositeLabelWithVocabLink(char *db,struct trackDb *parentTdb, struct trackDb *childTdb, char *vocabType, char *label) /* If the parentTdb has a controlledVocabulary setting and the vocabType is found, then label will be wrapped with the link to display it. Return string is cloned. */ { @@ -6424,36 +6433,39 @@ first = FALSE; } } } dyStringPrintf(dyLink,VOCAB_MULTILINK_END,members->groupTitle,members->groupTitle); freeMem(vocab); return dyStringCannibalize(&dyLink); } static boolean compositeUiByFilter(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName) /* UI for composite tracks: filter subgroups by multiselects to select subtracks. */ { membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,cart); if(membersForAll == NULL || membersForAll->filters == FALSE) // Not Matrix or filters return FALSE; +if(cartOptionalString(cart, "ajax") == NULL) + { jsIncludeFile("ui.core.js",NULL); webIncludeResourceFile("ui.dropdownchecklist.css"); jsIncludeFile("ui.dropdownchecklist.js",NULL); #ifdef NEW_JQUERY jsIncludeFile("ddcl.js",NULL); #endif///def NEW_JQUERY + } cgiDown(0.7); printf("Filter subtracks %sby: (select multiple %sitems - %s)
\n", (membersForAll->members[dimX] != NULL || membersForAll->members[dimY] != NULL ? "further ":""), (membersForAll->dimMax == dimA?"":"categories and "),FILTERBY_HELP_LINK); printf("\n"); // Do All [+][-] buttons if(membersForAll->members[dimX] == NULL && membersForAll->members[dimY] == NULL) // No matrix { #define PM_BUTTON_FILTER_COMP "" printf("
All:
"); printf(PM_BUTTON_FILTER_COMP,"true", "plus_fc",'+'); printf(PM_BUTTON_FILTER_COMP,"false","minus_fc",'-'); //#define PM_BUTTON2_FILTER_COMP "" @@ -6885,48 +6897,44 @@ } return TRUE; } void hCompositeUi(char *db, struct cart *cart, struct trackDb *tdb, char *primarySubtrack, char *fakeSubmit, char *formName, struct hash *trackHash) /* UI for composite tracks: subtrack selection. If primarySubtrack is * non-NULL, don't allow it to be cleared and only offer subtracks * that have the same type. If fakeSubmit is non-NULL, add a hidden * var with that name so it looks like it was pressed. */ { bool hasSubgroups = (trackDbSetting(tdb, "subGroup1") != NULL); boolean isMatrix = dimensionsExist(tdb); boolean viewsOnly = FALSE; -if (primarySubtrack == NULL) - { - if (!cartVarExists(cart, "ajax")) +if (primarySubtrack == NULL && !cartVarExists(cart, "ajax")) { if(trackDbSetting(tdb, "dragAndDrop") != NULL) jsIncludeFile("jquery.tablednd.js", NULL); jsIncludeFile("ajax.js",NULL); #ifdef TABLE_SCROLL jsIncludeFile("jquery.fixedtable.js",NULL); #endif//def TABLE_SCROLL - } jsIncludeFile("hui.js",NULL); } -#ifdef SUBTRACK_CFG_POPUP -printf(""); -cgiMakeHiddenVar("db", db); -printf("\n",tdb->track); +#ifdef SUBTRACK_CFG +cgiMakeHiddenVar("db", db); // TODO: Change these to json vars as per Larry's new method +printf("\n",tdb->track); #endif cgiDown(0.7); if (trackDbCountDescendantLeaves(tdb) < MANY_SUBTRACKS && !hasSubgroups) { if(primarySubtrack) compositeUiSubtracksMatchingPrimary(db, cart, tdb,primarySubtrack); else compositeUiSubtracks(db, cart, tdb, trackHash); return; } if (fakeSubmit) cgiMakeHiddenVar(fakeSubmit, "submit"); if(primarySubtrack == NULL) { @@ -6940,35 +6948,30 @@ { cgiDown(0.7); if(trackDbSettingOn(tdb, "allButtonPair")) { compositeUiAllButtons(db, cart, tdb, formName); } else if (!hasSubgroups || !isMatrix || primarySubtrack) { compositeUiNoMatrix(db, cart,tdb,primarySubtrack,formName); } else { compositeUiByMatrix(db, cart, tdb, formName); } } -#ifdef SUBTRACK_CFG_POPUP - if(primarySubtrack == NULL) - cfgLinkToDependentCfgs(cart,tdb,tdb->track); // Must be after views are set up to get view vis - printf("\n"); -#endif } cartSaveSession(cart); cgiContinueHiddenVar("g"); if(primarySubtrack) compositeUiSubtracksMatchingPrimary(db, cart, tdb,primarySubtrack); else compositeUiSubtracks(db, cart, tdb, trackHash); if (primarySubtrack == NULL) // primarySubtrack is set for tableBrowser but not hgTrackUi { if (trackDbCountDescendantLeaves(tdb) > 5) { cgiDown(0.7);