a53b9958fa734f73aeffb9ddfe2fbad1ca65f90c
galt
  Mon Jan 30 16:18:41 2017 -0800
Check-in of CSP2 Content-Security-Policy work. All C-language CGIs should now support CSP2 in browser to stop major forms of XSS javascript injection. Javascript on pages is gathered together, and then emitted in a single script block at the end with a nonce that tells the browser, this is js that we generated instead of being injected by a hacker. Both inline script from script blocks and inline js event handlers had to be pulled out and separated. You will not see js sprinkled through-out the page now. Older browsers that support CSP1 or that do not understand CSP at all will still work, just without protection. External js libraries loaded at runtime need to be added to the CSP policy header in src/lib/htmshell.c.

diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index 77ff269..2b37af1 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -42,42 +42,52 @@
 #include "pgSnp.h"
 #include "memgfx.h"
 #include "trackHub.h"
 #include "gtexUi.h"
 #include "genbank.h"
 #include "htmlPage.h"
 #include "longRange.h"
 #include "tagRepo.h"
 
 #define SMALLBUF 256
 #define MAX_SUBGROUP 9
 #define ADD_BUTTON_LABEL        "add"
 #define CLEAR_BUTTON_LABEL      "clear"
 #define JBUFSIZE 2048
 
-#define PM_BUTTON  "<IMG height=18 width=18 onclick=\"setCheckBoxesThatContain(" \
-                   "'%s',%s,true,'%s','','%s');\" id=\"btn_%s\" src=\"../images/%s\" alt=\"%s\">\n"
-#define DEF_BUTTON "<IMG onclick=\"setCheckBoxesThatContain('%s',true,false,'%s','','%s'); " \
-                   "setCheckBoxesThatContain('%s',false,false,'%s','_defOff','%s');\" " \
-                   "id=\"btn_%s\" src=\"../images/%s\" alt=\"%s\">\n"
+
+#define DEF_BUTTON "<IMG id=\"btn_%s\" src=\"../images/%s\" alt=\"%s\">\n"
+#define DEF_BUTTON_JS "setCheckBoxesThatContain('%s',true,false,'%s','','%s');" \
+	       "setCheckBoxesThatContain('%s',false,false,'%s','_defOff','%s');" 
 #define DEFAULT_BUTTON(nameOrId,anc,beg,contains) \
-        printf(DEF_BUTTON,(nameOrId),(beg),(contains),(nameOrId),(beg),(contains),(anc), \
-              "defaults_sm.png","default")
+    printf(DEF_BUTTON,(anc),"defaults_sm.png","default"); \
+    safef(id, sizeof id, "btn_%s", (anc)); \
+    safef(javascript, sizeof javascript, DEF_BUTTON_JS,(nameOrId),(beg),(contains),(nameOrId),(beg),(contains)); \
+    jsOnEventById("click", id, javascript);
+
+#define PM_BUTTON  "<IMG height=18 width=18 id=\"btn_%s\" src=\"../images/%s\" alt=\"%s\">\n"
+#define PM_BUTTON_JS  "setCheckBoxesThatContain('%s',%s,true,'%s','','%s');"
 #define PLUS_BUTTON(nameOrId,anc,beg,contains) \
-        printf(PM_BUTTON, (nameOrId),"true", (beg),(contains),(anc),"add_sm.gif",   "+")
+    printf(PM_BUTTON, (anc), "add_sm.gif",   "+"); \
+    safef(id, sizeof id, "btn_%s", (anc)); \
+    safef(javascript, sizeof javascript, PM_BUTTON_JS, (nameOrId),"true", (beg),(contains)); \
+    jsOnEventById("click", id, javascript);
 #define MINUS_BUTTON(nameOrId,anc,beg,contains) \
-        printf(PM_BUTTON, (nameOrId),"false",(beg),(contains),(anc),"remove_sm.gif","-")
+    printf(PM_BUTTON, (anc), "remove_sm.gif", "-"); \
+    safef(id, sizeof id, "btn_%s", (anc)); \
+    safef(javascript, sizeof javascript, PM_BUTTON_JS, (nameOrId),"false", (beg),(contains)); \
+    jsOnEventById("click", id, javascript);
 
 boolean isEncode2(char *database)
 // Return true for ENCODE2 assemblies
 {
 return (sameString(database, "hg18") || sameString(database, "hg19") || sameString(database, "mm9"));
 }
 
 static char *htmlStringForDownloadsLink(char *database, struct trackDb *tdb,
 				    char *name,boolean nameIsFile)
 // Returns an HTML string for a downloads link
 {
 // If has fileSortOrder, then link to new hgFileUi
 if (!nameIsFile && trackDbSetting(tdb, FILE_SORT_ORDER) != NULL)
 {
 char * link = needMem(PATH_LEN); // 512 should be enough
@@ -303,34 +313,39 @@
 return dyStringCannibalize(&dyTable);
 }
 
 boolean compositeMetadataToggle(char *db,struct trackDb *tdb,char *title,
     boolean embeddedInText,boolean showLongLabel)
 // If metadata from metaTbl exists, create a link that will allow toggling it's display
 {
 char *tagStormFile = trackDbSetting(tdb, "metaDb");
 if (tagStormFile == NULL)
     {
     const struct mdbObj *safeObj = metadataForTable(db,tdb,NULL);
     if (safeObj == NULL || safeObj->vars == NULL)
         return FALSE;
     }
 
-printf("%s<A HREF='#a_meta_%s' onclick='return metadataShowHide(\"%s\",%s,true);' "
+char id[256];
+safef(id, sizeof id, "div_%s_link", tdb->track);
+printf("%s<A id='%s' HREF='#a_meta_%s' "
    "title='Show metadata details...'>%s<img src='../images/downBlue.png'/></A>",
-       (embeddedInText?"&nbsp;":"<P>"),tdb->track,tdb->track, showLongLabel?"true":"false",
-       (title?title:""));
+   (embeddedInText?"&nbsp;":"<P>"),id,tdb->track, (title?title:""));
+char javascript[1024];
+safef(javascript, sizeof javascript, "return metadataShowHide(\"%s\",%s,true);", 
+    tdb->track, showLongLabel?"true":"false");
+jsOnEventById("click", id, javascript);
 printf("<DIV id='div_%s_meta' style='display:none;'>%s</div>",tdb->track, metadataAsHtmlTable(db,tdb,showLongLabel,FALSE));
 return TRUE;
 }
 
 void extraUiLinks(char *db,struct trackDb *tdb)
 // Show metadata, and downloads, schema links where appropriate
 {
 char *tagStormFile = trackDbSetting(tdb, "metaDb");
 boolean hasMetadata = (tagStormFile != NULL) || (!tdbIsComposite(tdb) && !trackHubDatabase(db)
                         && metadataForTable(db, tdb, NULL) != NULL);
 if (hasMetadata)
 printf("<b>Metadata:</b><br>%s\n", metadataAsHtmlTable(db, tdb, FALSE, FALSE));
 
 boolean schemaLink = (!tdbIsDownloadsOnly(tdb) && !trackHubDatabase(db)
 	      && isCustomTrack(tdb->table) == FALSE)
@@ -594,59 +609,59 @@
 // Given a string representation of track visibility, return as equivalent enum.
 {
 enum trackVisibility vis = hTvFromStringNoAbort(s);
 if ((int)vis < 0)
 errAbort("Unknown visibility %s", s);
 return vis;
 }
 
 char *hStringFromTv(enum trackVisibility vis)
 // Given enum representation convert to string.
 {
 return hTvStrings[vis];
 }
 
 void hTvDropDownClassWithJavascript(char *varName, enum trackVisibility vis, boolean canPack,
-                                    char *class,char * javascript)
+				char *class, struct slPair *events)
 // Make track visibility drop down for varName with style class
 {
 static char *noPack[] =
 {
 "hide",
 "dense",
 "full",
 };
 static char *pack[] =
 {
 "hide",
 "dense",
 "squish",
 "pack",
 "full",
 };
 static int packIx[] = {tvHide,tvDense,tvSquish,tvPack,tvFull};
 if (canPack)
 cgiMakeDropListClassWithStyleAndJavascript(varName, pack, ArraySize(pack),
 					   pack[packIx[vis]], class, TV_DROPDOWN_STYLE,
-                                               javascript);
+					   events);
 else
 cgiMakeDropListClassWithStyleAndJavascript(varName, noPack, ArraySize(noPack),
-                                               noPack[vis], class, TV_DROPDOWN_STYLE,javascript);
+					   noPack[vis], class, TV_DROPDOWN_STYLE, events);
 }
 
 void hTvDropDownClassVisOnlyAndExtra(char *varName, enum trackVisibility vis,
-                                     boolean canPack, char *class, char *visOnly,char *extra)
+				 boolean canPack, char *class, char *visOnly, struct slPair *events)
 // Make track visibility drop down for varName with style class, and potentially limited to visOnly
 {
 static char *denseOnly[] =
 {
 "hide",
 "dense",
 };
 static char *squishOnly[] =
 {
 "hide",
 "squish",
 };
 static char *packOnly[] =
 {
 "hide",
@@ -665,66 +680,66 @@
 };
 static char *pack[] =
 {
 "hide",
 "dense",
 "squish",
 "pack",
 "full",
 };
 static int packIx[] = {tvHide,tvDense,tvSquish,tvPack,tvFull};
 if (visOnly != NULL)
 {
 int visIx = (vis > 0) ? 1 : 0;
 if (sameWord(visOnly,"dense"))
     cgiMakeDropListClassWithStyleAndJavascript(varName, denseOnly, ArraySize(denseOnly),
-                                                   denseOnly[visIx],class,TV_DROPDOWN_STYLE,extra);
+					       denseOnly[visIx],class,TV_DROPDOWN_STYLE, events);
 else if (sameWord(visOnly,"squish"))
     cgiMakeDropListClassWithStyleAndJavascript(varName, squishOnly,
 					       ArraySize(squishOnly), squishOnly[visIx],
-                                                   class, TV_DROPDOWN_STYLE,extra);
+					       class, TV_DROPDOWN_STYLE, events);
 else if (sameWord(visOnly,"pack"))
     cgiMakeDropListClassWithStyleAndJavascript(varName, packOnly, ArraySize(packOnly),
-                                                   packOnly[visIx],class,TV_DROPDOWN_STYLE,extra);
+					       packOnly[visIx], class, TV_DROPDOWN_STYLE, events);
 else if (sameWord(visOnly,"full"))
     cgiMakeDropListClassWithStyleAndJavascript(varName, fullOnly, ArraySize(fullOnly),
-                                                   fullOnly[visIx],class,TV_DROPDOWN_STYLE,extra);
+					       fullOnly[visIx], class, TV_DROPDOWN_STYLE, events);
 else                        /* default when not recognized */
     cgiMakeDropListClassWithStyleAndJavascript(varName, denseOnly, ArraySize(denseOnly),
-                                                   denseOnly[visIx],class,TV_DROPDOWN_STYLE,extra);
+					       denseOnly[visIx], class, TV_DROPDOWN_STYLE, events);
 }
 else
 {
 if (canPack)
     cgiMakeDropListClassWithStyleAndJavascript(varName, pack, ArraySize(pack),
-                                                   pack[packIx[vis]],class,TV_DROPDOWN_STYLE,extra);
+					       pack[packIx[vis]], class, TV_DROPDOWN_STYLE, events);
 else
     cgiMakeDropListClassWithStyleAndJavascript(varName, noPack, ArraySize(noPack),
-                                                   noPack[vis], class, TV_DROPDOWN_STYLE,extra);
+					       noPack[vis], class, TV_DROPDOWN_STYLE, events);
 }
 }
 
