diff --git a/docs/documentation/components/table-sortable.html b/docs/documentation/components/table-sortable.html index ab95b40f..b661cf17 100644 --- a/docs/documentation/components/table-sortable.html +++ b/docs/documentation/components/table-sortable.html @@ -53,29 +53,54 @@

Sorteerbare tabel

Om inzicht te krijgen in de data kan het behulpzaam zijn om de gebruiker de data te - laten sorteren. Bijvoorbeeld op basis van op of aflopende data. + laten sorteren.

Benodigde stappen:

  1. - Voeg een button toe binnen de th om sorteerelemeent - klikbaar te maken. + Voeg een <button> toe binnen de <th> van elke sorteerbare kolom. +
  2. - Voeg binnen de knop een icoon toe indien gewenst. Voor meer informatie zie: - Icoonknoppen + Voeg binnen de knop van elke sorteerbare kolom een icoon toe. Voor meer informatie zie: + Iconen. +
  3. - Voeg abbr="" toe aan de <th> met een korte duidelijke - omschrijving om de gebruikerservaring te verbeteren voor gebruikers die gebruik - maken van een screenreader. + Voeg een toelichting over de sorteerknoppen toe aan de <caption>. Bijvoorbeeld: "kolomkoppen met knoppen zijn sorteerbaar". + +
  4. +
  5. + Voeg een abbr="" toe aan de <th> indien de tekst in de <th> erg lang is. +

Aandachtspunten

@@ -83,20 +108,23 @@

Aandachtspunten

Voorbeelden

Visueel voorbeeld:

- +
- - @@ -104,12 +132,20 @@

Visueel voorbeeld:

- - + + + + + + - - + + + + + +
- Tabelvoorbeeld met sorteerbare data: + Tabelvoorbeeld met sorteerbare data + , kolomkoppen met knoppen zijn sorteerbaar
- + - +
LoremIpsumJanineHinde
Henkde Vries
LoremIpsumMariaLin
JohnDoe
@@ -120,26 +156,43 @@

Html-voorbeeld:

<div class="horizontal-scroll"> <table> - <caption>Tabelvoorbeeld met sorteerbare data:</caption> + <caption> + Tabelvoorbeeld met sorteerbare data + <span class="visually-hidden">, kolomkoppen met knoppen zijn sorteerbaar</span> + </caption> <thead> <tr> - <th scope="col" abbr="Ascending data"> - <button title="Sort descending">Descending <span class="icon icon-ascending"></button> + <th scope="col"> + <button> + Voornaam + <span class="icon icon-sortable"></span> + </button> </th> - <th scope="col" abbr="Descending data"> - <button title="Sort ascending">Ascending <span class="icon icon-descending"></span></button> + <th scope="col" abbr="Achternaam"> + <button> + Achternaam (met tussenvoegsel) + <span class="icon icon-sortable"></span> + </button> </th> </tr> </thead> <tbody> <tr> - <td>Lorem</td> - <td>Ipsum</td> + <td>Janine</td> + <td>Hinde</td> + </tr> + <tr> + <td>Henk</td> + <td>de Vries</td> + </tr> + <tr> + <td>Maria</td> + <td>Lin</td> </tr> <tr> - <td>Lorem</td> - <td>Ipsum</td> + <td>John</td> + <td>Doe</td> </tr> </tbody> </table> diff --git a/docs/js/main.js b/docs/js/main.js index 846e5d40..e98c4aeb 100644 --- a/docs/js/main.js +++ b/docs/js/main.js @@ -5,3 +5,4 @@ import "@minvws/manon/form-help.js"; import "@minvws/manon/collapsible.js"; import "@minvws/manon/sidemenu.js"; import "@minvws/manon/language-selector.js"; +import "./sortable-table.js"; diff --git a/docs/js/sortable-table.js b/docs/js/sortable-table.js new file mode 100644 index 00000000..30d673ef --- /dev/null +++ b/docs/js/sortable-table.js @@ -0,0 +1,74 @@ +import { onDomReady } from "@minvws/manon/utils.js"; + +onDomReady(initSortableTable); + +function initSortableTable() { + var thead = document.querySelector("#sortable-table-example thead"); + var tbody = document.querySelector("#sortable-table-example tbody"); + if (!(thead instanceof HTMLTableSectionElement) || !(tbody instanceof HTMLTableSectionElement)) { + return; + } + thead.addEventListener("click", function(event) { + var button = event.target; + if (!(button instanceof HTMLButtonElement)) { + return; + } + var sortStatus = getSortStatus(thead); + var columnIndex = getColumnIndex(button.parentElement); + if (columnIndex === sortStatus.columnIndex) { + sortStatus.direction = sortStatus.direction === 'ascending' ? 'descending' : 'ascending'; + } else { + sortStatus.columnIndex = columnIndex; + sortStatus.direction = 'ascending'; + } + updateSortButtons(thead, sortStatus); + sortTableBody(tbody, sortStatus); + }); +} + +function getColumnIndex(th) { + return Array.prototype.indexOf.call(th.parentElement.children, th); +} + +function getSortStatus(thead) { + var sorted = thead.querySelector("[aria-sort]"); + if (!sorted) { + return { columnIndex: -1, direction: null }; + } + return { + columnIndex: getColumnIndex(sorted), + direction: sorted.getAttribute("aria-sort") + } +} + +function updateSortButtons(thead, sortStatus) { + var ths = thead.querySelectorAll("th"); + var sorted = thead.querySelector("th[aria-sort]"); + if (sorted && getColumnIndex(sorted) !== sortStatus.columnIndex) { + sorted.removeAttribute("aria-sort"); + var icon = sorted.querySelector(".icon"); + if (icon) { + icon.classList.remove("icon-sortable", "icon-ascending", "icon-descending"); + icon.classList.add("icon-sortable"); + } + } + var sort = ths[sortStatus.columnIndex]; + if (sort) { + sort.setAttribute("aria-sort", sortStatus.direction); + var icon = sort.querySelector(".icon"); + if (icon) { + icon.classList.remove("icon-sortable", "icon-ascending", "icon-descending"); + icon.classList.add("icon-" + sortStatus.direction); + } + } +} + +function sortTableBody(tbody, sortStatus) { + var cells = tbody.querySelectorAll("tr > td:nth-of-type(" + (sortStatus.columnIndex + 1) + ")"); + var comparator = sortStatus.direction === "ascending" + ? function (a, b) { return ('' + a.innerText).localeCompare(b.innerText); } + : function (a, b) { return ('' + b.innerText).localeCompare(a.innerText); }; + Array.prototype.slice.call(cells).sort(comparator).forEach(function (cell) { + tbody.appendChild(cell.parentNode); + }); +}