From 6cc872c18c65bfe4e794b67b8b8053fe5b950e72 Mon Sep 17 00:00:00 2001 From: Colin Rotherham Date: Mon, 27 Jan 2025 17:12:09 +0000 Subject: [PATCH] refactor(sortable table): remove jQuery --- .../sortable-table/sortable-table.js | 141 ++++++++++-------- 1 file changed, 78 insertions(+), 63 deletions(-) diff --git a/src/moj/components/sortable-table/sortable-table.js b/src/moj/components/sortable-table/sortable-table.js index a473841ce..87b159064 100755 --- a/src/moj/components/sortable-table/sortable-table.js +++ b/src/moj/components/sortable-table/sortable-table.js @@ -1,18 +1,23 @@ MOJFrontend.SortableTable = function (params) { - this.table = $(params.table) + this.table = params.table - if (this.table.data('moj-search-toggle-initialised')) { + if (this.table.dataset.mojSearchToggleInitialised) { return } - this.table.data('moj-search-toggle-initialised', true) + this.table.dataset.mojSearchToggleInitialised = 'true' + + this.head = this.table.querySelector('thead') + this.body = this.table.querySelector('tbody') + this.rows = this.body.querySelectorAll('tr') + this.headings = this.head.querySelectorAll('th') this.setupOptions(params) - this.body = this.table.find('tbody') this.createHeadingButtons() this.createStatusBox() this.initialiseSortedColumn() - this.table.on('click', 'th button', $.proxy(this, 'onSortButtonClick')) + + this.head.addEventListener('click', this.onbuttonClick.bind(this)) } MOJFrontend.SortableTable.prototype.setupOptions = function (params) { @@ -23,77 +28,97 @@ MOJFrontend.SortableTable.prototype.setupOptions = function (params) { } MOJFrontend.SortableTable.prototype.createHeadingButtons = function () { - const headings = this.table.find('thead th') - let heading - for (let i = 0; i < headings.length; i++) { - heading = $(headings[i]) - if (heading.attr('aria-sort')) { - this.createHeadingButton(heading, i) + const headings = Array.from(this.headings) + + for (const heading of headings) { + if (heading.hasAttribute('aria-sort')) { + this.createHeadingButton(heading) } } } -MOJFrontend.SortableTable.prototype.createHeadingButton = function ( - heading, - i -) { - const text = heading.text() - const button = $(``) - heading.text('') - heading.append(button) +MOJFrontend.SortableTable.prototype.createHeadingButton = function (heading) { + const headings = Array.from(this.headings) + const index = headings.indexOf(heading) + + const button = document.createElement('button') + + button.setAttribute('type', 'button') + button.setAttribute('data-index', index) + button.textContent = heading.textContent + + heading.textContent = '' + heading.appendChild(button) } MOJFrontend.SortableTable.prototype.createStatusBox = function () { - this.status = $( - '
' - ) - this.table.parent().append(this.status) + this.status = document.createElement('div') + + this.status.setAttribute('aria-atomic', 'true') + this.status.setAttribute('aria-live', 'polite') + this.status.setAttribute('class', 'govuk-visually-hidden') + this.status.setAttribute('role', 'status') + + this.table.insertAdjacentElement('afterend', this.status) } MOJFrontend.SortableTable.prototype.initialiseSortedColumn = function () { - const rows = this.getTableRowsArray() - - this.table - .find('th') - .filter('[aria-sort="ascending"], [aria-sort="descending"]') - .first() - .each((index, el) => { - const sortDirection = $(el).attr('aria-sort') - const columnNumber = $(el).find('button').attr('data-index') - const sortedRows = this.sort(rows, columnNumber, sortDirection) + for (const heading of Array.from(this.headings)) { + const button = heading.querySelector('button') + const sortDirection = heading.getAttribute('aria-sort') + + if (sortDirection === 'ascending' || sortDirection === 'descending') { + const columnNumber = button.getAttribute('data-index') + const sortedRows = this.sort(columnNumber, sortDirection) + this.addRows(sortedRows) - }) + } + } } -MOJFrontend.SortableTable.prototype.onSortButtonClick = function (e) { - const columnNumber = e.currentTarget.getAttribute('data-index') - const sortDirection = $(e.currentTarget).parent().attr('aria-sort') - let newSortDirection - if (sortDirection === 'none' || sortDirection === 'descending') { - newSortDirection = 'ascending' - } else { - newSortDirection = 'descending' +MOJFrontend.SortableTable.prototype.onbuttonClick = function (e) { + const button = e.target + + if ( + !button || + !button?.parentElement || + !(button instanceof HTMLButtonElement) + ) { + return } - const rows = this.getTableRowsArray() - const sortedRows = this.sort(rows, columnNumber, newSortDirection) + + const heading = button.parentElement + const columnNumber = button.getAttribute('data-index') + const sortDirection = heading.getAttribute('aria-sort') + + const newSortDirection = + sortDirection === 'none' || sortDirection === 'descending' + ? 'ascending' + : 'descending' + + const sortedRows = this.sort(columnNumber, newSortDirection) + this.addRows(sortedRows) this.removeButtonStates() - this.updateButtonState($(e.currentTarget), newSortDirection) + this.updateButtonState(button, heading, newSortDirection) } MOJFrontend.SortableTable.prototype.updateButtonState = function ( button, + heading, direction ) { - button.parent().attr('aria-sort', direction) + heading.setAttribute('aria-sort', direction) let message = this.statusMessage - message = message.replace(/%heading%/, button.text()) + message = message.replace(/%heading%/, button.textContent) message = message.replace(/%direction%/, this[`${direction}Text`]) - this.status.text(message) + this.status.textContent = message } MOJFrontend.SortableTable.prototype.removeButtonStates = function () { - this.table.find('thead th').attr('aria-sort', 'none') + for (const heading of Array.from(this.headings)) { + heading.setAttribute('aria-sort', 'none') + } } MOJFrontend.SortableTable.prototype.addRows = function (rows) { @@ -102,24 +127,14 @@ MOJFrontend.SortableTable.prototype.addRows = function (rows) { } } -MOJFrontend.SortableTable.prototype.getTableRowsArray = function () { - const rows = [] - const trs = this.body.find('tr') - for (let i = 0; i < trs.length; i++) { - rows.push(trs[i]) - } - return rows -} - MOJFrontend.SortableTable.prototype.sort = function ( - rows, columnNumber, sortDirection ) { - const newRows = rows.sort( + const newRows = Array.from(this.rows).sort( function (rowA, rowB) { - const tdA = $(rowA).find('td,th').eq(columnNumber) - const tdB = $(rowB).find('td,th').eq(columnNumber) + const tdA = rowA.querySelectorAll('td,th')[columnNumber] + const tdB = rowB.querySelectorAll('td,th')[columnNumber] const valueA = sortDirection === 'ascending' @@ -139,7 +154,7 @@ MOJFrontend.SortableTable.prototype.sort = function ( } MOJFrontend.SortableTable.prototype.getCellValue = function (cell) { - const val = cell.attr('data-sort-value') || cell.html() + const val = cell.getAttribute('data-sort-value') || cell.innerHTML const valAsNumber = Number(val) return isNaN(valAsNumber) ? val : valAsNumber