-void hideShowDropDownWithClassAndExtra(char *varName, boolean show, char *class, char *extra)
+void hideShowDropDownWithClassAndExtra(char *varName, boolean show, char *class, struct slPair *events)
 // Make hide/show dropdown for varName
 {
 static char *hideShow[] =
 {
 "hide",
 "show"
 };
 cgiMakeDropListClassWithStyleAndJavascript(varName, hideShow, ArraySize(hideShow),
-                                           hideShow[show], class, TV_DROPDOWN_STYLE,extra);
+				       hideShow[show], class, TV_DROPDOWN_STYLE, events);
 }
 
 
 /****** Some stuff for stsMap related controls *******/
 
 static char *stsMapOptions[] = {
 "All Genetic",
 "Genethon",
 "Marshfield",
 "deCODE",
 "GeneMap 99",
 "Whitehead YAC",
 "Whitehead RH",
 "Stanford TNG",
 };
@@ -1122,60 +1137,60 @@
 static void baseColorDropLists(struct cart *cart, struct trackDb *tdb, char *name)
 /* draw the baseColor drop list options */
 {
 enum baseColorDrawOpt curOpt = baseColorDrawOptEnabled(cart, tdb);
 char *curValue = baseColorDrawAllOptionValues[curOpt];
 char var[512];
 safef(var, sizeof(var), "%s." BASE_COLOR_VAR_SUFFIX, name);
 boolean gotCds = baseColorGotCds(tdb);
 boolean gotSeq = baseColorGotSequence(tdb);
 if (gotCds && gotSeq)
 {
 puts("<P><B>Color track by codons or bases:</B>");
 cgiMakeDropListFull(var, baseColorDrawAllOptionLabels,
 		    baseColorDrawAllOptionValues,
 		    ArraySize(baseColorDrawAllOptionLabels),
-			curValue, NULL);
+		    curValue, NULL, NULL);
 printf("<A HREF=\"%s\">Help on mRNA coloring</A><BR>",
        CDS_MRNA_HELP_PAGE);
 }
 else if (gotCds)
     {
     char buf[256];
     char *disabled = NULL;
     safef(buf, sizeof(buf), "onchange='codonColoringChanged(\"%s\")'", name);
     puts("<P><B>Color track by codons:</B>");
     cgiMakeDropListFull(var, baseColorDrawGenomicOptionLabels,
 			baseColorDrawGenomicOptionValues,
 			ArraySize(baseColorDrawGenomicOptionLabels),
-			curValue, buf);
+			curValue, "change", buf);
     printf("<A HREF=\"%s\">Help on codon coloring</A><BR>",
 	   CDS_HELP_PAGE);
     safef(buf, sizeof(buf), "%s.%s", name, CODON_NUMBERING_SUFFIX);
     if (curOpt == baseColorDrawOff)
         disabled = "disabled";
     printf("<br /><b><span id='%sCodonNumberingLabel' %s>Show codon numbering</b>:</span>\n", 
                 name, curOpt == baseColorDrawOff ? "class='disabled'" : "");
     cgiMakeCheckBoxJS(buf, cartUsualBooleanClosestToHome(cart, tdb, FALSE, CODON_NUMBERING_SUFFIX, TRUE), disabled);
     }
 else if (gotSeq)
     {
     puts("<P><B>Color track by bases:</B>");
     cgiMakeDropListFull(var, baseColorDrawItemOptionLabels,
 			baseColorDrawItemOptionValues,
 			ArraySize(baseColorDrawItemOptionLabels),
-			curValue, NULL);
+			curValue, NULL, NULL);
     printf("<A HREF=\"%s\">Help on base coloring</A><BR>",
 	   CDS_BASE_HELP_PAGE);
     }
 }
 
 void baseColorDrawOptDropDown(struct cart *cart, struct trackDb *tdb)
 /* Make appropriately labeled drop down of options if any are applicable.*/
 {
 baseColorDropLists(cart, tdb, tdb->track);
 }
 
 enum baseColorDrawOpt baseColorDrawOptEnabled(struct cart *cart,
 					  struct trackDb *tdb)
 /* Query cart & trackDb to determine what drawing mode (if any) is enabled. */
 {
@@ -1701,57 +1716,57 @@
 }
 
 enum wiggleAggregateFunctionEnum wiggleAggregateFunctionStringToEnum(char *string)
 /* Convert from string to enum representation. */
 {
 int x = stringIx(string, aggregateValues);
 if (x < 0)
 errAbort("hui::wiggleAggregateFunctionStringToEnum() - Unknown option %s", string);
 return x;
 }
 
 void aggregateDropDown(char *var, char *curVal)
 /* Make drop down menu for aggregate strategy */
 {
 cgiMakeDropListFull(var, aggregateLabels, aggregateValues,
-	ArraySize(aggregateValues), curVal, NULL);
+    ArraySize(aggregateValues), curVal, NULL, NULL);
 }
 
 static char *wiggleTransformFuncOptions[] = {
 "NONE",
 "LOG"
 };
 
 static char *wiggleTransformFuncLabels[] = {
 "NONE",
 "LOG (ln(1+x))"
 };
 
 enum wiggleTransformFuncEnum wiggleTransformFuncToEnum(char *string)
 /* Convert from string to enum representation. */
 {
 int x = stringIx(string, wiggleTransformFuncOptions);
 if (x < 0)
 errAbort("hui::wiggleTransformFuncToEnum() - Unknown option %s", string);
 return x;
 }
 
 void wiggleTransformFuncDropDown(char *var, char *curVal)
 /* Make drop down of options. */
 {
 cgiMakeDropListFull(var, wiggleTransformFuncLabels, wiggleTransformFuncOptions,
-    ArraySize(wiggleTransformFuncOptions), curVal, NULL);
+ArraySize(wiggleTransformFuncOptions), curVal, NULL, NULL);
 }
 
 static char *wiggleAlwaysZeroOptions[] = {
 "OFF",
 "ON"
 };
 
 enum wiggleAlwaysZeroEnum wiggleAlwaysZeroToEnum(char *string)
 /* Convert from string to enum representation. */
 {
 int x = stringIx(string, wiggleAlwaysZeroOptions);
 if (x < 0)
 errAbort("hui::wiggleAlwaysZeroToEnum() - Unknown option %s", string);
 return x;
 }
@@ -1997,49 +2012,53 @@
 if (selectedName == NULL)
 selectedName = trackFindLabel(nameList, "Known Genes");
 if (selectedName == NULL)
 selectedName = trackFindLabel(nameList, "SGD Genes");
 if (selectedName == NULL)
 selectedName = trackFindLabel(nameList, "BDGP Genes");
 if (selectedName == NULL)
 selectedName = trackFindLabel(nameList, "WormBase Genes");
 if (selectedName == NULL)
 selectedName = trackFindLabel(nameList, "RefSeq Genes");
 if (selectedName == NULL)
 selectedName = nameList->name;
 
 /* Make drop-down list. */
 {
-    char javascript[SMALLBUF], *autoSubmit;
+char javascript[SMALLBUF], *autoSubmit, *event;
 int nameCount = slCount(nameList);
 char **menu;
 int i;
 
 AllocArray(menu, nameCount);
 for (name = nameList, i=0; name != NULL; name = name->next, ++i)
     {
     menu[i] = name->label;
     }
 if (formName == NULL)
+    {
     autoSubmit = NULL;
+    event = NULL;
+    }
 else
     {
     safef(javascript, sizeof(javascript),
-                "onchange=\"document.%s.submit();\"", formName);
+	    "document.%s.submit();", formName);
     autoSubmit = javascript;
+    event = "change"; 
     }
-    cgiMakeDropListFull(varName, menu, menu, nameCount, selectedName, autoSubmit);
+cgiMakeDropListFull(varName, menu, menu, nameCount, selectedName, event, autoSubmit);
 freez(&menu);
 }
 
 /* Convert to track name */
 for (name = nameList; name != NULL; name = name->next)
 {
 if (sameString(selectedName, name->label))
     trackName = name->name;
 }
 
 /* Clean up and return. */
 slFreeList(&nameList);
 slFreeList(&trackList);
 return trackName;
 }
@@ -4110,101 +4129,104 @@
 colspan++;
 int columnCount = 0;
 if (sortOrder != NULL)
 printf("<TR id=\"subtracksHeader\" class='sortable%s'>\n",
 	    useDragAndDrop ? " nodrop nodrag" : "");
 else
 {
 printf("<TR%s>", useDragAndDrop ? " id='noDrag' class='nodrop nodrag'" : "");
 // First table row contains the display "selected/visible" or "all" radio buttons
 // NOTE: list subtrack radio buttons are inside tracklist table header if
 //       there are no sort columns.  The reason is to ensure spacing of lines
 //       column headers when the only column header is "Restricted Until"
 printf("<TD colspan='%d'><B>List subtracks:&nbsp;", colspan);
 char javascript[JBUFSIZE];
 safef(javascript, sizeof(javascript),
-          "class='allOrOnly' onclick='showOrHideSelectedSubtracks(true);'");
+      "showOrHideSelectedSubtracks(true);");
 int subCount = slCount(subtrackRefList);
 if (subCount > LARGE_COMPOSITE_CUTOFF)
     safef(buffer,SMALLBUF,"%s.displaySubtracks",parentTdb->track);
 else
     safecpy(buffer,SMALLBUF,"displaySubtracks");
