Beispiel:JS-Anw-sortierbare-Tabellen.html
Aus SELFHTML-Wiki
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" media="screen" href="./Beispiel:SELFHTML-Beispiel-Grundlayout.css" />
<title>Beispiel: Tabellensortierter</title>
<style>
table { border:1px solid black; border-spacing:0px; border-collapse:collapse }
table td { border:1px solid black; border-spacing:0px; border-collapse:collapse;padding:3px }
table th { border:1px solid black; border-spacing:0px; border-collapse:collapse;padding:3px }
table h2 { margin:0 }
table caption { padding: 0.5em; text-align: left; font-weight: bold; }
table.is_sortable thead th { background-color: lightgray; }
</style>
<script>
( function() {
"use strict";
const tableSort = function(tab) {
// Kopfzeile vorbereiten
const initTableHead = function(sp) {
const sortbutton = document.createElement("button");
sortbutton.type = "button";
sortbutton.className = "sortbutton unsorted";
sortbutton.addEventListener("click", function(e) { if(e.detail <= 1) tsort(sp); }, false);
sortbutton.innerHTML = "<span class='visually-hidden'>" + sort_hint.asc + "</span>"
+ "<span class='visually-hidden'>" + sort_hint.desc + "</span>"
+ tabletitel[sp].innerHTML + sortsymbol;
tabletitel[sp].innerHTML = "<span class='visually-hidden'>" + tabletitel[sp].innerHTML + "</span>";
tabletitel[sp].appendChild(sortbutton);
sortbuttons[sp] = sortbutton;
tabletitel[sp].abbr = "";
tabletitel[sp].setAttribute("aria-sort", "none");
} // initTableHead
// Tabellenfelder auslesen und auf Zahl oder String prüfen
const getData = function (ele, col) {
const val = ele.textContent;
// Tausendertrenner entfernen, und Komma durch Punkt ersetzen
const tval = val.replace(/\s/g,"").replace(",", ".");
if (!isNaN(tval) && tval.search(/[0-9]/) != -1) return tval; // Zahl
sorttype[col] = "s"; // String
return val;
} // getData
// Vergleichsfunktion für Strings
const vglFkt_s = function(a, b) {
return a[sorted].localeCompare(b[sorted],"de");
} // vglFkt_s
// Vergleichsfunktion für Zahlen
const vglFkt_n = function(a, b) {
return a[sorted] - b[sorted];
} // vglFkt_n
// Der Sortierer
const tsort = function(sp) {
if (sp == sorted) { // Tabelle ist schon nach dieser Spalte sortiert, also nur Reihenfolge umdrehen
arr.reverse();
sortbuttons[sp].classList.toggle("sortedasc");
sortbuttons[sp].classList.toggle("sorteddesc");
if(tabletitel[sp].abbr==sort_info.asc) {
tabletitel[sp].abbr = sort_info.desc;
tabletitel[sp].setAttribute("aria-sort", "descending");
}
else {
tabletitel[sp].abbr = sort_info.asc;
tabletitel[sp].setAttribute("aria-sort", "ascending");
}
}
else { // Sortieren
if (sorted > -1) {
sortbuttons[sorted].classList.remove("sortedasc");
sortbuttons[sorted].classList.remove("sorteddesc");
sortbuttons[sorted].classList.add("unsorted");
tabletitel[sorted].abbr = "";
tabletitel[sorted].setAttribute("aria-sort", "none");
}
sortbuttons[sp].classList.remove("unsorted");
sortbuttons[sp].classList.add("sortedasc");
sorted = sp;
tabletitel[sp].abbr = sort_info.asc;
tabletitel[sp].setAttribute("aria-sort", "ascending");
if(sorttype[sp] == "n") arr.sort(vglFkt_n);
else arr.sort(vglFkt_s);
}
for (let r = 0; r < nrows; r++) tbdy.appendChild(arr[r][ncols]); // Sortierte Daten zurückschreiben
} // tsort
// Tabellenelemente ermitteln
const thead = tab.tHead;
let tr_in_thead, tabletitel;
if (thead) tr_in_thead = thead.rows;
if (tr_in_thead) tabletitel = tr_in_thead[0].cells;
if ( !(tabletitel && tabletitel.length > 0) ) {
console.error("Tabelle hat keinen Kopf und/oder keine Kopfzellen.");
return;
}
let tbdy = tab.tBodies;
if ( !(tbdy) ) {
console.error("Tabelle hat keinen tbody.");
return;
}
tbdy = tbdy[0];
const tr = tbdy.rows;
if ( !(tr && tr.length > 0) ) {
console.error("Tabelle hat keine Zeilen im tbody.");
return;
}
const nrows = tr.length,
ncols = tr[0].cells.length;
// Einige Variablen
let arr = [],
sorted = -1,
sortbuttons = [],
sorttype = [];
// Hinweistexte
const sort_info = {
asc: "Tabelle ist aufsteigend nach dieser Spalte sortiert",
desc: "Tabelle ist absteigend nach dieser Spalte sortiert",
};
const sort_hint = {
asc: "Sortiere aufsteigend nach ",
desc: "Sortiere absteigend nach ",
};
// Sortiersymbol
const sortsymbol = '<svg role="img" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 190 110"><path d="M0 0 L50 100 L100 0 Z" style="stroke:currentColor;fill:transparent;stroke-width:10;"/><path d="M80 100 L180 100 L130 0 Z" style="stroke:currentColor;fill:transparent;stroke-width:10;"/></svg>';
// Stylesheets für Button im TH
if(!document.getElementById("Stylesheet_tableSort")) {
const sortbuttonStyle = document.createElement('style');
const stylestring = '.sortbutton { width: 100%; height: 100%; border: none; background-color: transparent; font: inherit; color: inherit; text-align: inherit; padding: 0; cursor: pointer; } '
+ '.sortierbar thead th span.visually-hidden { position: absolute !important; clip: rect(1px, 1px, 1px, 1px) !important; padding: 0 !important; border: 0 !important; height: 1px !important; width: 1px !important; overflow: hidden !important; white-space: nowrap !important; } '
+ '.sortierbar caption span { font-weight: normal; font-size: .8em; } '
+ '.sortbutton svg { margin-left: .2em; height: .7em; } '
+ '.sortbutton.sortedasc svg path:last-of-type { fill: currentColor !important; } '
+ '.sortbutton.sorteddesc svg path:first-of-type { fill: currentColor!important; } '
+ '.sortbutton.sortedasc > span.visually-hidden:first-of-type { display: none; } '
+ '.sortbutton.sorteddesc > span.visually-hidden:last-of-type { display: none; } '
+ '.sortbutton.unsorted > span.visually-hidden:last-of-type { display: none; } ';
sortbuttonStyle.innerText = stylestring;
sortbuttonStyle.id = "Stylesheet_tableSort";
document.head.appendChild(sortbuttonStyle);
}
// Kopfzeile vorbereiten
for (let i = 0; i < tabletitel.length; i++) initTableHead(i);
// Array mit Info, wie Spalte zu sortieren ist, vorbelegen
for (let c = 0; c < ncols; c++) sorttype[c] = "n";
// Tabelleninhalt in ein Array kopieren
for (let r = 0; r < nrows; r++) {
arr[r] = [];
for (let c = 0, cc; c < ncols; c++) {
cc = getData(tr[r].cells[c],c);
arr[r][c] = cc;
// tr[r].cells[c].innerHTML += "<br>"+cc+"<br>"+sorttype[c]; // zum Debuggen
}
arr[r][ncols] = tr[r];
}
// Tabelle die Klasse "is_sortable" geben
tab.classList.add("is_sortable");
// An caption Hinweis anhängen
const caption = tab.caption;
if(caption) caption.innerHTML += "<br><span>Ein Klick auf die Spaltenüberschrift sortiert die Tabelle.</span>";
} // tableSort
// Alle Tabellen suchen, die sortiert werden sollen, und den Tabellensortierer starten.
const initTableSort = function() {
const sort_Table = document.querySelectorAll("table.sortierbar");
for (let i = 0; i < sort_Table.length; i++) new tableSort(sort_Table[i]);
} // initTable
if (window.addEventListener) window.addEventListener("DOMContentLoaded", initTableSort, false); // nicht im IE8
})();
</script>
</head>
<body>
<h1>Beispiel: Tabellensortierer</h1>
<main>
<h2>Zahlen mit Dezimalkomma</h2>
<table class="sortierbar">
<caption>Im SI definierte Dezimalpräfixe</caption>
<thead>
<tr>
<th>Vorsilbe</th>
<th>Kurzzeichen</th>
<th>Zehnerpotenz<br>(10 hoch)</th>
<th>Wert</th>
<th>Zahl</th>
</tr>
</thead>
<tbody>
<tr>
<td>Yotta</td>
<td>Y</td>
<td>24</td>
<td>Quadrillion</td>
<td>1 000 000 000 000 000 000 000 000</td>
</tr>
<tr>
<td>Zetta</td>
<td>Z</td>
<td>21</td>
<td>Trilliarde</td>
<td>1 000 000 000 000 000 000 000</td>
</tr>
<tr>
<td>Exa</td>
<td>E</td>
<td>18</td>
<td>Trillion</td>
<td>1 000 000 000 000 000 000</td>
</tr>
<tr>
<td>Peta</td>
<td>P</td>
<td>15</td>
<td>Billiarde</td>
<td>1 000 000 000 000 000</td>
</tr>
<tr>
<td>Tera</td>
<td>T</td>
<td>12</td>
<td>Billion</td>
<td>1 000 000 000 000</td>
</tr>
<tr>
<td>Giga</td>
<td>G</td>
<td>9</td>
<td>Miliarde</td>
<td>1 000 000 000</td>
</tr>
<tr>
<td>Mega</td>
<td>M</td>
<td>6</td>
<td>Million</td>
<td>1 000 000</td>
</tr>
<tr>
<td>Kilo</td>
<td>k</td>
<td>3</td>
<td>Tausend</td>
<td>1 000</td>
</tr>
<tr>
<td>Hekto*</td>
<td>h</td>
<td>2 </td>
<td>Hundert</td>
<td>100</td>
</tr>
<tr>
<td>Deka*</td>
<td>da</td>
<td>1</td>
<td>Zehn</td>
<td>10</td>
</tr>
<tr>
<td>-</td>
<td>-</td>
<td>0</td>
<td>Eins</td>
<td>1</td>
</tr>
<tr>
<td>Dezi*</td>
<td>d</td>
<td>-1</td>
<td>Zehntel</td>
<td>0,1</td>
</tr>
<tr>
<td>Zenti*</td>
<td>c</td>
<td>-2</td>
<td>Hundertstel</td>
<td>0,01</td>
</tr>
<tr>
<td>Milli</td>
<td>m</td>
<td>-3</td>
<td>Tausendstel</td>
<td>0,001</td>
</tr>
<tr>
<td>Mikro</td>
<td>μ</td>
<td>-6</td>
<td>Millionstel</td>
<td>0,000 001</td>
</tr>
<tr>
<td>Nano</td>
<td>n</td>
<td>-9</td>
<td>Milliardstel</td>
<td>0,000 000 001</td>
</tr>
<tr>
<td>Piko</td>
<td>p</td>
<td>-12</td>
<td>Billionstel</td>
<td>0,000 000 000 001</td>
</tr>
<tr>
<td>Femto</td>
<td>f</td>
<td>-15</td>
<td>Billiardstel</td>
<td>0,000 000 000 000 001</td>
</tr>
<tr>
<td>Atto</td>
<td>a</td>
<td>-18</td>
<td>Trillionstel</td>
<td>0,000 000 000 000 000 001</td>
</tr>
<tr>
<td>Zepto</td>
<td>z</td>
<td>-21</td>
<td>Trilliardstel</td>
<td>0,000 000 000 000 000 000 001</td>
</tr>
<tr>
<td>Yokto</td>
<td>y</td>
<td>-24</td>
<td>Quadrillionstel</td>
<td>0,000 000 000 000 000 000 000 001</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan=5>* Die zu Hekto(h), Deka(da), Dezi(d) und Zenti(c) gehörigen Vielfache sind keine Potenzen von 1000</td>
</tr>
</tfoot>
</table>
<cite><a href="https://de.wikipedia.org/wiki/Vors%C3%A4tze_f%C3%BCr_Ma%C3%9Feinheiten#SI-Pr%C3%A4fixe">Quelle</a></cite>
</main>
</body>
</html>