app
Component Widgets
Public Made by Adomby adom
Reusable component widgets for pinouts, thermal vias, molecule relationships, reviewed chip outlines and lightweight four-level LOD cache listings.
← Commit history
adom-table: add mark= (cell emphasis) and {key} interpolation in heading=
Both come from converting adom/repo-ownership's bespoke ownership frame to this widget,
and both are general rather than specific to that page.
mark="warn:rule:PR ONLY|ASK; accent:rule:^merge:" colours cells whose value matches a
pattern. The widget HTML-escapes every cell, which is right, but it also flattened that
page's red PR-ONLY stop-signal into ordinary grey text - on a guardrail page the one thing
a reader must not miss. mark adds a class only; the cell text stays escaped, and a
malformed rule is dropped rather than thrown so one bad pattern cannot blank a table.
heading="Regenerated {generated}" interpolates a top-level field of the data envelope, so
a table can carry a freshness stamp without its host frame fetching the file a second time
just to print one line. An unknown token is left visible rather than silently vanishing.
Verified in Chrome against the real widget frame: 288 rows, correct labels, 2 warn cells,
1 accent cell, 4 dimmed dormant rows.
1 file changed
+37−3
widgets/adom-table.js+37−3@@ -503,11 +503,21 @@ * * Attributes: * columns="a,b,c" restrict and order columns (overrides the data's own order)- * heading="..." caption above the table+ * heading="..." caption above the table; {key} interpolates a top-level field of the+ * data envelope, so heading="Regenerated {generated}" keeps a freshness+ * stamp on the page without the host frame having to fetch the file+ * itself just to print one line * filter show the filter box (default on; filter="off" hides it) * 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)+ * 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+ * HTML-escaped - only a class is added - so this cannot inject markup.+ * Added because escaping every cell flattened adom/repo-ownership's+ * "PR ONLY" stop-signal into ordinary grey text, which on a guardrail+ * page is the one thing the reader must not miss. */ (function () { 'use strict';@@ -536,7 +546,7 @@ } window.AdomWidget.define('adom-table', {- attributes: ['columns', 'heading', 'filter', 'facet', 'sort', 'dim'],+ attributes: ['columns', 'heading', 'filter', 'facet', 'sort', 'dim', 'mark'], loadingText: 'Loading table', emptyText: 'No data supplied to <adom-table>', css: [@@ -553,12 +563,23 @@ '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.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}', 'caption{text-align:left;font-weight:600;padding:0 0 8px}' ].join(''), render: function (data, ctx) { var n = normalise(data, this.getAttribute('columns')); this._n = n; var heading = this.getAttribute('heading');+ // Substitute BEFORE escaping, and only from the data envelope's own top-level scalars,+ // so an unknown {token} is left visible as written rather than silently vanishing.+ if (heading && data && !Array.isArray(data)) {+ heading = heading.replace(/\{(\w+)\}/g, function (m, k) {+ var v = data[k];+ return (v == null || typeof v === 'object') ? m : String(v);+ });+ } var showFilter = this.getAttribute('filter') !== 'off'; var facet = this.getAttribute('facet'); var bar = '';@@ -579,6 +600,13 @@ var q = root.querySelector('input'), sel = root.querySelector('select'); var count = root.querySelector('[data-count]'); 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.+ var marks = (el.getAttribute('mark') || '').split(';').map(function (rule) {+ var m = rule.trim().match(/^(warn|accent|ok):([^:]+):([\s\S]+)$/);+ if (!m) return null;+ try { return { style: m[1], key: m[2], re: new RegExp(m[3]) }; } catch (e) { return null; }+ }).filter(Boolean); var s = (el.getAttribute('sort') || '').replace(/^-/, ''); var dir = (el.getAttribute('sort') || '')[0] === '-' ? -1 : 1; @@ -609,7 +637,13 @@ tb.innerHTML = out.map(function (r) { var isDim = dim.length === 2 && String(r[dim[0]]) === dim[1]; return '<tr' + (isDim ? ' class=dim' : '') + '>' + n.cols.map(function (c) {- return '<td>' + esc(r[c.key] == null ? '' : r[c.key]) + '</td>';+ var v = r[c.key] == null ? '' : r[c.key], cls = '';+ for (var i = 0; i < marks.length; i++) {+ if (marks[i].key === c.key && marks[i].re.test(String(v))) {+ cls = ' class="mk-' + marks[i].style + '"'; break;+ }+ }+ return '<td' + cls + '>' + esc(v) + '</td>'; }).join('') + '</tr>'; }).join(''); if (count) count.textContent = out.length + ' of ' + n.rows.length;