a66704e3ade50461e9be68288199903410f4f31e
braney
  Fri Oct 11 12:36:01 2019 -0700
remove EXTRA_FIELDS support which was a failed experiment, support "."
syntax with FILTER_TEXT, suppress automatic filter if text filter is
set.

diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index f1edce5..f053484 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -3626,31 +3626,30 @@
             strSwapChar(chipper,'_',' '); // Title does not have underscores
             }
         else if (filterBy->valueAndLabel)
             errAbort("filterBy values either all have labels in form of value|label "
                      "or none do.");
         }
     }
 }
 
 char *extractFieldName(char *cartVariable, char *filterType)
 /* Extract field name from a filter cart variable.  Variables can either be
  * <columnName>Filter* or <columnName>.Filter* */
 {
 char *field = cloneString(cartVariable);
 int ix = strlen(field) - strlen(filterType); 
-assert(ix > 1);
 field[ix] = '\0';
 if (field[ix - 1] == '.')
     field[ix - 1] = '\0';
 
 return field;
 }
 
 filterBy_t *buildFilterBy(struct trackDb *tdb, struct cart *cart, struct asObject *as, char *filterName, char *name)
 /* Build a filterBy_t structure from a <column>FilterValues statement. */
 {
 char *field = extractFieldName(filterName, FILTER_VALUES_NAME);
 char *setting = trackDbSetting(tdb, filterName);
 if (isEmpty(setting))
     errAbort("FilterValues setting of field '%s' must have a value.", field);
 
@@ -3979,31 +3978,37 @@
 
 
 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, FILTERBY_MULTIPLE_LIST_AND);
+    char *setting = cartOrTdbString(cart, tdb, settingString, NULL);
+    if (setting == NULL)
+        {
+        safef(settingString, sizeof settingString, "%s.%s", filterBy->column, FILTER_TYPE_NAME);
+        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 && tdbIsBigBed(tdb))
@@ -5945,97 +5950,73 @@
     }
 return FALSE;
 }
 
 
 static int numericFiltersShowAll(char *db, struct cart *cart, struct trackDb *tdb, boolean *opened,
                                  boolean boxed, boolean parentLevel,char *name, char *title)
 // Shows all *Filter style filters.  Note that these are in random order and have no graceful title
 {
 int count = 0;
 struct slName *filterSettings = trackDbSettingsWildMatch(tdb, FILTER_NUMBER_WILDCARD);
 if (filterSettings)
     {
     puts("<BR>");
     struct slName *filter = NULL;
-#ifdef EXTRA_FIELDS_SUPPORT
-    struct extraField *extras = extraFieldsGet(db,tdb);
-#else///ifndef EXTRA_FIELDS_SUPPORT
     struct sqlConnection *conn = NULL;
     if (!isHubTrack(db))
         conn = hAllocConnTrack(db, tdb);
     struct asObject *as = asForTdb(conn, tdb);
     hFreeConn(&conn);
-#endif///ndef EXTRA_FIELDS_SUPPORT
 
     while ((filter = slPopHead(&filterSettings)) != NULL)
         {
         if (differentString(filter->name,NO_SCORE_FILTER))
             {
             // Determine floating point or integer
             char *setting = trackDbSetting(tdb, filter->name);
             boolean isFloat = (strchr(setting,'.') != NULL);
 
             char *scoreName = cloneString(filter->name);
             char *field = extractFieldName(filter->name, FILTER_NUMBER_NAME);
 
-        #ifdef EXTRA_FIELDS_SUPPORT
-            if (extras != NULL)
-                {
-                struct extraField *extra = extraFieldsFind(extras, field);
-                if (extra != NULL)
-                    { // Found label so replace field
-                    field = extra->label;
-                    if (!isFloat)
-                        isFloat = (extra->type == ftFloat);
-                    }
-                }
-        #else///ifndef EXTRA_FIELDS_SUPPORT
             if (as != NULL)
                 {
                 struct asColumn *asCol = asColumnFind(as, field);
                 if (asCol != NULL)
                     { // Found label so replace field
                     field = asCol->comment;
                     if (!isFloat)
                         isFloat = asTypesIsFloating(asCol->lowType->type);
                     }
                 else 
                     errAbort("Building filter on field %s which is not in AS file.", field);
                 }
-        #endif///ndef EXTRA_FIELDS_SUPPORT
-            // FIXME: Label munging should be localized to showScoreFilter()
-            //  when that function is simplified
             char varName[256];
             char label[128];
             safef(varName, sizeof(varName), "%s%s", scoreName, _BY_RANGE);
             boolean filterByRange = trackDbSettingClosestToHomeOn(tdb, varName);
             safef(label, sizeof(label),"%s%s", filterByRange ? "": "Minimum ", field);
 
             showScoreFilter(cart,tdb,opened,boxed,parentLevel,name,title,label,scoreName,isFloat);
             freeMem(scoreName);
             count++;
             }
         slNameFree(&filter);
         }
-#ifdef EXTRA_FIELDS_SUPPORT
-    if (extras != NULL)
-        extraFieldsFree(&extras);
-#else///ifndef EXTRA_FIELDS_SUPPORT
     if (as != NULL)
         asObjectFree(&as);
-#endif///ndef EXTRA_FIELDS_SUPPORT
     }
 if (count > 0)
     puts("</TABLE>");
 return count;
 }
 
 
 boolean bedScoreHasCfgUi(struct trackDb *tdb)
 // Confirms that this track has a bedScore Cfg UI
 {
 // Assumes that cfgType == cfgBedScore
 if (trackDbSettingClosestToHome(tdb, FILTER_BY))
     return TRUE;
 if (trackDbSettingClosestToHome(tdb, GRAY_LEVEL_SCORE_MIN))
     return TRUE;
@@ -6057,83 +6038,93 @@
             one = TRUE;
             break;
             }
         }
     slNameFreeList(&filterSettings);
     if (one)
         return TRUE;
     }
 if (!blocked)  // scoreFilter is implicit unless NO_SCORE_FILTER
     return TRUE;
 
 return FALSE;
 }
 
 
