diff --git a/resources/app/stylesheets/app.less b/resources/app/stylesheets/app.less index 5bbed15..477c330 100644 --- a/resources/app/stylesheets/app.less +++ b/resources/app/stylesheets/app.less @@ -251,6 +251,16 @@ table { th { padding: @text-padding-v @text-padding-h @text-padding-v + .3rem @text-padding-v; } + + th[data-sort=desc]::after { + content: "🠻"; + display: inline; + } + + th[data-sort=asc]::after { + content: "🠹"; + display: inline; + } } tbody { diff --git a/resources/public/js/scripts.js b/resources/public/js/scripts.js index 3adada4..6052112 100644 --- a/resources/public/js/scripts.js +++ b/resources/public/js/scripts.js @@ -46,15 +46,19 @@ document.addEventListener('DOMContentLoaded', function () { const pageSize = 40 const range = (x, y) => - x > y ? [] : [x, ...range(x + 1, y)]; + x > y ? [] : [x, ...range(x + 1, y)]; const visibleRows = page => - range(page * pageSize, (page + 1) * pageSize - 1) + range(page * pageSize, (page + 1) * pageSize - 1) const tblRows = tbl => - [...tbl.tBodies[0].rows] + [...tbl.tBodies[0].rows] const partial11 = (fn, arg1) => - function (arg2) { - fn(arg1, arg2) - } + function (arg2) { + fn(arg1, arg2) + } + const partial21 = (fn, arg1, arg2) => + function(arg3) { + fn(arg1, arg2, arg3) + } function toggleVisibilities(tbl, ixsToShow) { tblRows(tbl).forEach(function (row, ix) { @@ -222,9 +226,52 @@ document.addEventListener('DOMContentLoaded', function () { return ctx } + function flipSortDir(dir) { + return (dir || 'asc') == 'asc' ? 'desc' : 'asc' + } + + function clearSortAttributes(tbl) { + [...tbl.tHead.rows[0].cells] + .forEach(th => th.removeAttribute('data-sort')) + } + + function onSort(ctx, ix, event) { + const tbl = ctx.tbl + console.debug(tbl, ix, event) + + const sortDir = event.target.getAttribute('data-sort') || 'asc' + const sortMod = sortDir == 'asc' ? 1 : -1; + + const rows = tblRows(tbl) + const newTbody = document.createElement('tbody') + + rows.sort((row1, row2) => { + const val1 = row1.cells[ix].textContent + const val2 = row2.cells[ix].textContent + return sortMod * (val1 > val2 ? 1 + : val2 > val1 ? -1 + : 0); + }) + + rows.forEach(row => newTbody.appendChild(row)) + tbl.replaceChild(newTbody, tbl.tBodies[0]) + + clearSortAttributes(tbl) + event.target.setAttribute('data-sort', flipSortDir(sortDir)) + changePage(ctx, 0) + } + + function enableSorting(ctx) { + const ths = ctx.tbl.querySelectorAll('thead th') + ths.forEach((th, ix) => { + th.addEventListener('click', partial21(onSort, ctx, ix)) + }) + } + document.querySelectorAll('table').forEach(function (tbl) { const ctx = addToolbar(tbl) changePage(ctx, 0) + enableSorting(ctx) }) }