6f07cab7fdf96c16066566d551fc310d0d8afb52
max
  Tue Mar 1 13:36:13 2016 -0800
for patents track, refs #14486:
- two additional trackDb statements to remove or separate extra fields
of bigBed files in track hubs
- changes to hgc to format extra fields as a table, looks somewhat
nicer
- two scripts to reformat patent tables to bigBed files

diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c
index 9325cf9..e95dc54 100644
--- src/hg/hgc/hgc.c
+++ src/hg/hgc/hgc.c
@@ -932,55 +932,50 @@
  * return itemName. */
 {
 char *sql = trackDbSetting(tdb, "idInUrlSql");
 char *id = itemName;
 if (sql != NULL)
     {
     char query[1024];
     sqlSafef(query, sizeof(query), sql, itemName);
     struct sqlConnection *conn = hAllocConn(database);
     id = sqlQuickString(conn, query);
     hFreeConn(&conn);
     }
 return id;
 }
 
-char* constructUrl(struct trackDb *tdb, char *urlSetting, char *idInUrl, boolean encode) 
+char* getUrlSetting(struct trackDb *tdb, char* urlSetting)
+/* get the "url" setting for the current track */
 {
-/* construct the url by replacing $$, etc in the url given by urlSetting.
- * Replace $$ with itemName.  */
-
-// check the url setting prefix and get the correct url setting from trackDb 
 char *url;
 if (sameWord(urlSetting, "url"))
     url = tdb->url;
 else
     url = trackDbSetting(tdb, urlSetting);
-
-if (url == NULL || url[0] == 0)
-    return NULL;
-
-char* eUrl = replaceInUrl(url, idInUrl, cart, database, seqName, winStart, winEnd, tdb->track, encode);
-return eUrl;
+return url;
 }
 
 void printIframe(struct trackDb *tdb, char *itemName)
 /* print an iframe with the URL specified in trackDb (iframeUrl), can have 
  * the standard codes in it (like $$ for itemName, etc)
  */
 {
-char* eUrl = constructUrl(tdb, "iframeUrl", itemName, FALSE);
+char *url = getUrlSetting(tdb, "iframeUrl");
+if (url==NULL)
+    return;
+char *eUrl = replaceInUrl(url, itemName, cart, database, seqName, winStart, winEnd, tdb->track, FALSE);
 if (eUrl==NULL)
     return;
 
 char *iframeOptions = trackDbSettingOrDefault(tdb, "iframeOptions", "width='100%%' height='1024'");
 // Resizing requires the hgcDetails pages to include a bit of javascript.
 //
 // Explanation how this works and why the javascript is needed:
 // http://stackoverflow.com/questions/153152/resizing-an-iframe-based-on-content
 // In short:
 // - iframes have a fixed size in html, resizing can only be done in javascript
 // - the iframed page cannot call the resize() function in the hgc html directly, as they have
 //   been loaded from different webservers
 // - one way around it is that the iframed page includes a helper page on our server and 
 //   send their size to the helper page (pages can call functions of included pages)
 // - the helper page then sends the size back to hgc (pages on the same server can
@@ -993,49 +988,64 @@
 { \
      document.getElementById('hgcIframe').height = parseInt(height)+10; \
 } \
 </script> \
  \
 <iframe id='hgcIframe' src='%s' %s></iframe> \
 <p>", eUrl, iframeOptions);
 }
 
 void printCustomUrlWithLabel(struct trackDb *tdb, char *itemName, char *itemLabel, char *urlSetting, boolean encode)
 /* Print custom URL specified in trackDb settings. */
 {
 char urlLabelSetting[32];
 
 // replace the $$ and other wildchards with the url given in tdb 
-char* eUrl = constructUrl(tdb, urlSetting, itemName, encode);
+char *url = getUrlSetting(tdb, "url");
+//char* eUrl = constructUrl(tdb, url, itemName, encode);
+if (url==NULL)
+    return;
+
+char* eUrl = replaceInUrl(url, itemName, cart, database, seqName, winStart, winEnd, tdb->track, encode);
 if (eUrl==NULL)
     return;
 
 /* create the url label setting for trackDb from the url
    setting prefix */
 safef(urlLabelSetting, sizeof(urlLabelSetting), "%sLabel", urlSetting);
-printf("<B>%s </B>",
-       trackDbSettingOrDefault(tdb, urlLabelSetting, "Outside Link:"));
+char *linkLabel = trackDbSettingOrDefault(tdb, urlLabelSetting, "Outside Link:");
+
+// if we got no item name from hgTracks or the item name does not appear in the URL
+// there is no need to show the item name at all
+if (isEmpty(itemName) || !stringIn("$$", url))
+    {
+    printf("<A TARGET=_blank HREF='%s'>%s</A><BR>",eUrl, linkLabel);
+    return;
+    }
+
+printf("<B>%s </B>",linkLabel);
+
 printf("<A HREF=\"%s\" target=_blank>", eUrl);
 
 if (sameWord(tdb->table, "npredGene"))
     {
     printf("%s (%s)</A><BR>\n", itemName, "NCBI MapView");
     }
 else
     {
     char *label = itemName;
-    if (isNotEmpty(itemLabel) && !sameString(itemName, itemLabel))
+    if (isNotEmpty(itemLabel) && sameString(itemName, itemLabel))
         label = itemLabel;
     printf("%s</A><BR>\n", label);
     }
 //freeMem(&eUrl); small memory leak
 }
 
 void printCustomUrl(struct trackDb *tdb, char *itemName, boolean encode)
 /* Wrapper to call printCustomUrlWithLabel using the url setting in trackDb */
 {
 char urlSetting[10];
 safef(urlSetting, sizeof(urlSetting), "url");
 
 printCustomUrlWithLabel(tdb, itemName, itemName, urlSetting, encode);
 }
 
