Beispiel:JS-Anw-sortierbare-Tabellen.html

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche
<!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 = "";
					} // 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"); 
							tabletitel[sp].abbr = (tabletitel[sp].abbr==sort_info.asc)?sort_info.desc:sort_info.asc;
						}
						else { // Sortieren 
							if (sorted > -1) {
								sortbuttons[sorted].classList.remove("sortedasc");
								sortbuttons[sorted].classList.remove("sorteddesc");
								sortbuttons[sorted].classList.add("unsorted");
								tabletitel[sorted].abbr = "";
							}
							sortbuttons[sp].classList.remove("unsorted");
							sortbuttons[sp].classList.add("sortedasc");
							sorted = sp;
							tabletitel[sp].abbr = sort_info.asc;
							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&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000</td>
					</tr>
					<tr>
						<td>Zetta</td>
						<td>Z</td>
						<td>21</td>
						<td>Trilliarde</td>
						<td>1&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000</td>
					</tr>
					<tr>
						<td>Exa</td>
						<td>E</td>
						<td>18</td>
						<td>Trillion</td>
						<td>1&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000</td>
					</tr>
					<tr>
						<td>Peta</td>
						<td>P</td>
						<td>15</td>
						<td>Billiarde</td>
						<td>1&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000</td>
					</tr>
					<tr>
						<td>Tera</td>
						<td>T</td>
						<td>12</td>
						<td>Billion</td>
						<td>1&#8239;000&#8239;000&#8239;000&#8239;000</td>
					</tr>
					<tr>
						<td>Giga</td>
						<td>G</td>
						<td>9</td>
						<td>Miliarde</td>
						<td>1&#8239;000&#8239;000&#8239;000</td>
					</tr>
					<tr>
						<td>Mega</td>
						<td>M</td>
						<td>6</td>
						<td>Million</td>
						<td>1&#8239;000&#8239;000</td>
					</tr>
					<tr>
						<td>Kilo</td>
						<td>k</td>
						<td>3</td>
						<td>Tausend</td>
						<td>1&#8239;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&#8239;001</td>
					</tr>
					<tr>
						<td>Nano</td>
						<td>n</td>
						<td>-9</td>
						<td>Milliardstel</td>
						<td>0,000&#8239;000&#8239;001</td>
					</tr>
					<tr>
						<td>Piko</td>
						<td>p</td>
						<td>-12</td>
						<td>Billionstel</td>
						<td>0,000&#8239;000&#8239;000&#8239;001</td>
					</tr>
					<tr>
						<td>Femto</td>
						<td>f</td>
						<td>-15</td>
						<td>Billiardstel</td>
						<td>0,000&#8239;000&#8239;000&#8239;000&#8239;001</td>
					</tr>
					<tr>
						<td>Atto</td>
						<td>a</td>
						<td>-18</td>
						<td>Trillionstel</td>
						<td>0,000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;001</td>
					</tr>
					<tr>
						<td>Zepto</td>
						<td>z</td>
						<td>-21</td>
						<td>Trilliardstel</td>
						<td>0,000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;001</td>
					</tr>
					<tr>
						<td>Yokto</td>
						<td>y</td>
						<td>-24</td>
						<td>Quadrillionstel</td>
						<td>0,000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;000&#8239;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>