-    cgiMakeOnClickRadioButton(buffer, "selected", !settings->displayAll,javascript);
+cgiMakeOnEventRadioButtonWithClass(buffer, "selected", !settings->displayAll, "allOrOnly", "click", javascript);
+
 puts("only selected/visible &nbsp;&nbsp;");
 safef(javascript, sizeof(javascript),
-          "class='allOrOnly' onclick='showOrHideSelectedSubtracks(false);'");
-    cgiMakeOnClickRadioButton(buffer, "all", settings->displayAll,javascript);
+      "showOrHideSelectedSubtracks(false);");
+cgiMakeOnEventRadioButtonWithClass(buffer, "all", settings->displayAll, "allOrOnly", "click", javascript);
 printf("all</B>");
 if (subCount > 5)
     printf("&nbsp;&nbsp;&nbsp;&nbsp;(<span class='subCBcount'></span>)");
 puts("</TD>");
 columnCount = colspan;
 }
 
 // Add column headers which are sort button links
 if (sortOrder != NULL)
 {
 printf("<TH>&nbsp;<INPUT TYPE=HIDDEN NAME='%s' class='sortOrder' VALUE='%s'></TH>\n",
        sortOrder->htmlId, sortOrder->sortOrder); // keeing track of sortOrder
 columnCount++;
 if (!tdbIsMultiTrack(parentTdb))  // An extra column for subVis/wrench so dragAndDrop works
     {
     printf("<TH></TH>\n");
     columnCount++;
     }
 // Columns in tdb order (unchanging), sort in cart order (changed by user action)
 int sIx=0;
 for (sIx=0;sIx<sortOrder->count;sIx++)
     {
     if (sameString(SORT_ON_TRACK_NAME,sortOrder->column[sIx]))
 	break; // All wrangler requested sort orders have been done.
     if (sameString(SORT_ON_RESTRICTED,sortOrder->column[sIx]))
 	break; // All wrangler requested sort orders have been done.
-        printf("<TH id='%s' class='sortable%s sort%d' abbr='use' "
-               "onclick='tableSortAtButtonPress(this);'>%s", sortOrder->column[sIx],
+    printf("<TH id='%s' class='sortable%s sort%d' abbr='use'>%s", 
+	    sortOrder->column[sIx],
 	   (sortOrder->forward[sIx] ? "" : " sortRev"),sortOrder->order[sIx],
 	   sortOrder->title[sIx]);
+    jsOnEventById("click", sortOrder->column[sIx], "tableSortAtButtonPress(this);");
     printf("<sup>%s",(sortOrder->forward[sIx]?"&darr;":"&uarr;"));
     if (sortOrder->count > 1)
 	printf("%d",sortOrder->order[sIx]);
     printf("</sup>");
     puts("</TH>");
     columnCount++;
     }
 
 // longLabel column
 assert(sameString(SORT_ON_TRACK_NAME,sortOrder->column[sIx]));
-    printf("<TH id='%s' class='sortable%s sort%d' onclick='tableSortAtButtonPress(this);' "
-           "align='left'>&nbsp;&nbsp;Track Name",
+printf("<TH id='%s' class='sortable%s sort%d' align='left'>&nbsp;&nbsp;Track Name",
        sortOrder->column[sIx],(sortOrder->forward[sIx]?"":" sortRev"),sortOrder->order[sIx]);
+jsOnEventById("click", sortOrder->column[sIx], "tableSortAtButtonPress(this);");
 printf("<sup>%s%d</sup>",(sortOrder->forward[sIx]?"&darr;":"&uarr;"),sortOrder->order[sIx]);
 puts("</TH>");
 columnCount++;
 }
 puts("<TH>&nbsp;</TH>"); // schema column
 columnCount++;
 
 // Finally there may be a restricted until column
 if (settings->restrictions)
 {
 if (sortOrder != NULL)
     {
     int sIx=sortOrder->count-1;
     assert(sameString(SORT_ON_RESTRICTED,sortOrder->column[sIx]));
-        printf("<TH id='%s' class='sortable%s sort%d' onclick='tableSortAtButtonPress(this);' "
-                "align='left'>&nbsp;Restricted Until", sortOrder->column[sIx],
+    printf("<TH id='%s' class='sortable%s sort%d' align='left'>&nbsp;Restricted Until", 
+	    sortOrder->column[sIx],
 	    (sortOrder->forward[sIx]?"":" sortRev"),sortOrder->order[sIx]);
+    jsOnEventById("click", sortOrder->column[sIx], "tableSortAtButtonPress(this);");
     printf("<sup>%s%d</sup>",(sortOrder->forward[sIx] ? "&darr;" : "&uarr;"),
 	   sortOrder->order[sIx]);
     puts("</TH>");
     }
 else
     {
     printf("<TH align='center'>&nbsp;");
     printf("<A HREF=\'%s\' TARGET=BLANK>Restricted Until</A>", ENCODE_DATA_RELEASE_POLICY);
     puts("&nbsp;</TH>");
     }
 columnCount++;
 }
 puts("</TR></THEAD>"); // The end of the header section.
 settings->columnCount = columnCount;
 }
@@ -4465,65 +4487,75 @@
 						membership->subgroups, membership->count)))
 	    dyStringPrintf(dyHtml," %s",membership->membership[ix]);
 	}
     }
 if (membersForAll->members[dimV] && -1 !=
 			    (ix = stringArrayIx(membersForAll->members[dimV]->groupTag,
 						membership->subgroups, membership->count)))
     dyStringPrintf(dyHtml, " %s",membership->membership[ix]);  // Saved view for last
 
 // And finally the checkBox is made!
 safef(buffer, sizeof(buffer), "%s_sel", subtrack->track);
 if (!enabledCB)
     {
     dyStringAppend(dyHtml, " disabled");
     cgiMakeCheckBoxFourWay(buffer,checkedCB,enabledCB,id,dyStringContents(dyHtml),
-                "onclick='matSubCbClick(this);' style='cursor:pointer' title='view is hidden'");
+	    "style='cursor:pointer' title='view is hidden'");
+    jsOnEventById("click", id, "matSubCbClick(this);");
     }
 else
+    {
     cgiMakeCheckBoxFourWay(buffer,checkedCB,enabledCB,id,dyStringContents(dyHtml),
-                               "onclick='matSubCbClick(this);' style='cursor:pointer'");
+			   "style='cursor:pointer'");
+    jsOnEventById("click", id, "matSubCbClick(this);");
+    }
 
 if (useDragAndDrop)
     printf("&nbsp;");
 
 if (!tdbIsMultiTrack(parentTdb))  // MultiTracks never have independent vis
     {
     printf("</TD><TD>"); // An extra column for subVis/wrench so dragAndDrop works
     enum trackVisibility vis = tdbVisLimitedByAncestors(cart,subtrack,FALSE,FALSE);
     char *view = NULL;
     if (membersForAll->members[dimV]
     && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups,
 				 membership->count)))
 	view = membership->membership[ix];
     char classList[256];
     if (view != NULL)
 	safef(classList,sizeof(classList),"clickable fauxInput%s subVisDD %s",
 			(visibleCB ? "":" disabled"),view); // view should be last!
     else
 	safef(classList,sizeof(classList),"clickable fauxInput%s subVisDD",
 			(visibleCB ? "":" disabled"));
-        #define SUBTRACK_CFG_VIS "<div id= '%s_faux' class='%s' style='width:65px;' " \
-                                 "onclick='return subCfg.replaceWithVis(this,\"%s\",true);'>" \
-                                 "%s</div>\n"
-        printf(SUBTRACK_CFG_VIS,subtrack->track,classList,subtrack->track,hStringFromTv(vis));
+    #define SUBTRACK_CFG_VIS "<div id='%s_faux' class='%s' style='width:65px;'>%s</div>\n"
+    printf(SUBTRACK_CFG_VIS,subtrack->track,classList,hStringFromTv(vis));
+    char id[256];
+    safef(id, sizeof id, "%s_faux", subtrack->track);
+    char javascript[1024];
+    safef(javascript, sizeof javascript, "return subCfg.replaceWithVis(this,\"%s\",true);", subtrack->track);
+    jsOnEventById("click", id, javascript);
+    
     if (cType != cfgNone)  // make a wrench
 	{
-            #define SUBTRACK_CFG_WRENCH "<span class='clickable%s' onclick='return " \
-                                        "subCfg.cfgToggle(this,\"%s\");' title='Configure this " \
-                                        "subtrack'><img src='../images/wrench.png'></span>\n"
-            printf(SUBTRACK_CFG_WRENCH,(visibleCB ? "":" disabled"),subtrack->track);
+	safef(id, sizeof id, "%s_toggle", subtrack->track);
+	#define SUBTRACK_CFG_WRENCH "<span id='%s' class='clickable%s' " \
+				    "title='Configure this subtrack'><img src='../images/wrench.png'></span>\n"
+	printf(SUBTRACK_CFG_WRENCH,id,(visibleCB ? "":" disabled"));
+	safef(javascript, sizeof javascript, "return subCfg.cfgToggle(this,\"%s\");", subtrack->track);
+	jsOnEventById("click", id, javascript);
 	}
     }
 printf("</TD>");
 
 // If sortable, then there must be a column per sortable dimension
 if (sortOrder != NULL)
     {
     int sIx=0;
     for (sIx=0; sIx <sortOrder->count; sIx++)
 	{
 	char *col = sortOrder->column[sIx];
 	ix = stringArrayIx(col, membership->subgroups, membership->count);
 			    // TODO: Sort needs to expand from subGroups to labels as well
 	if (ix >= 0)
 	    {
@@ -4701,40 +4733,40 @@
 boolean displayAll = sameString(displaySubs, "all");
 
 // Table wraps around entire list so that "Top" link can float to the correct place.
 cgiDown(0.7);
 printf("<table><tr><td class='windowSize'>");
 printf("<A NAME='DISPLAY_SUBTRACKS'></A>");
 if (sortOrder != NULL)
 {
 // First table row contains the display "selected/visible" or "all" radio buttons
 // NOTE: list subtrack radio buttons are inside tracklist table header if
 //       there are no sort columns.  The reason is to ensure spacing of lines
 //       column headers when the only column header is "Restricted Until"
 printf("<B>List subtracks:&nbsp;");
 char javascript[JBUFSIZE];
 safef(javascript, sizeof(javascript),
-          "class='allOrOnly' onclick='showOrHideSelectedSubtracks(true);'");
+      "showOrHideSelectedSubtracks(true);");
 if (subCount > LARGE_COMPOSITE_CUTOFF)
     safef(buffer,SMALLBUF,"%s.displaySubtracks",parentTdb->track);
 else
     safecpy(buffer,SMALLBUF,"displaySubtracks");
-    cgiMakeOnClickRadioButton(buffer, "selected", !displayAll,javascript);
+cgiMakeOnEventRadioButtonWithClass(buffer, "selected", !displayAll, "allOrOnly", "click", javascript);
 puts("only selected/visible &nbsp;&nbsp;");
 safef(javascript, sizeof(javascript),
-          "class='allOrOnly' onclick='showOrHideSelectedSubtracks(false);'");
-    cgiMakeOnClickRadioButton(buffer, "all", displayAll,javascript);
+      "showOrHideSelectedSubtracks(false);");
+cgiMakeOnEventRadioButtonWithClass(buffer, "all", displayAll, "allOrOnly", "click", javascript);
 printf("all</B>");
 if (slCount(subtrackRefList) > 5)
     printf("&nbsp;&nbsp;&nbsp;&nbsp;(<span class='subCBcount'></span>)");
 if (membersHaveMatrix(membersForAll))
     makeTopLink(parentTdb);
 printf("</td></tr></table>");
 }
 else
 {
 if (membersHaveMatrix(membersForAll))
     makeTopLink(parentTdb);
 }
 
 // Get info for subtrack list
 struct subtrackConfigSettings *settings = NULL;
@@ -4804,49 +4836,52 @@
 	   subtrack->longLabel);
     }
 else if (hSameTrackDbType(primaryType, subtrack->type))
     {
     puts("<TR><TD>");
     cgiMakeCheckBox(htmlIdentifier, checkedCB && enabledCB);
     printf("</TD><TD>%s</TD></TR>\n", subtrack->longLabel);
     }
 }
 puts("</TBODY><TFOOT></TFOOT>");
 puts("</TABLE>");
 if (slCount(subtrackRefList) > 5)
 puts("&nbsp;&nbsp;&nbsp;&nbsp;<span class='subCBcount'></span>");
 puts("<P>");
 if (!primarySubtrack)
