This commit is contained in:
parent
650f381148
commit
11fa3d1558
38 changed files with 819 additions and 148 deletions
167
public/sortable-table.js
Normal file
167
public/sortable-table.js
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* This content is licensed according to the W3C Software License at
|
||||
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
|
||||
*
|
||||
* File: sortable-table.js
|
||||
*
|
||||
* Desc: Adds sorting to a HTML data table that implements ARIA Authoring Practices
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
class SortableTable {
|
||||
constructor(tableNode) {
|
||||
this.tableNode = tableNode;
|
||||
|
||||
this.columnHeaders = tableNode.querySelectorAll("thead th");
|
||||
|
||||
this.sortColumns = [];
|
||||
|
||||
for (var i = 0; i < this.columnHeaders.length; i++) {
|
||||
var ch = this.columnHeaders[i];
|
||||
var buttonNode = ch.querySelector("button");
|
||||
if (buttonNode) {
|
||||
this.sortColumns.push(i);
|
||||
buttonNode.setAttribute("data-column-index", i);
|
||||
buttonNode.addEventListener("click", this.handleClick.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
this.optionCheckbox = document.querySelector(
|
||||
"input[type=\"checkbox\"][value=\"show-unsorted-icon\"]",
|
||||
);
|
||||
|
||||
if (this.optionCheckbox) {
|
||||
this.optionCheckbox.addEventListener(
|
||||
"change",
|
||||
this.handleOptionChange.bind(this),
|
||||
);
|
||||
if (this.optionCheckbox.checked) {
|
||||
this.tableNode.classList.add("show-unsorted-icon");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleClick(event) {
|
||||
var tgt = event.currentTarget;
|
||||
this.setColumnHeaderSort(tgt.getAttribute("data-column-index"));
|
||||
}
|
||||
|
||||
handleOptionChange(event) {
|
||||
var tgt = event.currentTarget;
|
||||
|
||||
if (tgt.checked) {
|
||||
this.tableNode.classList.add("show-unsorted-icon");
|
||||
} else {
|
||||
this.tableNode.classList.remove("show-unsorted-icon");
|
||||
}
|
||||
}
|
||||
|
||||
/* EVENT HANDLERS */
|
||||
|
||||
setColumnHeaderSort(columnIndex) {
|
||||
if (typeof columnIndex === "string") {
|
||||
columnIndex = parseInt(columnIndex);
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.columnHeaders.length; i++) {
|
||||
var ch = this.columnHeaders[i];
|
||||
var buttonNode = ch.querySelector("button");
|
||||
if (i === columnIndex) {
|
||||
var value = ch.getAttribute("aria-sort");
|
||||
if (value === "descending") {
|
||||
ch.setAttribute("aria-sort", "ascending");
|
||||
this.sortColumn(
|
||||
columnIndex,
|
||||
"ascending",
|
||||
ch.classList.contains("num"),
|
||||
);
|
||||
} else {
|
||||
ch.setAttribute("aria-sort", "descending");
|
||||
this.sortColumn(
|
||||
columnIndex,
|
||||
"descending",
|
||||
ch.classList.contains("num"),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (ch.hasAttribute("aria-sort") && buttonNode) {
|
||||
ch.removeAttribute("aria-sort");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sortColumn(columnIndex, sortValue, isNumber) {
|
||||
function compareValues(a, b) {
|
||||
if (sortValue === "ascending") {
|
||||
if (a.value === b.value) {
|
||||
return 0;
|
||||
} else {
|
||||
if (isNumber) {
|
||||
return a.value - b.value;
|
||||
} else {
|
||||
return a.value < b.value ? -1 : 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (a.value === b.value) {
|
||||
return 0;
|
||||
} else {
|
||||
if (isNumber) {
|
||||
return b.value - a.value;
|
||||
} else {
|
||||
return a.value > b.value ? -1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof isNumber !== "boolean") {
|
||||
isNumber = false;
|
||||
}
|
||||
|
||||
var tbodyNode = this.tableNode.querySelector("tbody");
|
||||
var rowNodes = [];
|
||||
var dataCells = [];
|
||||
|
||||
var rowNode = tbodyNode.firstElementChild;
|
||||
|
||||
var index = 0;
|
||||
while (rowNode) {
|
||||
rowNodes.push(rowNode);
|
||||
var rowCells = rowNode.querySelectorAll("th, td");
|
||||
var dataCell = rowCells[columnIndex];
|
||||
|
||||
var data = {};
|
||||
data.index = index;
|
||||
data.value = dataCell.textContent.toLowerCase().trim();
|
||||
if (isNumber) {
|
||||
data.value = parseFloat(data.value);
|
||||
}
|
||||
dataCells.push(data);
|
||||
rowNode = rowNode.nextElementSibling;
|
||||
index += 1;
|
||||
}
|
||||
|
||||
dataCells.sort(compareValues);
|
||||
|
||||
// remove rows
|
||||
while (tbodyNode.firstChild) {
|
||||
tbodyNode.removeChild(tbodyNode.lastChild);
|
||||
}
|
||||
|
||||
// add sorted rows
|
||||
for (var i = 0; i < dataCells.length; i += 1) {
|
||||
tbodyNode.appendChild(rowNodes[dataCells[i].index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize sortable table buttons
|
||||
window.addEventListener("load", function() {
|
||||
var sortableTables = document.querySelectorAll("table.sortable");
|
||||
for (var i = 0; i < sortableTables.length; i++) {
|
||||
new SortableTable(sortableTables[i]);
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue