0f483165e902359c81642c1ab20aed49ea96f272 tdreszer Fri Dec 10 09:21:38 2010 -0800 Split compositeUiSubtracks into hgTrackUi vs hgTable versions. Remade subtrack list using the new 'sortable' table methods. Remade makeTrackHashWithComposites to take in/out for tdbList, enabling few rebuilds of this list. diff --git src/hg/lib/hui.c src/hg/lib/hui.c index 45c059e..df80277 100644 --- src/hg/lib/hui.c +++ src/hg/lib/hui.c @@ -42,51 +42,52 @@ #define PM_BUTTON "<IMG height=18 width=18 onclick=\"setCheckBoxesThatContain('%s',%s,true,'%s','','%s');\" id=\"btn_%s\" src=\"../images/%s\" alt=\"%s\">\n" #define DEF_BUTTON "<IMG onclick=\"setCheckBoxesThatContain('%s',true,false,'%s','','%s'); setCheckBoxesThatContain('%s',false,false,'%s','_defOff','%s');\" id=\"btn_%s\" src=\"../images/%s\" alt=\"%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 BAM_CFG_UI_CHANGES 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 (!sameString(tdb->table, tdb->track)) +if (!sameWord(tdb->type,"downloadsOnly") && !sameString(tdb->table, tdb->track)) { 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, struct hash *trackHash) // Returns an HTML string for a downloads link { // Downloads directory if this is ENCODE if(trackDbSetting(tdb, "wgEncode") != NULL) { struct trackDb *dirKeeper = wgEncodeDownloadDirKeeper(database, tdb, trackHash); + char *actualName = (sameWord(dirKeeper->type,"downloadsOnly")?dirKeeper->track:tdb->table); struct dyString *dyLink = dyStringCreate("<A HREF=\"http://%s/goldenPath/%s/%s/%s/%s\" title='Download file' TARGET=ucscDownloads>%s</A>", hDownloadsServer(), trackDbSettingOrDefault(dirKeeper, "origAssembly",database), - ENCODE_DCC_DOWNLOADS, dirKeeper->table, (nameIsFile?name:""), name); + ENCODE_DCC_DOWNLOADS, actualName, (nameIsFile?name:""), name); return dyStringCannibalize(&dyLink); } return NULL; } static boolean makeNamedDownloadsLink(char *database, struct trackDb *tdb,char *name, struct hash *trackHash) // Make a downloads link (if appropriate and then returns TRUE) { char *htmlString = htmlStringForDownloadsLink(database,tdb,name,FALSE,trackHash); if (htmlString == NULL) return FALSE; printf("%s", htmlString); freeMem(htmlString); @@ -1967,47 +1968,48 @@ boolean leafOnly) /* Recursively add trackList to trackHash */ { struct trackDb *tdb; for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { if (hTrackOnChrom(tdb, chrom)) { if (tdb->subtracks == NULL || !leafOnly) hashAdd(trackHash, tdb->track, tdb); } rAddTrackListToHash(trackHash, tdb->subtracks, chrom, leafOnly); } } -struct hash *makeTrackHashWithComposites(char *database, char *chrom, - bool withComposites) -/* Make hash of trackDb items for this chromosome, including composites, - not just the subtracks. */ +struct hash *trackHashMakeWithComposites(char *db,char *chrom,struct trackDb **tdbList,bool withComposites) +// Make hash of trackDb items for this chromosome, including composites, not just the subtracks. +// May pass in prepopulated trackDb list, or may receive the trackDb list as an inout. { -struct trackDb *tdbs = hTrackDb(database); +struct trackDb *theTdbs = NULL; +if (tdbList == NULL || *tdbList == NULL) + { + theTdbs = hTrackDb(db); + if (tdbList != NULL) + *tdbList = theTdbs; + } +else + theTdbs = *tdbList; struct hash *trackHash = newHash(7); -rAddTrackListToHash(trackHash, tdbs, chrom, !withComposites); +rAddTrackListToHash(trackHash, theTdbs, chrom, !withComposites); return trackHash; } -struct hash *makeTrackHash(char *database, char *chrom) -/* Make hash of trackDb items for this chromosome. */ -{ -return makeTrackHashWithComposites(database, chrom, FALSE); -} - /****** Stuff for acembly related options *******/ static char *acemblyOptions[] = { "all genes", "main", "putative", }; enum acemblyOptEnum acemblyStringToEnum(char *string) /* Convert from string to enum representation. */ { int x = stringIx(string, acemblyOptions); if (x < 0) errAbort("hui::acemblyStringToEnum() - Unknown option %s", string); return x; @@ -3759,374 +3761,402 @@ } return date; } static void cfgLinkToDependentCfgs(struct cart *cart, struct trackDb *tdb,char *prefix) /* Link composite or view level controls to all associateled lower level controls */ { if (!cartVarExists(cart, "ajax") && tdbIsComposite(tdb)) #ifdef SUBTRACK_CFG_POPUP printf("<script type='text/javascript'>registerViewOnchangeAction('%s')</script>\n",prefix); #else///ifndef SUBTRACK_CFG_POPUP printf("<script type='text/javascript'>compositeCfgRegisterOnchangeAction(\"%s\")</script>\n",prefix); #endif///ndef SUBTRACK_CFG_POPUP } -static void compositeUiSubtracks(char *db, struct cart *cart, struct trackDb *parentTdb, - boolean selectedOnly, char *primarySubtrack, struct hash *trackHash) +static void compositeUiSubtracks(char *db, struct cart *cart, struct trackDb *parentTdb,struct hash *trackHash) /* 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. */ { -boolean doColorPatch = trackDbSettingOn(parentTdb, "showSubtrackColorOnUi"); struct trackDb *subtrack; -char *primaryType = getPrimaryType(primarySubtrack, parentTdb); -char htmlIdentifier[SMALLBUF]; struct dyString *dyHtml = newDyString(SMALLBUF); -char *colors[2] = { COLOR_BG_DEFAULT, - COLOR_BG_ALTDEFAULT }; +//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 #ifndef SUBTRACK_CFG_POPUP boolean dependentCfgsNeedBinding = FALSE; #endif///ndef SUBTRACK_CFG_POPUP // 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); int dimCount=0,di; for(di=0;di<membersForAll->dimMax;di++) { if(membersForAll->members[di]) dimCount++; } sortOrder_t* sortOrder = sortOrderGet(cart,parentTdb); boolean preSorted = FALSE; boolean useDragAndDrop = sameOk("subTracks",trackDbSetting(parentTdb, "dragAndDrop")); +// Table wraps around entire list so that "Top" link can float to the correct place. printf("<table><tr><td class='windowSize'>"); printf("<A NAME='DISPLAY_SUBTRACKS'></A>"); makeTopLink(parentTdb); -// Now we can start in on the table of subtracks +//printf("<style type='text/css'>td {padding: 0px 5px 0px;}</style>"); + +// 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'"); -if(sortOrder != NULL) - { - printf(" id='subtracks.%s.sortable'",parentTdb->track); dyStringClear(dyHtml); - dyStringPrintf(dyHtml, "tableSortable"); - colorIx = COLOR_BG_ALTDEFAULT_IX; - } -else - printf(" id='subtracks.%s'",parentTdb->track); +if (sortOrder != NULL) + dyStringPrintf(dyHtml, "sortable"); if(useDragAndDrop) { if(dyStringLen(dyHtml) > 0) dyStringAppendC(dyHtml,' '); dyStringPrintf(dyHtml, "tableWithDragAndDrop"); - printf(" class='%s'",dyStringContents(dyHtml)); - dyStringClear(dyHtml); + } +if (dyStringLen(dyHtml) > 0) + { + printf(" class='subtracks %s'",dyStringContents(dyHtml)); colorIx = COLOR_BG_ALTDEFAULT_IX; } +if (sortOrder != NULL) + puts("><THEAD class=sortable>"); +else puts("><THEAD>"); -if (!primarySubtrack) - { - char javascript[JBUFSIZE]; +// First table row contains the display "selected/visible" or "all" radio buttons boolean displayAll = sameString(cartUsualString(cart, "displaySubtracks", "all"), "all"); - boolean restrictions = FALSE; - for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) - { - subtrack = subtrackRef->val; - (void)metadataForTable(db,subtrack,NULL); - const char *date = metadataFindValue(subtrack,"dateUnrestricted"); - if(date != NULL) // Note this is stale memory (just freed), but non-NULL means found. - { - restrictions = TRUE; - break; - } - } - +boolean doColorPatch = trackDbSettingOn(parentTdb, "showSubtrackColorOnUi"); int colspan = 3; if (sortOrder != NULL) colspan = sortOrder->count+2; if (doColorPatch) colspan += 1; - printf("<TR"); - if(useDragAndDrop) - printf(" id=\"noDrag\" class='nodrop nodrag'"); - printf(">"); +printf("<TR%s>",useDragAndDrop?" id='noDrag' class='nodrop nodrag'":""); printf("<TD colspan='%d'><B>List subtracks: ", colspan); +char javascript[JBUFSIZE]; safef(javascript, sizeof(javascript), "onclick=\"showOrHideSelectedSubtracks(true);\""); cgiMakeOnClickRadioButton("displaySubtracks", "selected", !displayAll,javascript); puts("only selected/visible "); safef(javascript, sizeof(javascript), "onclick=\"showOrHideSelectedSubtracks(false);\""); cgiMakeOnClickRadioButton("displaySubtracks", "all", displayAll,javascript); printf("all</B>"); if(slCount(subtrackRefList) > 5) printf(" (<FONT class='subCBcount'></font>)"); puts("</TD>"); - if(sortOrder != NULL) // Add some sort buttons +// Add column headers which are sort button links +if (sortOrder != NULL) { puts("<TD colspan=5> </TD></TR>"); - printf("<TR id=\"%s.sortTr\" class='nodrop nodrag'>\n",parentTdb->track); // class='nodrop nodrag' - printf("<TD> <INPUT TYPE=HIDDEN NAME='%s' id='%s' VALUE=\"%s\"></TD>", sortOrder->htmlId, sortOrder->htmlId,sortOrder->sortOrder); // keeing track of priority + printf("<TR id=\"subtracksHeader\" class='nodrop nodrag sortable'>\n"); + printf("<TH> <INPUT TYPE=HIDDEN NAME='%s' class='sortOrder' VALUE=\"%s\"></TH>\n", sortOrder->htmlId, sortOrder->sortOrder); // keeing track of sortOrder // Columns in tdb order (unchanging), sort in cart order (changed by user action) int sIx=0; for(sIx=0;sIx<sortOrder->count;sIx++) { - printf ("<TH id='%s.%s.sortTh' abbr='%c' nowrap><A HREF='#nowhere' onclick=\"tableSortAtButtonPress(this,'%s');return false;\">%s</A><sup>%s", - parentTdb->track,sortOrder->column[sIx], - (sortOrder->forward[sIx]?'-':'+'), - sortOrder->column[sIx],sortOrder->title[sIx], - (sortOrder->forward[sIx]?"↓":"↑")); + printf("<TH id='%s' class='sortable%s sort%d' abbr='use' nowrap title='Sort list on this column' onclick='tableSortAtButtonPress(this);'>%s", + sortOrder->column[sIx],(sortOrder->forward[sIx]?"":" sortRev"),sortOrder->order[sIx],sortOrder->title[sIx]); + printf("<sup>%s",(sortOrder->forward[sIx]?"↓":"↑")); if (sortOrder->count > 1) printf ("%d",sortOrder->order[sIx]); - puts ("</sup></TH>"); + printf("</sup>"); + puts ("</TH>"); } puts("<TD> </TD>"); } - puts("<TH> </TH>"); - //puts("<TH align=\"center\" nowrap> Table </TH>"); - if(restrictions) + +// Determine whether there is a restricted until date column +for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) + { + subtrack = subtrackRef->val; + (void)metadataForTable(db,subtrack,NULL); + if (NULL != metadataFindValue(subtrack,"dateUnrestricted")) { printf("<TH align=\"center\" nowrap> "); printf("<A HREF=\'%s\' TARGET=BLANK>Restricted Until</A>", ENCODE_DATA_RELEASE_POLICY); puts(" </TH>"); + break; // Don't need more than one } } +puts("</TR></THEAD>"); // The end of the header section. +// The subtracks need to be sorted by priority but only sortable and dragable will have non-default (cart) priorities to sort on if(sortOrder != NULL || useDragAndDrop) { preSorted = tdbRefSortPrioritiesFromCart(cart, &subtrackRefList); // preserves user's prev sort/drags - puts("</TR></THEAD><TBODY id='sortable_tbody'>"); + puts("<TBODY class='sortable altColors'>"); } else { slSort(&subtrackRefList, trackDbRefCmp); // straight from trackDb.ra preSorted = TRUE; - puts("</TR></THEAD><TBODY>"); + puts("<TBODY>"); } +// Finally the big "for loop" to list each subtrack as a table row. for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) { subtrack = subtrackRef->val; - boolean isPrimary = FALSE; 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); - isPrimary = (primarySubtrack && - sameString(subtrack->track, primarySubtrack)); - safef(htmlIdentifier, sizeof(htmlIdentifier), "%s_sel", subtrack->track); - - - if (primarySubtrack) - { - if (isPrimary) - { - puts("<TR><TD>"); - cgiMakeHiddenBoolean(htmlIdentifier, TRUE); - puts("[on] "); - printf ("</TD><TD>%s [selected on main page]</TD></TR>\n", - subtrack->longLabel); - } - else if (hSameTrackDbType(primaryType, subtrack->type)) - { - puts("<TR><TD>"); - cgiMakeCheckBox(htmlIdentifier, checkedCB && enabledCB); - printf ("</TD><TD>%s</TD></TR>\n", subtrack->longLabel); - } - } - else - { 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(trackDbSettingClosestToHomeOn(subtrack, "configurable") == FALSE) #endif///ndef SUBTRACK_CFG_POPUP 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("<TR valign='top' BGCOLOR=\"%s\"",colors[colorIx]); - if(useDragAndDrop) - printf(" class='trDraggable'"); + printf("<TR valign='top' class='%s%s'",colors[colorIx],(useDragAndDrop?" trDraggable":"")); + printf(" id=tr_%s p%s>\n",id,(!displayAll?" style='display:none'":"")); - printf(" id=\"tr_%s\" nowrap%s>\n",id,(selectedOnly?" style='display:none'":"")); - printf("<TD%s",(enabledCB?"":" title='view is hidden'")); - if (useDragAndDrop) - printf(" class='dragHandle' title='Drag to reorder'>"); - else - printf(">"); + // Now the TD that holds the checkbox + printf("<TD%s%s>", + (enabledCB?"":" title='view is hidden'"), + (useDragAndDrop?" class='dragHandle' title='Drag to reorder'":"")); + + // The checkbox has identifying classes including subCB and the tag for each dimension (e.g. class='subCB GM12878 CTCF Peak') dyStringClear(dyHtml); - dyStringAppend(dyHtml, "subCB"); + dyStringAppend(dyHtml, "subCB"); // always first for(di=dimX;di<membersForAll->dimMax;di++) { if(membersForAll->members[di] && -1 != (ix = stringArrayIx(membersForAll->members[di]->groupTag, membership->subgroups, membership->count))) dyStringPrintf(dyHtml," %s",membership->membership[ix]); } - // Save view for last if(membersForAll->members[dimV] && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count))) - dyStringPrintf(dyHtml, " %s",membership->membership[ix]); + 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 + + // 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("<INPUT TYPE=HIDDEN NAME='%s' id='%s' VALUE=\"%.0f\">", htmlIdentifier, htmlIdentifier, priority); // keeing track of priority + printf("<INPUT TYPE=HIDDEN NAME='%s' class='trPos' VALUE=\"%.0f\">", htmlIdentifier, priority); // keeing track of priority } + // A color patch which helps distinguish subtracks in some types of composites if (doColorPatch) { printf("<TD BGCOLOR='#%02X%02X%02X'> </TD>", 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 "<A HREF='#a_cfg_%s' onclick='return popUpSubtrackCfg(\"%s\",\"%s\");' title='%s'>%s</A>\n" + #define CFG_SUBTRACK_LINK "<A HREF='#a_cfg_%s' onclick='return popUpSubtrackCfg(\"%s\",\"%s\");' title='%s'>%s</A>" #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 "<A HREF='#a_cfg_%s' onclick='return subtrackCfgShow(\"%s\");' title='Subtrack Configuration'>%s</A>\n" + #define CFG_SUBTRACK_LINK "<A HREF='#a_cfg_%s' onclick='return subtrackCfgShow(\"%s\");' title='Subtrack Configuration'>%s</A>" #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;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) { char *titleRoot=labelRoot(membership->titles[ix],NULL); - printf ("<TD id='%s' nowrap abbr='%s' align='left'> ",sortOrder->column[sIx],membership->membership[ix]); + // Each sortable column requires hidden goop (in the "abbr" field currently) which is the actual sort on value + printf ("<TD id='%s_%s' nowrap abbr='%s' align='left'> ",subtrack->track,sortOrder->column[sIx],membership->membership[ix]); #ifdef SUBTRACK_CFG_POPUP dyStringPrintf(dyLabel,"%s ",titleRoot); - if (cType != cfgNone && sameString("view",sortOrder->column[sIx])) + 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 else - printf("%s\n",titleRoot); + printf("%s",titleRoot); puts ("</TD>"); freeMem(titleRoot); } } } - else + else // Non-sortable tables do not have sort by columns but will display a short label (which may be a configurable link) { printf ("<TD nowrap='true'> "); indentIfNeeded(hierarchy,membership); #ifdef SUBTRACK_CFG_POPUP - if (cType != cfgNone && cType != cfgWigMaf) // FIXME: wigMaf restriction is temporary unto configurable off is set + 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 if(cType != cfgNone) MAKE_CFG_SUBTRACK_LINK(subtrack->track,subtrack->shortLabel); #endif///ndef SUBTRACK_CFG_POPUP else - printf("%s\n",subtrack->shortLabel); + printf("%s",subtrack->shortLabel); puts ("</TD>"); } #ifdef SUBTRACK_CFG_POPUP dyStringFree(&dyLabel); #endif///def SUBTRACK_CFG_POPUP - printf ("<TD nowrap='true' title='select to copy'><div> %s", subtrack->longLabel); + + // The long label column (note that it may have a "..." that allows getting at all the metadata) + printf ("<TD nowrap title='select to copy'> %s", subtrack->longLabel); if(trackDbSetting(parentTdb, "wgEncode") && trackDbSetting(subtrack, "accession")) printf (" [GEO:%s]", trackDbSetting(subtrack, "accession")); compositeMetadataToggle(db,subtrack,"...",TRUE,FALSE, trackHash); - printf("</div>"); + 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) { dependentCfgsNeedBinding = TRUE; // configurable subtrack needs to be bound to composite settings #define CFG_SUBTRACK_DIV "<DIV id='div_%s_cfg'%s><INPUT TYPE=HIDDEN NAME='%s' value='%s'>\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); - puts("</DIV>\n"); + printf("</DIV>"); } #endif///ndef SUBTRACK_CFG_POPUP - printf("<TD nowrap> "); + + // A schema link for each track + printf("</td>\n<TD nowrap> "); makeSchemaLink(db,subtrack,"schema"); - puts(" "); + printf(" "); + // Do we have a restricted until date? char *dateDisplay = encodeRestrictionDateDisplay(db,subtrack); if (dateDisplay) - printf("</TD><TD align=\"CENTER\"> %s ", dateDisplay); + printf("</TD>\n<TD align=\"CENTER\"> %s ", dateDisplay); - puts("</TD></TR>"); + // End of row and free ourselves of this subtrack + puts("</TD></TR>\n"); checkBoxIdFree(&id); - } subgroupMembershipFree(&membership); } - } + +// End of the table puts("</TBODY><TFOOT></TFOOT>"); puts("</TABLE>"); printf("</td></tr></table>"); + +// Count of subtracks is filled in by javascript. if(slCount(subtrackRefList) > 5) puts(" <FONT class='subCBcount'></font>"); puts("<P>"); -if (!primarySubtrack) + +// Tying subtracks with matrix and subtrack cfgs with views requires javascript help puts("<script type='text/javascript'>matInitializeMatrix();</script>"); #ifndef SUBTRACK_CFG_POPUP if(dependentCfgsNeedBinding) cfgLinkToDependentCfgs(cart,parentTdb,parentTdb->track); #endif//ndef SUBTRACK_CFG_POPUP + +// Finally we are free of all this membersForAllSubGroupsFree(parentTdb,&membersForAll); dyStringFree(&dyHtml) sortOrderFree(&sortOrder); dividersFree(÷rs); hierarchyFree(&hierarchy); } -static void compositeUiAllSubtracks(char *db, struct cart *cart, struct trackDb *tdb, - char *primarySubtrack, struct hash *trackHash) -/* Show checkboxes for all subtracks, not just selected ones. */ +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 */ { -compositeUiSubtracks(db, cart, tdb, FALSE, primarySubtrack, trackHash); -} +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")) + tdbRefSortPrioritiesFromCart(cart, &subtrackRefList); // preserves user's prev sort/drags +else + slSort(&subtrackRefList, trackDbRefCmp); // straight from trackDb.ra + +// Now we can start in on the table of subtracks +printf("\n<TABLE CELLSPACING='2' CELLPADDING='0' border='0' id='subtracks.%s'><THEAD>\n</TR></THEAD><TBODY>\n",parentTdb->track); -static void compositeUiSelectedSubtracks(char *db, struct cart *cart, struct trackDb *tdb, - char *primarySubtrack, struct hash *trackHash) -/* Show checkboxes only for selected subtracks. */ +for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) { -compositeUiSubtracks(db, cart, tdb, TRUE, primarySubtrack, trackHash); + struct trackDb *subtrack = subtrackRef->val; + int fourState = subtrackFourStateChecked(subtrack,cart); + boolean checkedCB = fourStateChecked(fourState); + boolean enabledCB = fourStateEnabled(fourState); + safef(htmlIdentifier, sizeof(htmlIdentifier), "%s_sel", subtrack->track); + + if (sameString(subtrack->track, primarySubtrack)) + { + puts("<TR><TD>"); + cgiMakeHiddenBoolean(htmlIdentifier, TRUE); + puts("[on] "); + printf ("</TD><TD>%s [selected on main page]</TD></TR>\n", + subtrack->longLabel); + } + else if (hSameTrackDbType(primaryType, subtrack->type)) + { + puts("<TR><TD>"); + cgiMakeCheckBox(htmlIdentifier, checkedCB && enabledCB); + printf ("</TD><TD>%s</TD></TR>\n", subtrack->longLabel); + } + } +puts("</TBODY><TFOOT></TFOOT>"); +puts("</TABLE>"); +if (slCount(subtrackRefList) > 5) + puts(" <FONT class='subCBcount'></font>"); +puts("<P>"); +if (!primarySubtrack) + puts("<script type='text/javascript'>matInitializeMatrix();</script>"); } static void makeAddClearSubmitTweak(char javascript[JBUFSIZE], char *formName, char *buttonVar, char *label) /* safef into javascript a sequence of commands that will force a refresh * of this same form, updating the values of whatever variables are necessary * to say what we want to do. */ { safef(javascript, JBUFSIZE*sizeof(char), "document.%s.action = '%s'; document.%s.%s.value='%s'; " "document.%s.submit();", formName, cgiScriptName(), formName, buttonVar, label, formName); } @@ -6133,31 +6163,31 @@ const char * mdbVal = metadataFindValue(childTdb,mdbVar); // one for each is enough if(mdbVal != NULL) { if(!first) dyStringAppendC(dyLink,','); dyStringAppend(dyLink,(char *)mdbVal); first = FALSE; } } } dyStringPrintf(dyLink,VOCAB_MULTILINK_END,members->groupTitle,members->groupTitle); freeMem(vocab); return dyStringCannibalize(&dyLink); } -static boolean hCompositeUiByFilter(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName) +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; jsIncludeFile("ui.core.js",NULL); jsIncludeFile("ui.dropdownchecklist.js",NULL); webIncludeResourceFile("ui.dropdownchecklist.css"); // TODO: // 1) Scroll long lists should be configurable through tdb setting // #define FILTER_COMPOSITE_OPEN_SIZE 16 // 2) columnCount (Number of filterBoxes per row) should be configurable through tdb setting printf("<B>Filter subtracks %sby:</B> (select multiple %sitems - %s)<BR>\n", @@ -6213,31 +6243,31 @@ #ifdef FILTER_COMPOSITE_ONLYONE if(membersForAll->members[dimIx]->fcType == fctOneOnly) printf(" (select only one)"); #endif///def FILTER_COMPOSITE_ONLYONE printf("</TD><TD width='20'></TD>\n"); } printf("</TR></TABLE>\n"); puts("<BR>\n"); return TRUE; } -static boolean hCompositeUiByMatrix(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName) +static boolean compositeUiByMatrix(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName) /* UI for composite tracks: matrix of checkboxes. */ { //int ix; char objName[SMALLBUF]; membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,cart); if(membersForAll == NULL || membersForAll->dimensions == NULL) // Not Matrix! return FALSE; int ixX,ixY; members_t *dimensionX = membersForAll->members[dimX]; members_t *dimensionY = membersForAll->members[dimY]; // use array of char determine all the cells (in X,Y,Z dimensions) that are actually populated char *value; @@ -6278,31 +6308,31 @@ { if(subtrackInAllCurrentABCs(subtrack,membersForAll)) // Only bother if the subtrack is found in all ABC dims checked { enabd[ixX][ixY]++; if(fourStateChecked(fourState) == 1) chked[ixX][ixY]++; } } } } } // If there is no matrix and if there is a filterComposite, then were are done. if(dimensionX == NULL && dimensionY == NULL) { - if (hCompositeUiByFilter(db, cart, parentTdb, formName)) + if (compositeUiByFilter(db, cart, parentTdb, formName)) return FALSE; } // Tell the user what to do: char javascript[JBUFSIZE]; //puts("<B>Select subtracks by characterization:</B><BR>"); printf("<B>Select subtracks by "); if(dimensionX && !dimensionY) safef(javascript, sizeof(javascript), "%s:</B>",dimensionX->groupTitle); else if(!dimensionX && dimensionY) safef(javascript, sizeof(javascript), "%s:</B>",dimensionY->groupTitle); else if(dimensionX && dimensionY) safef(javascript, sizeof(javascript), "%s and %s:</B>",dimensionX->groupTitle,dimensionY->groupTitle); else safef(javascript, sizeof(javascript), "multiple variables:</B>"); @@ -6410,55 +6440,55 @@ } } } if(dimensionX && cntX>MATRIX_RIGHT_BUTTONS_AFTER) matrixYheadings(db,parentTdb, membersForAll,ixY,FALSE); puts("</TR>\n"); } } if(dimensionY && cntY>MATRIX_BOTTOM_BUTTONS_AFTER) matrixXheadings(db,parentTdb,membersForAll,FALSE); puts("</TD></TR></TABLE>"); puts("<BR>\n"); // If any filter additional filter composites, they can be added at the end. -hCompositeUiByFilter(db, cart, parentTdb, formName); +compositeUiByFilter(db, cart, parentTdb, formName); return TRUE; } -static boolean hCompositeUiAllButtons(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName) +static boolean compositeUiAllButtons(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName) /* UI for composite tracks: all/none buttons only (as opposed to matrix or lots of buttons */ { if (trackDbCountDescendantLeaves(parentTdb) <= 1) return FALSE; if(dimensionsExist(parentTdb)) return FALSE; #define PM_BUTTON_GLOBAL "<IMG height=18 width=18 onclick=\"matSubCBsCheck(%s);\" id='btn_%s' src='../images/%s'>" #define BUTTON_PLUS_ALL_GLOBAL() printf(PM_BUTTON_GLOBAL,"true", "plus_all", "add_sm.gif") #define BUTTON_MINUS_ALL_GLOBAL() printf(PM_BUTTON_GLOBAL,"false","minus_all","remove_sm.gif") printf("<P><B>Select subtracks:</B><P>All: "); BUTTON_PLUS_ALL_GLOBAL(); BUTTON_MINUS_ALL_GLOBAL(); puts("</P>"); return TRUE; } -static boolean hCompositeUiNoMatrix(char *db, struct cart *cart, struct trackDb *parentTdb, +static boolean compositeUiNoMatrix(char *db, struct cart *cart, struct trackDb *parentTdb, char *primarySubtrack, char *formName) /* UI for composite tracks: subtrack selection. This is the default UI without matrix controls. */ { int i, j, k; char *words[SMALLBUF]; char option[SMALLBUF]; int wordCnt; char javascript[JBUFSIZE]; char *primaryType = getPrimaryType(primarySubtrack, parentTdb); char *name, *value; char buttonVar[32]; char setting[] = "subGroupN"; char *button; struct trackDb *subtrack; @@ -6596,101 +6626,98 @@ } } puts ("</TABLE>"); } 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 displayAll = - sameString(cartUsualString(cart, "displaySubtracks", "all"), "all"); boolean isMatrix = dimensionsExist(tdb); boolean viewsOnly = FALSE; if (!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("<div id='popit' style='display: none'></div>"); cgiMakeHiddenVar("db", db); printf("<input type=HIDDEN id='track' value='%s';</input>\n",tdb->track); #endif puts("<P>"); if (trackDbCountDescendantLeaves(tdb) < MANY_SUBTRACKS && !hasSubgroups) { - compositeUiAllSubtracks(db, cart, tdb, primarySubtrack, trackHash); + if(primarySubtrack) + compositeUiSubtracksMatchingPrimary(db, cart, tdb,primarySubtrack); + else + compositeUiSubtracks(db, cart, tdb, trackHash); return; } if (fakeSubmit) cgiMakeHiddenVar(fakeSubmit, "submit"); if(primarySubtrack == NULL) { if(subgroupingExists(tdb,"view")) { hCompositeDisplayViewDropDowns(db, cart,tdb); if(subgroupCount(tdb) <= 1) viewsOnly = TRUE; } if(!viewsOnly) { if(trackDbSettingOn(tdb, "allButtonPair")) { - hCompositeUiAllButtons(db, cart, tdb, formName); + compositeUiAllButtons(db, cart, tdb, formName); } else if (!hasSubgroups || !isMatrix || primarySubtrack) { - hCompositeUiNoMatrix(db, cart,tdb,primarySubtrack,formName); + compositeUiNoMatrix(db, cart,tdb,primarySubtrack,formName); } else { - hCompositeUiByMatrix(db, cart, tdb, formName); + 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("<script type='text/javascript'>registerFormSubmit('mainForm');</script>\n"); #endif } cartSaveSession(cart); cgiContinueHiddenVar("g"); -if(displayAll) - { - compositeUiAllSubtracks(db, cart, tdb, primarySubtrack, trackHash); - } +if(primarySubtrack) + compositeUiSubtracksMatchingPrimary(db, cart, tdb,primarySubtrack); else - { - compositeUiSelectedSubtracks(db, cart, tdb, primarySubtrack, trackHash); - } + compositeUiSubtracks(db, cart, tdb, trackHash); if (primarySubtrack == NULL) // primarySubtrack is set for tableBrowser but not hgTrackUi { if (trackDbCountDescendantLeaves(tdb) > 5) { cgiMakeButton("Submit", "Submit"); puts("<P>"); } } } boolean superTrackDropDownWithExtra(struct cart *cart, struct trackDb *tdb, int visibleChild,char *extra) /* Displays hide/show dropdown for supertrack. * Set visibleChild to indicate whether 'show' should be grayed