-    puts("<script type='text/javascript'>matInitializeMatrix();</script>");
+    jsInline("matInitializeMatrix();");
 }
 
-static void makeAddClearButtonPair(char *class,char *seperator)
+static void makeAddClearButtonPair(char *idPrefix, char *class,char *separator)
 // Print an [Add][Clear] button pair that uses javascript to check subtracks
 {
 char buf[256];
 if (class)
     safef(buf, sizeof buf,"matSetMatrixCheckBoxes(true,'%s'); return false;", class);
 else
     safef(buf, sizeof buf,"matSetMatrixCheckBoxes(true); return false;");
-cgiMakeOnClickButton(buf, ADD_BUTTON_LABEL);
-if (seperator)
-    printf("%s",seperator);
+char id[256];
+safef(id, sizeof id, "%s_add", idPrefix);
+cgiMakeOnClickButton(id, buf, ADD_BUTTON_LABEL);
+if (separator)
+    printf("%s",separator);
 if (class)
     safef(buf, sizeof buf,"matSetMatrixCheckBoxes(false,'%s'); return false;", class);
 else
     safef(buf, sizeof buf,"matSetMatrixCheckBoxes(false); return false;");
-cgiMakeOnClickButton(buf, CLEAR_BUTTON_LABEL);
+safef(id, sizeof id, "%s_clr", idPrefix);
+cgiMakeOnClickButton(id, buf, CLEAR_BUTTON_LABEL);
 }
 
 #define MANY_SUBTRACKS  8
 #define WIGGLE_HELP_PAGE  "../goldenPath/help/hgWiggleTrackHelp.html"
 
 boolean cfgBeginBoxAndTitle(struct trackDb *tdb, boolean boxed, char *title)
 // Handle start of box and title for individual track type settings
 {
 if (!boxed)
     {
     boxed = trackDbSettingOn(tdb,"boxedCfg");
     if (boxed)
         printf("<BR>");
     }
 if (boxed)
@@ -4885,67 +4920,69 @@
 cgiMakeCheckBox(varName, option);
 printf("<BR>\n");
 char *style = option ? "display:block" : "display:none";
 printf("<DIV ID=\"densGraphOptions\" STYLE=\"%s\">\n", style);
 
 // we need to fool the wiggle dialog into defaulting to autoscale and maximum
 char *origType = tdb->type;
 tdb->type = "bedGraph";
 if (hashFindVal(tdb->settingsHash, AUTOSCALE) == NULL)
     hashAdd(tdb->settingsHash, AUTOSCALE, "on");
 if (hashFindVal(tdb->settingsHash, WINDOWINGFUNCTION) == NULL)
     hashAdd(tdb->settingsHash, WINDOWINGFUNCTION, wiggleWindowingEnumToString( wiggleWindowingMax));
 wigCfgUi(cart,tdb,name,title,TRUE);
 tdb->type = origType;
 printf("</DIV>\n\n");
-printf("<script>\n");
-printf("   $(\"input[name='%s']\").click( function() { $('#densGraphOptions').toggle();} );\n", varName);
-printf("</script>\n\n");
+char javascript[1024];
+safef(javascript, sizeof javascript, "$(\"input[name='%s']\").click( function() { $('#densGraphOptions').toggle();} );\n"
+    , varName); // XSS FILTER?
+jsInline(javascript);
 }
 
 void wiggleScaleDropDownJavascript(char *name)
 /* print some js that deactivates the min/max range if autoscaling is activated */
 {
-printf("<script type=\"text/javascript\">\n");
-printf("  $(\"[name='%s.autoScale']\").change(function()\n", name);
-printf("  {\n");
-printf("  val= $(this).find(':selected').val(); \n");
-printf("  if (val==\"auto-scale to data view\")\n");
-printf("     {\n");
-printf("     $(\"[name='%s.minY']\")[0].disabled=true;\n", name);
-printf("     $(\"[name='%s.maxY']\")[0].disabled=true;\n", name);
-printf("     $(\".%sAutoScaleDesc\").attr('style', 'color:grey;');\n", name);
-printf("     }\n");
-printf("     else\n");
-printf("     {\n");
-printf("     $(\"[name='%s.minY']\")[0].disabled=false;\n", name);
-printf("     $(\"[name='%s.maxY']\")[0].disabled=false;\n", name);
-printf("     $(\".%sAutoScaleDesc\").attr('style', 'color:black;');\n", name);
-printf("     }\n");
-printf("  });\n");
-printf("\n");
-printf("  $( document ).ready(function()\n");
-printf("  {\n");
-printf("  val= $(\"[name='%s.autoScale']\").find(':selected').val(); \n", name);
-printf("  if (val==\"auto-scale to data view\")\n");
-printf("     {\n");
-printf("     $(\"[name='%s.minY']\")[0].disabled=true;\n", name);
-printf("     $(\"[name='%s.maxY']\")[0].disabled=true;\n", name);
-printf("     $(\".%sAutoScaleDesc\").attr('style', 'color:grey;');\n", name);
-printf("     }\n");
-printf("  });\n");
-printf("</script>\n");
+struct dyString *dy = dyStringNew(1024);
+dyStringPrintf(dy, "  $(\"[name='%s.autoScale']\").change(function()\n", name);
+dyStringPrintf(dy, "  {\n");
+dyStringPrintf(dy, "  val= $(this).find(':selected').val(); \n");
+dyStringPrintf(dy, "  if (val==\"auto-scale to data view\")\n");
+dyStringPrintf(dy, "     {\n");
+dyStringPrintf(dy, "     $(\"[name='%s.minY']\")[0].disabled=true;\n", name);
+dyStringPrintf(dy, "     $(\"[name='%s.maxY']\")[0].disabled=true;\n", name);
+dyStringPrintf(dy, "     $(\".%sAutoScaleDesc\").attr('style', 'color:grey;');\n", name);
+dyStringPrintf(dy, "     }\n");
+dyStringPrintf(dy, "     else\n");
+dyStringPrintf(dy, "     {\n");
+dyStringPrintf(dy, "     $(\"[name='%s.minY']\")[0].disabled=false;\n", name);
+dyStringPrintf(dy, "     $(\"[name='%s.maxY']\")[0].disabled=false;\n", name);
+dyStringPrintf(dy, "     $(\".%sAutoScaleDesc\").attr('style', 'color:black;');\n", name);
+dyStringPrintf(dy, "     }\n");
+dyStringPrintf(dy, "  });\n");
+dyStringPrintf(dy, "\n");
+dyStringPrintf(dy, "  $( document ).ready(function()\n");
+dyStringPrintf(dy, "  {\n");
+dyStringPrintf(dy, "  val= $(\"[name='%s.autoScale']\").find(':selected').val(); \n", name);
+dyStringPrintf(dy, "  if (val==\"auto-scale to data view\")\n");
+dyStringPrintf(dy, "     {\n");
+dyStringPrintf(dy, "     $(\"[name='%s.minY']\")[0].disabled=true;\n", name);
+dyStringPrintf(dy, "     $(\"[name='%s.maxY']\")[0].disabled=true;\n", name);
+dyStringPrintf(dy, "     $(\".%sAutoScaleDesc\").attr('style', 'color:grey;');\n", name);
+dyStringPrintf(dy, "     }\n");
+dyStringPrintf(dy, "  });\n");
+jsInline(dy->string);
+dyStringFree(&dy);
 }
 
 void wigCfgUi(struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed)
 /* UI for the wiggle track */
 {
 char *typeLine = NULL;  /*  to parse the trackDb type line  */
 char *words[8];     /*  to parse the trackDb type line  */
 int wordCount = 0;  /*  to parse the trackDb type line  */
 char option[256];
 double minY;        /*  from trackDb or cart    */
 double maxY;        /*  from trackDb or cart    */
 double tDbMinY;     /*  data range limits from trackDb type line */
 double tDbMaxY;     /*  data range limits from trackDb type line */
 int defaultHeight;  /*  pixels per item */
 char *horizontalGrid = NULL;    /*  Grid lines, off by default */
@@ -5069,32 +5106,35 @@
 printf("&nbsp;&nbsp;&nbsp;at y =");
 safef(option, sizeof(option), "%s.%s", name, YLINEMARK );
 cgiMakeDoubleVarInRange(option, yLineMark, "Indicator at Y", 0, NULL, NULL);
 safef(option, sizeof(option), "%s.%s", name, YLINEONOFF );
 wiggleYLineMarkDropDown(option, yLineMarkOnOff);
 printf("</td>");
 if (boxed)
     puts("</TD></TR></TABLE>");
 else
     {
     puts("</TD></TR></TABLE>");
     printf("<A HREF=\"%s\" TARGET=_blank>Graph configuration help</A>",WIGGLE_HELP_PAGE);
     }
 
 // add a little javascript call to make sure we don't get whiskers with stacks in multiwigs
+
+char javascript[1024];
+safef(javascript, sizeof javascript, "$(function () { multiWigSetupOnChange('%s'); });\n", name);
 if (didAggregate)
-    printf("<script> $(function () { multiWigSetupOnChange('%s'); }); </script>\n", name);
+    jsInline(javascript);
 
 cfgEndBox(boxed);
 }
 
 
 void filterButtons(char *filterTypeVar, char *filterTypeVal, boolean none)
 /* Put up some filter buttons. */
 {
 printf("<B>Filter:</B> ");
 radioButton(filterTypeVar, filterTypeVal, "red");
 radioButton(filterTypeVar, filterTypeVal, "green");
 radioButton(filterTypeVar, filterTypeVal, "blue");
 radioButton(filterTypeVar, filterTypeVal, "exclude");
 radioButton(filterTypeVar, filterTypeVal, "include");
 if (none)
@@ -5199,41 +5239,30 @@
     // maxShade is used to access the array.
     int maxShade = 9;
     int scoreMinGrayLevel = scoreMin * maxShade/scoreMax;
     if (scoreMinGrayLevel <= 0) scoreMinGrayLevel = 1;
     char *setting = trackDbSettingClosestToHome(tdb, MIN_GRAY_LEVEL);
     int minGrayLevel = cartUsualIntClosestToHome(cart, tdb, parentLevel, MIN_GRAY_LEVEL,
                         setting ? atoi(setting) : scoreMinGrayLevel);
     if (minGrayLevel <= 0) minGrayLevel = 1;
     if (minGrayLevel > maxShade) minGrayLevel = maxShade;
     puts("\n<B>Shade of lowest-scoring items: </B>");
     // Add javascript to select so that its color is consistent with option colors:
     int level = 255 - (255*minGrayLevel / maxShade);
     printf("<SELECT NAME=\"%s.%s\" STYLE='color: #%02x%02x%02x' class='normalText'",
            prefix, MIN_GRAY_LEVEL, level, level, level);
     int i;
-#ifdef OMIT
-    // IE works without this code and FF doesn't work with it.
-    printf(" onchange=\"switch(this.value) {");
-    for (i = 1;  i < maxShade;  i++)
-        {
-        level = 255 - (255*i / maxShade);
-        printf("case '%d': $(this).css('color','#%02x%02x%02x'); break; ",i, level, level, level);
-        }
-    level = 255 - (255*i / maxShade);
-    printf("default: $(this).css('color','#%02x%02x%02x'); }\"", level, level, level);
-#endif//def OMIT
     puts(">\n");
     // Use class to set color of each option:
     for (i = 1;  i <= maxShade;  i++)
         {
         level = 255 - (255*i / maxShade);
         printf("<OPTION%s STYLE='color: #%02x%02x%02x' VALUE=%d>",
                (minGrayLevel == i ? " SELECTED" : ""), level, level, level, i);
         if (i == maxShade)
             printf("&bull; black</OPTION>\n");
         else
             printf("&bull; gray (%d%%)</OPTION>\n", i * (100/maxShade));
         }
     printf("</SELECT>\n");
     }
 }
