e0e5b9a1895ba717a40da8d979c5d917189a02a1 kate Fri Apr 30 09:22:25 2021 -0700 Second cut TF facelift, based on feedback from JK, Key features: 1) Short help messages in pop-ups on each step. 2) Remove step numbers and instead distinguish steps with styling 3) Save vertical space (keep 'get output' button above fold). refs #27408 diff --git src/hg/hgTables/mainPage.c src/hg/hgTables/mainPage.c index 900ae87..ef9ce24 100644 --- src/hg/hgTables/mainPage.c +++ src/hg/hgTables/mainPage.c @@ -1,1111 +1,1156 @@ /* mainPage - stuff to put up the first table browser page. */ /* Copyright (C) 2014 The Regents of the University of California * See README in this or parent directory for licensing information. */ #include "common.h" #include "linefile.h" #include "hash.h" #include "htmshell.h" #include "cheapcgi.h" #include "cart.h" #include "cartTrackDb.h" #include "textOut.h" #include "jksql.h" #include "hdb.h" #include "web.h" #include "jsHelper.h" #include "hui.h" #include "hgColors.h" #include "trackDb.h" #include "grp.h" #include "hgTables.h" #include "joiner.h" #include "trackDb.h" #include "hubConnect.h" #include "trackHub.h" #include "hgConfig.h" static struct dyString *onChangeStart() /* Start up a javascript onChange command */ { struct dyString *dy = jsOnChangeStart(); jsDropDownCarryOver(dy, hgtaTrack); jsDropDownCarryOver(dy, hgtaGroup); jsTrackedVarCarryOver(dy, hgtaRegionType, "regionType"); jsTextCarryOver(dy, hgtaRange); jsDropDownCarryOver(dy, hgtaOutputType); jsTextCarryOver(dy, hgtaOutFileName); return dy; } static char *onChangeClade() /* Return javascript executed when they change clade. */ { struct dyString *dy = onChangeStart(); jsDropDownCarryOver(dy, "clade"); jsDropDownCarryOver(dy, hgtaTable); dyStringAppend(dy, " document.hiddenForm.org.value=0;"); dyStringAppend(dy, " document.hiddenForm.db.value=0;"); dyStringAppend(dy, " document.hiddenForm.position.value='';"); return jsOnChangeEnd(&dy); } static char *onChangeOrg() /* Return javascript executed when they change organism. */ { struct dyString *dy = onChangeStart(); jsDropDownCarryOver(dy, "clade"); jsDropDownCarryOver(dy, "org"); jsDropDownCarryOver(dy, hgtaTable); dyStringAppend(dy, " document.hiddenForm.db.value=0;"); dyStringAppend(dy, " document.hiddenForm.position.value='';"); return jsOnChangeEnd(&dy); } static char *onChangeDb() /* Return javascript executed when they change database. */ { struct dyString *dy = onChangeStart(); jsDropDownCarryOver(dy, "clade"); jsDropDownCarryOver(dy, "db"); jsDropDownCarryOver(dy, hgtaTable); dyStringAppend(dy, " document.hiddenForm.position.value='';"); return jsOnChangeEnd(&dy); } static char *onChangeGroupOrTrack() /* Return javascript executed when they change group. */ { struct dyString *dy = onChangeStart(); jsDropDownCarryOver(dy, "clade"); jsDropDownCarryOver(dy, "db"); jsDropDownCarryOver(dy, "org"); dyStringPrintf(dy, " document.hiddenForm.%s.value=0;", hgtaTable); return jsOnChangeEnd(&dy); } static char *onChangeTable() /* Return javascript executed when they change group. */ { struct dyString *dy = onChangeStart(); jsDropDownCarryOver(dy, "clade"); jsDropDownCarryOver(dy, "db"); jsDropDownCarryOver(dy, "org"); jsDropDownCarryOver(dy, hgtaTable); return jsOnChangeEnd(&dy); } void makeRegionButtonExtraHtml(char *val, char *selVal, char *extraHtml) /* Make region radio button including a little Javascript to save selection state * and optional extra html attributes. */ { jsMakeTrackingRadioButtonExtraHtml(hgtaRegionType, "regionType", val, selVal, extraHtml); } void makeRegionButton(char *val, char *selVal) /* Make region radio button including a little Javascript * to save selection state. */ { makeRegionButtonExtraHtml(val, selVal, NULL); } struct grp *showGroupField(char *groupVar, char *event, char *groupScript, struct sqlConnection *conn, boolean allTablesOk) /* Show group control. Returns selected group. */ { struct grp *group, *groupList = fullGroupList; struct grp *selGroup = findSelectedGroup(groupList, groupVar); hPrintf("group:\n"); hPrintf("\n"); return selGroup; } static void addIfExists(struct hash *hash, struct slName **pList, char *name) /* Add name to tail of list if it exists in hash. */ { if (hashLookup(hash, name)) slNameAddTail(pList, name); } struct slName *getDbListForGenome() /* Get list of selectable databases. */ { struct hash *hash = sqlHashOfDatabases(); struct slName *dbList = NULL; addIfExists(hash, &dbList, database); addIfExists(hash, &dbList, "uniProt"); addIfExists(hash, &dbList, "proteome"); addIfExists(hash, &dbList, "go"); addIfExists(hash, &dbList, "hgFixed"); addIfExists(hash, &dbList, "visiGene"); addIfExists(hash, &dbList, "ultra"); return dbList; } char *findSelDb() /* Find user selected database (as opposed to genome database). */ { struct slName *dbList = getDbListForGenome(); char *selDb = cartUsualString(cart, hgtaTrack, NULL); if (!slNameInList(dbList, selDb)) selDb = cloneString(dbList->name); slFreeList(&dbList); return selDb; } struct trackDb *showTrackField(struct grp *selGroup, char *trackVar, char *event, char *trackScript, boolean disableNoGenome) /* Show track control. Returns selected track. */ { struct trackDb *track, *selTrack = NULL; if (trackScript == NULL) trackScript = ""; if (sameString(selGroup->name, "allTables")) { char *selDb = findSelDb(); struct slName *dbList = getDbListForGenome(), *db; hPrintf("database:\n"); hPrintf("\n"); } else { boolean allTracks = sameString(selGroup->name, "allTracks"); hPrintf("track:\n"); hPrintf("\n"); } hPrintf("\n"); return selTrack; } char *unsplitTableName(char *table) /* Convert chr*_name to name */ { if (startsWith("chr", table)) { char *s = strrchr(table, '_'); if (s != NULL) { table = s + 1; } } return table; } struct slName *tablesForDb(char *db) /* Find tables associated with database. */ { boolean isGenomeDb = sameString(db, database); struct sqlConnection *conn = hAllocConn(db); struct slName *raw, *rawList = sqlListTables(conn); struct slName *cooked, *cookedList = NULL; struct hash *uniqHash = newHash(0); hFreeConn(&conn); for (raw = rawList; raw != NULL; raw = raw->next) { if (cartTrackDbIsAccessDenied(db, raw->name)) continue; if (isGenomeDb) { /* Deal with tables split across chromosomes. */ char *root = unsplitTableName(raw->name); if (cartTrackDbIsAccessDenied(db, root)) continue; if (!hashLookup(uniqHash, root)) { hashAdd(uniqHash, root, NULL); cooked = slNameNew(root); slAddHead(&cookedList, cooked); } } else { char dbTable[256]; safef(dbTable, sizeof(dbTable), "%s.%s", db, raw->name); cooked = slNameNew(dbTable); slAddHead(&cookedList, cooked); } } hashFree(&uniqHash); slFreeList(&rawList); slSort(&cookedList, slNameCmp); return cookedList; } char *showTableField(struct trackDb *track, char *varName, boolean useJoiner) /* Show table control and label. */ { struct slName *name, *nameList = NULL; char *selTable; if (track == NULL) nameList = tablesForDb(findSelDb()); else nameList = cartTrackDbTablesForTrack(database, track, useJoiner); /* Get currently selected table. If it isn't in our list * then revert to first in list. */ selTable = cartUsualString(cart, varName, nameList->name); if (!slNameInListUseCase(nameList, selTable)) selTable = nameList->name; /* Print out label and drop-down list. */ hPrintf("table: "); hPrintf("\n"); if (!trackHubDatabase(database)) { char *restrictDate = encodeRestrictionDateDisplay(database,selTdb); if (restrictDate) { hPrintf("restricted until: %s", ENCODE_DATA_RELEASE_POLICY, restrictDate); freeMem(restrictDate); } } return selTable; } struct outputType /* Info on an output type. */ { struct outputType *next; char *name; /* Symbolic name of type. */ char *label; /* User visible label. */ }; static void showOutDropDown(struct outputType *otList, struct outputType *otDefault) /* Display output drop-down. */ { struct outputType *ot; char *outputType = cartUsualString(cart, hgtaOutputType, otList->name); if (otDefault != NULL && otDefault != otList) { boolean otInOtList = FALSE; for (ot = otList; ot != NULL; ot = ot->next) if (sameString(ot->name, outputType)) { otInOtList = TRUE; break; } if (! otInOtList) outputType = otDefault->name; } hPrintf("\n"); hPrintf(" "); hPrintf("
", database); hPrintf(" "); jsInline("function checkGtfNote() {" "if (document.getElementById('outputTypeDropdown').value==='gff') " " document.getElementById('gffNote').style.display=''; " "else " " document.getElementById('gffNote').style.display='none'; " "}" "$(document).ready(checkGtfNote);\n" ); jsOnEventById("change", "outputTypeDropdown", "checkGtfNote()"); jsInline("function checkSnpTablesNote() {" "var trackName = document.getElementById('hgta_track').value;" "if (trackName.startsWith('dbSnp') || trackName.startsWith('snp')) " " document.getElementById('snpTablesNote').style.display=''; " "else " " document.getElementById('snpTablesNote').style.display='none'; " "}" "$(document).ready(checkSnpTablesNote);\n" ); jsOnEventById("change", "outputTypeDropdown", "checkSnpTablesNote()"); if (!cfgOptionBooleanDefault("hgta.disableSendOutput", FALSE)) { hPrintf(" Send output to "); struct dyString *dy = dyStringNew(256); dyStringAppend(dy, "document.getElementById('checkboxGreat').checked=false;"); if (isGenomeSpaceEnabled()) dyStringAppend(dy, "document.getElementById('checkboxGenomeSpace').checked=false;"); dyStringAppend(dy, "return true;"); cgiMakeCheckBoxWithId("sendToGalaxy", doGalaxy(), "checkboxGalaxy"); jsOnEventById("click", "checkboxGalaxy", dy->string); hPrintf("Galaxy\n"); nbSpaces(2); cgiMakeCheckBoxWithId("sendToGreat", doGreat(), "checkboxGreat"); jsOnEventById("click", "checkboxGreat", "return onSelectGreat();"); hPrintf(" GREAT"); if (isGenomeSpaceEnabled()) { nbSpaces(2); cgiMakeCheckBoxWithId("sendToGenomeSpace", doGenomeSpace(), "checkboxGenomeSpace"); jsOnEventById("click", "checkboxGenomeSpace", "document.getElementById('checkboxGreat').checked=false;" "document.getElementById('checkboxGalaxy').checked=false; return true;"); hPrintf(" GenomeSpace"); } } hPrintf("\n"); } struct outputType otAllFields = { NULL, outPrimaryTable,"all fields from selected table", }; struct outputType otSelected = { NULL, outSelectedFields, "selected fields from primary and related tables", }; struct outputType otSequence = { NULL, outSequence, "sequence", }; struct outputType otPal = { NULL, outPalOptions, "CDS FASTA alignment from multiple alignment", }; struct outputType otGff = { NULL, outGff, "GTF - gene transfer format (limited)", }; struct outputType otBed = { NULL, outBed, "BED - browser extensible data", }; struct outputType otCustomTrack = { NULL, outCustomTrack, "custom track", }; struct outputType otHyperlinks = { NULL, outHyperlinks, "hyperlinks to Genome Browser", }; struct outputType otWigData = { NULL, outWigData, "data points", }; struct outputType otWigBed = { NULL, outWigBed, "bed format", }; struct outputType otMaf = { NULL, outMaf, "MAF - multiple alignment format", }; struct outputType otChromGraphData = { NULL, outChromGraphData, "data points", }; struct outputType otMicroarrayNames = { NULL, outMicroarrayNames, "microarray names", }; struct outputType otMicroarrayGroupings = { NULL, outMicroarrayGroupings, "microarray groupings", }; static void showOutputTypeRow(boolean isWig, boolean isBedGr, boolean isPositional, boolean isMaf, boolean isChromGraphCt, boolean isPal, boolean isMicroarray, boolean isHalSnake) /* Print output line. */ { struct outputType *otList = NULL, *otDefault = NULL; boolean bedifiedOnly = (anySubtrackMerge(database, curTable) || anyIntersection()); hPrintf("clade:\n"); printCladeListHtml(hGenome(database), "change", onChangeClade()); nbSpaces(3); hPrintf("genome:\n"); printGenomeListForCladeHtml(database, "change", onChangeOrg()); } else { hPrintf(" |
genome:\n"); printGenomeListHtml(database, "change", onChangeOrg()); } nbSpaces(3); hPrintf("assembly:\n"); printAssemblyListHtml(database, "change", onChangeDb()); hPrintf(" |
"); selGroup = showGroupField(hgtaGroup, "change", onChangeGroupOrTrack(), conn, hAllowAllTables()); nbSpaces(3); curTrack = showTrackField(selGroup, hgtaTrack, "change", onChangeGroupOrTrack(), FALSE); nbSpaces(3); boolean hasCustomTracks = FALSE; struct trackDb *t; for (t = fullTrackList; t != NULL; t = t->next) { if (isCustomTrack(t->table)) { hasCustomTracks = TRUE; break; } } hOnClickButton("showMainCtlTbl_Ct", "document.customTrackForm.submit();return false;", hasCustomTracks ? CT_MANAGE_BUTTON_LABEL : CT_ADD_BUTTON_LABEL); hPrintf(" "); if (hubConnectTableExists()) hOnClickButton("showMainCtlTbl_Hub", "document.trackHubForm.submit();return false;", "track hubs"); hPrintf(" |
"); curTable = showTableField(curTrack, hgtaTable, TRUE); if (isHubTrack(curTable) || (strchr(curTable, '.') == NULL)) /* In same database */ { hti = getHti(database, curTable, conn); isPositional = htiIsPositional(hti); } isLongTabix = isLongTabixTable( curTable); isBam = isBamTable(curTable); isHic = isHicTable(curTable); isVcf = isVcfTable(curTable, NULL); isWig = isWiggle(database, curTable); if (isBigWigTable(curTable)) { isPositional = TRUE; isWig = TRUE; } isHalSnake = isHalTable( curTable); isMaf = isMafTable(database, curTrack, curTable); isBedGr = isBedGraph(curTable); isArray = isMicroarray(curTrack, curTable); struct trackDb *tdb = findTdbForTable(database, curTrack, curTable, ctLookupName); isPal = isPalCompatible(conn, tdb, curTable); nbSpaces(1); if (isCustomTrack(curTable)) { isChromGraphCt = isChromGraph(tdb); } cgiMakeButton(hgtaDoSchema, "describe table schema"); hPrintf(" |
region:\n"); /* If regionType not allowed force it to "genome". */ if ((sameString(regionType, hgtaRegionTypeUserRegions) && userRegionsFileName() == NULL) || (sameString(regionType, hgtaRegionTypeEncode) && !doEncode)) regionType = hgtaRegionTypeGenome; // Is "genome" is not allowed because of tdb 'tableBrowser noGenome'? boolean disableGenome = ((curTrack && cartTrackDbIsNoGenome(database, curTrack->table)) || (curTable && cartTrackDbIsNoGenome(database, curTable))); // If "genome" is selected but not allowed, force it to "range": if (sameString(regionType, hgtaRegionTypeGenome) && disableGenome) regionType = hgtaRegionTypeRange; jsTrackingVar("regionType", regionType); if (disableGenome) { makeRegionButtonExtraHtml(hgtaRegionTypeGenome, regionType, "DISABLED"); hPrintf(" genome (unavailable for selected track)" " "); } else { makeRegionButton(hgtaRegionTypeGenome, regionType); hPrintf(" genome "); } if (doEncode) { makeRegionButton(hgtaRegionTypeEncode, regionType); hPrintf(" ENCODE Pilot regions "); } makeRegionButton(hgtaRegionTypeRange, regionType); hPrintf(" position "); hPrintf("\n", hgtaRange, hgtaRange, range); jsOnEventById("focus", hgtaRange, jsRadioUpdate(hgtaRegionType, "regionType", "range")); cgiMakeButton(hgtaDoLookupPosition, "lookup"); hPrintf(" "); if (userRegionsFileName() != NULL) { makeRegionButton(hgtaRegionTypeUserRegions, regionType); hPrintf(" defined regions "); cgiMakeButton(hgtaDoSetUserRegions, "change"); hPrintf(" "); cgiMakeButton(hgtaDoClearUserRegions, "clear"); } else cgiMakeButton(hgtaDoSetUserRegions, "define regions"); hPrintf(" |
");
char *noGenomeNote = trackDbSettingClosestToHome(curTrack, "noGenomeReason");
hPrintf("Note: This track is unavailable for genome-wide download. ");
if (noGenomeNote)
hPrintf("Reason: %s", noGenomeNote);
else
hPrintf("Usually, this is due to distribution restrictions of the source database or the size of the track. Please see the track documentation for more details. Contact us if you are still unable to access the data. ");
hPrintf(" |
identifiers (names/accessions):\n"); cgiMakeButton(hgtaDoPasteIdentifiers, "paste list"); hPrintf(" "); cgiMakeButton(hgtaDoUploadIdentifiers, "upload list"); if (identifierFileName() != NULL) { hPrintf(" "); cgiMakeButton(hgtaDoClearIdentifiers, "clear list"); } hPrintf(" |
filter:\n"); if (anyFilter()) { cgiMakeButton(hgtaDoFilterPage, "edit"); hPrintf(" "); cgiMakeButton(hgtaDoClearFilter, "clear"); if (isWig || isBedGr) wigShowFilter(conn); } else { cgiMakeButton(hgtaDoFilterPage, "create"); } hPrintf(" |
subtrack merge:\n"); if (anySubtrackMerge(database, curTable)) { cgiMakeButton(hgtaDoSubtrackMergePage, "edit"); hPrintf(" "); cgiMakeButton(hgtaDoClearSubtrackMerge, "clear"); } else { cgiMakeButton(hgtaDoSubtrackMergePage, "create"); } hPrintf(" |
intersection with %s:\n", cartString(cart, hgtaIntersectTable)); cgiMakeButton(hgtaDoIntersectPage, "edit"); hPrintf(" "); cgiMakeButton(hgtaDoClearIntersect, "clear"); hPrintf(" |
intersection:\n"); cgiMakeButton(hgtaDoIntersectPage, "create"); hPrintf(" |
correlation:\n");
if (differentWord(table2, "none") && strlen(table2) && ! isNoGenomeDisabled(database, table2))
{
struct grp *groupList = fullGroupList;
struct grp *selGroup = findSelectedGroup(groupList, hgtaCorrelateGroup);
struct trackDb *tdb2 = findSelectedTrack(fullTrackList, selGroup,hgtaCorrelateTrack);
if (tdbIsComposite(tdb2))
{
struct slRef *tdbRefList = trackDbListGetRefsToDescendantLeaves(tdb2->subtracks);
struct slRef *tdbRef;
for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next)
{
struct trackDb *subTdb = tdbRef->val;
if (sameString(table2, subTdb->table))
{
tdb2 = subTdb;
break;
}
}
slFreeList(&tdbRefList);
}
cgiMakeButton(hgtaDoCorrelatePage, "calculate");
cgiMakeButton(hgtaDoClearCorrelate, "clear");
if (tdb2 && tdb2->shortLabel)
hPrintf(" (with: %s)", tdb2->shortLabel);
#ifdef NOT_YET
/* debugging dbg vvvvv */
if (curTrack && curTrack->type) /* dbg */
{
hPrintf(" (debug: '%s', '%s(%s)')", curTrack->type, tdb2->type, table2); } /* debugging debug ^^^^^ */ #endif } else cgiMakeButton(hgtaDoCorrelatePage, "create"); hPrintf(" |
\n"); hPrintf("output file: "); cgiMakeTextVar(hgtaOutFileName, fileName, 29); hPrintf(" (leave blank to keep output in browser) |
\n"); hPrintf("file type returned: "); cgiMakeRadioButton(hgtaCompressType, textOutCompressNone, sameWord(textOutCompressNone, compressType)); hPrintf(" plain text  "); cgiMakeRadioButton(hgtaCompressType, textOutCompressGzip, sameWord(textOutCompressGzip, compressType)); hPrintf(" gzip compressed"); hPrintf(" |
" "To reset all user cart settings (including custom tracks), \n" "click here.\n", getScriptName()); } static char *getGenomeSpaceText() /* fetch GenomeSpace text if enabled */ { if (isGenomeSpaceEnabled()) { return "Send data to " "GenomeSpace for use with diverse computational tools. "; } else { return ""; } } void mainPageAfterOpen(struct sqlConnection *conn) /* Put up main page assuming htmlOpen()/htmlClose() * will happen in calling routine. */ { hPrintf( - "Use this program to retrieve the data associated with a track in text " + "Use this program to retrieve data associated with a track in text " "format, to calculate intersections between tracks, and to retrieve " - "DNA sequence covered by a track. For help in using this application " + "DNA sequence covered by a track." +); +hPrintf(" More..."); +hPrintf( + " " , getGenomeSpaceText() ); +hPrintf(" "); + +// Show more or less intro text +char jsText[1024]; +safef(jsText, sizeof jsText, + "$('#tbHelpMore').hide();" + "$('#tbHelp').show();" + "$('#tbHelpLess').show();" + ); +jsOnEventById("click", "tbHelpMore", jsText); +safef(jsText, sizeof jsText, + "$('#tbHelpMore').show();" + "$('#tbHelp').hide();" + "$('#tbHelpLess').hide();" + ); +jsOnEventById("click", "tbHelpLess", jsText); // When GREAT is selected, disable the other checkboxes and force output to BED jsInline( "function onSelectGreat() {\n" " document.getElementById('checkboxGalaxy').checked=false;\n"); if (isGenomeSpaceEnabled()) jsInline( " document.getElementById('checkboxGenomeSpace').checked=false;\n"); jsInline( " document.getElementById('outBed').selected=true;\n" " return true;\n" "}\n"); // Disable/enable noGenome tracks depending on whether region is genome. jsInline( "function maybeDisableNoGenome() {\n" " var regionTypeSelected = $('input[name=\"hgta_regionType\"]:checked').val();\n" " var regionIsGenome = (regionTypeSelected === 'genome');\n" " var $noGenomeOptions = $('select[name=\"hgta_track\"] option.hgtaNoGenome');\n" " $noGenomeOptions.attr('disabled', regionIsGenome)\n" " .css('color', regionIsGenome ? '' : 'black');\n" "}\n" "$(document).ready(function() {\n" // once when the page loads, and every time the user changes the region type: " maybeDisableNoGenome();\n" " $('input[name=\"hgta_regionType\"]').change(maybeDisableNoGenome);\n" "});\n"); /* Main form. */ hPrintf("
\n"); /* Hidden form - for benefit of javascript. */ { static char *saveVars[] = { "clade", "org", "db", hgtaGroup, hgtaTrack, hgtaTable, hgtaRegionType, hgtaRange, hgtaOutputType, hgtaOutFileName}; jsCreateHiddenForm(cart, getScriptName(), saveVars, ArraySize(saveVars)); } /* Hidden form for jumping to custom tracks CGI. */ hPrintf("\n"); /* Hidden form for jumping to track hub manager CGI. */ hPrintf("\n"); webNewSection("Using the Table Browser\n"); printMainHelp(); cartFlushHubWarnings(); } void doMainPage(struct sqlConnection *conn) /* Put up the first page user sees. */ { htmlOpen("Table Browser"); +webIncludeResourceFile("jquery-ui.css"); mainPageAfterOpen(conn); htmlClose(); } + +