b8d33c3a3fc4c67dcea6509e744160f8d2c21e7c tdreszer Fri Feb 25 12:33:30 2011 -0800 Support for multi-selects for mdb searches on advanced tab. Requires cv.ra change to be active. diff --git src/hg/hgTracks/searchTracks.c src/hg/hgTracks/searchTracks.c index 40e6b3d..dabb9f2 100644 --- src/hg/hgTracks/searchTracks.c +++ src/hg/hgTracks/searchTracks.c @@ -9,43 +9,47 @@ #include "hash.h" #include "cheapcgi.h" #include "hPrint.h" #include "htmshell.h" #include "cart.h" #include "hgTracks.h" #include "web.h" #include "jksql.h" #include "hdb.h" #include "mdb.h" #include "fileUi.h" #include "trix.h" #include "jsHelper.h" #include "imageV2.h" + #define ANYLABEL "Any" #define TRACK_SEARCH_FORM "trackSearch" #define SEARCH_RESULTS_FORM "searchResults" #define METADATA_NAME_PREFIX "hgt_mdbVar" #define METADATA_VALUE_PREFIX "hgt_mdbVal" #define TRACK_SEARCH_CURRENT_TAB "tsCurTab" #define TRACK_SEARCH_SIMPLE "tsSimple" #define TRACK_SEARCH_ON_NAME "tsName" #define TRACK_SEARCH_ON_TYPE "tsType" #define TRACK_SEARCH_ON_GROUP "tsGroup" #define TRACK_SEARCH_ON_DESCR "tsDescr" #define TRACK_SEARCH_SORT "tsSort" +// If there are problems with multiSelect support, it can quickly be blocked! +//#define BLOCK_MULTI_SELECT_SUPPORT + //#define FILES_SEARCH #ifdef FILES_SEARCH #define TRACK_SEARCH_ON_FILETYPE "tsFileType" #endif///def FILES_SEARCH // Currently selected tab enum searchTab { simpleTab = 0, advancedTab = 1, filesTab = 2, }; static int gCmpGroup(const void *va, const void *vb) /* Compare groups based on label. */ { @@ -319,30 +323,31 @@ { retVar[count] = oneTerm->name; retLab[count] = oneTerm->val; count++; } } // Don't do it, unless you clone strings above: slPairFreeValsAndList(&whileList); *metaVars = retVar; *metaLabels = retLab; return count; } static int printMdbSelects(struct sqlConnection *conn,struct cart *cart,enum searchTab selectedTab,char ***pMdbVar,char ***pMdbVal,int *numMetadataNonEmpty,int cols) // Prints a table of mdb selects if appropriate and returns number of them +// TODO: move to lib since hgTracks and hgFileSearch share it { // figure out how many metadata selects are visible. int delSearchSelect = cartUsualInt(cart, TRACK_SEARCH_DEL_ROW, 0); // 1-based row to delete int addSearchSelect = cartUsualInt(cart, TRACK_SEARCH_ADD_ROW, 0); // 1-based row to insert after int numMetadataSelects = 0; char **mdbVar = NULL; char **mdbVal = NULL; char **mdbVars = NULL; char **mdbVarLabels = NULL; int i, count = metaDbVars(conn, &mdbVars, &mdbVarLabels); for(;;) { char buf[256]; safef(buf, sizeof(buf), "%s%d", METADATA_NAME_PREFIX, numMetadataSelects + 1); @@ -376,32 +381,49 @@ else offset = 1; safef(buf, sizeof(buf), "%s%d", METADATA_NAME_PREFIX, i + offset); mdbVar[i] = cloneString(cartOptionalString(cart, buf)); if(selectedTab!=simpleTab) { int j; boolean found = FALSE; // We need to make sure mdbVar[i] is valid in this assembly; if it isn't, reset it to "cell". for(j = 0; j < count && !found; j++) if(sameString(mdbVars[j], mdbVar[i])) found = TRUE; if(found) { safef(buf, sizeof(buf), "%s%d", METADATA_VALUE_PREFIX, i + offset); - mdbVal[i] = cloneString(cartOptionalString(cart, buf)); - if(sameString(mdbVal[i], ANYLABEL)) + enum mdbCvSearchable searchBy = mdbCvSearchMethod(mdbVar[i]); + #ifdef BLOCK_MULTI_SELECT_SUPPORT + if (searchBy == cvsSearchByMultiSelect) // NOTE: Temprorarily bypass cv.ra + searchBy = cvsSearchBySingleSelect; + #endif///def BLOCK_MULTI_SELECT_SUPPORT + if (searchBy == cvsSearchByMultiSelect) + { + // Multi-selects as comma delimited list of values + struct slName *vals = cartOptionalSlNameList(cart,buf); + if (vals) + { + mdbVal[i] = slNameListToString(vals,','); // A comma delimited list of values + slNameFreeList(&vals); + } + } + else + mdbVal[i] = cloneString(cartUsualString(cart, buf,ANYLABEL)); + + if (mdbVal[i] != NULL && sameString(mdbVal[i], ANYLABEL)) mdbVal[i] = NULL; } else { mdbVar[i] = cloneString("cell"); mdbVal[i] = NULL; } if(!isEmpty(mdbVal[i])) (*numMetadataNonEmpty)++; } } if(delSearchSelect > 0) { char buf[255]; safef(buf, sizeof(buf), "%s%d", METADATA_NAME_PREFIX, numMetadataSelects + 1); @@ -410,94 +432,99 @@ cartRemove(cart, buf); } } else { // create defaults numMetadataSelects = 2; mdbVar = needMem(sizeof(char *) * numMetadataSelects); mdbVal = needMem(sizeof(char *) * numMetadataSelects); mdbVar[0] = "cell"; mdbVar[1] = "antibody"; mdbVal[0] = ANYLABEL; mdbVal[1] = ANYLABEL; } - hPrintf("<tr><td colspan='%d' align='right' class='lineOnTop' style='height:20px; max-height:20px;'><em style='color:%s; width:200px;'>ENCODE terms</em></td></tr>", cols,COLOR_DARKGREY); + hPrintf("<tr><td colspan='%d' align='right' class='lineOnTop' style='height:20px; max-height:20px;'><em style='color:%s; width:200px;'>ENCODE terms</em></td></tr>\n", cols,COLOR_DARKGREY); for(i = 0; i < numMetadataSelects; i++) { char **terms = NULL, **labels = NULL; char buf[256]; int len; #define PLUS_MINUS_BUTTON "<input type='button' id='%sButton%d' value='%c' style='font-size:.7em;' title='%s' onclick='findTracksMdbSelectPlusMinus(this,%d)'>" - #define PRINT_PM_BUTTON(type,num,value) printf(PLUS_MINUS_BUTTON, (type), (num), (value), ((value) == '+' ? "add another row after":"delete"), (num)); - #ifndef PLUS_MINUS_BUTTON - #define PRINT_BUTTON(name,value,msg,js) printf("<input type='submit' name='%s' value='%s' style='font-size:.7em;' title='%s this row' onclick='%s'>", (name), (value), (msg), (js)); - #endif//ndef PLUS_MINUS_BUTTON - hPrintf("<tr class='mdbSelect'><td nowrap>\n"); + #define PRINT_PM_BUTTON(type,num,value) printf(PLUS_MINUS_BUTTON, (type), (num), (value), ((value) == '+' ? "add another row after":"delete"), (num)) + hPrintf("<tr valign='top' class='mdbSelect'><td nowrap>\n"); if(numMetadataSelects > 2 || i >= 2) - { - #ifdef PLUS_MINUS_BUTTON PRINT_PM_BUTTON("minus", i + 1, '-'); - #else///ifndef PLUS_MINUS_BUTTON - safef(buf, sizeof(buf), "return delSearchSelect(this, %d);", i + 1); - PRINT_BUTTON(TRACK_SEARCH, "-", "delete this row", buf); - #endif//ndef PLUS_MINUS_BUTTON - } else hPrintf(" "); - #ifdef PLUS_MINUS_BUTTON PRINT_PM_BUTTON("plus", i + 1, '+'); - #else///ifndef PLUS_MINUS_BUTTON - hPrintf("</td><td>\n"); - safef(buf, sizeof(buf), "return addSearchSelect(this, %d);", i + 1); - PRINT_BUTTON(TRACK_SEARCH, "+", "add another row after this row", buf); - #endif//ndef PLUS_MINUS_BUTTON hPrintf("</td><td>and </td><td colspan=3 nowrap>\n"); safef(buf, sizeof(buf), "%s%i", METADATA_NAME_PREFIX, i + 1); - cgiDropDownWithTextValsAndExtra(buf, mdbVarLabels, mdbVars,count,mdbVar[i],"class='mdbVar' style='font-size:.9em;' onchange='findTracksMdbVarChanged(this);'"); - // TODO: move to lib since hgTracks and hgApi share enum mdbCvSearchable searchBy = mdbCvSearchMethod(mdbVar[i]); + #ifdef BLOCK_MULTI_SELECT_SUPPORT + if (searchBy == cvsSearchByMultiSelect) // NOTE: Temprorarily bypass cv.ra + searchBy = cvsSearchBySingleSelect; + #else///ndef BLOCK_MULTI_SELECT_SUPPORT + cgiDropDownWithTextValsAndExtra(buf, mdbVarLabels, mdbVars,count,mdbVar[i],"class='mdbVar' style='font-size:.9em;' onchange='findTracksMdbVarChanged(this);'"); + safef(buf, sizeof(buf), "%s%i", METADATA_VALUE_PREFIX, i + 1); + #endif///ndef BLOCK_MULTI_SELECT_SUPPORT if (searchBy == cvsSearchByMultiSelect) { - // TO BE IMPLEMENTED + #ifdef BLOCK_MULTI_SELECT_SUPPORT + cgiDropDownWithTextValsAndExtra(buf, mdbVarLabels, mdbVars,count,mdbVar[i],"class='mdbVar' style='font-size:.9em;' onchange='findTracksMdbVarChanged(this);'"); + safef(buf, sizeof(buf), "%s%i", METADATA_VALUE_PREFIX, i + 1); + #endif///ndef BLOCK_MULTI_SELECT_SUPPORT + printf("</td>\n<td align='right' id='isLike%i' style='width:10px; white-space:nowrap;'>is (any of)</td>\n<td nowrap id='%s' style='max-width:600px;'>\n",i + 1,buf); + #define MULTI_SELECT_CBS_FORMAT "<SELECT MULTIPLE=true name='%s' style='display: none; min-width:200px; font-size:.9em;' class='filterBy mdbVal' onchange='findTracksMdbValChanged(this)'>\n" + printf(MULTI_SELECT_CBS_FORMAT,buf); + len = getTermArray(conn, &labels, &terms, mdbVar[i]); + int tix=0; + for(;tix < len;tix++) + { + char *selected = findWordByDelimiter(terms[tix],',', mdbVal[i]); + printf("<OPTION%s value='%s'>%s</OPTION>\n",(selected != NULL?" SELECTED":""),terms[tix],labels[tix]); + } + printf("</SELECT>\n"); } else if (searchBy == cvsSearchBySingleSelect) { + #ifdef BLOCK_MULTI_SELECT_SUPPORT + cgiDropDownWithTextValsAndExtra(buf, mdbVarLabels, mdbVars,count,mdbVar[i],"class='mdbVar noMulti' style='font-size:.9em;' onchange='findTracksMdbVarChanged(this);'"); safef(buf, sizeof(buf), "%s%i", METADATA_VALUE_PREFIX, i + 1); - hPrintf("</td><td align='right' id='isLike%d' style='width:10px;'>is</td><td nowrap id='%s' style='max-width:600px;'>\n",i + 1,buf); + #endif///ndef BLOCK_MULTI_SELECT_SUPPORT + hPrintf("</td>\n<td align='right' id='isLike%i' style='width:10px; white-space:nowrap;'>is</td>\n<td nowrap id='%s' style='max-width:600px;'>\n",i + 1,buf); len = getTermArray(conn, &labels, &terms, mdbVar[i]); - #ifdef PLUS_MINUS_BUTTON - cgiMakeDropListFull(buf, labels, terms, len, mdbVal[i], "class='mdbVal single' style='min-width:200px; font-size:.9em;' onchange='findTracksMdbValChanged(this);'"); - #else///ifndef PLUS_MINUS_BUTTON - cgiMakeDropListFull(buf, labels, terms, len, mdbVal[i], "class='mdbVal single' style='min-width:200px; font-size:.9em;' onchange='findTracksSearchButtonsEnable(true);'"); - #endif//ndef PLUS_MINUS_BUTTON + cgiMakeDropListFull(buf, labels, terms, len, mdbVal[i], "class='mdbVal' style='min-width:200px; font-size:.9em;' onchange='findTracksMdbValChanged(this);'"); } else if (searchBy == cvsSearchByFreeText) { + #ifdef BLOCK_MULTI_SELECT_SUPPORT + cgiDropDownWithTextValsAndExtra(buf, mdbVarLabels, mdbVars,count,mdbVar[i],"class='mdbVar noMulti' style='font-size:.9em;' onchange='findTracksMdbVarChanged(this);'"); safef(buf, sizeof(buf), "%s%i", METADATA_VALUE_PREFIX, i + 1); - hPrintf("</td><td align='right' id='isLike%d' style='width:10px;'>contains</td><td nowrap id='%s' style='max-width:600px;'>\n",i + 1,buf); - hPrintf("<input type='text' name='%s' value='%s' class='mdbVal freeText' onkeyup='findTracksSearchButtonsEnable(true);' style='max-width:310px; width:310px; font-size:.9em;'>", + #endif///ndef BLOCK_MULTI_SELECT_SUPPORT + hPrintf("</td><td align='right' id='isLike%i' style='width:10px; white-space:nowrap;'>contains</td>\n<td nowrap id='%s' style='max-width:600px;'>\n",i + 1,buf); + hPrintf("<input type='text' name='%s' value='%s' class='mdbVal freeText' style='max-width:310px; width:310px; font-size:.9em;' onchange='findTracksMdbVarChanged(true);'>\n", buf,(mdbVal[i] ? mdbVal[i]: "")); } else if (searchBy == cvsSearchByDateRange || searchBy == cvsSearchByIntegerRange) { // TO BE IMPLEMENTED } - hPrintf("<span id='helpLink%d'>help</span></td>\n", i + 1); + hPrintf("<span id='helpLink%i'> </span></td>\n", i + 1); hPrintf("</tr>\n"); } hPrintf("<tr><td colspan='%d' align='right' style='height:10px; max-height:10px;'> </td></tr>", cols); //hPrintf("<tr><td colspan='%d' align='right' class='lineOnTop' style='height:20px; max-height:20px;'> </td></tr>", cols); return numMetadataSelects; } static struct slRef *simpleSearchForTracksstruct(struct trix *trix,char **descWords,int descWordCount) // Performs the simple search and returns the found tracks. { struct slRef *tracks = NULL; struct trixSearchResult *tsList; @@ -835,30 +862,39 @@ "<li>Look and feel of found track list (here) and composite subtrack list (hgTrackUi) should converge. Jim suggests look and feel of hgTracks 'Configure Tracks...' list instead.</li>" "<li>Drop-down list of terms (cells, antibodies, etc.) should be multi-select with checkBoxes as seen in filterComposites. Perhaps saved for v2.0.</li>" "</ul></p>\n"); } #endif///def OMIT hPrintf("</div>"); // This div allows the clear button to empty it } void doSearchTracks(struct group *groupList) { if (!advancedJavascriptFeaturesEnabled(cart)) { warn("Requires advanced javascript features."); return; } + +#ifndef BLOCK_MULTI_SELECT_SUPPORT +webIncludeResourceFile("ui.dropdownchecklist.css"); +//jsIncludeFile("ui.core.js",NULL); // NOTE: This appears to be not needed as long as jquery-ui.js comes before ui.dropdownchecklist.js +jsIncludeFile("ui.dropdownchecklist.js",NULL); +// This line is needed to get the multi-selects initialized +hPrintf("<script type='text/javascript'>$(document).ready(function() { $('.filterBy').each( function(i) { $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: true });});});</script>\n"); +#endif///ndef BLOCK_MULTI_SELECT_SUPPORT + struct group *group; char *groups[128]; char *labels[128]; int numGroups = 1; groups[0] = ANYLABEL; labels[0] = ANYLABEL; char *nameSearch = cartOptionalString(cart, TRACK_SEARCH_ON_NAME); char *typeSearch = cartOptionalString(cart, TRACK_SEARCH_ON_TYPE); #ifdef FILES_SEARCH char *fileTypeSearch = cartOptionalString(cart, TRACK_SEARCH_ON_FILETYPE); #endif///def FILES_SEARCH char *descSearch=FALSE; char *groupSearch = cartOptionalString(cart, TRACK_SEARCH_ON_GROUP); boolean doSearch = sameString(cartOptionalString(cart, TRACK_SEARCH), "Search") || cartUsualInt(cart, TRACK_SEARCH_PAGER, -1) >= 0; struct sqlConnection *conn = hAllocConn(database);