-void textFiltersShowAll(char *db, struct cart *cart, struct trackDb *tdb)
+static int textFiltersShowAll(char *db, struct cart *cart, struct trackDb *tdb)
 /* Show all the text filters for this track. */
 {
+int count = 0;
 struct slName *filter, *filterSettings = trackDbSettingsWildMatch(tdb, FILTER_TEXT_WILDCARD);
 if (filterSettings)
     {
     struct sqlConnection *conn = NULL;
     if (!isHubTrack(db))
         conn = hAllocConnTrack(db, tdb);
     while ((filter = slPopHead(&filterSettings)) != NULL)
         {
         char *setting = trackDbSetting(tdb, filter->name);
         char *value = cartUsualStringClosestToHome(cart, tdb, FALSE, filter->name, setting);
         char *field = extractFieldName(filter->name, FILTER_TEXT_NAME);
         struct asObject *as = asForTdb(conn, tdb);
         struct asColumn *asCol = asColumnFind(as, field);
         if (asCol == NULL)
             errAbort("Building filter on field %s which is not in AS file.", field);
 
+        count++;
         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);
+        if (setting == NULL)
+            {
+            safef(settingString, sizeof settingString, "%s.%s", field, FILTER_TYPE_NAME);
             setting = cartOrTdbString(cart, tdb, settingString, FILTERTEXT_WILDCARD);
+            }
         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>");
         }
     }
+
+return count;
 }
 
 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)
     skipScoreFilter = TRUE;
 
-textFiltersShowAll(db, cart, tdb);
+if (textFiltersShowAll(db, cart, tdb))
+    skipScoreFilter = TRUE;
 
 // Add any multi-selects next
 filterBy_t *filterBySet = filterBySetGet(tdb,cart,name);
 if (filterBySet != NULL)
     {
     if (!tdbIsComposite(tdb) && cartOptionalString(cart, "ajax") == NULL)
         jsIncludeFile("hui.js",NULL);
 
     if (!isBoxOpened)   // Note filterBy boxes are not double "boxed",
         printf("<BR>"); // if there are no other filters
     filterBySetCfgUi(cart,tdb,filterBySet,TRUE, name);
     filterBySetFree(&filterBySet);
     skipScoreFilter = TRUE;
     }
 
@@ -8936,137 +8927,30 @@
 if (tableName)
     {
     char *date = firstWordInLine(sqlTableUpdate(conn, tableName));
     if (date != NULL)
 	printf("<B>Data last updated:&nbsp;</B>%s<BR>\n", date);
     }
 hFreeConn(&conn);
 }
 
 void printBbiUpdateTime(time_t *timep)
 /* for bbi files, print out the timep value */
 {
     printf("<B>Data last updated:&nbsp;</B>%s<BR>\n", sqlUnixTimeToDate(timep, FALSE));
 }
 