@@ -6317,74 +6346,76 @@
 boolean lineBreakJustPrinted;
 char trackName[255];
 char query[256];
 char **row;
 struct sqlConnection *conn;
 struct sqlResult *sr;
 char *words[MAX_SP_SIZE];
 int defaultOffSpeciesCnt = 0;
 
 if (cartOptionalString(cart, "ajax") == NULL)
     jsIncludeFile("utils.js",NULL);
 //jsInit();
 puts("\n<P><B>Species selection:</B>&nbsp;");
 
 cgiContinueHiddenVar("g");
-PLUS_BUTTON( "id", "plus_pw","cb_maf_","_maf_");
-MINUS_BUTTON("id","minus_pw","cb_maf_","_maf_");
+char id[256];
+char javascript[1024];
+PLUS_BUTTON( "id", "plus_pw","cb_maf_","_maf_")
+MINUS_BUTTON("id","minus_pw","cb_maf_","_maf_")
 
 char prefix[512];
 safef(prefix, sizeof prefix, "%s.", name);
 char *defaultOffSpecies = trackDbSetting(tdb, "speciesDefaultOff");
 struct hash *offHash = NULL;
 if (defaultOffSpecies)
     {
     offHash = newHash(5);
-    DEFAULT_BUTTON( "id", "default_pw","cb_maf_","_maf_");
+    DEFAULT_BUTTON( "id", "default_pw","cb_maf_","_maf_")  // DEBUG RESTORE
     int wordCt = chopLine(defaultOffSpecies, words);
     defaultOffSpeciesCnt = wordCt;
 
     /* build hash of species that should be off */
     int ii;
     for(ii=0; ii < wordCt; ii++)
         hashAdd(offHash, words[ii], NULL);
     }
 
 if (groupCt == 1)
     puts("\n<TABLE><TR>");
 group = -1;
 lineBreakJustPrinted = FALSE;
 for (wmSpecies = wmSpeciesList, i = 0, j = 0; wmSpecies != NULL;
 		    wmSpecies = wmSpecies->next, i++)
     {
     char *label;
     prevGroup = group;
     group = wmSpecies->group;
     if (groupCt != 1 && group != prevGroup)
 	{
 	i = 0;
 	j = 0;
 	if (group != 0)
 	    puts("</TR></TABLE>\n");
         /* replace underscores in group names */
         subChar(groups[group], '_', ' ');
         printf("<P>&nbsp;&nbsp;<B><EM>%s</EM></B>", groups[group]);
         printf("&nbsp;&nbsp;");
         safef(option, sizeof(option), "plus_%s", groups[group]);
-        PLUS_BUTTON( "id",option,"cb_maf_",groups[group]);
+        PLUS_BUTTON( "id",option,"cb_maf_",groups[group])
         safef(option, sizeof(option),"minus_%s", groups[group]);
-        MINUS_BUTTON("id",option,"cb_maf_",groups[group]);
+        MINUS_BUTTON("id",option,"cb_maf_",groups[group])
 
         puts("\n<TABLE><TR>");
         }
     if (hIsGsidServer())
 	numberPerRow = 6;
     else
 	numberPerRow = 5;
 
     /* new logic to decide if line break should be displayed here */
     if ((j != 0 && (j % numberPerRow) == 0) && (lineBreakJustPrinted == FALSE))
         {
         puts("</TR><TR>");
         lineBreakJustPrinted = TRUE;
         }
 
@@ -6628,39 +6659,40 @@
 cfgEndBox(boxed);
 }
 
 static char *grayLabels[] =
     { "alignment quality",
       "base qualities",
       "unpaired ends",
     };
 static char *grayValues[] =
     { BAM_GRAY_MODE_ALI_QUAL,
       BAM_GRAY_MODE_BASE_QUAL,
       BAM_GRAY_MODE_UNPAIRED,
     };
 
 // When a child input of a radio set is changed, click its radio button:
