0cb4c703bd9ff662207617fa0980092ac670aece
braney
  Tue Sep 4 16:52:03 2018 -0700
add wildcard filtering and fix-up single selection in filterValue settings refs #20227

diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index 8f6d815..7f29b6f 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -3953,64 +3953,71 @@
 	   "<TABLE cellpadding=3><TR valign='top'>\n",filterTypeTitle,FILTERBY_HELP_LINK);
 
 filterBy_t *filterBy = NULL;
 if (cartOptionalString(cart, "ajax") == NULL)
     {
     webIncludeResourceFile("ui.dropdownchecklist.css");
     jsIncludeFile("ui.dropdownchecklist.js",NULL);
     jsIncludeFile("ddcl.js",NULL);
     }
 
 int ix=0;
 for(filterBy = filterBySet;filterBy != NULL; filterBy = filterBy->next, ix++)
     {
     char settingString[4096];
     safef(settingString, sizeof settingString, "%s%s", filterBy->column, FILTER_TYPE_NAME);
-    char *setting = cartOrTdbString(cart, tdb, settingString, NULL);
-    boolean isMultiple = (setting != NULL) && (sameString(setting, FILTERBY_MULTIPLE) ||sameString(setting, FILTERBY_MULTIPLE_LIST_OR) ||sameString(setting, FILTERBY_MULTIPLE_LIST_AND));
+    char *setting = cartOrTdbString(cart, tdb, settingString, FILTERBY_MULTIPLE_LIST_AND);
+    boolean isMultiple = sameString(setting, FILTERBY_MULTIPLE) ||sameString(setting, FILTERBY_MULTIPLE_LIST_OR) ||sameString(setting, FILTERBY_MULTIPLE_LIST_AND);
    
     puts("<TD>");
     char selectStatement[4096];
     if (isMultiple)
         safef(selectStatement, sizeof selectStatement, " (select multiple items - %s)", FILTERBY_HELP_LINK);
     else
         selectStatement[0] = 0;
     if(count == 1)
 	printf("<B>%s by %s</B>%s",filterTypeTitle,filterBy->title,selectStatement);
     else
 	printf("<B>%s</B>",filterBy->title);
     printf("<BR>\n");
 
     if (isMultiple)
         {
         char cartSettingString[4096];
         safef(cartSettingString, sizeof cartSettingString, "%s.%s", tdb->track, settingString);
         printf("<b>Match if  ");
         cgiMakeRadioButton(cartSettingString, FILTERBY_MULTIPLE_LIST_AND, sameString(setting, FILTERBY_MULTIPLE_LIST_AND));
         printf(" all ");
         cgiMakeRadioButton(cartSettingString, FILTERBY_MULTIPLE_LIST_OR, sameString(setting, FILTERBY_MULTIPLE_LIST_OR));
         printf(" one or more match</b> ");
         }
     // TODO: columnCount (Number of filterBoxes per row) should be configurable through tdb setting
-    #define FILTER_BY_FORMAT "<SELECT id='%s%d' name='%s' %s style='display: none; font-size:.9em;' class='filterBy'><BR>\n"
-    printf(FILTER_BY_FORMAT,selectIdPrefix,ix,filterBy->htmlName, isMultiple ? "multiple" : "");
 
     // value is always "All", even if label is different, to simplify javascript code
+    if (isMultiple)
+        {
+        printf( "<SELECT id='%s%d' name='%s' multiple style='display: none; font-size:.9em;' class='filterBy'><BR>\n", selectIdPrefix,ix,filterBy->htmlName);
         printf("<OPTION%s value=\"All\">%s</OPTION>\n", (filterByAllChosen(filterBy)?" SELECTED":""), allLabel);
+        ix = 1;
+        }
+    else
+        {
+        printf( "<SELECT id='%s%d' name='%s' style='font-size:.9em;'<BR>\n", selectIdPrefix,ix,filterBy->htmlName);
+        ix = 0;
+        }
     struct slName *slValue;
 
-    int ix=1;
     for (slValue=filterBy->slValues;slValue!=NULL;slValue=slValue->next,ix++)
 	{
 	char varName[32];
 	char *label = NULL;
 	char *name = NULL;
 	if (filterBy->useIndex)
 	    {
 	    safef(varName, sizeof(varName), "%d",ix);
 	    name = varName;
 	    label = slValue->name;
 	    }
 	else
 	    {
 	    label = (filterBy->valueAndLabel ? slValue->name + strlen(slValue->name)+1
 					     : slValue->name);
@@ -5881,35 +5888,46 @@
 void textFiltersShowAll(char *db, struct cart *cart, struct trackDb *tdb)
 /* Show all the text filters for this track. */
 {
 struct slName *filter, *filterSettings = trackDbSettingsWildMatch(tdb, FILTER_TEXT_WILDCARD);
 if (filterSettings)
     {
     while ((filter = slPopHead(&filterSettings)) != NULL)
         {
         char *setting = trackDbSetting(tdb, filter->name);
         char *value = cartUsualStringClosestToHome(cart, tdb, FALSE, filter->name, setting);
         char *field = cloneString(filter->name);
         int ix = strlen(field) - strlen(FILTER_TEXT_NAME);
         assert(ix > 0);
         field[ix] = '\0';
 
-        printf("<P><B>Filter items by regular expression in '%s' field: ", field);
+        printf("<P><B>Filter items in '%s' field: ", field);
 
         char cgiVar[128];
         safef(cgiVar,sizeof(cgiVar),"%s.%s",tdb->track,filter->name);
         cgiMakeTextVar(cgiVar, value, 45);
+
+        char settingString[4096];
+        safef(settingString, sizeof settingString, "%s%s", field, FILTER_TYPE_NAME);
+        setting = cartOrTdbString(cart, tdb, settingString, NULL);
+        safef(cgiVar,sizeof(cgiVar),"%s.%s",tdb->track,settingString);
+        printf(" using ");
+        printf("<SELECT name='%s'> ", cgiVar);
+        printf("<OPTION %s>%s</OPTION>", sameString(setting, FILTERTEXT_WILDCARD) ? "SELECTED" : "",  FILTERTEXT_WILDCARD );
+        printf("<OPTION %s>%s</OPTION>", sameString(setting, FILTERTEXT_REGEXP) ? "SELECTED" : "",  FILTERTEXT_REGEXP );
+        printf("</SELECT>");
+        printf("</P>");
         }
     }
 }
 
 void scoreCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *name, char *title,
                 int maxScore, boolean boxed)
 // Put up UI for filtering bed track based on a score
 {
 char option[256];
 boolean parentLevel = isNameAtParentLevel(tdb,name);
 boolean skipScoreFilter = FALSE;
 
 // Numeric filters are first
 boolean isBoxOpened = FALSE;
 if (numericFiltersShowAll(db, cart, tdb, &isBoxOpened, boxed, parentLevel, name, title) > 0)