1b9262ae53dd23ca560dcc0e90773cfdd3b2ba3c kate Fri Jan 9 14:51:47 2015 -0800 Refactor subtrack table construction (500 line function) diff --git src/hg/lib/hui.c src/hg/lib/hui.c index 49d5293..d9a1004 100644 --- src/hg/lib/hui.c +++ src/hg/lib/hui.c @@ -3978,173 +3978,90 @@ char *date = NULL; if (metadataForTable(db,trackDb,NULL) != NULL) { date = cloneString((char *)metadataFindValue(trackDb,"dateUnrestricted")); if (date != NULL) date = strSwapChar(date, ' ', 0); // Truncate time (not expected, but just in case) if (excludePast && !isEmpty(date) && dateIsOld(date, MDB_ENCODE_DATE_FORMAT)) freez(&date); } return date; } -static void compositeUiSubtracks(char *db, struct cart *cart, struct trackDb *parentTdb) -// Display list of subtracks and descriptions with checkboxes to control visibility and -// possibly other nice things including links to schema and metadata and a release date. -{ -struct trackDb *subtrack; -struct dyString *dyHtml = newDyString(SMALLBUF); -//char *colors[2] = { COLOR_BG_DEFAULT, -// COLOR_BG_ALTDEFAULT }; -char *colors[2] = { "bgLevel1", - "bgLevel1" }; -int colorIx = COLOR_BG_DEFAULT_IX; // Start with non-default allows alternation - -// Get list of leaf subtracks to work with -struct slRef *subtrackRef, *subtrackRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks); - -// Look for dividers, heirarchy, dimensions, sort and dragAndDrop! -char **lastDivide = NULL; -dividers_t *dividers = dividersSettingGet(parentTdb); -if (dividers) - lastDivide = needMem(sizeof(char*)*dividers->count); -hierarchy_t *hierarchy = hierarchySettingGet(parentTdb); - -membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,NULL); -sortOrder_t* sortOrder = sortOrderGet(cart,parentTdb); -boolean preSorted = FALSE; -boolean useDragAndDrop = sameOk("subTracks",trackDbSetting(parentTdb, "dragAndDrop")); -char buffer[SMALLBUF]; -char *displaySubs = NULL; -int subCount = slCount(subtrackRefList); -#define LARGE_COMPOSITE_CUTOFF 30 -if (subCount > LARGE_COMPOSITE_CUTOFF && membersForAll->dimensions != NULL) - { - // ignore displaySubtracks setting for large composites with a matrix as - // matrix effectively shows all - safef(buffer,SMALLBUF,"%s.displaySubtracks",parentTdb->track); - displaySubs = cartUsualString(cart, buffer,"some"); // track specific defaults to only selected - } -else - { - displaySubs = cartUsualString(cart, "displaySubtracks", "all"); // browser wide defaults to all - } -boolean displayAll = sameString(displaySubs, "all"); - -// Determine whether there is a restricted until date column -boolean restrictions = FALSE; -for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) - { - subtrack = subtrackRef->val; - (void)metadataForTable(db,subtrack,NULL); - if (NULL != metadataFindValue(subtrack,"dateUnrestricted")) - { - restrictions = TRUE; - break; - } - } +/* Subtrack configuration settings */ -// Table wraps around entire list so that "Top" link can float to the correct place. -cgiDown(0.7); -printf("<table><tr><td class='windowSize'>"); -printf("<A NAME='DISPLAY_SUBTRACKS'></A>"); -if (sortOrder != NULL) +struct subtrackConfigSettings { - // First table row contains the display "selected/visible" or "all" radio buttons - // NOTE: list subtrack radio buttons are inside tracklist table header if - // there are no sort columns. The reason is to ensure spacing of lines - // column headers when the only column header is "Restricted Until" - printf("<B>List subtracks: "); - char javascript[JBUFSIZE]; - safef(javascript, sizeof(javascript), - "class='allOrOnly' onclick='showOrHideSelectedSubtracks(true);'"); - if (subCount > LARGE_COMPOSITE_CUTOFF) - safef(buffer,SMALLBUF,"%s.displaySubtracks",parentTdb->track); - else - safecpy(buffer,SMALLBUF,"displaySubtracks"); - cgiMakeOnClickRadioButton(buffer, "selected", !displayAll,javascript); - puts("only selected/visible "); - safef(javascript, sizeof(javascript), - "class='allOrOnly' onclick='showOrHideSelectedSubtracks(false);'"); - cgiMakeOnClickRadioButton(buffer, "all", displayAll,javascript); - printf("all</B>"); - if (slCount(subtrackRefList) > 5) - printf(" (<span class='subCBcount'></span>)"); - makeTopLink(parentTdb); - printf("</td></tr></table>"); - } -else - makeTopLink(parentTdb); + sortOrder_t *sortOrder; /* from trackDb setting */ + boolean useDragAndDrop; /* from trackDb setting */ + boolean restrictions; /* from metadata ? */ + boolean colorPatch; /* from trackDb setting */ + boolean displayAll; /* from radiobutton */ + int bgColorIx; /* from logic over other settings */ + int columnCount; /* determined from trackDb settings */ + }; +#define LARGE_COMPOSITE_CUTOFF 30 -// Now we can start in on the table of subtracks It may be sortable and/or dragAndDroppable -printf("\n<TABLE CELLSPACING='2' CELLPADDING='0' border='0'"); -dyStringClear(dyHtml); -if (sortOrder != NULL) - dyStringPrintf(dyHtml, "sortable"); -if (useDragAndDrop) - { - if (dyStringLen(dyHtml) > 0) - dyStringAppendC(dyHtml,' '); - dyStringPrintf(dyHtml, "tableWithDragAndDrop"); - } -printf(" class='subtracks"); -if (dyStringLen(dyHtml) > 0) +static void printSubtrackTableHeader(struct trackDb *parentTdb, struct slRef *subtrackRefList, + struct subtrackConfigSettings *settings) +/* Print header of subtrack table, including classes describing display appearance and behavior. + Return number of columns */ { - printf(" bglevel1 %s'",dyStringContents(dyHtml)); - colorIx = COLOR_BG_ALTDEFAULT_IX; - } +char buffer[SMALLBUF]; +boolean useDragAndDrop = settings->useDragAndDrop; +sortOrder_t *sortOrder = settings->sortOrder; if (sortOrder != NULL) - puts("'><THEAD class=sortable>"); + puts("<THEAD class=sortable>"); else - puts("'><THEAD>"); - -boolean doColorPatch = trackDbSettingOn(parentTdb, "showSubtrackColorOnUi"); + puts("<THEAD>"); int colspan = 3; if (sortOrder != NULL) colspan = sortOrder->count+2; else if (!tdbIsMultiTrack(parentTdb)) // An extra column for subVis/wrench so dragAndDrop works colspan++; -if (doColorPatch) +if (settings->colorPatch) colspan += 1; int columnCount = 0; if (sortOrder != NULL) - printf("<TR id=\"subtracksHeader\" class='sortable%s'>\n",useDragAndDrop?" nodrop nodrag":""); + printf("<TR id=\"subtracksHeader\" class='sortable%s'>\n", + useDragAndDrop ? " nodrop nodrag" : ""); else { printf("<TR%s>", useDragAndDrop ? " id='noDrag' class='nodrop nodrag'" : ""); // First table row contains the display "selected/visible" or "all" radio buttons // NOTE: list subtrack radio buttons are inside tracklist table header if // there are no sort columns. The reason is to ensure spacing of lines // column headers when the only column header is "Restricted Until" printf("<TD colspan='%d'><B>List subtracks: ", colspan); char javascript[JBUFSIZE]; safef(javascript, sizeof(javascript), "class='allOrOnly' onclick='showOrHideSelectedSubtracks(true);'"); + int subCount = slCount(subtrackRefList); if (subCount > LARGE_COMPOSITE_CUTOFF) safef(buffer,SMALLBUF,"%s.displaySubtracks",parentTdb->track); else safecpy(buffer,SMALLBUF,"displaySubtracks"); - cgiMakeOnClickRadioButton(buffer, "selected", !displayAll,javascript); + cgiMakeOnClickRadioButton(buffer, "selected", !settings->displayAll,javascript); puts("only selected/visible "); safef(javascript, sizeof(javascript), "class='allOrOnly' onclick='showOrHideSelectedSubtracks(false);'"); - cgiMakeOnClickRadioButton(buffer, "all", displayAll,javascript); + cgiMakeOnClickRadioButton(buffer, "all", settings->displayAll,javascript); printf("all</B>"); - if (slCount(subtrackRefList) > 5) + if (subCount > 5) printf(" (<span class='subCBcount'></span>)"); puts("</TD>"); columnCount = colspan; } // Add column headers which are sort button links if (sortOrder != NULL) { printf("<TH> <INPUT TYPE=HIDDEN NAME='%s' class='sortOrder' VALUE='%s'></TH>\n", sortOrder->htmlId, sortOrder->sortOrder); // keeing track of sortOrder columnCount++; if (!tdbIsMultiTrack(parentTdb)) // An extra column for subVis/wrench so dragAndDrop works { printf("<TH></TH>\n"); columnCount++; @@ -4170,73 +4087,125 @@ } // longLabel column assert(sameString(SORT_ON_TRACK_NAME,sortOrder->column[sIx])); printf("<TH id='%s' class='sortable%s sort%d' onclick='tableSortAtButtonPress(this);' " "align='left'> Track Name", sortOrder->column[sIx],(sortOrder->forward[sIx]?"":" sortRev"),sortOrder->order[sIx]); printf("<sup>%s%d</sup>",(sortOrder->forward[sIx]?"↓":"↑"),sortOrder->order[sIx]); puts("</TH>"); columnCount++; } puts("<TH> </TH>"); // schema column columnCount++; // Finally there may be a restricted until column -if (restrictions) +if (settings->restrictions) { if (sortOrder != NULL) { int sIx=sortOrder->count-1; assert(sameString(SORT_ON_RESTRICTED,sortOrder->column[sIx])); printf("<TH id='%s' class='sortable%s sort%d' onclick='tableSortAtButtonPress(this);' " "align='left'> Restricted Until", sortOrder->column[sIx], (sortOrder->forward[sIx]?"":" sortRev"),sortOrder->order[sIx]); printf("<sup>%s%d</sup>",(sortOrder->forward[sIx] ? "↓" : "↑"), sortOrder->order[sIx]); puts("</TH>"); } else { printf("<TH align='center'> "); printf("<A HREF=\'%s\' TARGET=BLANK>Restricted Until</A>", ENCODE_DATA_RELEASE_POLICY); puts(" </TH>"); } columnCount++; } puts("</TR></THEAD>"); // The end of the header section. +settings->columnCount = columnCount; +} + +static void printSubtrackTableFooter(int subCount, struct subtrackConfigSettings *settings) +/* Print footer with restriction policy if needed */ +{ +boolean restrictions = settings->restrictions; +sortOrder_t *sortOrder = settings->sortOrder; +int columnCount = settings->columnCount; + +if (subCount > 5 || (restrictions && sortOrder != NULL)) + { + printf("<TFOOT style='background-color:%s;'><TR valign='top'>", COLOR_BG_DEFAULT_DARKER); + if (restrictions && sortOrder != NULL) + printf("<TD colspan=%d> ",columnCount-1); + else + printf("<TD colspan=%d> ",columnCount); + + // Count of subtracks is filled in by javascript. + if (subCount > 5) + printf("<span class='subCBcount'></span>\n"); + + // Restriction policy needs a link + if (restrictions && sortOrder != NULL) + printf("</TD><TH><A HREF='%s' TARGET=BLANK style='font-size:.9em;'>Restriction Policy</A>", + ENCODE_DATA_RELEASE_POLICY); + + printf("</TD></TR></TFOOT>\n"); + } +} + +static void printSubtrackTableBody(struct trackDb *parentTdb, struct slRef *subtrackRefList, + struct subtrackConfigSettings *settings, struct cart *cart) +/* Print list of subtracks */ +{ +sortOrder_t *sortOrder = settings->sortOrder; +boolean useDragAndDrop = settings->useDragAndDrop; +boolean restrictions = settings->restrictions; +struct dyString *dyHtml = newDyString(SMALLBUF); +char buffer[SMALLBUF]; +char *db = cartString(cart, "db"); // The subtracks need to be sorted by priority but only sortable and dragable will have // non-default (cart) priorities to sort on +boolean preSorted = FALSE; if (sortOrder != NULL || useDragAndDrop) { // preserves user's prev sort/drags preSorted = tdbRefSortPrioritiesFromCart(cart, &subtrackRefList); printf("<TBODY class='%saltColors'>\n", (sortOrder != NULL ? "sortable " : "") ); } else { slSort(&subtrackRefList, trackDbRefCmp); // straight from trackDb.ra preSorted = TRUE; puts("<TBODY>"); } // Finally the big "for loop" to list each subtrack as a table row. printf("\n<!-- ----- subtracks list ----- -->\n"); +membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,NULL); +struct slRef *subtrackRef; + +/* Color handling ?? */ +//char *colors[2] = { COLOR_BG_DEFAULT, +// COLOR_BG_ALTDEFAULT }; +char *colors[2] = { "bgLevel1", + "bgLevel1" }; +int colorIx = settings->bgColorIx; + for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) { - subtrack = subtrackRef->val; + struct trackDb *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); boolean visibleCB = fourStateVisible(fourState); membership_t *membership = subgroupMembershipGet(subtrack); eCfgType cType = cfgNone; if (!tdbIsMultiTrack(parentTdb)) // MultiTracks never have configurable subtracks! cType = cfgTypeFromTdb(subtrack,FALSE); if (cType != cfgNone) { // Turn off configuring for certain track type or if explicitly turned off int cfgSubtrack = configurableByAjax(subtrack,cType); @@ -4253,40 +4222,46 @@ membersForAll->members[dimV]->tags, membersForAll->members[dimV]->count))) { if (membersForAll->members[dimV]->subtrackCount[ix2] < 2) cType = cfgNone; } } } else if (slCount(subtrackRefList) < 2 // don't bother if there is a single subtrack && cfgTypeFromTdb(parentTdb,FALSE) != cfgNone) // but the composite is configurable. cType = cfgNone; } if (sortOrder == NULL && !useDragAndDrop) { + char **lastDivide = NULL; + dividers_t *dividers = dividersSettingGet(parentTdb); + if (dividers) + lastDivide = needMem(sizeof(char*)*dividers->count); if (divisionIfNeeded(lastDivide,dividers,membership) ) colorIx = (colorIx == COLOR_BG_DEFAULT_IX ? COLOR_BG_ALTDEFAULT_IX : COLOR_BG_DEFAULT_IX); + dividersFree(÷rs); } // 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("<TR valign='top' class='%s%s'",colors[colorIx],(useDragAndDrop?" trDraggable":"")); - printf(" id=tr_%s%s>\n",id,(!visibleCB && !displayAll?" style='display:none'":"")); + printf("<TR valign='top' class='%s%s'", + colors[colorIx],(useDragAndDrop?" trDraggable":"")); + printf(" id=tr_%s%s>\n",id,(!visibleCB && !settings->displayAll?" style='display:none'":"")); // Now the TD that holds the checkbox printf("<TD%s%s>", (enabledCB?"":" title='view is hidden'"), (useDragAndDrop?" class='dragHandle' title='Drag to reorder'":"")); // A hidden field to keep track of subtrack order if it could change if (sortOrder != NULL || useDragAndDrop) { safef(buffer, sizeof(buffer), "%s.priority", subtrack->track); float priority = (float)cartUsualDouble(cart, buffer, subtrack->priority); printf("<INPUT TYPE=HIDDEN NAME='%s' class='trPos' VALUE=\"%.0f\">", buffer, priority); // keeing track of priority } @@ -4319,30 +4294,31 @@ (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! safef(buffer, sizeof(buffer), "%s_sel", subtrack->track); if (!enabledCB) { dyStringAppend(dyHtml, " disabled"); cgiMakeCheckBoxFourWay(buffer,checkedCB,enabledCB,id,dyStringContents(dyHtml), "onclick='matSubCbClick(this);' style='cursor:pointer' title='view is hidden'"); } else cgiMakeCheckBoxFourWay(buffer,checkedCB,enabledCB,id,dyStringContents(dyHtml), "onclick='matSubCbClick(this);' style='cursor:pointer'"); + if (useDragAndDrop) printf(" "); if (!tdbIsMultiTrack(parentTdb)) // MultiTracks never have independent vis { printf("</TD><TD>"); // An extra column for subVis/wrench so dragAndDrop works enum trackVisibility vis = tdbVisLimitedByAncestors(cart,subtrack,FALSE,FALSE); char *view = NULL; if (membersForAll->members[dimV] && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count))) view = membership->membership[ix]; char classList[256]; if (view != NULL) safef(classList,sizeof(classList),"clickable fauxInput%s subVisDD %s", @@ -4353,31 +4329,31 @@ #define SUBTRACK_CFG_VIS "<div id= '%s_faux' class='%s' style='width:65px;' " \ "onclick='return subCfg.replaceWithVis(this,\"%s\",true);'>" \ "%s</div>\n" printf(SUBTRACK_CFG_VIS,subtrack->track,classList,subtrack->track,hStringFromTv(vis)); if (cType != cfgNone) // make a wrench { #define SUBTRACK_CFG_WRENCH "<span class='clickable%s' onclick='return " \ "subCfg.cfgToggle(this,\"%s\");' title='Configure this " \ "subtrack'><img src='../images/wrench.png'></span>\n" printf(SUBTRACK_CFG_WRENCH,(visibleCB ? "":" disabled"),subtrack->track); } } printf("</TD>"); // A color patch which helps distinguish subtracks in some types of composites - if (doColorPatch) + if (settings->colorPatch) { printf("<TD BGCOLOR='#%02X%02X%02X'> </TD>", subtrack->colorR, subtrack->colorG, subtrack->colorB); } // If sortable, then there must be a column per sortable dimension if (sortOrder != NULL) { int sIx=0; for (sIx=0;sIx<sortOrder->count;sIx++) { ix = stringArrayIx(sortOrder->column[sIx], membership->subgroups, membership->count); // TODO: Sort needs to expand from subGroups to labels as well if (ix >= 0) { @@ -4387,31 +4363,33 @@ 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("<TD id='%s_%s' abbr='%s' align='left'> ", subtrack->track,sortOrder->column[sIx],membership->membership[ix]); printf("%s",titleRoot); puts("</TD>"); 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("<TD> "); + hierarchy_t *hierarchy = hierarchySettingGet(parentTdb); indentIfNeeded(hierarchy,membership); + hierarchyFree(&hierarchy); printf("%s",subtrack->shortLabel); puts("</TD>"); } // The long label column (note that it may have a metadata dropdown) printf("<TD title='select to copy'> %s", subtrack->longLabel); if (trackDbSetting(parentTdb, "wgEncode") && trackDbSetting(subtrack, "accession")) printf(" [GEO:%s]", trackDbSetting(subtrack, "accession")); compositeMetadataToggle(db,subtrack,NULL,TRUE,FALSE); printf(" "); // 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) { @@ -4443,59 +4421,156 @@ if (dateIsOld(dateDisplay, MDB_ENCODE_DATE_FORMAT)) printf("</TD>\n<TD align='center' nowrap style='color: #BBBBBB;'> %s ", dateDisplay); else printf("</TD>\n<TD align='center'> %s ", dateDisplay); } } // End of row and free ourselves of this subtrack puts("</TD></TR>\n"); checkBoxIdFree(&id); } // End of the table puts("</TBODY>"); -if (slCount(subtrackRefList) > 5 || (restrictions && sortOrder != NULL)) +dyStringFree(&dyHtml) +membersForAllSubGroupsFree(parentTdb,&membersForAll); +} + +static void printSubtrackTable(struct trackDb *parentTdb, struct slRef *subtrackRefList, + struct subtrackConfigSettings *settings, struct cart *cart) +/* Print table of subtracks */ { - printf("<TFOOT style='background-color:%s;'><TR valign='top'>", COLOR_BG_DEFAULT_DARKER); - if (restrictions && sortOrder != NULL) - printf("<TD colspan=%d> ",columnCount-1); +// Print table tag +printf("\n<TABLE CELLSPACING='2' CELLPADDING='0' border='0'"); +struct dyString *dyHtml = newDyString(SMALLBUF); +if (settings->sortOrder != NULL) + dyStringPrintf(dyHtml, "sortable"); +if (settings->useDragAndDrop) + { + if (dyStringLen(dyHtml) > 0) + dyStringAppendC(dyHtml,' '); + dyStringPrintf(dyHtml, "tableWithDragAndDrop"); + } +printf(" class='subtracks"); +if (dyStringLen(dyHtml) > 0) + { + printf(" bglevel1 %s'",dyStringContents(dyHtml)); + settings->bgColorIx = COLOR_BG_ALTDEFAULT_IX; + } else - printf("<TD colspan=%d> ",columnCount); + settings->bgColorIx = COLOR_BG_DEFAULT_IX; // Start with non-default allows alternation +puts("'>"); +dyStringFree(&dyHtml) - // Count of subtracks is filled in by javascript. +// save count of subtracks for use by footer code +int subCount = slCount(subtrackRefList); + +printSubtrackTableHeader(parentTdb, subtrackRefList, settings); +printSubtrackTableBody(parentTdb, subtrackRefList, settings, cart); +printSubtrackTableFooter(subCount, settings); +puts("</TABLE>"); +} + +static void compositeUiSubtracks(char *db, struct cart *cart, struct trackDb *parentTdb) +// Display list of subtracks and descriptions with checkboxes to control visibility and +// possibly other nice things including links to schema and metadata and a release date. +{ +char buffer[SMALLBUF]; +struct trackDb *subtrack; + +// Get list of leaf subtracks to work with +struct slRef *subtrackRef, *subtrackRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks); + +membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,NULL); +sortOrder_t* sortOrder = sortOrderGet(cart,parentTdb); +char *displaySubs = NULL; +int subCount = slCount(subtrackRefList); +if (subCount > LARGE_COMPOSITE_CUTOFF && membersForAll->dimensions != NULL) + { + // ignore displaySubtracks setting for large composites with a matrix as + // matrix effectively shows all + safef(buffer,SMALLBUF,"%s.displaySubtracks",parentTdb->track); + displaySubs = cartUsualString(cart, buffer,"some"); // track specific defaults to only selected + } +else + { + displaySubs = cartUsualString(cart, "displaySubtracks", "all"); // browser wide defaults to all + } +boolean displayAll = sameString(displaySubs, "all"); + +// Table wraps around entire list so that "Top" link can float to the correct place. +cgiDown(0.7); +printf("<table><tr><td class='windowSize'>"); +printf("<A NAME='DISPLAY_SUBTRACKS'></A>"); +if (sortOrder != NULL) + { + // First table row contains the display "selected/visible" or "all" radio buttons + // NOTE: list subtrack radio buttons are inside tracklist table header if + // there are no sort columns. The reason is to ensure spacing of lines + // column headers when the only column header is "Restricted Until" + printf("<B>List subtracks: "); + char javascript[JBUFSIZE]; + safef(javascript, sizeof(javascript), + "class='allOrOnly' onclick='showOrHideSelectedSubtracks(true);'"); + if (subCount > LARGE_COMPOSITE_CUTOFF) + safef(buffer,SMALLBUF,"%s.displaySubtracks",parentTdb->track); + else + safecpy(buffer,SMALLBUF,"displaySubtracks"); + cgiMakeOnClickRadioButton(buffer, "selected", !displayAll,javascript); + puts("only selected/visible "); + safef(javascript, sizeof(javascript), + "class='allOrOnly' onclick='showOrHideSelectedSubtracks(false);'"); + cgiMakeOnClickRadioButton(buffer, "all", displayAll,javascript); + printf("all</B>"); if (slCount(subtrackRefList) > 5) - printf("<span class='subCBcount'></span>\n"); + printf(" (<span class='subCBcount'></span>)"); + makeTopLink(parentTdb); + printf("</td></tr></table>"); + } +else + makeTopLink(parentTdb); - // Restriction policy needs a link - if (restrictions && sortOrder != NULL) - printf("</TD><TH><A HREF='%s' TARGET=BLANK style='font-size:.9em;'>Restriction Policy</A>", - ENCODE_DATA_RELEASE_POLICY); +// Get info for subtrack list +struct subtrackConfigSettings *subtrackConfig = NULL; +AllocVar(subtrackConfig); - printf("</TD></TR></TFOOT>\n"); +// Determine whether there is a restricted until date column +subtrackConfig->restrictions = FALSE; +for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) + { + subtrack = subtrackRef->val; + (void)metadataForTable(db,subtrack,NULL); + if (NULL != metadataFindValue(subtrack,"dateUnrestricted")) + { + subtrackConfig->restrictions = TRUE; + break; } -puts("</TABLE>"); + } +subtrackConfig->colorPatch = trackDbSettingOn(parentTdb, "showSubtrackColorOnUi"); +subtrackConfig->useDragAndDrop = sameOk("subTracks",trackDbSetting(parentTdb, "dragAndDrop")); +subtrackConfig->sortOrder = sortOrder; +subtrackConfig->displayAll = displayAll; + +printSubtrackTable(parentTdb, subtrackRefList, subtrackConfig, cart); + if (sortOrder == NULL) printf("</td></tr></table>"); -// 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]; // Get list of leaf subtracks to work with and sort them struct slRef *subtrackRef, *subtrackRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks); if (NULL != trackDbSetting(parentTdb, "sortOrder") || NULL != trackDbSetting(parentTdb, "dragAndDrop"))