a8f29caea973a2482924c38c981b59a28e22e8ec max Fri Oct 22 05:14:38 2021 -0700 making hgHubConnect more self-explanatory, with more text. The development tab is revamped to provide a visual indicator of what's going on while hubCheck is running. (The concept with an IFRAME could well be applied to hgc links from hgTracks, to avoid a full page reload.), refs #28324 diff --git src/hg/hgHubConnect/hgHubConnect.c src/hg/hgHubConnect/hgHubConnect.c index 3b9bd21..b483490 100644 --- src/hg/hgHubConnect/hgHubConnect.c +++ src/hg/hgHubConnect/hgHubConnect.c @@ -19,30 +19,32 @@ #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" #include "trix.h" #include "net.h" #include "hubSearchText.h" #include "pipeline.h" #include "hubPublic.h" +static boolean measureTiming; + struct cart *cart; /* The user's ui state. */ struct hash *oldVars = NULL; static char *pageTitle = "Track Data Hubs"; char *database = NULL; char *organism = NULL; struct hubOutputStructure { struct hubOutputStructure *next; struct dyString *metaTags; struct dyString *descriptionMatch; struct genomeOutputStructure *genomes; int genomeCount; struct hash *genomeOutHash; @@ -210,32 +212,38 @@ el = slNameNew(genomes->name); slAddHead(&list, el); } slReverse(&list); printGenomeList(thub->url, list, row, withLink); } 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("
\n" - " \n" +puts("
\n" + "
"); + +printf("
\n", "../cgi-bin/hgGateway"); +cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); +cartSaveSession(cart); + +puts("
\n" " \n" " \n" " \n"); jsOnEventById("click", "hubAddButton", "var hubText = document.getElementById('hubUrl');" "hubText.value=$.trim(hubText.value);" "if(validateUrl($('#hubUrl').val())) { " " document.addHubForm.elements['hubUrl'].value=hubText.value;" " document.addHubForm.submit(); return true; } " "else { return false; }" @@ -247,45 +255,62 @@ 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 +puts("

If have a new hub URL, you can add it here, then connect/disconnect " + " as needed. Other users will not see your hub.

" + "

To share your hub with others, connect it below, then save a session " + "from the Genome Browser (\"My Data > My Sessions\"). " + " You can put the session link " + "into a manuscript or send it to others. This means that you can always update the session later. " + "Users who click the session link will lose their own Genome Browser " + "configuration, connected hubs and custom tracks.

" + "

If you want to avoid overriding their sessions, construct a link for others with " + "the hubUrl argument, like this: " + "https://genome.ucsc.edu/cgi-bin/hgTracks?db=hg38&hubUrl=URL_TO_HUB" + "

" + "

Contact us if you want to add a hub to the list of public hubs.

\n" + ); + if (unlistedHubCount == 0) { // nothing to see here printf(""); - printf("
\n" " \n" "\n" "
No Unlisted Track Hubs
"); + printf(""); + puts(""); // return from within DIV and FROM is probably not a good idea + puts(""); // tabSection and .unlistedHubs return; } // time to output the big table. First the header -printf( +puts( " " "Display " "Hub Name " "Description " - "Assemblies " + "AssembliesClick to connect and browse directly " "\n" "\n"); // start first row printf(""); char id[256]; int count = 0; for(hub = unlistedHubList; hub; hub = hub->next) { char hubName[64]; safef(hubName, sizeof(hubName), "%s%u", hgHubConnectHubVarPrefix, hub->id); if (!cartUsualBoolean(cart, hubName, FALSE)) continue; @@ -337,222 +362,204 @@ ourPrintCell(hub->trackHub->longLabel); } else ourPrintCell(""); if (hub->trackHub != NULL) printGenomes(hub->trackHub, count, !hubHasError); else ourPrintCell(""); puts(""); } printf("\n"); -printf(""); +puts(""); +printf(""); // .tabSection +printf(""); // #unlistedHubs + } void doValidateNewHub(char *hubUrl) /* Run hubCheck on a hub. */ { udcSetCacheTimeout(1); printf("
"); char *cmd[] = {"loader/hubCheck", "-htmlOut", "-noTracks", hubUrl, NULL}; struct pipeline *pl = pipelineOpen1(cmd, pipelineRead | pipelineNoAbort, NULL, NULL); struct lineFile *lf = pipelineLineFile(pl); char *line; while (lineFileNext(lf, &line, NULL)) jsInlineF("%s", line); pipelineClose(&pl); // the 'false' below prevents a few hub-search specific jstree configuration options jsInline("hubSearchTree.init(false);"); } void hgHubConnectDeveloperMode() /* Put up the controls for the "Hub Development" Tab, which includes a button to run the * hubCheck utility on a hub and load a hub with the udcTimeout and measureTiming * variables turned on */ { // put out the top of our page char *hubUrl = cartOptionalString(cart, "validateHubUrl"); -boolean doHubValidate = cartVarExists(cart, hgHubDoHubCheck); // the outer div for all the elements in the tab -printf("\n
\n"); +puts("
"); -// the row to enter in the url and the button and settings to validate/load -printf("
\n"); -printf("\n"); +char *hubUrlVal = ""; if (hubUrl != NULL) + hubUrlVal = catThreeStrings(" value='", hubUrl, "'"); + +puts("
"); +puts("

Create your own hub

"); +puts("For information on making track hubs, please see the following pages: \n " + "\n" + "Example hub URL: http://genome.ucsc.edu/goldenPath/help/examples/hubDirectory/hub.txt"); +puts("
"); // .tabSection + +puts("
"); +puts("

Check a hub for errors

"); +printf(""); +printf("\n", hubUrlVal); +printf("\n"); + +puts("
When debugging a hub, it is sometimes helpful to check it for errors. " + "With the button above, you can validate the hub's configuration files, including hub.txt, " + "genomes.txt and trackDb.txt. " + "A hierarchical tree of tracks is presented with any errors in red. A hub " + "with no errors still shows the tree which can be used to explore the track hierarchy. " + "Hub error checking will always refresh the files and never use our remote file cache (see below)." + "
\n " +); +puts("
"); // .tabSection + +puts("
"); +puts("

Enable Genome Browser debugging modes

"); +puts("
These apply to all connected hubs. By default, caching is activated and track load times are not shown, but you can change these settings when debugging your hub.
"); +puts("
"); +puts("
"); + +// output the udcTimeout button +char *noCacheLabel = "Deactivate (Always refresh)"; +char *timeout = "5"; +char *cacheStatus = "ON"; +char *description = "Always refresh files, do not cache contents at UCSC. This means that data access is slower, but you can see the effect of changes to your files immediately on the Genome Browser."; +if (cartNonemptyString(cart, "udcTimeout")) { - printf(" \n", hubUrl); + noCacheLabel = "Activate (Always cache)"; + timeout = ""; + cacheStatus = "OFF"; + description = "Always cache contents at UCSC. This means that data access is faster, but you cannot see the effect of changes to your files on the Genome Browser for at least 5 minutes."; } -else +printf("File caching: %s  ", cacheStatus); +printf("", timeout, noCacheLabel); + +printf("
%s
", description); +puts("For custom tracks, this affects only the remote formats (bigBed, bigWig, tabix, BAM, CRAM, etc), not text files (BED, PSL, etc), which are stored at UCSC.
"); + +// output the measureTiming button +char *timeLabel = "Show timings"; +char *timeVal = "on"; +char *timeDesc = "Shows loading time in milliseconds for each track, to help debug performance problems."; +char *timeStatus = "OFF"; +if (cartNonemptyString(cart, "measureTiming")) { - printf(" \n"); - } -printf("\n"); -printf(" or \n"); -printf("\n"); -printf("
\n"); // validateHubUrlRow div - -printf("
\n"); -printf("\n"); -printf("Optional View Hub Settings"); - -char *measureTiming = cartCgiUsualString(cart, "measureTiming", NULL); -char *udcTimeout = cartCgiUsualString(cart, "udcTimeout", NULL); -boolean doMeasureTiming = isNotEmpty(measureTiming); -boolean doUdcTimeout = isNotEmpty(udcTimeout); - -printf("
\n"); -printf("
    \n
  • \n"); -// measureTiming first -printf("", doMeasureTiming ? "checked": ""); -printf("\n"); - -// and a tooltip explaining this checkbox -printf("
    (?)\n"); -printf("" - "Checking this box shows the timing measurements at the bottom of the Genome Browser page. " - "Useful for determining slowdowns to loading or drawing tracks." - "\n"); -printf("
  • \n"); // tooltip div - -printf("
  • \n"); -// udcTimeout enable/disable -printf("", doUdcTimeout ? "checked" : ""); -printf("\n"); -// add a tooltip explaining these checkboxes -printf("
    (?)\n"); -printf("" - "Checking this box changes the cache expiration time (default of 5 minutes) " - "and allows the Genome Browser to reload Hub configuration and data files with each refresh." - "\n"); -printf("
  • \n"); // tooltip div -printf("
\n"); -printf("
\n"); // extraSettingsList div -printf("
\n"); // extraSettingsContainer div - -if (hubUrl != NULL && doHubValidate) - doValidateNewHub(hubUrl); -else - printf("
Enter URL to hub to check configuration settings " - "or load hub
\n"); -printf("
"); // hubDeveloper div - -jsOnEventById("click", "hubValidateButton", - "var validateText = document.getElementById('validateHubUrl');" - "var udcTimeout = document.getElementById('disableUdcTimeout').checked === true;" - "var doMeasureTiming = document.getElementById('addMeasureTiming').checked === true;" - "validateText.value=$.trim(validateText.value);" - "if(validateUrl($('#validateHubUrl').val())) { " - " document.validateHubForm.elements['validateHubUrl'].value=validateText.value;" - " document.validateHubForm.elements['" hgHubDoHubCheck "'].value='on';" - " if (doMeasureTiming) { document.validateHubForm.elements['measureTiming'].value='1'; }" - " else { document.validateHubForm.elements['measureTiming'].value=''}" - " if (udcTimeout) { document.validateHubForm.elements['udcTimeout'].value='1'; }" - " else { document.validateHubForm.elements['udcTimeout'].value=''}" - " document.validateHubForm.submit(); return true; }" - "else { return false; }" - ); -jsOnEventById("click", "hubLoadMaybeTiming", - "var validateText = document.getElementById('validateHubUrl');" - "var udcTimeout = document.getElementById('disableUdcTimeout').checked === true;" - "var doMeasureTiming = document.getElementById('addMeasureTiming').checked === true;" - "validateText.value=$.trim(validateText.value);" - "if(validateUrl($('#validateHubUrl').val())) {" - " loc = \"../cgi-bin/hgTracks?hgHub_do_firstDb=on&hgHub_do_redirect=on&hgHubConnect.remakeTrackHub=on\" + \"&hubUrl=\" + validateText.value;" - " if (doMeasureTiming) { loc += \"&measureTiming=1\";} else { loc += \"&measureTiming=[]\"; }" - " if (udcTimeout) { loc += \"&udcTimeout=5\"; } else { loc += \"&udcTimeout=[]\"; }" - " window.location.href=loc; " - "} else { return false; }" - ); + timeLabel = "Hide timings"; + timeVal = ""; + timeDesc = "Hide timing measurements."; + timeStatus = "OFF"; + } + +printf("Load times: %s  ", timeStatus); +printf("", timeVal, timeLabel); + +printf("
%s
", timeDesc); + +puts("
"); // margin-left +puts("
"); // tabSection +puts("
"); // #hubDeveloper + +jsOnEventById("click", "hubValidateButton", "makeIframe(event)"); } void printSearchAndFilterBoxes(int searchEnabled, char *hubSearchTerms, char *dbFilter) /* Create the text boxes for search and database filtering along with the required * javscript */ { -char event[4096]; +printf("\n", "../cgi-bin/hgHubConnect"); if (searchEnabled) { - safef(event, sizeof(event), - "document.searchHubForm.elements['hubSearchTerms'].value=$('#hubSearchTerms').val();" - "document.searchHubForm.elements['hubDbFilter'].value=$('#hubDbFilter').val();" - "document.searchHubForm.submit();return true;"); - printf("Enter search terms to find in public track hub description pages:
" + cgiMakeHiddenVar(hgHubDoSearch, "on"); + cgiMakeHiddenVar(hgHubDbFilter, ""); + cartSaveSession(cart); + + printf("The list below can be filtered on words in the description pages or assemblies.
" + "Search terms: " " \n", + "type=\"text\" size=\"50\" value=\"%s\"> \n", hubSearchTerms!=NULL?hubSearchTerms:""); - printf("
\n"); - } -else - { - safef(event, sizeof(event), - "document.searchHubForm.elements['hubDbFilter'].value=$('#hubDbFilter').val();" - "document.searchHubForm.submit();return true;"); + printf("\n"); } -printf("Filter hubs by assembly: " +printf("Assembly: " " \n" "\n", + "class=\"hubField\" type=\"submit\" value=\"Search Public Hubs\">\n", hgHubDbFilter, dbFilter!=NULL?dbFilter:""); -jsOnEventById("click", "hubSearchButton", event); -puts("

\n"); +puts(""); } void printSearchTerms(char *hubSearchTerms) /* Write out a reminder about the current search terms and a note about * how to navigate detailed search results */ { printf("Displayed list restricted by search terms: %s\n", hubSearchTerms); puts("\n"); jsOnEventById("click", "hubDeleteSearchButton", "document.searchHubForm.elements['hubSearchTerms'].value='';" "document.searchHubForm.elements['hubDbFilter'].value='';" "document.searchHubForm.submit();return true;"); puts("

\n"); printf("When exploring the detailed search results for a hub, you may right-click " "on an assembly or track line to open it in a new window.\n"); puts("

\n"); } void printHubListHeader() /* Write out the header for a list of hubs in its own table */ { -puts("Clicking Connect redirects to the gateway page of the selected hub's default assembly.
"); -printf(" " +puts("
" " " " " " " " " - " " - "
DisplayHub NameDescriptionAssemblies
\n"); + //"Assemblies " + "AssembliesClick to connect and browse directly " + ""); } void outputPublicTableRow(struct hubEntry *hubInfo, int count) /* Prints out a table row with basic information about a hub and a button * to connect to that hub */ { int id = hubInfo->id; char jsId[256]; struct slName *dbListNames = slNameListFromComma(hubInfo->dbList); printf("\n"); if (id != 0) { ourCellStart(); char hubName[32]; safef(hubName, sizeof(hubName), "%s%u", hgHubConnectHubVarPrefix, id); @@ -1098,36 +1105,39 @@ /* Compare to sort based on shortLabel */ { const struct hubEntry *a = *((struct hubEntry **)va); const struct hubEntry *b = *((struct hubEntry **)vb); return strcasecmp(a->shortLabel, b->shortLabel); } void printHubList(struct slName *hubsToPrint, struct hash *hubLookup, struct hash *searchResultHash) /* Print out a list of hubs, possibly along with search hits to those hubs. * hubLookup takes hub URLs to struct hubEntry * searchResultHash takes hub URLs to struct hubSearchText * (list of hits on that hub) */ { +printf("
\n", "../cgi-bin/hgGateway"); +cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); +cartSaveSession(cart); + int count = 0; struct hubEntry *hubList = NULL; struct hubEntry *hubInfo; long slTime; long printOutputForHubTime; -boolean measureTiming = cartUsualBoolean(cart, "measureTiming", FALSE); if (hubsToPrint != NULL) { printHubListHeader(); if (searchResultHash == NULL) // if not displaying search results, join the hub s into one table printf("\n"); struct slName *thisHubName = NULL; for (thisHubName = hubsToPrint; thisHubName != NULL; thisHubName = thisHubName->next) { hubInfo = (struct hubEntry *) hashFindVal(hubLookup, thisHubName->name); if (hubInfo == NULL) { /* This shouldn't happen often, but maybe the search hits list was built from an outdated * search text file that includes hubs for which no info is available. * Skip this hub. */ @@ -1171,112 +1181,133 @@ } jsInline( "function lineUpCols()\n" " {\n" " var tableList = $('table.hubList');\n" " if (tableList.length == 0)\n" " return;\n" " var colWidths = new Array();\n" " var combinedTrackTable = $('#hideThisTable');\n" " for (i=0; i"); +} static bool outputPublicTable(struct sqlConnection *conn, char *publicTable, char *statusTable, struct hash **pHash) /* Put up the list of public hubs and other controls for the page. */ { char *hubSearchTerms = cartOptionalString(cart, hgHubSearchTerms); char *dbFilter = cartOptionalString(cart, hgHubDbFilter); char *lcDbFilter = cloneString(dbFilter); if (isNotEmpty(lcDbFilter)) tolowers(lcDbFilter); // make sure all the public hubs are in the hubStatus table. +long lastTime= clock1000(); addPublicHubsToHubStatus(cart, conn, publicTable, statusTable); +printf("Time of addPublicHubsToHubStatus: %ld
", (clock1000()-lastTime)); + // build full public hub lookup hash, taking each URL to struct hubEntry * for that hub struct hash *hubLookup = buildPublicLookupHash(conn, publicTable, statusTable, pHash); -printf("
\n"); +puts("
"); + +puts("
"); + +printf( + "

" + "Track data hubs are collections of external tracks that can be added to the UCSC Genome Browser. " + "Click \"Connect\" below to show the \"Genomes\" page with all assemblies covered by a hub. " + "Hub tracks then show up under the hub's own blue bar track group under the browser graphic, " + "as well as under \"Genome Browser > Configure\". See the " + "" + "User's Guide. " + "

" + "

Track Hubs are created and maintained by external sources." + " The public hubs below were submitted to us, we have performed " + " basic quality checks. UCSC is not responsible for their content.

" +); char *hubSearchTableName = hubSearchTextTableName(); int searchEnabled = sqlTableExists(conn, hubSearchTableName); printSearchAndFilterBoxes(searchEnabled, hubSearchTerms, dbFilter); struct hash *searchResultHash = NULL; struct slName *hubsToPrint = NULL; if (searchEnabled && !isEmpty(hubSearchTerms)) { printSearchTerms(hubSearchTerms); // Forcing checkDescriptions to TRUE right now, but we might want to add this as a // checkbox option for users in the near future. bool checkDescriptions = TRUE; searchResultHash = newHash(5); getHubSearchResults(conn, hubSearchTableName, - hubSearchTerms, checkDescriptions, lcDbFilter, hubLookup, &searchResultHash, &hubsToPrint, NULL); - } + hubSearchTerms, checkDescriptions, lcDbFilter, hubLookup, &searchResultHash, &hubsToPrint, NULL); } else { // There is no active search, so just add all hubs to the list struct hashEl *hel; struct hashEl *helList; helList = hashElListHash(hubLookup); for (hel = helList; hel != NULL; hel = hel->next) { if (isNotEmpty(lcDbFilter)) { struct hubEntry *hubEnt = (struct hubEntry *) hel->val; char *lcDbList = cloneString(hubEnt->dbList); if (isNotEmpty(lcDbList)) tolowers(lcDbList); if ((lcDbList == NULL) || (stringIn(lcDbFilter, lcDbList) == NULL)) continue; } slNameAddHead(&hubsToPrint, hel->name); } } slReverse(&hubsToPrint); +printf("
\n"); // .tabSection + printHubList(hubsToPrint, hubLookup, searchResultHash); -printf("
"); +printf("
"); // #publicHubs return (hubsToPrint != NULL); } - 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); char *statusTable = cfgOptionEnvDefault("HGDB_HUB_STATUS_TABLE", hubStatusTableConfVariable, defaultHubStatusTableName); + if (!(sqlTableExists(conn, publicTable) && outputPublicTable(conn, publicTable,statusTable, &retHash)) ) { printf("
\n"); printf("No Public Track Hubs found that match search criteria.
"); printf("
"); } hDisconnectCentral(&conn); return retHash; } static void tryHubOpen(unsigned id) /* try to open hub, leaks trackHub structure */ @@ -1366,280 +1397,253 @@ static void doClearHub(struct cart *theCart) { char *url = cartOptionalString(cart, hgHubDataText); printf("
clearing hub %s\n",url);
 if (url != NULL)
     hubClearStatus(url);
 else
     errAbort("must specify url in %s\n", hgHubDataText);
 printf("
Completed\n");
 }
 
 
 static void checkTrackDbs(struct hubConnectStatus *hubList)
 {
+//long beforeCheck = clock1000();
+
 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);
     }
+
+if (measureTiming)
+    printf("hgHubConnect: checkTrackDbs time: %lu millis
\n", clock1000() - beforeCheck); } int hubConnectStatusCmp(const void *va, const void *vb) /* Compare to sort based on shortLabel */ { const struct hubConnectStatus *a = *((struct hubConnectStatus **)va); const struct hubConnectStatus *b = *((struct hubConnectStatus **)vb); struct trackHub *ta = a->trackHub; struct trackHub *tb = b->trackHub; if ((ta == NULL) || (tb == NULL)) return 0; return strcasecmp(tb->shortLabel, ta->shortLabel); } +void printIncludes() +/* print the CSS and javascript include lines */ +{ +printf( +"\n" +"\n" +"\n" +"\n" +); +jsIncludeFile("utils.js", NULL); +jsIncludeFile("jquery-ui.js", NULL); +webIncludeResourceFile("jquery-ui.css"); +jsIncludeFile("ajax.js", NULL); +jsIncludeFile("hgHubConnect.js", NULL); +webIncludeResourceFile("hgHubConnect.css"); +jsIncludeFile("jquery.cookie.js", NULL); +jsIncludeFile("spectrum.min.js", NULL); // there is no color picker used anywhere on this page. why include this? +} + void doMiddle(struct cart *theCart) /* Write header and body of html page. */ { cart = theCart; +measureTiming = cartUsualBoolean(cart, "measureTiming", FALSE); if(cgiIsOnWeb()) checkForGeoMirrorRedirect(cart); if (cartVarExists(cart, hgHubDoClear)) { doClearHub(cart); cartWebEnd(); return; } if (cartVarExists(cart, hgHubCheckUrl)) { doResetHub(cart); } if (cartVarExists(cart, hgHubDoRedirect)) { if (doRedirect(cart)) { cartWebEnd(); return; } } +if (cartVarExists(cart, hgHubDoHubCheck)) + { + puts(""); + puts(""); + puts(""); + printIncludes(); + + jsInline("trackData = [];\n"); + char *hubUrl = cartOptionalString(cart, "validateHubUrl"); + jsInline("document.body.style.margin = 0;\n"); + // simulate the look and feel of a dialog window with a blue bar at the top + puts("
" + "Hub Check" + "" + "close
"); + + puts("
"); + if (isEmpty(hubUrl)) + printf("Please wait, loading and checking hub, this can take 15 seconds to several minutes."); + else + { + puts("

"); + puts("  

"); + jsOnEventByIdF("click", "reloadButton", "reloadIframe()"); + jsOnEventByIdF("click", "closeButton", "closeIframe()"); + jsOnEventByIdF("click", "windowX", "closeIframe()"); + + printf("
Finished checking %s
", hubUrl); + doValidateNewHub(hubUrl); + puts("

Our command line tool hubCheck " + "can be used to obtain the same output from a Unix command line.

"); + } + puts("
"); // margin 10px + puts(""); // ui-dialog-titlebar + puts(""); // ui-dialog + cartWebEnd(); + return; + } + cartWebStart(cart, NULL, "%s", pageTitle); -printf( -"\n" -"\n" -"\n" -"\n" -); -jsIncludeFile("utils.js", NULL); -jsIncludeFile("jquery-ui.js", NULL); -webIncludeResourceFile("jquery-ui.css"); -jsIncludeFile("ajax.js", NULL); -jsIncludeFile("hgHubConnect.js", NULL); -webIncludeResourceFile("hgHubConnect.css"); -jsIncludeFile("jquery.cookie.js", NULL); -jsIncludeFile("spectrum.min.js", NULL); +printIncludes(); -boolean doHubDevMode = cfgOptionBooleanDefault("hgHubConnect.validateHub", FALSE); -printf("
\n"); -printf( - "

Track data hubs are collections of external tracks that can be imported into the UCSC Genome Browser. " - "Hub tracks show up under the hub's own blue label bar on the main browser page, " - "as well as on the configure page. For more information, including where to " - "host your track hub, see the " - "" - "User's Guide." - "To import a public hub click its \"Connect\" button below.

" - "

NOTE: Because Track Hubs are created and maintained by external sources," - " UCSC is not responsible for their content.

" - ); -printf("
\n"); -if (doHubDevMode) - { - printf("
\n"); - printf("

Check the configuration settings for a hub, including the settings " - "in the hub.txt, genomes.txt, and trackDb.txt files. If there are errors in the hub " - "setup, a heirarchal tree of tracks is presented with the errors in red text. A hub " - "with no errors still has the tree present but needs to be clicked to be expanded to " - " explore the track heirarchy.

\n" - "

Also present are buttons to load the hub with track timing measuring turned on " - "in order to profile slow loading tracks, and an option to disable the track caching " - "mechanism so the Genome Browser picks up changes to the configuration files or " - "track data files. For more information on making track hubs, please see the following links: \n " - "

\n" - "
\n " - ); +if (cartVarExists(cart, hgHubDoHubCheck)) + { + jsInline("trackData = [];\n"); + char *hubUrl = cartOptionalString(cart, "validateHubUrl"); + doValidateNewHub(hubUrl); + cartWebEnd(); + return; } // this variable is used by hub search and hub validate, initialize here so we don't // overwrite it unintentionally depending on which path the CGI takes jsInline("trackData = [];\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("%s\n", survey, surveyLabel ? surveyLabel : "Take survey"); hPutc('\n'); // grab all the hubs that are listed in the cart struct hubConnectStatus *hubList = hubConnectStatusListFromCartAll(cart); checkTrackDbs(hubList); slSort(&hubList, hubConnectStatusCmp); -// here's a little form for the add new hub button +// here's a little invisible form for the add new hub button printf("\n", "../cgi-bin/hgHubConnect"); cgiMakeHiddenVar("hubUrl", ""); cgiMakeHiddenVar( hgHubDoFirstDb, "on"); cgiMakeHiddenVar( hgHubDoRedirect, "on"); cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); cartSaveSession(cart); puts(""); -// this is the form for the connect hub button +// this is the invisible form for the connect hub button printf("
\n", "../cgi-bin/hgHubConnect"); cgiMakeHiddenVar("hubUrl", ""); cgiMakeHiddenVar("db", ""); cgiMakeHiddenVar( hgHubDoRedirect, "on"); cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); cartSaveSession(cart); puts(""); -// this is the form for the disconnect hub button +// this is the invisible form for the disconnect hub button - it's submitted via javascript printf("
\n", "../cgi-bin/hgHubConnect"); cgiMakeHiddenVar("hubId", ""); cgiMakeHiddenVar(hgHubDoDisconnect, "on"); cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); cartSaveSession(cart); puts(""); -// this is the form for the reset hub button +// this is the invisible form for the reset hub button - it's submitted via javascript printf("
\n", "../cgi-bin/hgHubConnect"); cgiMakeHiddenVar(hgHubCheckUrl, ""); cartSaveSession(cart); puts(""); -// this is the form for the search hub button -printf("
\n", "../cgi-bin/hgHubConnect"); -cgiMakeHiddenVar(hgHubSearchTerms, ""); -cgiMakeHiddenVar(hgHubDoSearch, "on"); -cgiMakeHiddenVar(hgHubDbFilter, ""); -cartSaveSession(cart); -puts(""); - -// this is the form for the validate button -if (doHubDevMode) - { - printf("
\n", "../cgi-bin/hgHubConnect"); - cgiMakeHiddenVar("validateHubUrl", ""); - cgiMakeHiddenVar("measureTiming", ""); - cgiMakeHiddenVar("udcTimeout", ""); - // allows saving the old url in the search bar but not run hubCheck on it right away - // mostly for when you come back to hgHubConnect after just looking at hgTracks - cgiMakeHiddenVar(hgHubDoHubCheck, "off"); - cartSaveSession(cart); - puts(""); - } // ... and now the main form -printf("
\n", "../cgi-bin/hgGateway"); -cartSaveSession(cart); -// we have two tabs for the public and unlisted hubs +// we have three tabs for the public and unlisted hubs and hub development printf("
" " "); +// The public hubs table is getting big and takes a while to download. +// Jquery UI's tabs() command will layout the page, but because of +// jsInlining, it will only be called at the end of the page. This can lead to the page "jumping". +// To make the inline code run now, let's flush JS inlines. +// I'm not sure that this makes a visible difference, but it doesn't do any harm either +jsInlineFinish(); +jsInlineReset(); + struct hash *publicHash = hgHubConnectPublic(); -hgHubConnectUnlisted(hubList, publicHash); -if (doHubDevMode) - hgHubConnectDeveloperMode(); -// add the event listener for toggling the right description text -jsInline( - "var oldDesc = document.getElementById('description');\n" - "var newDesc = document.getElementById('developerModeDescription');\n" - "if (location.hash === \"#hubDeveloper\") {\n" - " toggleTwoDivs(newDesc, oldDesc);\n" - "}\n" - "window.addEventListener('hashchange', function() {\n" - " if (location.hash === \"#hubDeveloper\") {" - " toggleTwoDivs(newDesc, oldDesc);\n" - " } else {\n" - " toggleTwoDivs(oldDesc, newDesc);\n" - " }\n" - "});\n" - "var plusButton = document.getElementById('advancedSettingsButton');\n" - "plusButton.addEventListener('click', function() {\n" - " var advancedSettingsDiv = document.getElementById('extraSettingsContainer');\n" - " var extraSettingsList = document.getElementById('extraSettingsList');\n" - " if (extraSettingsList.style.display != 'none') {\n" - " extraSettingsList.style.display = 'none';\n" - " imgTag = advancedSettingsDiv.getElementsByTagName('img')[0];\n" - " imgTag.src = \"../images/add_sm.gif\";\n" - " } else {\n" - " extraSettingsList.style.display = 'block';\n" - " imgTag = advancedSettingsDiv.getElementsByTagName('img')[0];\n" - " imgTag.src = \"../images/remove_sm.gif\";\n" - " }\n" - "});" - ); -printf("
"); -printf("
"); +hgHubConnectUnlisted(hubList, publicHash); -printf("" - "Contact us to add a public hub." - "\n"); -printf("
"); +hgHubConnectDeveloperMode(); -cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); +printf("
"); // #tabs -puts(""); -printf("\n"); cartWebEnd(); } char *excludeVars[] = {"Submit", "submit", "hc_one_url", hgHubDoHubCheck, - hgHubCheckUrl, hgHubDoClear, hgHubDoDisconnect,hgHubDoRedirect, hgHubDataText, + hgHubCheckUrl, hgHubDoClear, hgHubDoRefresh, hgHubDoDisconnect,hgHubDoRedirect, hgHubDataText, hgHubConnectRemakeTrackHub, NULL}; int main(int argc, char *argv[]) /* Process command line. */ { long enteredMainTime = clock1000(); + oldVars = hashNew(10); cgiSpoof(&argc, argv); cartEmptyShell(doMiddle, hUserCookie(), excludeVars, oldVars); cgiExitTime("hgHubConnect", enteredMainTime); return 0; }