@@ -1466,38 +1476,50 @@
     }
 
 // split the id into parts and print each part as a link
 struct slName *slIds = slNameListFromComma(idList);
 struct slName *itemId = NULL;
 
 // handle id->name mapping for multi-source items
 int nameCount;
 char **idNames = getIdNameMap(tdb, col, &nameCount);
 
 printf("<td>");
 for (itemId = slIds; itemId!=NULL; itemId = itemId->next) 
     {
     if (itemId != slIds)
         printf(", ");
-    char *itemName = itemId->name;
+    char *itemName = trimSpaces(itemId->name);
+
     if (idNames)
         {
         unsigned int id = sqlUnsigned(itemName);
         if (id < nameCount)
             itemName = idNames[sqlUnsigned(itemName)];
         }
-    char *idUrl = replaceInUrl(url, trimSpaces(itemName), cart, database, seqName, winStart, 
+
+    // a | character can optionally be used to separate the ID used for $$ from the name shown in the link (like in Wikimedia markup)
+    char *idForUrl = itemName;
+    if (strstr(itemName, "|"))
+        {
+        char *parts[2];
+	chopString(itemName, "|", parts, ArraySize(parts));
+        idForUrl = parts[0];
+        itemName = parts[1];
+        }
+
+    char *idUrl = replaceInUrl(url, idForUrl, cart, database, seqName, winStart, 
                     winEnd, tdb->track, TRUE);
     printf("<a href=\"%s\" target=\"_blank\">%s</a>", idUrl, itemName);
     } 
 printf("</td></tr>\n");
 freeMem(slIds);
 //freeMem(idNames);
 }
 
 int extraFieldsPrint(struct trackDb *tdb,struct sqlResult *sr,char **fields,int fieldCount)
 // Any extra bed or bigBed fields (defined in as and occurring after N in bed N + types.
 // sr may be null for bigBeds.
 // Returns number of extra fields actually printed.
 {
 struct sqlConnection *conn = NULL ;
 if (!trackHubDatabase(database))
@@ -1510,66 +1532,102 @@
 // We are trying to print extra fields so we need to figure out how many fields to skip
 int start = 0;
 char *type = cloneString(tdb->type);
 char *word = nextWord(&type);
 if (word && (sameWord(word,"bed") || sameWord(word,"bigBed") || sameWord(word,"bigGenePred")))
     {
     if (NULL != (word = nextWord(&type)))
         start = sqlUnsigned(word);
     else // custom beds and bigBeds may not have full type "begBed 9 +"
         start = max(0,slCount(as->columnList) - fieldCount);
     }
 int count = 0;
 struct asColumn *col = as->columnList;
 char *urlsStr = trackDbSetting(tdb, "urls");
 struct hash* fieldToUrl = hashFromString(urlsStr);
+boolean skipEmptyFields = trackDbSettingOn(tdb, "skipEmptyFields");
 
+// make list of fields to skip
+char *skipFieldsStr = trackDbSetting(tdb, "skipFields");
+struct slName *skipIds = NULL;
+if (skipFieldsStr)
+    skipIds = slNameListFromComma(skipFieldsStr);
+
+// make list of fields that are separated from other fields
+char *sepFieldsStr = trackDbSetting(tdb, "sepFields");
+struct slName *sepFields = NULL;
+if (sepFieldsStr)
+    sepFields = slNameListFromComma(sepFieldsStr);
+
+// iterate over fields, print as table rows
 for (;col != NULL && count < fieldCount;col=col->next)
     {
     if (start > 0)  // skip past already known fields
         {
         start--;
         continue;
         }
     int ix = count;
     if (sr != NULL)
         {
         ix = sqlFieldColumn(sr, col->name); // If sr provided, name must match sql columnn name!
         if (ix == -1 || ix > fieldCount)      // so extraField really just provides a label
             continue;
         }
 
-    // Print as table rows
+    char *fieldName = col->name;
+
     if (count == 0)
-        printf("<br><table>");
+        printf("<br><table class='bedExtraTbl'>");
+    
     count++;
-    printf("<tr><td><B>%s:</B></td>", col->comment);
+
+    // do not print a row if the fieldName from the .as file is in the "skipFields" list
+    if (skipIds && slNameInList(skipIds, fieldName))
+        continue;
+
+    // split this table to separate current row from the previous one, if the trackDb option is set
+    if (sepFields && slNameInList(sepFields, fieldName))
+        printf("</tr></table>\n<p>\n<table class='bedExtraTbl'>");
+
+    // skip this row if it's empty and "skipEmptyFields" option is set
+    if (skipEmptyFields && isEmpty(fields[ix]))
+        continue;
+
+    // field description
+    printf("<tr><td>%s</td>", col->comment); // bold style now in HGStyle.css
+
     if (col->isList || col->isArray || col->lowType->stringy || asTypesIsInt(col->lowType->type))
         printIdOrLinks(col, fieldToUrl, tdb, fields[ix]);
     else if (asTypesIsFloating(col->lowType->type))
         {
         double valDouble = strtod(fields[ix],NULL);
         if (errno == 0 && valDouble != 0)
             printf("<td>%g</td></tr>\n", valDouble);
         else
             printf("<td>%s</td></tr>\n", fields[ix]); // decided not to print error
         }
     else
         printf("<td>%s</td></tr>\n", fields[ix]);
     }
 asObjectFree(&as);
 freeMem(fieldToUrl);
+if (skipIds)
+    slFreeList(skipIds);
+if (sepFields)
+    slFreeList(sepFields);
+
 if (count > 0)
     printf("</table>\n");
 
 return count;
 }
 
 void genericBedClick(struct sqlConnection *conn, struct trackDb *tdb,
 		     char *item, int start, int bedSize)
 /* Handle click in generic BED track. */
 {
 char table[64];
 boolean hasBin;
 struct bed *bed;
 char query[512];
 struct sqlResult *sr;
@@ -3881,31 +3939,31 @@
     if (sameString(type, "maf") || sameString(type, "wigMaf") || sameString(type, "bigMaf") || sameString(type, "netAlign")
         || sameString(type, "encodePeak"))
         headerItem = NULL;
     else if ((  sameString(type, "narrowPeak")
              || sameString(type, "broadPeak")
              || sameString(type, "gappedPeak") )
          &&  headerItem
          &&  sameString(headerItem, ".") )
         headerItem = NULL;
     }
 
 /* Print header. */
 genericHeader(tdb, headerItem);
 
 itemForUrl = getIdInUrl(tdb, item);
-if (itemForUrl != NULL && itemForUrl[0] != 0)
+if (itemForUrl != NULL && trackDbSetting(tdb, "url"))
     {
     printCustomUrl(tdb, itemForUrl, item == itemForUrl);
     printIframe(tdb, itemForUrl);
     }
 
 if (plus != NULL)
     {
     fputs(plus, stdout);
     }
 
 if (container != NULL)
     {
     genericContainerClick(conn, container, tdb, item, itemForUrl);
     }
 else if (wordCount > 0)