8593c40cb74ab6ee9f2318056626305d9d9544d3 braney Fri Apr 10 12:54:44 2026 -0700 Fix color picker from code review, refs #37329, refs #20460 - Replace Spectrum JS color picker with native HTML5 color input, matching existing Hi-C picker - Color saved on form submit, not immediately via AJAX - Add checkbox to enable/disable color override; auto-checks when user picks a color - Gate color picker behind hg.conf showColorPicker=on (off by default) - Only show picker for non-composite tracks that support it: bed, bigBed, genePred, bigGenePred, wig, bigWig, rmsk, interact, bigInteract, bigLolly, vcfTabix, vcf - Add colorFromCart calls to interact, lolly, vcf phased, and pgSnp drawing code - Revert hui.js Spectrum changes from cfeb4d4 (no longer needed) - Use htmlColorForCode()/htmlColorToRGB() from htmlColor.h instead of hand-rolled hex parsing in colorFromCart Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> diff --git src/hg/lib/hui.c src/hg/lib/hui.c index 3aa37e9c255..dd23bf845e3 100644 --- src/hg/lib/hui.c +++ src/hg/lib/hui.c @@ -6034,45 +6034,55 @@ { printf("<DIV><B>Show only transcripts with these accessions:</B> "); char varName[1024]; safef(varName, sizeof(varName), "%s.nameFilter", name); char *onlyTransStr = cartUsualString(cart, varName, ""); cgiMakeTextVar(varName, onlyTransStr, 60); printInfoIcon("Enter the primary accession of the track, so RefSeq IDs for the RefSeq track, Gencode IDs for the Gencode track, etc. Separate multiple accessions with commas."); puts("</DIV>\n\n"); } void colorTrackOption(struct cart *cart, char *name, struct trackDb *tdb) /* color picker for overriding track color */ { +if (!cfgOptionBooleanDefault("showColorPicker", FALSE)) + return; + char varName[1024]; safef(varName, sizeof(varName), "%s.colorOverride", name); char defaultColor[16]; safef(defaultColor, sizeof(defaultColor), "#%02x%02x%02x", tdb->colorR, tdb->colorG, tdb->colorB); char *rawCartValue = cartOptionalString(cart, varName); boolean hasOverride = (rawCartValue != NULL && rawCartValue[0] != '\0'); char *colorValue = hasOverride ? rawCartValue : defaultColor; -boolean hasItemRgb = !trackDbSettingOff(tdb, "itemRgb"); -printf(" <div id='colorPicker_%s'>", name); -jsInlineF("makeHighlightPicker('%s', document.getElementById('colorPicker_%s'), '%s', '<b>Change track color: </b> ', '%s', '%s', %s, %s);", - varName, name, name, colorValue, defaultColor, hasItemRgb ? "true" : "false", hasOverride ? "true" : "false"); -puts("</div>\n\n"); +char checkVar[1024]; +safef(checkVar, sizeof(checkVar), "%s.colorOverrideOn", name); +boolean isOn = cartUsualBoolean(cart, checkVar, hasOverride); + +printf("<br><b>Override track color:</b> "); +cgiMakeCheckBox(checkVar, isOn); +printf(" <input type='color' name='%s' id='%s' value='%s' />\n", + varName, varName, colorValue); +jsInlineF("document.getElementById('%s').addEventListener('input', function() {" + "document.querySelector('input[type=checkbox][name=\"%s\"]').checked=true;" + "});\n", varName, checkVar); +puts("\n"); } void wiggleScaleDropDownJavascript(char *name) /* print some js that deactivates the min/max range if autoscaling is activated */ { 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!=\"use vertical viewing range setting\")\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");