-#define UPDATE_RADIO_FORMAT "%s=\"\
+
+#define UPDATE_RADIO_FORMAT_JS "\
     var inputs = document.getElementsByName('%s'); \
     if (inputs) { \
       for (var i=0; i < inputs.length; i++) { \
         if (inputs[i].type == 'radio') { \
           inputs[i].checked = (inputs[i].value == '%s'); \
         } \
       } \
-    }\""
+    }"
 
 void bamCfgUi(struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed)
 /* BAM: short-read-oriented alignment file format. */
 {
 boxed = cfgBeginBoxAndTitle(tdb, boxed, title);
 char cartVarName[1024];
 
 printf("<TABLE%s><TR><TD>",boxed?" width='100%'":"");
 
 #ifdef NOTNOW  // temporarily (?) remove this check box because code doesn't allow for setting wiggle options
 char *showWig = cartOrTdbString(cart, tdb, BAMWIG_MODE, "0");
 safef(cartVarName, sizeof(cartVarName), "%s.%s", name, BAMWIG_MODE);
 cgiMakeCheckBox(cartVarName, SETTING_IS_ON(showWig));
 printf("</TD><TD>Only show coverage of reads</TD>");
 printf("</TR>\n");
@@ -6702,43 +6734,43 @@
 puts("<BR>");
 indelShowOptionsWithName(cart, tdb, name);
 printf("<BR>\n");
 printf("<B>Additional coloring modes:</B><BR>\n");
 safef(cartVarName, sizeof(cartVarName), "%s." BAM_COLOR_MODE, name);
 char *selected = cartOrTdbString(cart, tdb, BAM_COLOR_MODE, BAM_COLOR_MODE_DEFAULT);
 cgiMakeRadioButton(cartVarName, BAM_COLOR_MODE_STRAND, sameString(selected, BAM_COLOR_MODE_STRAND));
 printf("Color by strand (blue for +, red for -)<BR>\n");
 cgiMakeRadioButton(cartVarName, BAM_COLOR_MODE_GRAY, sameString(selected, BAM_COLOR_MODE_GRAY));
 printf("Use gray for\n");
 char cartVarName2[1024];
 safef(cartVarName2, sizeof(cartVarName2), "%s." BAM_GRAY_MODE, name);
 int grayMenuSize = canPair ? ArraySize(grayLabels) : ArraySize(grayLabels)-1;
 char *sel2 = cartOrTdbString(cart, tdb, BAM_GRAY_MODE, BAM_GRAY_MODE_DEFAULT);
 char onChange[2048];
-safef(onChange, sizeof(onChange), UPDATE_RADIO_FORMAT,
-      "onChange", cartVarName, BAM_COLOR_MODE_GRAY);
-cgiMakeDropListFull(cartVarName2, grayLabels, grayValues, grayMenuSize, sel2, onChange);
+safef(onChange, sizeof(onChange), UPDATE_RADIO_FORMAT_JS,
+      cartVarName, BAM_COLOR_MODE_GRAY);
+cgiMakeDropListFull(cartVarName2, grayLabels, grayValues, grayMenuSize, sel2, "change", onChange);
 printf("<BR>\n");
 if (trackDbSettingClosestToHome(tdb, "noColorTag") == NULL)
     {
     cgiMakeRadioButton(cartVarName, BAM_COLOR_MODE_TAG, sameString(selected, BAM_COLOR_MODE_TAG));
     printf("Use R,G,B colors specified in user-defined tag ");
     safef(cartVarName2, sizeof(cartVarName2), "%s." BAM_COLOR_TAG, name);
     sel2 = cartOrTdbString(cart, tdb, BAM_COLOR_TAG, BAM_COLOR_TAG_DEFAULT);
-    safef(onChange, sizeof(onChange), UPDATE_RADIO_FORMAT,
-	  "onkeypress", cartVarName, BAM_COLOR_MODE_TAG);
-    cgiMakeTextVarWithExtraHtml(cartVarName2, sel2, 30, onChange);
+    safef(onChange, sizeof(onChange), UPDATE_RADIO_FORMAT_JS,
+	  cartVarName, BAM_COLOR_MODE_TAG);
+    cgiMakeTextVarWithExtraHtml(cartVarName2, sel2, 30, "keypress", onChange);
     printf("<BR>\n");
     }
 cgiMakeRadioButton(cartVarName, BAM_COLOR_MODE_OFF, sameString(selected, BAM_COLOR_MODE_OFF));
 printf("No additional coloring");
 
 // let the user choose to see the track in wiggle mode
 wigOption(cart, name, title, tdb);
 
 //TODO: include / exclude flags
 
 if (!boxed && fileExists(hHelpFile("hgBamTrackHelp")))
     printf("<P><A HREF=\"../goldenPath/help/hgBamTrackHelp.html\" TARGET=_BLANK>BAM "
            "configuration help</A></P>");
 
 cfgEndBox(boxed);
@@ -6807,35 +6839,41 @@
 {
 char *visibility = NULL;
 compositeViewCfgExpandedByDefault(parentTdb,view,&visibility);
 enum trackVisibility vis = hTvFromString(visibility);
 freeMem(visibility);
 return vis;
 }
 
 static boolean hCompositeDisplayViewDropDowns(char *db, struct cart *cart, struct trackDb *parentTdb)
 // UI for composite view drop down selections.
 {
 int ix;
 char varName[SMALLBUF];
 char classes[SMALLBUF];
 char javascript[JBUFSIZE];
-#define CFG_LINK  "<B><A HREF=\"#a_cfg_%s\" onclick=\"return (showConfigControls('%s') == " \
-                  "false);\" title=\"%s Configuration\">%s</A><INPUT TYPE=HIDDEN " \
+char id[256];
+#define CFG_LINK  "<B><A HREF=\"#a_cfg_%s\" id='%s' "\
+                  "title=\"%s Configuration\">%s</A><INPUT TYPE=HIDDEN " \
                   "NAME='%s.showCfg' value='%s'></B>"
+#define CFG_LINK_JS "return (showConfigControls('%s') == false);"
 #define MAKE_CFG_LINK(name,title,viewTrack,open) \
-                    printf(CFG_LINK, (name),(name),(title),(title),(viewTrack),((open)?"on":"off"))
+		    safef(id, sizeof id, "%s_link", (name)); \
+                    printf(CFG_LINK, (name),id,(title),(title),(viewTrack),((open)?"on":"off")); \
+		    safef(javascript, sizeof javascript, CFG_LINK_JS, (name)); \
+		    jsOnEventById("click", id, javascript);
+		    			
 
 // membersForAll is generated once per track, then cached
 membersForAll_t *membersForAll = membersForAllSubGroupsGet(parentTdb, cart);
 members_t *membersOfView = membersForAll->members[dimV];
 if (membersOfView == NULL)
     return FALSE;
 
 char configurable[membersOfView->count];
 memset(configurable,cfgNone,sizeof(configurable));
 int firstOpened = -1;
 boolean makeCfgRows = FALSE;
 struct trackDb **matchedViewTracks = needMem(sizeof(struct trackDb *) * membersOfView->count);
 
 for (ix = 0; ix < membersOfView->count; ix++)
     {
@@ -6863,47 +6901,50 @@
 
 toLowerN(membersOfView->groupTitle, 1);
 printf("<B>Select %s</B> (<A HREF='../goldenPath/help/multiView.html' title='Help on views' "
        "TARGET=_BLANK>help</A>):\n", membersOfView->groupTitle);
 printf("<TABLE><TR style='text-align:left;'>\n");
 // Make row of vis drop downs
 for (ix = 0; ix < membersOfView->count; ix++)
     {
     char *viewName = membersOfView->tags[ix];
     if (matchedViewTracks[ix] != NULL)
         {
         printf("<TD>");
         if (configurable[ix] != cfgNone)
             {
             MAKE_CFG_LINK(membersOfView->tags[ix],membersOfView->titles[ix],
-                          matchedViewTracks[ix]->track,(firstOpened == ix));
+                          matchedViewTracks[ix]->track,(firstOpened == ix))
             }
         else
             printf("<B>%s</B>",membersOfView->titles[ix]);
         puts("</TD>");
 
         safef(varName, sizeof(varName), "%s", matchedViewTracks[ix]->track);
         enum trackVisibility tv = hTvFromString(cartUsualString(cart,varName,
                                       hStringFromTv(visCompositeViewDefault(parentTdb,viewName))));
 
-        safef(javascript, sizeof(javascript), "onchange=\"matSelectViewForSubTracks(this,'%s');\" "
-                                              "onfocus='this.lastIndex=this.selectedIndex;'",
-                                              viewName);
+	struct slPair *events = NULL;
+        safef(javascript, sizeof(javascript), "matSelectViewForSubTracks(this,'%s');", viewName);
+	slPairAdd(&events, "change", cloneString(javascript));
+    
+        safef(javascript, sizeof(javascript), "this.lastIndex=this.selectedIndex;");
+	slPairAdd(&events, "focus", cloneString(javascript));
 
         printf("<TD>");
         safef(classes, sizeof(classes), "viewDD normalText %s", membersOfView->tags[ix]);
-        hTvDropDownClassWithJavascript(varName, tv, parentTdb->canPack,classes,javascript);
+        hTvDropDownClassWithJavascript(varName, tv, parentTdb->canPack, classes, events);
         puts(" &nbsp; &nbsp; &nbsp;</TD>");
         }
     }
 puts("</TR>");
 
 // Make row of cfg boxes if needed
 if (makeCfgRows)
     {
     puts("</TABLE><TABLE>");
     for (ix = 0; ix < membersOfView->count; ix++)
         {
         struct trackDb *view = matchedViewTracks[ix];
         if (view != NULL)
             {
             char *viewName = membersOfView->tags[ix];
@@ -6976,49 +7017,62 @@
             if (cvTerm != NULL)
                 {
                 char *link = wgEncodeVocabLink(words[0],
                                     (sameWord(cvSetting,"antibody") ?  "target" : "term"),
                                     (char *)cvTerm,(char *)cvTerm,rootLabel,suffix);
                 return link;
                 }
             }
         }
     }
 freeMem(words[0]);
 freeMem(rootLabel);
 return cloneString(label);
 }
 
-#define PM_BUTTON_UC "<IMG height=18 width=18 onclick=\"return " \
-                     "(matSetMatrixCheckBoxes(%s%s%s%s%s%s) == false);\" id='btn_%s' " \
-                     "src='../images/%s'>"
-
+#define PM_BUTTON_UC "<IMG height=18 width=18 id='%s' src='../images/%s'>"
+#define PM_BUTTON_UC_JS "return (matSetMatrixCheckBoxes(%s%s%s%s%s%s) == false);" 
+#define PM_MAKE_BUTTON_UC(s1,s2,s3,s4,s5,s6,name,img) \
+    safef(id, sizeof id, "btn_%s", (name)); \
+    printf(PM_BUTTON_UC, id, (img)); \
+    safef(javascript, sizeof javascript, PM_BUTTON_UC_JS, (s1),(s2),(s3),(s4),(s5),(s6)); \
+    jsOnEventById("click", id, javascript);
 #define MATRIX_RIGHT_BUTTONS_AFTER 8
 #define MATRIX_BOTTOM_BUTTONS_AFTER 20
 
-static void buttonsForAll()
+static void buttonsForAll(boolean left)
 {
-printf(PM_BUTTON_UC,"true", "", "", "", "", "",  "plus_all",    "add_sm.gif");
-printf(PM_BUTTON_UC,"false","", "", "", "", "", "minus_all", "remove_sm.gif");
+char id[256];
+char javascript[1024];
+char fullname[256];
+safef(fullname, sizeof fullname, "plus_all_%s" , left?"left":"right");
+PM_MAKE_BUTTON_UC("true", "", "", "", "", "",  fullname,    "add_sm.gif")
+safef(fullname, sizeof fullname, "minus_all_%s", left?"left":"right");
+PM_MAKE_BUTTON_UC("false","", "", "", "", "", fullname, "remove_sm.gif")
 }
 
-static void buttonsForOne(char *name,char *class,boolean vertical)
+static void buttonsForOne(char *class, boolean vertical, boolean left)
 {
-printf(PM_BUTTON_UC, "true",  ",'", class, "'", "", "", name,    "add_sm.gif");
+char id[256];
+char javascript[1024];
+char fullname[256];
+safef(fullname, sizeof fullname, "plus_%s_all_%s" , class, left?"left":"right");
+PM_MAKE_BUTTON_UC("true",  ",'", class, "'", "", "", fullname,    "add_sm.gif")
 if (vertical)
     puts("<BR>");
-printf(PM_BUTTON_UC, "false", ",'", class, "'", "", "", name, "remove_sm.gif");
+safef(fullname, sizeof fullname, "minus_%s_all_%s", class, left?"left":"right");
+PM_MAKE_BUTTON_UC("false", ",'", class, "'", "", "", fullname, "remove_sm.gif")
 }
 
 #define MATRIX_SQUEEZE 10
 static boolean matrixSqueeze(membersForAll_t* membersForAll)
 // Returns non-zero if the matrix will be squeezed.  Non-zero is actually squeezedLabelHeight
 {
 char *browserVersion;
 if (btIE == cgiClientBrowser(&browserVersion, NULL, NULL) && *browserVersion < '9')
     return 0;
 
 members_t *dimensionX = membersForAll->members[dimX];
 members_t *dimensionY = membersForAll->members[dimY];
 if (dimensionX && dimensionY)
     {
     if (dimensionX->count>MATRIX_SQUEEZE)
@@ -7038,31 +7092,31 @@
 return FALSE;
 }
 
 static void matrixXheadingsRow1(char *db,struct trackDb *parentTdb,boolean squeeze,
                                 membersForAll_t* membersForAll,boolean top)
 // prints the top row of a matrix: 'All' buttons; X titles; buttons 'All'
 {
 members_t *dimensionX = membersForAll->members[dimX];
 members_t *dimensionY = membersForAll->members[dimY];
 
 printf("<TR ALIGN=CENTER valign=%s>\n",top?"BOTTOM":"TOP");
 if (dimensionX && dimensionY)
     {
     printf("<TH ALIGN=LEFT valign=%s>",top?"TOP":"BOTTOM");
     //printf("<TH ALIGN=LEFT valign=%s>",(top == squeeze)?"BOTTOM":"TOP");//"TOP":"BOTTOM");
-    buttonsForAll();
+    buttonsForAll(TRUE);
     puts("&nbsp;All</TH>");
     }
 
 // If there is an X dimension, then titles go across the top
 if (dimensionX)
     {
     int ixX,cntX=0;
     if (dimensionY)
         {
         if (squeeze)
             printf("<TH align=RIGHT><div class='%s'><B><EM>%s</EM></B></div></TH>",
                    (top?"up45":"dn45"), dimensionX->groupTitle);
         else
             printf("<TH align=RIGHT><B><EM>%s</EM></B></TH>", dimensionX->groupTitle);
         }
@@ -7095,72 +7149,70 @@
                 }
             cntX++;
             }
         }
     // If dimension is big enough, then add Y buttons to right as well
     if (cntX>MATRIX_RIGHT_BUTTONS_AFTER)
         {
         if (dimensionY)
             {
             if (squeeze)
                 printf("<TH align=LEFT><div class='%s'><B><EM>%s</EM></B></div></TH>",
                        (top?"up45":"dn45"), dimensionX->groupTitle);
             else
                 printf("<TH align=LEFT><B><EM>%s</EM></B></TH>", dimensionX->groupTitle);
             printf("<TH ALIGN=RIGHT valign=%s>All&nbsp;",top?"TOP":"BOTTOM");
-            buttonsForAll();
+            buttonsForAll(FALSE);
             puts("</TH>");
             }
         else
             printf("<TH ALIGN=LEFT valign=%s><B><EM>%s</EM></B>&nbsp;&nbsp;</TH>",
                    top ? "TOP" : "BOTTOM", dimensionX->groupTitle);
         }
     }
 else if (dimensionY)
     {
     printf("<TH ALIGN=RIGHT WIDTH=100 nowrap>");
     printf("<B><EM>%s</EM></B>", dimensionY->groupTitle);
     printf("</TH><TH ALIGN=CENTER WIDTH=60>");
-    buttonsForAll();
+    buttonsForAll(FALSE);
     puts("</TH>");
     }
 puts("</TR>\n");
 }
 
 static void matrixXheadingsRow2(struct trackDb *parentTdb, boolean squeeze,
                                 membersForAll_t* membersForAll)
 // prints the 2nd row of a matrix: Y title; X buttons; title Y
 {
 members_t *dimensionX = membersForAll->members[dimX];
 members_t *dimensionY = membersForAll->members[dimY];
 
 // If there are both X and Y dimensions, then there is a row of buttons in X
 if (dimensionX && dimensionY)
     {
     int ixX,cntX=0;
     printf("<TR ALIGN=CENTER><TH ALIGN=CENTER colspan=2><B><EM>%s</EM></B></TH>",
            dimensionY->groupTitle);
     for (ixX = 0; ixX < dimensionX->count; ixX++)    // Special row of +- +- +-
         {
         if (dimensionX->subtrackList
         &&  dimensionX->subtrackList[ixX]
         &&  dimensionX->subtrackList[ixX]->val)
             {
-            char objName[SMALLBUF];
             printf("<TD nowrap class='matCell %s all'>\n",dimensionX->tags[ixX]);
-            safef(objName, sizeof(objName), "plus_%s_all", dimensionX->tags[ixX]);
-            buttonsForOne( objName, dimensionX->tags[ixX], squeeze );
+            buttonsForOne( dimensionX->tags[ixX], squeeze, TRUE);
             puts("</TD>");
             cntX++;
             }
         }
     // If dimension is big enough, then add Y buttons to right as well
     if (cntX>MATRIX_RIGHT_BUTTONS_AFTER)
         printf("<TH ALIGN=CENTER colspan=2><B><EM>%s</EM></B></TH>", dimensionY->groupTitle);
     puts("</TR>\n");
     }
 }
 
 static boolean matrixXheadings(char *db,struct trackDb *parentTdb, membersForAll_t* membersForAll,
                                boolean top)
 // UI for X headings in matrix
 {
@@ -7181,47 +7233,45 @@
                             int ixY,boolean left)
 // prints the column of Y labels and buttons
 {
 members_t *dimensionX = membersForAll->members[dimX];
 members_t *dimensionY = membersForAll->members[dimY];
 
 struct trackDb *childTdb = NULL;
 if (dimensionY
 &&  dimensionY->subtrackList
 &&  dimensionY->subtrackList[ixY]
 &&  dimensionY->subtrackList[ixY]->val)
     childTdb = dimensionY->subtrackList[ixY]->val;
 
 if (dimensionX && dimensionY && childTdb != NULL) // Both X and Y, then column of buttons
     {
-    char objName[SMALLBUF];
     printf("<TH class='matCell all %s' ALIGN=%s nowrap colspan=2>",
            dimensionY->tags[ixY],left?"RIGHT":"LEFT");
     if (left)
         printf("%s&nbsp;",compositeLabelWithVocabLink(db,parentTdb,childTdb,dimensionY->groupTag,
                                                       dimensionY->titles[ixY]));
-    safef(objName, sizeof(objName), "plus_all_%s", dimensionY->tags[ixY]);
-    buttonsForOne( objName, dimensionY->tags[ixY], FALSE );
+    buttonsForOne( dimensionY->tags[ixY], FALSE, left);
     if (!left)
         printf("&nbsp;%s",compositeLabelWithVocabLink(db,parentTdb,childTdb,dimensionY->groupTag,
                                                       dimensionY->titles[ixY]));
     puts("</TH>");
     }
 else if (dimensionX)
     {
     printf("<TH ALIGN=%s>",left?"RIGHT":"LEFT");
-    buttonsForAll();
+    buttonsForAll(TRUE);
     puts("</TH>");
     }
 else if (left && dimensionY && childTdb != NULL)
     printf("<TH class='matCell all %s' ALIGN=RIGHT nowrap>%s</TH>\n",dimensionY->tags[ixY],
            compositeLabelWithVocabLink(db,parentTdb,childTdb,dimensionY->groupTag,
                                        dimensionY->titles[ixY]));
 }
 
 static int displayABCdimensions(char *db,struct cart *cart, struct trackDb *parentTdb,
                                 struct slRef *subtrackRefList, membersForAll_t* membersForAll)
 // This will walk through all declared nonX&Y dimensions (X and Y is the 2D matrix of CBs.
 // NOTE: ABC dims are only supported if there are X & Y both.
 //       Also expected number should be passed in
 {
 int count=0,ix;
@@ -7234,39 +7284,40 @@
     count++;
 
     if (count==1) // First time set up a table
         puts("<BR><TABLE>");
     printf("<TR><TH valign=top align='right'>&nbsp;&nbsp;<B><EM>%s</EM></B>:</TH>",
            membersForAll->members[ix]->groupTitle);
     int aIx;
     for (aIx=0;aIx<membersForAll->members[ix]->count;aIx++)
         {
         if (membersForAll->members[ix]->tags[aIx] != NULL)
             {
             assert(membersForAll->members[ix]->subtrackList[aIx]->val != NULL);
             printf("<TH align=left nowrap>");
             char objName[SMALLBUF];
             char javascript[JBUFSIZE];
+            char other[JBUFSIZE];
             boolean alreadySet=FALSE;
             if (membersForAll->members[ix]->selected != NULL)
                 alreadySet = membersForAll->members[ix]->selected[aIx];
             safef(objName, sizeof(objName), "%s.mat_%s_dim%c_cb",parentTdb->track,
                   membersForAll->members[ix]->tags[aIx],membersForAll->letters[ix]);
-            safef(javascript,sizeof(javascript),
-                  "onclick='matCbClick(this);' class=\"matCB abc %s\"",
-                  membersForAll->members[ix]->tags[aIx]);
-            cgiMakeCheckBoxJS(objName,alreadySet,javascript);
+            safef(javascript,sizeof(javascript), "matCbClick(this);");
+	    safef(other, sizeof other, "class='matCB abc %s'", membersForAll->members[ix]->tags[aIx]);
+            cgiMakeCheckBoxIdAndMore(objName,alreadySet,objName,other);
+	    jsOnEventById("click", objName, javascript);
             printf("%s",compositeLabelWithVocabLink(db,parentTdb,
                    membersForAll->members[ix]->subtrackList[aIx]->val,
                    membersForAll->members[ix]->groupTag,
                    membersForAll->members[ix]->titles[aIx]));
             puts("</TH>");
             }
         }
     puts("</TR>");
     }
 if (count>0)
     puts("</TABLE>");
 return count;
 }
 
 #ifdef DEBUG
