c67551cbe58354d143a5a3f0a363f3a4f9c1fdc7
braney
  Mon Apr 13 15:11:42 2026 -0700
Use Spectrum.js color picker for track color override in hui.c refs #20460

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 dd23bf845e3..de614c44f8f 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -6053,35 +6053,54 @@
 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;
 
 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",
+printf(" <input type='text' name='%s' id='%s_text' value='%s' size='8' />",
     varName, varName, colorValue);
-jsInlineF("document.getElementById('%s').addEventListener('input', function() {"
-    "document.querySelector('input[type=checkbox][name=\"%s\"]').checked=true;"
-    "});\n", varName, checkVar);
+printf("&nbsp;<input id='%s_picker' />\n", varName);
+jsInlineF(
+    "(function() {\n"
+    "  var textEl = document.getElementById('%s_text');\n"
+    "  var pickerEl = document.getElementById('%s_picker');\n"
+    "  var checkEl = document.querySelector('input[type=checkbox][name=\"%s\"]');\n"
+    "  $(pickerEl).spectrum({\n"
+    "    color: textEl.value,\n"
+    "    showPalette: true,\n"
+    "    showSelectionPalette: true,\n"
+    "    showInitial:true,\n"
+    "    showInput: true,\n"
+    "    preferredFormat: 'hex',\n"
+    "    hideAfterPaletteSelect: true,\n"
+    "    change: function(color) { textEl.value = color.toHexString(); checkEl.checked = true; }\n"
+    "  });\n"
+    "  textEl.addEventListener('change', function() {\n"
+    "    $(pickerEl).spectrum('set', textEl.value);\n"
+    "    checkEl.checked = true;\n"
+    "  });\n"
+    "})();\n",
+    varName, 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);