093cdb88859d6e144f97c121b9175f9e7ac98f07
chmalee
  Tue Sep 27 09:22:47 2022 -0700
Get $<fieldName> substitution supported in bigBarChart url link outs, refs #29954

diff --git src/hg/hgc/barChartClick.c src/hg/hgc/barChartClick.c
index 5fe5692..c6b809c 100644
--- src/hg/hgc/barChartClick.c
+++ src/hg/hgc/barChartClick.c
@@ -27,36 +27,45 @@
 #include "pipeline.h"
 #include "chromAlias.h"
 
 #define EXTRA_FIELDS_SIZE 256
 
 struct barChartItemData
 /* Measured value for a sample and the sample category at a locus.
  * Used for barChart track details (boxplot) */
     {
     struct barChartItemData *next;  /* Next in singly linked list. */
     char *sample;	/* Sample identifier */
     char *category;     /* Sample category (from barChartSample table  or barChartSampleUrl file) */
     double value;	/* Measured value (e.g. expression level) */
     };
 
-static struct barChartBed *getBarChartFromFile(struct trackDb *tdb, char *file, 
+struct barChartPlusRow
+/* Keep original row around for url processing */
+    {
+    struct barChartPlusRow *next;
+    struct barChartBed *barChart;
+    char **row;
+    };
+
+static struct barChartPlusRow *getBarChartFromFile(struct trackDb *tdb, char *file,
                                                 char *item, char *chrom, int start, int end,
                                                 struct asObject **retAs, char **extraFieldsRet,
                                                 int *extraFieldsCountRet)
 /* Retrieve barChart BED item from big file */
 {
+struct barChartPlusRow *ret = NULL;
 boolean hasOffsets = TRUE;
 struct bbiFile *bbi =  bigBedFileOpenAlias(file, chromAliasFindAliases);
 struct asObject *as = bigBedAsOrDefault(bbi);
 if (retAs != NULL)
     *retAs = as;
 hasOffsets = (
     asColumnFind(as, BARCHART_OFFSET_COLUMN) != NULL &&
     asColumnFind(as, BARCHART_LEN_COLUMN) != NULL);
 struct lm *lm = lmInit(0);
 struct bigBedInterval *bb, *bbList =  bigBedIntervalQuery(bbi, chrom, start, end, 0, lm);
 for (bb = bbList; bb != NULL; bb = bb->next)
     {
     char *rest = cloneString(bb->rest);
     char startBuf[16], endBuf[16];
     char *row[32];
@@ -64,80 +73,87 @@
     struct barChartBed *barChart = barChartBedLoadOptionalOffsets(row, hasOffsets);
     if (barChart == NULL)
         continue;
     if (sameString(barChart->name, item))
         {
         char *restFields[EXTRA_FIELDS_SIZE];
         int restCount = chopTabs(rest, restFields);
         int restBedFields = (6 + (hasOffsets ? 2 : 0));
         if (restCount > restBedFields)
             {
             int i;
             for (i = 0; i < restCount - restBedFields; i++)
                 extraFieldsRet[i] = restFields[restBedFields + i];
             *extraFieldsCountRet = (restCount - restBedFields);
             }
-        return barChart;
+        AllocVar(ret);
+        ret->barChart = barChart;
+        ret->row = row;
+        return ret;
         }
     }
 return NULL;
 }
 
-static struct barChartBed *getBarChartFromTable(struct trackDb *tdb, char *table, 
+static struct barChartPlusRow *getBarChartFromTable(struct trackDb *tdb, char *table,
                                                 char *item, char *chrom, int start, int end)
 /* Retrieve barChart BED item from track table */
 {
+struct barChartPlusRow *ret = NULL;
 struct sqlConnection *conn = NULL;
 struct customTrack *ct = lookupCt(tdb->track);
 if (ct == NULL)
     conn = hAllocConnTrack(database, tdb);
 else
     {
     conn = hAllocConn(CUSTOM_TRASH);
     table = ct->dbTableName;
     }
 if (conn == NULL)
     return NULL;
 struct barChartBed *barChart = NULL;
 char **row;
 char query[512];
 struct sqlResult *sr;
 if (sqlTableExists(conn, table))
     {
     boolean hasOffsets = (sqlColumnExists(conn, table, BARCHART_OFFSET_COLUMN) &&
                          sqlColumnExists(conn, table, BARCHART_LEN_COLUMN));
     sqlSafef(query, sizeof query,
                 "SELECT * FROM %s WHERE name='%s'"
                     "AND chrom='%s' AND chromStart=%d AND chromEnd=%d",
                                 table, item, chrom, start, end);
     sr = sqlGetResult(conn, query);
     row = sqlNextRow(sr);
     if (row != NULL)
         {
         barChart = barChartBedLoadOptionalOffsets(row, hasOffsets);
+        AllocVar(ret);
+        ret->barChart = barChart;
+        ret->row = row;
         }
     sqlFreeResult(&sr);
     }
 hFreeConn(&conn);
-return barChart;
+return ret;
 }
 
-static struct barChartBed *getBarChart(struct trackDb *tdb, char *item, char *chrom, int start, int end,
+static struct barChartPlusRow *getBarChart(struct trackDb *tdb, char *item, char *chrom, int start, int end,
                                         struct asObject **retAs, char **extraFieldsReg, int *extraFieldsCountRet)
 /* Retrieve barChart BED item from track */
 {
-struct barChartBed *barChart = NULL;
+struct barChartPlusRow *barChart = NULL;
 char *file = hReplaceGbdb(trackDbSetting(tdb, "bigDataUrl"));
 if (file != NULL)
     barChart = getBarChartFromFile(tdb, file, item, chrom, start, end, retAs, extraFieldsReg, extraFieldsCountRet);
 else
     barChart = getBarChartFromTable(tdb, tdb->table, item, chrom, start, end);
 return barChart;
 }
 
 static struct barChartItemData *getSampleValsFromFile(struct trackDb *tdb,
                         struct hash *categoryHash, struct barChartBed *bed,
                         char *dataFile, char *sampleFile)
 /* Get all data values in a file for this item (locus) */
 {
 // Get sample categories from sample file
 // Format: id, category, extras
@@ -529,49 +545,52 @@
 struct asColumn *asCol;
 int i;
 for (i=0, asCol = as->columnList; asCol != NULL && i<ix; asCol = asCol->next, i++);
     return asCol;
 }
 
 void doBarChartDetails(struct trackDb *tdb, char *item)
 /* Details of barChart item */
 {
 int start = cartInt(cart, "o");
 int end = cartInt(cart, "t");
 struct asObject *as = NULL;
 char *extraFields[EXTRA_FIELDS_SIZE];
 int extraFieldCount = 0;
 int numColumns = 0;
-struct barChartBed *chartItem = getBarChart(tdb, item, seqName, start, end, &as, extraFields, &extraFieldCount);
+struct barChartPlusRow *bcRow = getBarChart(tdb, item, seqName, start, end, &as, extraFields, &extraFieldCount);
+struct barChartBed *chartItem = bcRow->barChart;
+char **row = bcRow->row;
 if (chartItem == NULL)
     errAbort("Can't find item %s in barChart table/file %s\n", item, tdb->table);
 
 genericHeader(tdb, item);
 
 // get name and name2 from trackDb, .as file, or use defaults
 struct asColumn *nameCol = NULL, *name2Col = NULL;
 //struct asColumn *name2Col;
 char *nameLabel = NULL, *name2Label = NULL;
 if (as != NULL)
     {
     numColumns = slCount(as->columnList);
     nameCol = asFindColByIx(as, BARCHART_NAME_COLUMN_IX);
     name2Col = asFindColByIx(as, BARCHART_NAME2_COLUMN_IX);
     }
 nameLabel = trackDbSettingClosestToHomeOrDefault(tdb, "bedNameLabel", nameCol ? nameCol->comment : "Item");
+struct slPair *fields = getFields(tdb, row);
 if (trackDbSettingClosestToHomeOrDefault(tdb, "url", NULL) != NULL)
-    printCustomUrl(tdb, item, TRUE);
+    printCustomUrlWithFields(tdb, item, nameLabel, TRUE, fields);
 else
     printf("<b>%s: </b>%s ", nameLabel, chartItem->name);
 name2Label = name2Col ? name2Col->comment : "Alternative name";
 if (differentString(chartItem->name2, ""))
     {
     if (trackDbSettingClosestToHomeOrDefault(tdb, "url2", NULL) != NULL)
         printOtherCustomUrl(tdb, chartItem->name2, "url2", TRUE);
     else
         printf("(%s: %s)<br>\n", name2Label, chartItem->name2);
     }
 else
     printf("<br>\n");
 
 int categId;
 float highLevel = barChartMaxValue(chartItem, &categId);