@@ -7355,56 +7406,68 @@
 if (membersForAll == NULL || membersForAll->filters == FALSE) // Not Matrix or filters
     return FALSE;
 if (cartOptionalString(cart, "ajax") == NULL)
     {
     webIncludeResourceFile("ui.dropdownchecklist.css");
     jsIncludeFile("ui.dropdownchecklist.js",NULL);
     jsIncludeFile("ddcl.js",NULL);
     }
 
 cgiDown(0.7);
 printf("<B>Select subtracks %sby:</B> (select multiple %sitems - %s)<BR>\n",
        (membersForAll->members[dimX] != NULL || membersForAll->members[dimY] != NULL ? "further ":""),
        (membersForAll->dimMax == dimA?"":"categories and "),FILTERBY_HELP_LINK);
 printf("<TABLE><TR valign='top'>\n");
 
+char id[256];
+char javascript[1024];
+
 // Do All [+][-] buttons
 if (membersForAll->members[dimX] == NULL && membersForAll->members[dimY] == NULL) // No matrix
     {
     printf("<TD align='left' width='50px'><B>All:</B><BR>");
     // TODO: Test when a real world case actually calls this.  Currently no trackDb.ra cases exist
-    #define PM_BUTTON_FILTER_COMP "<input type='button' class='inOutButton' " \
-                                  "onclick=\"waitOnFunction(filterCompositeSet,this,%s); " \
-                                  "return false;\" id='btn_%s' value='%c'>"
-    printf(PM_BUTTON_FILTER_COMP,"true",  "plus_fc",'+');
-    printf(PM_BUTTON_FILTER_COMP,"false","minus_fc",'-');
+    #define PM_BUTTON_FILTER_COMP "<input type='button' class='inOutButton' id='%s' value='%c'>"
+    #define PM_BUTTON_FILTER_COMP_JS "waitOnFunction(filterCompositeSet,this,%s);return false;"
+    #define MAKE_PM_BUTTON_FILTER_COMP(tf,fc,plmi) \
+    printf(PM_BUTTON_FILTER_COMP, id, (plmi)); \
+    safef(id, sizeof id, "'btn_%s", (fc)); \
+    safef(javascript, sizeof javascript, PM_BUTTON_FILTER_COMP_JS, (tf)); \
+    jsOnEventById("click", id, javascript);
+
+    MAKE_PM_BUTTON_FILTER_COMP("true",  "plus_fc",'+')
+    MAKE_PM_BUTTON_FILTER_COMP("false","minus_fc",'-')
     printf("</TD>\n");
     }
 
 // Now make a filterComp box for each ABC dimension
 int dimIx=dimA;
 for (dimIx=dimA;dimIx<membersForAll->dimMax;dimIx++)
     {
     printf("<TD align='left'><B>%s:</B><BR>\n",
            labelWithVocabLinkForMultiples(db,parentTdb,membersForAll->members[dimIx]));
 
-    #define FILTER_COMPOSITE_FORMAT "<SELECT id='fc%d' name='%s.filterComp.%s' %s " \
-                                    "onchange='filterCompositeSelectionChanged(this);' " \
+    #define FILTER_COMPOSITE_FORMAT "<SELECT id='%s' name='%s.filterComp.%s' %s " \
                                     "style='display: none; font-size:.8em;' " \
                                     "class='filterComp'><BR>\n"
-    printf(FILTER_COMPOSITE_FORMAT,dimIx,parentTdb->track,membersForAll->members[dimIx]->groupTag,
+    #define FILTER_COMPOSITE_FORMAT_JS "filterCompositeSelectionChanged(this);"
+    safef(id, sizeof id, "fc%d",dimIx); 
+    printf(FILTER_COMPOSITE_FORMAT,id,parentTdb->track,membersForAll->members[dimIx]->groupTag,
            "multiple");
+    safef(javascript, sizeof javascript, FILTER_COMPOSITE_FORMAT_JS);
+    jsOnEventById("change", id, javascript);
+
 
     // DO we support anything besides multi?
     //  (membersForAll->members[dimIx]->fcType == fctMulti?"multiple ":""));
     if (membersForAll->members[dimIx]->fcType != fctOneOnly)
         printf("<OPTION%s>All</OPTION>\n",
                (sameWord("All",membersForAll->checkedTags[dimIx])?" SELECTED":"") );
 
     int ix=0;
     for (ix=0;ix<membersForAll->members[dimIx]->count; ix++)
         {
         boolean alreadySet = membersForAll->members[dimIx]->selected[ix];
         printf("<OPTION%s value=%s>%s</OPTION>\n",(alreadySet?" SELECTED":""),
                membersForAll->members[dimIx]->tags[ix],membersForAll->members[dimIx]->titles[ix]);
         }
     printf("</SELECT>");
@@ -7538,94 +7601,94 @@
 
 (void)matrixXheadings(db,parentTdb,membersForAll,TRUE);
 
 // Now the Y by X matrix
 int cntX=0,cntY=0;
 for (ixY = 0; ixY < sizeOfY; ixY++)
     {
     if (dimensionY == NULL || (dimensionY->tags[ixY]))
         {
         cntY++;
         assert(!dimensionY || ixY < dimensionY->count);
         printf("<TR ALIGN=CENTER>");
 
         matrixYheadings(db,parentTdb, membersForAll,ixY,TRUE);
 
-#define MAT_CB_SETUP "<INPUT TYPE=CHECKBOX NAME='%s' VALUE=on %s>"
-#define MAT_CB(name,js) printf(MAT_CB_SETUP,(name),(js));
+#define MAT_CB_SETUP "<INPUT TYPE=CHECKBOX NAME='%s' ID='%s' VALUE=on %s>"
+#define MAT_CB(name,js) printf(MAT_CB_SETUP,(name),(name),(js));
         for (ixX = 0; ixX < sizeOfX; ixX++)
             {
             if (dimensionX == NULL || (dimensionX->tags[ixX]))
                 {
                 assert(!dimensionX || ixX < dimensionX->count);
 
                 if (cntY==1) // Only do this on the first good Y
                     cntX++;
 
                 if (dimensionX && ixX == dimensionX->count)
                     break;
                 char *ttlX = NULL;
                 char *ttlY = NULL;
                 if (dimensionX)
                     {
                     ttlX = cloneString(dimensionX->titles[ixX]);
                     stripString(ttlX,"<i>");
                     stripString(ttlX,"</i>");
                     }
                 if (dimensionY != NULL)
                     {
                     ttlY = cloneString(dimensionY->titles[ixY]);
                     stripString(ttlY,"<i>");
                     stripString(ttlY,"</i>");
                     }
                 if (cells[ixX][ixY] > 0)
                     {
                     boolean halfChecked = (  chked[ixX][ixY] > 0
                                           && chked[ixX][ixY] < enabd[ixX][ixY]);
 
-                    struct dyString *dyJS = dyStringCreate("onclick='matCbClick(this);'");
+                    struct dyString *dySettings = dyStringNew(256);
                     if (dimensionX && dimensionY)
                         {
                         safef(objName, sizeof(objName), "mat_%s_%s_cb",
                               dimensionX->tags[ixX],dimensionY->tags[ixY]);
                         }
                     else
                         {
                         safef(objName, sizeof(objName), "mat_%s_cb",
                               (dimensionX ? dimensionX->tags[ixX] : dimensionY->tags[ixY]));
                         }
                     if (ttlX && ttlY)
                         printf("<TD class='matCell %s %s'>\n",
                                dimensionX->tags[ixX],dimensionY->tags[ixY]);
                     else
                         printf("<TD class='matCell %s'>\n",
                                (dimensionX ? dimensionX->tags[ixX] : dimensionY->tags[ixY]));
-                    dyStringPrintf(dyJS, " class=\"matCB");
+                    dyStringPrintf(dySettings, " class=\"matCB");
                     if (halfChecked)
-                        dyStringPrintf(dyJS, " disabled"); // appears disabled but still clickable!
+                        dyStringPrintf(dySettings, " disabled"); // appears disabled but still clickable!
                     if (dimensionX)
-                        dyStringPrintf(dyJS, " %s",dimensionX->tags[ixX]);
+                        dyStringPrintf(dySettings, " %s",dimensionX->tags[ixX]);
                     if (dimensionY)
-                        dyStringPrintf(dyJS, " %s",dimensionY->tags[ixY]);
-                    dyStringAppendC(dyJS,'"');
+                        dyStringPrintf(dySettings, " %s",dimensionY->tags[ixY]);
+                    dyStringAppendC(dySettings,'"');
                     if (chked[ixX][ixY] > 0)
-                        dyStringAppend(dyJS," CHECKED");
+                        dyStringAppend(dySettings," CHECKED");
                     if (halfChecked)
-                        dyStringAppend(dyJS," title='Not all associated subtracks have been"
-                                            " selected'");
+                        dyStringAppend(dySettings," title='Not all associated subtracks have been selected'");
 
-                    MAT_CB(objName,dyStringCannibalize(&dyJS)); // X&Y are set by javascript
+                    MAT_CB(objName,dyStringCannibalize(&dySettings));
+                    jsOnEventById("click", objName, "matCbClick(this);"); // X&Y are set by javascript
                     puts("</TD>");
                     }
                 else
                     {
                     if (ttlX && ttlY)
                         printf("<TD class='matCell %s %s'></TD>\n",
                                dimensionX->tags[ixX],dimensionY->tags[ixY]);
                     else
                         printf("<TD class='matCell %s'></TD>\n",
                                (dimensionX ? dimensionX->tags[ixX] : dimensionY->tags[ixY]));
                     }
                 }
             }
         if (dimensionX && cntX>MATRIX_RIGHT_BUTTONS_AFTER)
             matrixYheadings(db,parentTdb, membersForAll,ixY,FALSE);
@@ -7645,36 +7708,44 @@
 compositeUiByFilter(db, cart, parentTdb, formName);
 
 return TRUE;
 }
 
 static boolean compositeUiAllButtons(char *db, struct cart *cart, struct trackDb *parentTdb,
                                      char *formName)
 // UI for composite tracks: all/none buttons only (as opposed to matrix or lots of buttons
 {
 if (trackDbCountDescendantLeaves(parentTdb) <= 1)
     return FALSE;
 
 if (dimensionsExist(parentTdb))
     return FALSE;
 
-#define PM_BUTTON_GLOBAL "<IMG height=18 width=18 onclick=\"matSubCBsCheck(%s);\" " \
-                         "id='btn_%s' src='../images/%s'>"
-#define    BUTTON_PLUS_ALL_GLOBAL()  printf(PM_BUTTON_GLOBAL,"true",  "plus_all",   "add_sm.gif")
-#define    BUTTON_MINUS_ALL_GLOBAL() printf(PM_BUTTON_GLOBAL,"false","minus_all","remove_sm.gif")
-BUTTON_PLUS_ALL_GLOBAL();
-BUTTON_MINUS_ALL_GLOBAL();
+#define PM_BUTTON_GLOBAL "<IMG height=18 width=18 id='%s' src='../images/%s'>"
+#define PM_BUTTON_GLOBAL_JS "matSubCBsCheck(%s);"
+char id[256];
+char javascript[1024];
+safef(id, sizeof id, "btn_plus_all"); 
+safef(javascript, sizeof javascript, PM_BUTTON_GLOBAL_JS, "true");
+printf(PM_BUTTON_GLOBAL, id, "add_sm.gif");
+jsOnEventById("click", id, javascript);
+
+safef(id, sizeof id, "btn_minus_all"); 
+safef(javascript, sizeof javascript, PM_BUTTON_GLOBAL_JS, "false");
+printf(PM_BUTTON_GLOBAL, id, "remove_sm.gif");
+jsOnEventById("click", id, javascript);
+
 puts("&nbsp;<B>Select all subtracks</B><BR>");
 return TRUE;
 }
 
 static boolean compositeUiNoMatrix(char *db, struct cart *cart, struct trackDb *parentTdb,
                                    char *formName)
 // UI for composite tracks: subtrack selection.  This is the default UI
 // without matrix controls.
 {
 int i, j, k;
 char *words[SMALLBUF];
 char option[SMALLBUF];
 int wordCnt;
 char *name, *value;
 char buttonVar[1024];
@@ -7688,31 +7759,31 @@
 
 puts("<TABLE>");
 if (hasSubgroups)
     {
     puts("<TR><B>Select subtracks:</B></TR>");
     puts("<TR><TD><B><EM>&nbsp; &nbsp; All</EM></B>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"
          "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </TD><TD>");
     }
 else
     {
     puts("<TR><TD><B>All subtracks:</B></TD><TD>");
     }
 safef(buttonVar, sizeof buttonVar, "%s", "button_all");
 if (formName)
     {
-    makeAddClearButtonPair(NULL,"</TD><TD>"); // NULL means all
+    makeAddClearButtonPair("cpmUiNoMtx_but_all", NULL,"</TD><TD>"); // NULL means all
     }
 else
     {
     cgiMakeButton(buttonVar, ADD_BUTTON_LABEL);
     puts("</TD><TD>");
     cgiMakeButton(buttonVar, CLEAR_BUTTON_LABEL);
     }
 button = cgiOptionalString(buttonVar);
 if (isNotEmpty(button))
     {
     struct slRef *tdbRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks);
     struct slRef *tdbRef;
     for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next)
         {
 	subtrack = tdbRef->val;
@@ -7736,31 +7807,33 @@
         continue;
     subGroup = cloneString(words[0]);
     if (sameWord(subGroup,"view"))
         continue;  // Multi-view should have taken care of "view" subgroup already
     puts("<TABLE>");
     printf("<TR><TD><B><EM>&nbsp; &nbsp; %s</EM></B></TD></TR>", words[1]);
     for (j = 2; j < wordCnt; j++)
         {
         if (!parseAssignment(words[j], &name, &value))
             continue;
         printf("<TR><TD>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s</TD><TD>",
                value);
         safef(buttonVar, sizeof buttonVar, "%s_%s", subGroup, name);
         if (formName)
             {
-            makeAddClearButtonPair(name,"</TD><TD>");
+	    char id[256];
+	    safef(id, sizeof id, "cpmUiNoMtx_but_%d", i);
+            makeAddClearButtonPair(id, name,"</TD><TD>");
             }
         else
             {
             cgiMakeButton(buttonVar, ADD_BUTTON_LABEL);
             puts("</TD><TD>");
             cgiMakeButton(buttonVar, CLEAR_BUTTON_LABEL);
             }
         puts("</TD></TR>");
         button = cgiOptionalString(buttonVar);
         if (isEmpty(button))
             continue;
 	struct slRef *tdbRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks);
 	struct slRef *tdbRef;
 	for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next)
             {
@@ -7855,31 +7928,31 @@
     compositeUiSubtracksMatchingPrimary(db, cart, tdb,primarySubtrack);
 else
     compositeUiSubtracks(db, cart, tdb);
 
 if (primarySubtrack == NULL)  // primarySubtrack is set for tableBrowser but not hgTrackUi
     {
     if (trackDbCountDescendantLeaves(tdb) > 5)
         {
         cgiDown(0.7);
         cgiMakeButton("Submit", "Submit");
         }
     }
 }
 
 boolean superTrackDropDownWithExtra(struct cart *cart, struct trackDb *tdb,
-                                    int visibleChild,char *extra)
+                                    int visibleChild, struct slPair *events)
 // Displays hide/show dropdown for supertrack.
 // Set visibleChild to indicate whether 'show' should be grayed
 // out to indicate that no supertrack members are visible:
 //    0 to gray out (no visible children)
 //    1 don't gray out (there are visible children)
 //   -1 don't know (this function should determine)
 // If -1,i the subtracks field must be populated with the child trackDbs.
 // Returns false if not a supertrack
 {
 if (!tdbIsSuperTrack(tdb))
     return FALSE;
 
 // determine if supertrack is show/hide
 boolean show = FALSE;
 char *setting =
@@ -7891,31 +7964,31 @@
 if (show && (visibleChild == -1))
     {
     visibleChild = 0;
     struct slRef *childRef;
     for ( childRef = tdb->children; childRef != NULL; childRef = childRef->next)
         {
 	struct trackDb *cTdb = childRef->val;
         cTdb->visibility =
                 hTvFromString(cartUsualString(cart, cTdb->track,
                                       hStringFromTv(cTdb->visibility)));
         if (cTdb->visibility != tvHide)
             visibleChild = 1;
         }
     }
 hideShowDropDownWithClassAndExtra(tdb->track, show, (show && visibleChild) ?
-                                  "normalText visDD" : "hiddenText visDD",extra);
+                                  "normalText visDD" : "hiddenText visDD", events);
 return TRUE;
 }
 
 int tvConvertToNumericOrder(enum trackVisibility v)
 {
 return ((v) == tvFull   ? 4 : \
         (v) == tvPack   ? 3 : \
         (v) == tvSquish ? 2 : \
         (v) == tvDense  ? 1 : 0);
 }
 
 int tvCompare(enum trackVisibility a, enum trackVisibility b)
 /* enum trackVis isn't in numeric order by visibility, so compare
  * symbolically: */
 {