f081da12001f6451aca5f05a0ca153e58d332671 tdreszer Tue Oct 8 12:13:06 2013 -0700 Fixed braney's allergy as per redmine 11889. Long lists of assemblies were not wrapping in the HTML table because there were no spaces. So this now insures spaces in the list. diff --git src/hg/hgHubConnect/hgHubConnect.c src/hg/hgHubConnect/hgHubConnect.c index 834adb4..61b43bc 100644 --- src/hg/hgHubConnect/hgHubConnect.c +++ src/hg/hgHubConnect/hgHubConnect.c @@ -1,535 +1,548 @@ /* hgHubConnect - the CGI web-based program to select track data hubs to connect with. */ #include "common.h" #include "hash.h" #include "linefile.h" #include "errabort.h" #include "errCatch.h" #include "hCommon.h" #include "dystring.h" #include "jksql.h" #include "cheapcgi.h" #include "htmshell.h" #include "hdb.h" #include "hui.h" #include "cart.h" #include "dbDb.h" #include "web.h" #include "trackHub.h" #include "hubConnect.h" #include "dystring.h" #include "hPrint.h" #include "jsHelper.h" #include "obscure.h" #include "hgConfig.h" #define hgHub "hgHub_" /* prefix for all control variables */ #define hgHubDo hgHub "do_" /* prefix for all commands */ #define hgHubDoClear hgHubDo "clear" #define hgHubDoDisconnect hgHubDo "disconnect" #define hgHubDoReset hgHubDo "reset" struct cart *cart; /* The user's ui state. */ struct hash *oldVars = NULL; static char *destUrl = "../cgi-bin/hgTracks"; static char *pageTitle = "Track Data Hubs"; char *database = NULL; char *organism = NULL; static void ourCellStart() { fputs("<TD>", stdout); // do not add a newline } static void ourCellEnd() { puts("</TD>"); } static void ourPrintCell(char *str) { ourCellStart(); if (str != NULL) fputs(str, stdout); // do not add a newline -- was causing trailing blanks get copied in cut and paste ourCellEnd(); } static char *removeLastComma(char *string) { if (string != NULL) { int len = strlen(string); if ( string[len - 1] == ',') string[len - 1] = 0; + else if (len > 2 && endsWith(string,", ")) + string[len - 2] = 0; } return string; } static void printGenomes(struct trackHub *thub) /* print supported assembly names from trackHub */ { /* List of associated genomes. */ struct trackHubGenome *genomes = thub->genomeList; struct dyString *dy = newDyString(100); for(; genomes; genomes = genomes->next) dyStringPrintf(dy,"%s, ", trackHubSkipHubName(genomes->name)); ourPrintCell(removeLastComma( dyStringCannibalize(&dy))); } +static void printGenomeList(struct slName *genomes) +/* print supported assembly names from sl list */ +{ +/* List of associated genomes. */ +struct dyString *dy = newDyString(100); + +for(; genomes; genomes = genomes->next) + dyStringPrintf(dy,"%s, ", trackHubSkipHubName(genomes->name)); +ourPrintCell(removeLastComma( dyStringCannibalize(&dy))); +} + static void hgHubConnectUnlisted(struct hubConnectStatus *hubList, struct hash *publicHash) /* Put up the list of unlisted hubs and other controls for the page. */ /* uses publicHash to distingusih public hubs from unlisted ones */ /* NOTE: Destroys hubList */ { // put out the top of our page printf("<div id=\"unlistedHubs\" class=\"hubList\"> \n" "<table id=\"unlistedHubsTable\"> \n" "<thead><tr> \n" "<th colspan=\"6\" id=\"addHubBar\"><label for=\"hubUrl\">URL:</label> \n" "<input name=\"hubText\" id=\"hubUrl\" class=\"hubField\"" "type=\"text\" size=\"65\"> \n" "<input name=\"hubAddButton\"" "onClick=\"hubText.value=$.trim(hubText.value);if(validateUrl($('#hubUrl').val())) { document.addHubForm.elements['hubUrl'].value=hubText.value;" "document.addHubForm.submit();return true;} else { return false;}\" " "class=\"hubField\" type=\"button\" value=\"Add Hub\">\n" "</th> \n" "</tr> \n"); // count up the number of unlisted hubs we currently have int unlistedHubCount = 0; struct hubConnectStatus *unlistedHubList = NULL; struct hubConnectStatus *hub, *nextHub; for(hub = hubList; hub; hub = nextHub) { nextHub = hub->next; // if url is not in publicHash, it's unlisted */ if (!((publicHash != NULL) && hashLookup(publicHash, hub->hubUrl))) { unlistedHubCount++; slAddHead(&unlistedHubList, hub); } } hubList = NULL; // hubList no longer valid if (unlistedHubCount == 0) { // nothing to see here printf("<tr><td>No Unlisted Track Hubs</td></tr>"); printf("</thead></table></div>"); return; } // time to output the big table. First the header printf( "<tr> " "<th>Display</th> " "<th>Hub Name</th> " "<th>Description</th> " "<th>Assemblies</th> " "<th>URL</th> " "<th>Disconnect</th> " "</tr>\n" "</thead>\n"); // start first row printf("<tbody><tr>"); int count = 0; for(hub = unlistedHubList; hub; hub = hub->next) { if (count) webPrintLinkTableNewRow(); // ends last row and starts a new one count++; // if there's an error message, we don't let people select it if (isEmpty(hub->errorMessage)) { ourCellStart(); char hubName[32]; safef(hubName, sizeof(hubName), "%s%u", hgHubConnectHubVarPrefix, hub->id); cartMakeCheckBox(cart, hubName, FALSE); ourCellEnd(); } else { // give people a chance to clear the error ourCellStart(); printf( "<input name=\"hubClearButton\"" "onClick=\"document.resetHubForm.elements['hubUrl'].value='%s';" "document.resetHubForm.submit();return true;\" " "class=\"hubField\" type=\"button\" value=\"check hub\">\n" , hub->hubUrl); ourCellEnd(); } if (hub->trackHub != NULL) ourPrintCell(hub->trackHub->shortLabel); else ourPrintCell(""); if (!isEmpty(hub->errorMessage)) printf("<TD><span class=\"hubError\">ERROR: %s </span>" "<a href=\"../goldenPath/help/hgTrackHubHelp.html#Debug\">Debug</a></TD>\n", hub->errorMessage); else if (hub->trackHub != NULL) ourPrintCell(hub->trackHub->longLabel); else ourPrintCell(""); if (hub->trackHub != NULL) printGenomes(hub->trackHub); else ourPrintCell(""); ourPrintCell(hub->hubUrl); ourCellStart(); printf( "<input name=\"hubDisconnectButton\"" "onClick=\"document.disconnectHubForm.elements['hubId'].value='%d';" "document.disconnectHubForm.submit();return true;\" " "class=\"hubField\" type=\"button\" value=\"X\">\n" , hub->id); ourCellEnd(); } printf("</TR></tbody></TABLE>\n"); printf("</div>"); } static struct hash *outputPublicTable(struct sqlConnection *conn, char *publicTable) /* Put up the list of public hubs and other controls for the page. */ { struct hash *publicHash = NULL; char query[512]; sqlSafef(query, sizeof(query), "select hubUrl,shortLabel,longLabel,dbList from %s", publicTable); struct sqlResult *sr = sqlGetResult(conn, query); char **row; boolean gotAnyRows = FALSE; while ((row = sqlNextRow(sr)) != NULL) { char *url = row[0], *shortLabel = row[1], *longLabel = row[2], *dbList = row[3]; if (gotAnyRows) webPrintLinkTableNewRow(); else { /* output header */ printf("<div id=\"publicHubs\" class=\"hubList\"> \n"); printf("<table id=\"publicHubsTable\"> " "<thead><tr> " "<th>Display</th> " "<th>Hub Name</th> " "<th>Description</th> " "<th>Assemblies</th> " "<th>URL</th> " "</tr></thead>\n"); // start first row printf("<tbody> <tr>"); gotAnyRows = TRUE; // allocate the hash to store hubUrl's publicHash = newHash(5); } char *errorMessage = NULL; // get an id for this hub unsigned id = hubFindOrAddUrlInStatusTable(database, cart, url, &errorMessage); if ((id != 0) && isEmpty(errorMessage)) { ourCellStart(); char hubName[32]; safef(hubName, sizeof(hubName), "%s%u", hgHubConnectHubVarPrefix, id); cartMakeCheckBox(cart, hubName, FALSE); ourCellEnd(); } else if (!isEmpty(errorMessage)) { // give user a chance to clear the error ourCellStart(); printf( "<input name=\"hubClearButton\"" "onClick=\"document.resetHubForm.elements['hubUrl'].value='%s';" "document.resetHubForm.submit();return true;\" " "class=\"hubField\" type=\"button\" value=\"check hub\">" , url); ourCellEnd(); } else errAbort("cannot get id for hub with url %s\n", url); ourPrintCell(shortLabel); if (isEmpty(errorMessage)) ourPrintCell(longLabel); else printf("<TD><span class=\"hubError\">ERROR: %s </span>" "<a href=\"../goldenPath/help/hgTrackHubHelp.html#Debug\">Debug</a></TD>", errorMessage); - ourPrintCell(removeLastComma(dbList)); + printGenomeList(slNameListFromComma(dbList)); // Leaking a bit of memory ourPrintCell(url); hashStore(publicHash, url); } sqlFreeResult(&sr); if (gotAnyRows) { printf("</TR></tbody></TABLE>\n"); printf("</div>"); } return publicHash; } struct hash *hgHubConnectPublic() /* Put up the list of public hubs and other controls for the page. */ { struct hash *retHash = NULL; struct sqlConnection *conn = hConnectCentral(); char *publicTable = cfgOptionEnvDefault("HGDB_HUB_PUBLIC_TABLE", hubPublicTableConfVariable, defaultHubPublicTableName); if (!(sqlTableExists(conn, publicTable) && (retHash = outputPublicTable(conn, publicTable)) != NULL )) { printf("<div id=\"publicHubs\" class=\"hubList\"> \n"); printf("No Public Track Hubs for this genome assembly<BR>"); printf("</div>"); } hDisconnectCentral(&conn); return retHash; } static void tryHubOpen(unsigned id) /* try to open hub, leaks trackHub structure */ { /* try opening this again to reset error */ struct sqlConnection *conn = hConnectCentral(); struct errCatch *errCatch = errCatchNew(); struct hubConnectStatus *hub = NULL; if (errCatchStart(errCatch)) hub = hubConnectStatusForId(conn, id); errCatchEnd(errCatch); if (errCatch->gotError) hubUpdateStatus( errCatch->message->string, NULL); else hubUpdateStatus(NULL, hub); errCatchFree(&errCatch); hDisconnectCentral(&conn); } static void doResetHub(struct cart *theCart) { char *url = cartOptionalString(cart, hgHubDataText); if (url != NULL) { unsigned id = hubResetError(url); tryHubOpen(id); } else errAbort("must specify url in %s\n", hgHubDataText); } static void doClearHub(struct cart *theCart) { char *url = cartOptionalString(cart, hgHubDataText); printf("<pre>clearing hub %s\n",url); if (url != NULL) hubClearStatus(url); else errAbort("must specify url in %s\n", hgHubDataText); printf("<pre>Completed\n"); } static void doDisconnectHub(struct cart *theCart) { char *id = cartOptionalString(cart, "hubId"); if (id != NULL) { char buffer[1024]; safef(buffer, sizeof buffer, "hgHubConnect.hub.%s", id); cartRemove(cart, buffer); } cartRemove(theCart, "hubId"); } static void checkTrackDbs(struct hubConnectStatus *hubList) { struct hubConnectStatus *hub = hubList; for(; hub; hub = hub->next) { struct errCatch *errCatch = errCatchNew(); if (errCatchStart(errCatch)) { hubAddTracks(hub, database); } errCatchEnd(errCatch); if (errCatch->gotError) { hub->errorMessage = cloneString(errCatch->message->string); hubUpdateStatus( errCatch->message->string, hub); } else hubUpdateStatus(NULL, hub); } } void doMiddle(struct cart *theCart) /* Write header and body of html page. */ { boolean gotDisconnect = FALSE; cart = theCart; if (cartVarExists(cart, hgHubDoClear)) { doClearHub(cart); cartWebEnd(); return; } if (cartVarExists(cart, hgHubDoDisconnect)) { gotDisconnect = TRUE; doDisconnectHub(cart); // now rebuild the cart variable ("trackHubs") that has which lists which // hubs are on. hubConnectHubsInCart(cart); } if (cartVarExists(cart, hgHubDoReset)) { doResetHub(cart); } cartWebStart(cart, NULL, "%s", pageTitle); jsIncludeFile("jquery.js", NULL); jsIncludeFile("utils.js", NULL); jsIncludeFile("jquery-ui.js", NULL); webIncludeResourceFile("jquery-ui.css"); jsIncludeFile("ajax.js", NULL); jsIncludeFile("hgHubConnect.js", NULL); jsIncludeFile("jquery.cookie.js", NULL); printf("<div id=\"hgHubConnectUI\"> <div id=\"description\"> \n"); printf( "<P>Track data hubs are collections of tracks from outside of UCSC that " "can be imported into the Genome Browser. To import a public hub check " "the box in the list below. " "After import the hub will show up as a group of tracks with its own blue " "bar and label underneath the main browser graphic, and in the " "configure page. For more information, see the " "<A HREF=\"../goldenPath/help/hgTrackHubHelp.html\" TARGET=_blank>" "User's Guide</A>.</P>\n" "<P><B>NOTE: Because Track Hubs are created and maintained by external sources," " UCSC is not responsible for their content.</B></P>" ); printf("</div>\n"); getDbAndGenome(cart, &database, &organism, oldVars); char *survey = cfgOptionEnv("HGDB_HUB_SURVEY", "hubSurvey"); char *surveyLabel = cfgOptionEnv("HGDB_HUB_SURVEY_LABEL", "hubSurveyLabel"); if (survey && differentWord(survey, "off")) hPrintf("<span style='background-color:yellow;'><A HREF='%s' TARGET=_BLANK><EM><B>%s</EM></B></A></span>\n", survey, surveyLabel ? surveyLabel : "Take survey"); hPutc('\n'); // check to see if we have any new hubs hubCheckForNew(cart); // grab all the hubs that are listed in the cart struct hubConnectStatus *hubList = hubConnectStatusListFromCartAll(cart); checkTrackDbs(hubList); // here's a little form for the add new hub button printf("<FORM ACTION=\"%s\" NAME=\"addHubForm\">\n", "../cgi-bin/hgHubConnect"); cgiMakeHiddenVar("hubUrl", ""); cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); puts("</FORM>"); // this the form for the disconnect hub button printf("<FORM ACTION=\"%s\" NAME=\"disconnectHubForm\">\n", "../cgi-bin/hgHubConnect"); cgiMakeHiddenVar("hubId", ""); cgiMakeHiddenVar(hgHubDoDisconnect, "on"); cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); puts("</FORM>"); // this the form for the reset hub button printf("<FORM ACTION=\"%s\" NAME=\"resetHubForm\">\n", "../cgi-bin/hgHubConnect"); cgiMakeHiddenVar("hubUrl", ""); cgiMakeHiddenVar(hgHubDoReset, "on"); cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); puts("</FORM>"); // ... and now the main form if (cartVarExists(cart, hgHubConnectCgiDestUrl)) destUrl = cartOptionalString(cart, hgHubConnectCgiDestUrl); printf("<FORM ACTION=\"%s\" METHOD=\"POST\" NAME=\"mainForm\">\n", destUrl); cartSaveSession(cart); // we have two tabs for the public and unlisted hubs printf("<div id=\"tabs\">" "<ul> <li><a href=\"#publicHubs\">Public Hubs</a></li>" "<li><a href=\"#unlistedHubs\">My Hubs</a></li> " "</ul> "); struct hash *publicHash = hgHubConnectPublic(); hgHubConnectUnlisted(hubList, publicHash); printf("</div>"); printf("<div class=\"tabFooter\">"); cgiMakeButton("Submit", "Use Selected Hubs"); char *emailAddress = cfgOptionDefault("hub.emailAddress","genome@soe.ucsc.edu"); printf("<span class=\"small\">" "Contact <A HREF=\"mailto:%s\">%s</A> to add a public hub." "</span>\n", emailAddress,emailAddress); printf("</div>"); cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); printf("</div>\n"); puts("</FORM>"); cartWebEnd(); } char *excludeVars[] = {"Submit", "submit", "hc_one_url", hgHubDoReset, hgHubDoClear, hgHubDoDisconnect, hgHubDataText, hgHubConnectRemakeTrackHub, NULL}; int main(int argc, char *argv[]) /* Process command line. */ { long enteredMainTime = clock1000(); oldVars = hashNew(10); setUdcCacheDir(); cgiSpoof(&argc, argv); cartEmptyShell(doMiddle, hUserCookie(), excludeVars, oldVars); cgiExitTime("hgHubConnect", enteredMainTime); return 0; }