-#ifdef EXTRA_FIELDS_SUPPORT
-static struct extraField *asFieldsGet(char *db, struct trackDb *tdb)
-// returns the as style fields from a table or remote data file
-{
-struct extraField *asFields = NULL;
-struct sqlConnection *conn = hAllocConnTrack(db, tdb);
-struct asObject *as = asForTdb(conn, tdb);
-hFreeConn(&conn);
-if (as != NULL)
-    {
-    struct asColumn *asCol = as->columnList;
-    for (;asCol != NULL; asCol = asCol->next)
-        {
-        struct extraField *asField  = NULL;
-        AllocVar(asField);
-        asField->name = cloneString(asCol->name);
-        if (asCol->comment != NULL && strlen(asCol->comment) > 0)
-            asField->label = cloneString(asCol->comment);
-        else
-            asField->label = cloneString(asField->name);
-        asField->type = ftString; // default
-        if (asTypesIsInt(asCol->lowType->type))
-            asField->type = ftInteger;
-        else if (asTypesIsFloating(asCol->lowType->type))
-            asField->type = ftFloat;
-        slAddHead(&asFields,asField);
-        }
-    if (asFields != NULL)
-        slReverse(&asFields);
-    asObjectFree(&as);
-    }
-return asFields;
-}
-
-struct extraField *extraFieldsGet(char *db, struct trackDb *tdb)
-// returns any extraFields defined in trackDb
-{
-char *fields = trackDbSetting(tdb, "extraFields"); // showFileds pValue=P_Value qValue=qValue
-if (fields == NULL)
-    return asFieldsGet(db, tdb);
-
-char *field = NULL;
-struct extraField *extras = NULL;
-struct extraField *extra = NULL;
-while (NULL != (field  = cloneNextWord(&fields)))
-    {
-    AllocVar(extra);
-    extra->name = field;
-    extra->label = field; // defaults to name
-    char *equal = strchr(field,'=');
-    if (equal != NULL)
-        {
-        *equal = '\0';
-        extra->label = equal + 1;
-        assert(*(extra->label)!='\0');
-        }
-
-    extra->type = ftString;
-    if (*(extra->label) == '[')
-        {
-        if (startsWith("[i",extra->label))
-            extra->type = ftInteger;
-        else if (startsWith("[f",extra->label))
-            extra->type = ftFloat;
-        extra->label = strchr(extra->label,']');
-        assert(extra->label != NULL);
-        extra->label += 1;
-        }
-    // clone independently of 'field' and swap in blanks
-    extra->label = cloneString(strSwapChar(extra->label,'_',' '));
-    slAddHead(&extras,extra);
-    }
-
-if (extras != NULL)
-    slReverse(&extras);
-return extras;
-}
-
-struct extraField *extraFieldsFind(struct extraField *extras, char *name)
-// returns the extraField matching the name (case insensitive).  Note: slNameFind does NOT work.
-{
-struct extraField *extra = extras;
-for (; extra != NULL; extra = extra->next)
-    {
-    if (sameWord(name, extra->name))
-        break;
-    }
-return extra;
-}
-
-void extraFieldsFree(struct extraField **pExtras)
-// frees all mem for extraFields list
-{
-if (pExtras != NULL)
-    {
-    struct extraField *extra = NULL;
-    while (NULL != (extra  = slPopHead(pExtras)))
-        {
-        freeMem(extra->name);
-        freeMem(extra->label);
-        freeMem(extra);
-        }
-    *pExtras = NULL;
-    }
-}
-#endif///def EXTRA_FIELDS_SUPPORT
-
 static boolean tableDescriptionsExists(struct sqlConnection *conn)
 /* Cache flag for whether tableDescriptions exists in conn, in case we will need to
  * fetch a lot of descriptions from tableDescriptions. */
 {
 static struct hash *hash = NULL;
 if (hash == NULL)
     hash = hashNew(0);
 char *db = sqlGetDatabase(conn);
 int exists =  hashIntValDefault(hash, db, -1);
 if (exists < 0)
     {
     exists = sqlTableExists(conn, "tableDescriptions");
     hashAddInt(hash, db, exists);
     }
 return (boolean)exists;