Listing tables on company, taxonomy and generic list pages get column headers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDRjtmAiNpo5mK5N3d7QwZ
54 lines
2.4 KiB
JavaScript
54 lines
2.4 KiB
JavaScript
// Tables with a header row can be re-ordered by clicking a column header.
|
|
(function () {
|
|
function headerRow(table) {
|
|
if (table.tHead && table.tHead.rows.length) return table.tHead.rows[table.tHead.rows.length - 1];
|
|
var first = table.rows[0];
|
|
if (!first || first.cells.length < 2) return null;
|
|
for (var i = 0; i < first.cells.length; i++) if (first.cells[i].tagName !== "TH") return null;
|
|
return first;
|
|
}
|
|
|
|
function value(row, col) {
|
|
var cell = row.cells[col];
|
|
return cell ? cell.textContent.trim() : "";
|
|
}
|
|
|
|
function number(text) {
|
|
return /^[-+]?[\d.,\s]*\d[\d.,\s]*\S{0,3}$/.test(text) ? parseFloat(text.replace(/[\s,]/g, "")) : NaN;
|
|
}
|
|
|
|
function sort(table, head, th) {
|
|
var col = th.cellIndex, down = th.getAttribute("aria-sort") === "ascending";
|
|
var rows = [];
|
|
for (var b = 0; b < table.tBodies.length; b++)
|
|
for (var r = 0; r < table.tBodies[b].rows.length; r++)
|
|
if (table.tBodies[b].rows[r] !== head) rows.push(table.tBodies[b].rows[r]);
|
|
if (!rows.length) return;
|
|
var numeric = rows.every(function (row) { var v = value(row, col); return !v || !isNaN(number(v)); });
|
|
var compare = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" }).compare;
|
|
rows.map(function (row, i) { return { row: row, text: value(row, col), i: i }; })
|
|
.sort(function (a, b) {
|
|
if (!a.text || !b.text) return a.text || b.text ? (a.text ? -1 : 1) : a.i - b.i; // empty cells last
|
|
var d = numeric ? number(a.text) - number(b.text) : compare(a.text, b.text);
|
|
return (down ? -d : d) || a.i - b.i;
|
|
})
|
|
.forEach(function (item) { rows[0].parentNode.appendChild(item.row); });
|
|
for (var i = 0; i < head.cells.length; i++) head.cells[i].removeAttribute("aria-sort");
|
|
th.setAttribute("aria-sort", down ? "descending" : "ascending");
|
|
}
|
|
|
|
document.querySelectorAll("table").forEach(function (table) {
|
|
var head = headerRow(table);
|
|
if (!head || table.querySelector("[rowspan], [colspan]")) return;
|
|
table.classList.add("sortable");
|
|
Array.prototype.forEach.call(head.cells, function (th) {
|
|
th.tabIndex = 0;
|
|
th.title = "Sort by this column";
|
|
th.addEventListener("click", function () { sort(table, head, th); });
|
|
th.addEventListener("keydown", function (e) {
|
|
if (e.key === "Enter" || e.key === " ") { e.preventDefault(); sort(table, head, th); }
|
|
});
|
|
});
|
|
});
|
|
})();
|