327ff85429911eaa58790c850bc5e83ad4b1548f angie Wed May 26 19:33:36 2021 -0700 User request (HT Krisandra Allen, WA DOH): add a box in which sequence names/IDs can be pasted instead of uploaded from file. diff --git src/hg/hgPhyloPlace/hgPhyloPlace.c src/hg/hgPhyloPlace/hgPhyloPlace.c index dd8661e..1ec2a3c 100644 --- src/hg/hgPhyloPlace/hgPhyloPlace.c +++ src/hg/hgPhyloPlace/hgPhyloPlace.c @@ -16,30 +16,31 @@ #include "net.h" #include "options.h" #include "phyloPlace.h" #include "portable.h" #include "trackLayout.h" #include "udc.h" #include "web.h" /* Global Variables */ struct cart *cart = NULL; // CGI and other variables struct hash *oldVars = NULL; // Old contents of cart before it was updated by CGI boolean measureTiming = FALSE; // Print out how long things take char *leftLabelWidthForLongNames = "55";// Leave plenty of room for tree and long virus strain names #define seqFileVar "sarsCoV2File" +#define pastedIdVar "namesOrIds" #define remoteFileVar "remoteFile" static struct lineFile *lineFileFromFileInput(struct cart *cart, char *fileVar) /* Return a lineFile on data from an uploaded file with cart variable name fileVar. * If the file is binary, attempt to decompress it. Return NULL if no data are found * or if there is a problem decompressing binary data. If retFileName is not NULL */ { struct lineFile *lf = NULL; // Depending on whether the file is plain text or binary, different cart variables are present. char *filePlainContents = cartOptionalString(cart, fileVar); char cartVar[2048]; safef(cartVar, sizeof cartVar, "%s__binary", fileVar); char *fileBinaryCoords = cartOptionalString(cart, cartVar); // Also get the file name for error reporting. safef(cartVar, sizeof cartVar, "%s__filename", fileVar); @@ -138,33 +139,43 @@ // Container for bootstrap grid layout puts( "<div class='container-fluid'>\n"); } static void newPageEndStuff() { puts( "</div>"); jsIncludeFile("utils.js", NULL); webIncludeFile("inc/gbFooter.html"); webEndJWest(); } -#define CHECK_FILE_INPUT_JS(varName) "{ var $fileInput = $('input[name="varName"]'); " \ - "if ($fileInput && $fileInput[0] && $fileInput[0].files && !$fileInput[0].files.length) {" \ - " alert('Please choose a file first, then click the upload button.');" \ +#define CHECK_FILE_OR_PASTE_INPUT_JS(fileVarName, pasteVarName) \ + "{ var $fileInput = $('input[name="fileVarName"]');" \ + " var $pasteInput = $('textarea[name="pasteVarName"]');" \ + " if ($fileInput && $fileInput[0] && $fileInput[0].files && !$fileInput[0].files.length &&" \ + " $pasteInput && !$pasteInput.val()) {" \ + " alert('Please either choose a file or paste in sequence names/IDs first, ' +" \ + " 'and then click the upload button.');" \ + " return false; " \ + " } else if ($fileInput && $fileInput[0] && $fileInput[0].files && " \ + " !!$fileInput[0].files.length &&" \ + " $pasteInput && !!$pasteInput.val()) {" \ + " alert('Sorry, unable to process both a file and pasted-in sequence names/IDs at the ' +" \ + " 'same time. Please clear one or the other and then click the upload button.');" \ " return false; " \ " } else { loadingImage.run(); return true; } }" static void inputForm() /* Ask the user for FASTA or VCF. */ { printf("<form action='%s' name='mainForm' method=POST enctype='multipart/form-data'>\n\n", "hgPhyloPlace"); cartSaveSession(cart); char *db = "wuhCor1"; cgiMakeHiddenVar("db", db); puts(" <div class='gbControl col-md-12'>"); puts("<div class='readableWidth'>"); puts("<p>Upload your SARS-CoV-2 sequence (FASTA or VCF file) to find the most similar\n" "complete, high-coverage samples from \n" @@ -218,47 +229,50 @@ "<p>In order to enable rapid progress in SARS-CoV-2 research and genomic contact tracing,\n" "please share your SARS-CoV-2 sequences by submitting them to an " "<a href='https://ncbiinsights.ncbi.nlm.nih.gov/2020/08/17/insdc-covid-data-sharing/' " "target=_blank>INSDC</a> member institution\n" "(<a href='https://submit.ncbi.nlm.nih.gov/sarscov2/' target=_blank>NCBI</a>,\n" "<a href='https://www.covid19dataportal.org/submit-data' target=_blank>EMBL-EBI</a>\n" "or <a href='https://www.ddbj.nig.ac.jp/ddbj/websub.html' target=_blank>DDBJ</a>)\n" "and <a href='https://www.gisaid.org/' target=_blank>GISAID</a>.\n" "</p>\n"); puts("</div>"); puts(" </div>"); puts(" <div class='gbControl col-md-12'>"); printf("<p>Select your FASTA, VCF or list of sequence names/IDs: "); printf("<input type='file' id='%s' name='%s'>", seqFileVar, seqFileVar); +printf("</p><p>or paste in sequence names/IDs:<br>\n"); +cgiMakeTextArea(pastedIdVar, "", 10, 70); struct treeChoices *treeChoices = loadTreeChoices(db); if (treeChoices) { puts("</p><p>"); printf("Phylogenetic tree version: "); char *phyloPlaceTree = cartOptionalString(cart, "phyloPlaceTree"); cgiMakeDropListWithVals("phyloPlaceTree", treeChoices->descriptions, treeChoices->protobufFiles, treeChoices->count, phyloPlaceTree); } puts("</p><p>"); printf("Number of samples per subtree showing sample placement: "); int subtreeSize = cartUsualInt(cart, "subtreeSize", 50); cgiMakeIntVarWithLimits("subtreeSize", subtreeSize, "Number of samples in subtree showing neighborhood of placement", 5, 10, 5000); puts("</p><p>"); -cgiMakeOnClickSubmitButton(CHECK_FILE_INPUT_JS(seqFileVar), "submit", "upload"); +cgiMakeOnClickSubmitButton(CHECK_FILE_OR_PASTE_INPUT_JS(seqFileVar, pastedIdVar), + "submit", "upload"); puts("</p>"); // Add a loading image to reassure people that we're working on it when they upload a big file printf("<div><img id='loadingImg' src='../images/loading.gif' />\n"); printf("<span id='loadingMsg'></span></div>\n"); jsInline("$(document).ready(function() {\n" " loadingImage.init($('#loadingImg'), $('#loadingMsg'), " "'<p style=\"color: red; font-style: italic;\">Uploading and processing your sequences " "may take some time. Please leave this window open while we work on your sequences.</p>');" "});\n"); puts(" </div>"); puts("</form>"); } static void exampleForm() @@ -425,30 +439,36 @@ measureTiming = cartUsualBoolean(cart, "measureTiming", measureTiming); char *submitLabel = cgiOptionalString("submit"); if (submitLabel && sameString(submitLabel, "try example")) { char *exampleFile = phyloPlaceDbSettingPath(db, "exampleFile"); struct lineFile *lf = lineFileOpen(exampleFile, TRUE); resultsPage(db, lf); } else if (cgiOptionalString(remoteFileVar)) { char *url = cgiString(remoteFileVar); struct lineFile *lf = netLineFileOpen(url); resultsPage(db, lf); } +else if (isNotEmpty(trimSpaces(cgiOptionalString(pastedIdVar)))) + { + char *pastedIds = cgiString(pastedIdVar); + struct lineFile *lf = lineFileOnString("pasted names/IDs", TRUE, pastedIds); + resultsPage(db, lf); + } else if (cgiOptionalString(seqFileVar) || cgiOptionalString(seqFileVar "__filename")) { struct lineFile *lf = lineFileFromFileInput(cart, seqFileVar); resultsPage(db, lf); } else mainPage(db); } #define LD_LIBRARY_PATH "LD_LIBRARY_PATH" static void addLdLibraryPath() /* usher requires a tbb lib that is not in the yum package tbb-devel, so for now * I'm adding the .so files to hgPhyloPlaceData. Set environment variable LD_LIBRARY_PATH * to pick them up from there. */ @@ -462,24 +482,25 @@ char cwd[4096]; getcwd(cwd, sizeof cwd); dyStringPrintf(dy, "%s/%s", cwd, PHYLOPLACE_DATA_DIR); } if (isNotEmpty(oldValue)) dyStringPrintf(dy, ":%s", oldValue); setenv(LD_LIBRARY_PATH, dyStringCannibalize(&dy), TRUE); } int main(int argc, char *argv[]) /* Process command line. */ { /* Null terminated list of CGI Variables we don't want to save to cart */ char *excludeVars[] = {"submit", "Submit", seqFileVar, seqFileVar "__binary", seqFileVar "__filename", + pastedIdVar, NULL}; long enteredMainTime = clock1000(); cgiSpoof(&argc, argv); oldVars = hashNew(10); addLdLibraryPath(); cartEmptyShellNoContent(doMiddle, hUserCookie(), excludeVars, oldVars); cgiExitTime("hgPhyloPlace", enteredMainTime); return 0; }