Skip to content

Commit

Permalink
Add table sorting
Browse files Browse the repository at this point in the history
Fixes #1120.
  • Loading branch information
zcorpan committed Dec 20, 2024
1 parent c0bf609 commit ac455a5
Showing 1 changed file with 80 additions and 8 deletions.
88 changes: 80 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@
td.more-info :any-link:not([title="Discussion"]) { padding: 0; text-decoration: none; }
td.link :any-link { padding: 0.25rem; }
th.concerns { width: 7em; }
th.position { width: 4em; }
th.position { width: 4.25em; }
th.topics { width: 3.5em; }
th.venues { width: 3.5em; }
th.venues { width: 4em; }
th.more-info { width: 9.5em; }
th, td { padding: 0.5rem; }
th.link { width: 3em; text-align: center; }
Expand All @@ -126,6 +126,14 @@
span.negative { background-color: var(--negative-bg-color); color: var(--negative-color); }
span.neutral { border-color: currentColor; }
span.defer, span.under-consideration { background-color: var(--defer-bg-color); color: var(--defer-color); }

/* sorting */
th.sortable { padding-top: 0; padding-bottom: 0; }
th button { appearance: none; padding: 0.25em 0; font: inherit; display: inline; background-color: transparent; border: none; cursor: default; user-select: none; }
th button::after { font-size: 0.8125em; content: " ▼"; opacity: 0.3; }
th button:hover::after, th button:focus::after { opacity: 0.6 }
th[aria-sort] button::after { opacity: 1; }
th[aria-sort="descending"] button::after { content: " ▲"; }
</style>

<script>
Expand Down Expand Up @@ -164,12 +172,12 @@ <h1><img src="asset/Mozilla-2024.svg" alt="Mozilla" width="240" height="50"> Sta
<thead>
<tr>
<th class="link">Link</th>
<th class="specification">Specification</th>
<th class="position">Position</th>
<th class="concerns">Concerns</th>
<th class="topics">Topics</th>
<th class="venues">Venues</th>
<th class="more-info">More info</th>
<th class="specification sortable">Specification</th>
<th class="position sortable">Position</th>
<th class="concerns sortable">Concerns</th>
<th class="topics sortable">Topics</th>
<th class="venues sortable">Venues</th>
<th class="more-info sortable">More info</th>
</tr>
</thead>
<tbody>
Expand Down Expand Up @@ -439,6 +447,69 @@ <h2>Legend</h2>
}
}

// Sorting
function setupSorting() {
const table = document.querySelector("table");

const headers = table.querySelectorAll("th");

headers.forEach((header, columnIndex) => {
if (!header.classList.contains('sortable')) {
return;
}
const button = document.createElement("button");
const isInitDescending = header.classList.contains("more-info");
const sortNumerically = isInitDescending;
button.setAttribute("aria-label", `Sort by ${header.textContent}`);
button.textContent = header.textContent;
header.setAttribute("aria-label", header.textContent);
header.textContent = '';
header.append(button);
if (isInitDescending) {
header.setAttribute("aria-sort", "descending");
}

button.onclick = () => {
const isAscending = header.getAttribute("aria-sort") !== "ascending";
sortTable(table, columnIndex, isAscending, sortNumerically);
headers.forEach((h) => h.removeAttribute("aria-sort"));
header.setAttribute("aria-sort", isAscending ? "ascending" : "descending");
};
});
}

function sortTable(table, columnIndex, ascending, sortNumerically) {
const tbody = table.querySelector("tbody");
const rows = Array.from(tbody.querySelectorAll("tr[id]")); // Don't include .details rows

rows.sort((rowA, rowB) => {
const cellA = rowA.cells[columnIndex];
const cellB = rowB.cells[columnIndex];
const a = cellA.firstChild instanceof HTMLImageElement ? cellA.firstChild.alt : cellA.textContent;
const b = cellB.firstChild instanceof HTMLImageElement ? cellB.firstChild.alt : cellB.textContent;

// Handle empty cells: Always place them at the end
if (a === "" || b === "") {
if (a === "" && b === "") {
return 0;
}
return a === "" ? 1 : -1;
}

return ascending
? a.localeCompare(b, undefined, { numeric: sortNumerically })
: b.localeCompare(a, undefined, { numeric: sortNumerically });
});

for (const row of rows) {
const detailsRow = row.nextElementSibling?.className === 'details' ? row.nextElementSibling : null;
tbody.append(row);
if (detailsRow) {
tbody.append(detailsRow);
}
}
}

async function init() {
const data = await getData();
const tbody = document.querySelector('tbody');
Expand All @@ -459,6 +530,7 @@ <h2>Legend</h2>
};

setupSearch();
setupSorting();

document.querySelector('.noscript').remove();
document.documentElement.classList.remove('loading');
Expand Down

0 comments on commit ac455a5

Please sign in to comment.