@stimulus-library/controllers
Version:
A library of useful controllers for Stimulus
110 lines (109 loc) • 4.3 kB
JavaScript
import { BaseController } from "@stimulus-library/utilities";
import { useCollectionEventListener } from "@stimulus-library/mixins";
export class TableSortController extends BaseController {
constructor() {
super(...arguments);
this._lastIndex = null;
this._reverse = false;
}
get _tableHead() {
const head = this.el.tHead;
if (head == null) {
throw new Error("Expected table to have a <thead> element.");
}
return head;
}
get _tableHeaders() {
const rows = this._tableHead.rows;
if (rows.length == 0) {
throw new Error("Expected table to have a <thead> element with at least one row.");
}
return Array.from(rows[0].cells);
}
get _tableBody() {
return this.el.tBodies[0];
}
get _tableRows() {
return Array.from(this._tableBody.rows);
}
connect() {
requestAnimationFrame(() => {
useCollectionEventListener(this, this._tableHeaders, "click", this.sort);
if (this.hasStartSortValue) {
this.sort(this._headerCellByIndex(this.startSortValue));
}
});
}
sort(event_or_target) {
let headerCell;
if (event_or_target instanceof Event) {
event_or_target.preventDefault();
headerCell = event_or_target.target;
}
else {
headerCell = event_or_target;
}
const headerCellIndex = this._indexOfHeaderCell(headerCell);
if (headerCell.dataset.sortable == "false") {
return;
}
if (headerCell.dataset.sort == "asc") {
this._reverse = true;
this._otherHeaderCells(headerCell).forEach(cell => delete cell.dataset.sort);
headerCell.dataset.sort = "desc";
this._sortByColumn(headerCellIndex);
}
else {
this._reverse = false;
this._otherHeaderCells(headerCell).forEach(cell => delete cell.dataset.sort);
headerCell.dataset.sort = "asc";
this._sortByColumn(headerCellIndex);
}
}
_indexOfHeaderCell(cell) {
return this._tableHeaders.indexOf(cell);
}
_headerCellByIndex(index) {
const cell = this._tableHeaders[index];
if (!cell) {
throw new Error(`No cell at index ${index}`);
}
return cell;
}
_otherHeaderCells(cell) {
return Array.from(this._tableHeaders).filter(otherCell => otherCell != cell);
}
_sortByColumn(index) {
const frag = document.createDocumentFragment();
const rows = this._tableRows;
const newRows = rows.sort((row, otherRow) => {
var _a, _b, _c, _d, _e, _f;
const cells = Array.from(row.cells);
const otherCells = Array.from(otherRow.cells);
const x = ((_b = (_a = cells[index]) === null || _a === void 0 ? void 0 : _a.dataset) === null || _b === void 0 ? void 0 : _b.sortValue) || ((_c = cells[index]) === null || _c === void 0 ? void 0 : _c.innerText) || "";
const y = ((_e = (_d = otherCells[index]) === null || _d === void 0 ? void 0 : _d.dataset) === null || _e === void 0 ? void 0 : _e.sortValue) || ((_f = otherCells[index]) === null || _f === void 0 ? void 0 : _f.innerText) || "";
const sortVal = x.localeCompare(y, "en", { sensitivity: "base", numeric: true, caseFirst: "upper" });
if (row.dataset.sortTop || otherRow.dataset.sortBottom) {
if (row.dataset.sortTop && otherRow.dataset.sortTop) {
return sortVal;
}
return -1;
}
if (row.dataset.sortBottom || otherRow.dataset.sortTop) {
if (row.dataset.sortBottom && otherRow.dataset.sortBottom) {
return sortVal;
}
return 1;
}
if (this._reverse) {
return sortVal > 0 ? -1 : 1;
}
return sortVal;
});
newRows.forEach(row => frag.appendChild(row));
this._tableBody.innerHTML = "";
this._tableBody.appendChild(frag);
this._lastIndex = index;
}
}
TableSortController.values = { startSort: Number };