UNPKG

@stimulus-library/controllers

Version:

A library of useful controllers for Stimulus

110 lines (109 loc) 4.3 kB
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 };