← Commit history

adom-table: colorby="col:field" - colour a column from the data

Ray ·aa39b4b9f0 ·1mo ago ·parent d730a8e
Converting adom/repo-ownership's hand-built frame to this widget quietly dropped its per-owner colour coding: every person had a coloured dot and name, and the widget rendered them all in the same grey. Ray noticed the table had gone black and white. I had listed the loss in my own notes and then never put it in front of him, which is the actual mistake. The colour comes from the ROW, not from a palette in here: colorby="owner:owner_color" paints the owner column using each row's owner_color. A widget cannot know a team's colours, and hardcoding them would drift from the other renderings - repo-ownership paints its svg export from the same map, so page and picture now cannot disagree. Only #rgb / #rrggbb is accepted; anything else is dropped rather than written into a style attribute, so a data file can never inject CSS through this.
1 file changed +21−1
widgets/adom-table.js+21−1
@@ -511,6 +511,12 @@  *   facet="owner"     add a dropdown that filters on one column's distinct values  *   sort="col"        initial sort column; prefix "-" for descending  *   dim="key:value"   render rows matching key=value at reduced opacity (e.g. archived)+ *   colorby="col:field"  colour the text (and a leading dot) of `col` using the CSS colour+ *                     carried in each row's `field`. The colour comes from the DATA, not from+ *                     a palette in here, so a page and its other renderings (an svg export,+ *                     say) cannot drift into disagreeing about who is which colour. Only+ *                     #rgb / #rrggbb is accepted; anything else is dropped rather than+ *                     written into a style attribute.  *   mark="style:key:re[; ...]"  colour cells whose value matches a pattern, e.g.  *                     mark="warn:rule:PR ONLY|ASK; accent:rule:^merge:"  *                     styles: warn (red) accent (blue) ok (green). The cell text is still@@ -546,7 +552,7 @@   }    window.AdomWidget.define('adom-table', {-    attributes: ['columns', 'heading', 'filter', 'facet', 'sort', 'dim', 'mark'],+    attributes: ['columns', 'heading', 'filter', 'facet', 'sort', 'dim', 'mark', 'colorby'],     loadingText: 'Loading table',     emptyText: 'No data supplied to <adom-table>',     css: [@@ -563,6 +569,8 @@       'th[aria-sort="descending"]:after{content:" \\2193"}',       'td{padding:5px 8px;border-bottom:1px solid var(--line2,#161b22);vertical-align:top}',       'tr.dim td{opacity:.45}',+      'td .cdot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:7px;',+      'vertical-align:baseline;flex:none}',       'td.mk-warn{color:var(--aw-red,#f85149);font-weight:600}',       'td.mk-accent{color:var(--aw-blue,#58a6ff);font-weight:600}',       'td.mk-ok{color:var(--aw-green,#3fb950);font-weight:600}',@@ -602,6 +610,13 @@       var dim = (el.getAttribute('dim') || '').split(':');       // A malformed rule is dropped, never thrown: one bad pattern in an attribute must not       // blank the whole table, which is the failure mode a guardrail page can least afford.+      // colorby="col:field" - never interpolate a raw cell value into a style attribute;+      // only a literal hex colour is allowed through.+      var cb = (el.getAttribute('colorby') || '').split(':');+      var colorCol = cb.length === 2 ? cb[0] : null, colorField = cb.length === 2 ? cb[1] : null;+      function safeColor(v) {+        return /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(String(v || '')) ? String(v) : null;+      }       var marks = (el.getAttribute('mark') || '').split(';').map(function (rule) {         var m = rule.trim().match(/^(warn|accent|ok):([^:]+):([\s\S]+)$/);         if (!m) return null;@@ -643,6 +658,11 @@                 cls = ' class="mk-' + marks[i].style + '"'; break;               }             }+            var col = (colorCol && c.key === colorCol) ? safeColor(r[colorField]) : null;+            if (col) {+              return '<td' + cls + ' style="color:' + col + '">' ++                     '<span class=cdot style="background:' + col + '"></span>' + esc(v) + '</td>';+            }             return '<td' + cls + '>' + esc(v) + '</td>';           }).join('') + '</tr>';         }).join('');