init
This commit is contained in:
26
static/config.yaml
Normal file
26
static/config.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
phone_rules:
|
||||
# Präfixe, die von Telefonnummern entfernt werden sollen
|
||||
# trim_prefixes:
|
||||
# - "0049"
|
||||
# - "+49"
|
||||
# - "49"
|
||||
# - "00"
|
||||
# - "0"
|
||||
|
||||
# Regeln zur Formatierung von Telefonnummern
|
||||
#format_rules:
|
||||
# "+49": "0" # Ersetzt internationale Vorwahl durch nationale
|
||||
# "00": "0" # Ersetzt internationale Vorwahl durch nationale
|
||||
|
||||
# Standard-Präfix für Nummern ohne Ländervorwahl
|
||||
#default_prefix: "+49"
|
||||
|
||||
# Ungültige Telefonnummer, die ignoriert werden soll
|
||||
invalid_number: "+49 5331 89"
|
||||
|
||||
# Konfiguration für Deutschland
|
||||
country:
|
||||
prefix: "49" # Ländervorwahl ohne '+' oder '00'
|
||||
area_codes:
|
||||
- "5331" # Vorwahl für Wolfenbüttel
|
||||
internal_prefix: "89" # Präfix für interne Nummern
|
169
static/css/main.css
Normal file
169
static/css/main.css
Normal file
@ -0,0 +1,169 @@
|
||||
:root {
|
||||
--background-body: #f5f5f5;
|
||||
--background: #e0e0e0;
|
||||
--text-main: #363636;
|
||||
--text-bright: #000;
|
||||
--links: #0076d1;
|
||||
--focus: rgba(0,150,191,0.67);
|
||||
--border: #dbdbdb;
|
||||
--code: #000;
|
||||
--animation-duration: 0.1s;
|
||||
--button-hover: #9b9b9b;
|
||||
--scrollbar-thumb: #aaa;
|
||||
--form-placeholder: #949494;
|
||||
--form-text: #1d1d1d;
|
||||
--table-header: #d0d0d0;
|
||||
--table-row-odd: #e8e8e8;
|
||||
--table-row-even: #f0f0f0;
|
||||
--sort-arrow: #666;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
line-height: 1.4;
|
||||
max-width: 80%;
|
||||
margin: 0 auto;
|
||||
padding: 0 10%;
|
||||
color: var(--text-main);
|
||||
background: var(--background-body);
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: var(--table-header);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
padding-right: 20px; /* Space for sort indicator */
|
||||
}
|
||||
|
||||
tr:nth-child(odd) {
|
||||
background-color: var(--table-row-odd);
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: var(--table-row-even);
|
||||
}
|
||||
|
||||
.header-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
flex-grow: 1;
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
#searchInput {
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
padding: 12px 20px;
|
||||
margin: 8px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Sort indicators */
|
||||
th::after {
|
||||
content: '\25B2'; /* Upward triangle */
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
opacity: 0.3;
|
||||
color: var(--sort-arrow);
|
||||
}
|
||||
|
||||
th.asc::after {
|
||||
content: '\25B2'; /* Upward triangle */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
th.desc::after {
|
||||
content: '\25BC'; /* Downward triangle */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
th:hover::after {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 20px;
|
||||
padding: 10px 0;
|
||||
background-color: var(--background);
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
.footer-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
a[href^="tel:"]:before {
|
||||
content: "📞 ";
|
||||
}
|
||||
|
||||
a[href^="mailto:"]:before {
|
||||
content: "📧 ";
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 768px) {
|
||||
body {
|
||||
max-width: 95%;
|
||||
padding: 0 2.5%;
|
||||
}
|
||||
|
||||
.header-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Accessibility improvements */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
107
static/css/print.css
Normal file
107
static/css/print.css
Normal file
@ -0,0 +1,107 @@
|
||||
@media print {
|
||||
@page {
|
||||
size: A4 landscape;
|
||||
margin: 0.8cm;
|
||||
@bottom-right {
|
||||
content: "Seite " counter(page) " von " counter(pages);
|
||||
font-size: 8pt;
|
||||
margin-right: -0.5cm;
|
||||
margin-bottom: -0.5cm;
|
||||
}
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 9pt;
|
||||
line-height: 1.3;
|
||||
background: none;
|
||||
color: #000;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.dynamic-table-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 1.5cm;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
max-width: 29.7cm; /* A4 landscape width minus margins */
|
||||
border-collapse: collapse;
|
||||
page-break-inside: auto;
|
||||
}
|
||||
|
||||
thead {
|
||||
display: table-header-group;
|
||||
}
|
||||
|
||||
tbody {
|
||||
display: table-row-group;
|
||||
}
|
||||
|
||||
tr {
|
||||
page-break-inside: avoid;
|
||||
page-break-after: auto;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 0.1cm;
|
||||
border: 1px solid #000;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f0f0f0 !important;
|
||||
-webkit-print-color-adjust: exact;
|
||||
color-adjust: exact;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* Hide elements not needed for print */
|
||||
#searchInput, .sort-icon::after, .header-container, footer, .print-date {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Column widths */
|
||||
th:nth-child(1), td:nth-child(1),
|
||||
th:nth-child(2), td:nth-child(2) {
|
||||
width: 15%;
|
||||
}
|
||||
th:nth-child(3), td:nth-child(3) {
|
||||
width: 20%;
|
||||
}
|
||||
th:nth-child(4), td:nth-child(4) {
|
||||
width: 10%;
|
||||
}
|
||||
th:nth-child(5), td:nth-child(5) {
|
||||
width: 25%;
|
||||
}
|
||||
th:nth-child(6), td:nth-child(6) {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
/* Remove top margin for the first page */
|
||||
.dynamic-table-container:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Ensure content on subsequent pages starts at the top */
|
||||
@page :not(:first) {
|
||||
margin-top: 0.8cm;
|
||||
}
|
||||
}
|
21
static/images/ccheart_black.svg
Normal file
21
static/images/ccheart_black.svg
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Creator: CorelDRAW 2018 (64-Bit Evaluation Version) -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="20.4978in" height="18.0152in" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
|
||||
viewBox="0 0 46296.26 40689.13"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.fil0 {fill:black}
|
||||
]]>
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Layer_x0020_1">
|
||||
<metadata id="CorelCorpID_0Corel-Layer"/>
|
||||
<g id="_1761831900240">
|
||||
<path class="fil0" d="M23204.91 7530.98c2944.63,-3188.84 6384.04,-4639.01 10366.38,-4077.21 4110.34,579.88 7609.97,3518.41 8854.17,7479.01 957.39,3047.58 559.96,6460.83 -722.09,9573.35 -1993.98,4840.97 -7886.31,11722.09 -18555.24,16532.85 -10668.92,-4810.76 -16561.25,-11691.88 -18555.24,-16532.85 -1282.05,-3112.52 -1679.47,-6525.77 -722.09,-9573.35 1244.19,-3960.6 4743.83,-6899.13 8854.17,-7479.01 3982.46,-561.82 7421.94,888.46 10366.64,4077.48 5.4,5.84 56.52,61.37 56.53,61.36 0.04,0.04 51.9,-56.36 56.79,-61.63zm-56.79 -4522.44c-6431.69,-5048.01 -16512.25,-3730.83 -21147.65,3855.94 -1539.08,2519.03 -2117.14,5447.75 -1981.3,8355.45 235.64,5043.59 2412.75,9452.27 5610.61,13256.78 4306.02,5122.9 10531.26,9148.59 17382.21,12152.72 9.53,4.18 88.63,38.56 136.13,59.69 41.66,-17.53 114.6,-50.41 137.01,-60.3 6815.65,-3004.07 13075.56,-7030.12 17381.33,-12152.12 3198.08,-3804.33 5374.97,-8213.2 5610.61,-13256.78 135.85,-2907.7 -442.2,-5836.43 -1981.3,-8355.45 -4635.4,-7586.77 -14715.95,-8903.95 -21147.65,-3855.94z"/>
|
||||
<path class="fil0" d="M22983.64 21630.19l-2928.01 -1451.38c-1017.73,1483.99 -1758.21,2488.33 -3897.08,1902.25 -1678.91,-460.05 -2175.85,-2300.18 -2239.67,-3843.76 -87.17,-2108.39 649.94,-4543.46 3168.15,-4413.24 1609.13,83.19 2294.75,1032.23 2661.15,1885.36l3196.99 -1638.9c-1574.75,-3004.31 -5265.13,-4026.05 -8393.32,-3188.81 -3328.66,890.9 -5014.61,3952.95 -4955.5,7255.23 60.43,3375.58 1680.8,6291.51 5161.55,7052.54 1697.16,371.06 3545.13,284.81 5116.74,-503.18 1216.27,-609.83 2567.56,-1786.86 3109,-3056.12zm13802.46 0l-2928.01 -1451.38c-1017.73,1483.99 -1758.21,2488.33 -3897.08,1902.25 -1678.91,-460.05 -2175.86,-2300.18 -2239.67,-3843.76 -87.18,-2108.39 649.94,-4543.46 3168.15,-4413.24 1609.13,83.19 2294.74,1032.23 2661.15,1885.36l3196.99 -1638.9c-1574.75,-3004.31 -5265.14,-4026.05 -8393.32,-3188.81 -3328.66,890.9 -5014.61,3952.95 -4955.5,7255.23 60.42,3375.58 1680.8,6291.51 5161.55,7052.54 1697.16,371.06 3545.13,284.81 5116.74,-503.18 1216.27,-609.83 2567.56,-1786.86 3109,-3056.12z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
BIN
static/images/ccheart_black.svg_.zip
Normal file
BIN
static/images/ccheart_black.svg_.zip
Normal file
Binary file not shown.
BIN
static/images/favicon-16x16.png
Normal file
BIN
static/images/favicon-16x16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 659 B |
BIN
static/images/favicon-32x32.png
Normal file
BIN
static/images/favicon-32x32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
static/images/favicon.ico
Normal file
BIN
static/images/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
static/images/favicon_io.zip
Normal file
BIN
static/images/favicon_io.zip
Normal file
Binary file not shown.
21
static/images/logo.svg
Normal file
21
static/images/logo.svg
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Creator: CorelDRAW 2018 (64-Bit Evaluation Version) -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="20.4978in" height="18.0152in" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
|
||||
viewBox="0 0 46296.26 40689.13"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.fil0 {fill:black}
|
||||
]]>
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Layer_x0020_1">
|
||||
<metadata id="CorelCorpID_0Corel-Layer"/>
|
||||
<g id="_1761831900240">
|
||||
<path class="fil0" d="M23204.91 7530.98c2944.63,-3188.84 6384.04,-4639.01 10366.38,-4077.21 4110.34,579.88 7609.97,3518.41 8854.17,7479.01 957.39,3047.58 559.96,6460.83 -722.09,9573.35 -1993.98,4840.97 -7886.31,11722.09 -18555.24,16532.85 -10668.92,-4810.76 -16561.25,-11691.88 -18555.24,-16532.85 -1282.05,-3112.52 -1679.47,-6525.77 -722.09,-9573.35 1244.19,-3960.6 4743.83,-6899.13 8854.17,-7479.01 3982.46,-561.82 7421.94,888.46 10366.64,4077.48 5.4,5.84 56.52,61.37 56.53,61.36 0.04,0.04 51.9,-56.36 56.79,-61.63zm-56.79 -4522.44c-6431.69,-5048.01 -16512.25,-3730.83 -21147.65,3855.94 -1539.08,2519.03 -2117.14,5447.75 -1981.3,8355.45 235.64,5043.59 2412.75,9452.27 5610.61,13256.78 4306.02,5122.9 10531.26,9148.59 17382.21,12152.72 9.53,4.18 88.63,38.56 136.13,59.69 41.66,-17.53 114.6,-50.41 137.01,-60.3 6815.65,-3004.07 13075.56,-7030.12 17381.33,-12152.12 3198.08,-3804.33 5374.97,-8213.2 5610.61,-13256.78 135.85,-2907.7 -442.2,-5836.43 -1981.3,-8355.45 -4635.4,-7586.77 -14715.95,-8903.95 -21147.65,-3855.94z"/>
|
||||
<path class="fil0" d="M22983.64 21630.19l-2928.01 -1451.38c-1017.73,1483.99 -1758.21,2488.33 -3897.08,1902.25 -1678.91,-460.05 -2175.85,-2300.18 -2239.67,-3843.76 -87.17,-2108.39 649.94,-4543.46 3168.15,-4413.24 1609.13,83.19 2294.75,1032.23 2661.15,1885.36l3196.99 -1638.9c-1574.75,-3004.31 -5265.13,-4026.05 -8393.32,-3188.81 -3328.66,890.9 -5014.61,3952.95 -4955.5,7255.23 60.43,3375.58 1680.8,6291.51 5161.55,7052.54 1697.16,371.06 3545.13,284.81 5116.74,-503.18 1216.27,-609.83 2567.56,-1786.86 3109,-3056.12zm13802.46 0l-2928.01 -1451.38c-1017.73,1483.99 -1758.21,2488.33 -3897.08,1902.25 -1678.91,-460.05 -2175.86,-2300.18 -2239.67,-3843.76 -87.18,-2108.39 649.94,-4543.46 3168.15,-4413.24 1609.13,83.19 2294.74,1032.23 2661.15,1885.36l3196.99 -1638.9c-1574.75,-3004.31 -5265.14,-4026.05 -8393.32,-3188.81 -3328.66,890.9 -5014.61,3952.95 -4955.5,7255.23 60.42,3375.58 1680.8,6291.51 5161.55,7052.54 1697.16,371.06 3545.13,284.81 5116.74,-503.18 1216.27,-609.83 2567.56,-1786.86 3109,-3056.12z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
67
static/index.html
Normal file
67
static/index.html
Normal file
@ -0,0 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/static/css/main.css">
|
||||
<link rel="stylesheet" href="/static/css/print.css">
|
||||
<title>☎ Telefonbuch ☎</title>
|
||||
<link rel="icon" type="image/x-icon" href="/static/images/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/static/images/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/static/images/favicon-16x16.png">
|
||||
<script src="/static/js/phonebook.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header-container">
|
||||
<img src="/static/images/logo.svg" alt="MKN Raute" class="logo">
|
||||
<h1>☎ Telefonbuch ☎</h1>
|
||||
<img src="/static/images/logo.svg" alt="MKN Raute" class="logo">
|
||||
</div>
|
||||
<input type="text" id="searchInput" onkeyup="searchTable()" placeholder="Suche nach Namen, Telefonnummern, Abteilung oder E-Mail...">
|
||||
<div class="dynamic-table-container">
|
||||
<table id="phonebookTable" class="dynamic-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="desc" aria-sort="descending">Nachname</th>
|
||||
<th class="min-width-cell">Vorname</th>
|
||||
<th class="min-width-cell dynamic-width">Telefonnummer</th>
|
||||
<th class="min-width-cell">Interne Rufnummer</th>
|
||||
<th class="min-width-cell">E-Mail</th>
|
||||
<th class="min-width-cell dynamic-width">Abteilung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .}}
|
||||
<tr>
|
||||
<td class="min-width-cell">{{.LastName}}</td>
|
||||
<td class="min-width-cell">{{.FirstName}}</td>
|
||||
<td class="min-width-cell dynamic-width">
|
||||
{{range .Phones}}
|
||||
({{.Type}}) <a href="tel:{{.PhoneNumber}}">{{.PhoneNumber}}</a><br>
|
||||
{{else}}-{{end}}
|
||||
</td>
|
||||
<td class="min-width-cell">{{if .InternalPhone}}<a href="tel:{{.InternalPhone}}">{{.InternalPhone}}</a>{{else}}-{{end}}</td>
|
||||
<td class="min-width-cell"><a href="mailto:{{.Email}}">{{.Email}}</a></td>
|
||||
<td class="min-width-cell dynamic-width">{{if .Department}}{{.Department}}{{else}}-{{end}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="print-date">Stand der Liste: <span id="currentDate"></span></div>
|
||||
<footer>
|
||||
<div class="footer-container">
|
||||
<div class="developer">
|
||||
Entwickelt von Steffen Probst
|
||||
</div>
|
||||
<div class="license">
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0.html" target="_blank">GPL-3.0 Lizenz</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
document.getElementById('currentDate').textContent = new Date().toLocaleDateString('de-DE');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
84
static/js/phonebook.js
Normal file
84
static/js/phonebook.js
Normal file
@ -0,0 +1,84 @@
|
||||
function searchTable() {
|
||||
const input = document.getElementById("searchInput");
|
||||
const filter = input.value; // Entfernung von .toUpperCase()
|
||||
const table = document.getElementById("phonebookTable");
|
||||
const tr = table.getElementsByTagName("tr");
|
||||
|
||||
for (let i = 1; i < tr.length; i++) {
|
||||
let visible = false;
|
||||
const td = tr[i].getElementsByTagName("td");
|
||||
for (let j = 0; j < td.length; j++) {
|
||||
if (td[j]) {
|
||||
const txtValue = td[j].textContent || td[j].innerText;
|
||||
if (txtValue.indexOf(filter) > -1) { // Entfernung von .toUpperCase()
|
||||
visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tr[i].style.display = visible ? "" : "none";
|
||||
}
|
||||
}
|
||||
|
||||
let lastSortedColumn = 0;
|
||||
let sortDirections = Array(document.querySelectorAll('#phonebookTable th').length).fill('asc');
|
||||
|
||||
// Array to keep track of the sort state for each column
|
||||
let sortStates = [];
|
||||
|
||||
function sortTable(n) {
|
||||
const table = document.getElementById("phonebookTable");
|
||||
const tbody = table.querySelector("tbody");
|
||||
const rows = Array.from(tbody.querySelectorAll("tr"));
|
||||
const th = table.querySelectorAll("th")[n];
|
||||
|
||||
// Initialize sort state if not set
|
||||
if (sortStates[n] === undefined) {
|
||||
sortStates[n] = 'asc';
|
||||
} else {
|
||||
// Toggle sort direction
|
||||
sortStates[n] = sortStates[n] === 'asc' ? 'desc' : 'asc';
|
||||
}
|
||||
|
||||
const isAsc = sortStates[n] === 'asc';
|
||||
|
||||
// Clear all sorting classes
|
||||
table.querySelectorAll("th").forEach(header => header.classList.remove("asc", "desc"));
|
||||
|
||||
// Set the appropriate class for the clicked header
|
||||
th.classList.add(isAsc ? "asc" : "desc");
|
||||
|
||||
rows.sort((a, b) => {
|
||||
let aValue = a.cells[n].textContent.trim();
|
||||
let bValue = b.cells[n].textContent.trim();
|
||||
|
||||
// Check if the values are numbers
|
||||
if (!isNaN(aValue) && !isNaN(bValue)) {
|
||||
return isAsc ? aValue - bValue : bValue - aValue;
|
||||
}
|
||||
|
||||
// For non-numeric values, use localeCompare for proper string comparison
|
||||
return isAsc ?
|
||||
aValue.localeCompare(bValue, undefined, {sensitivity: 'base'}) :
|
||||
bValue.localeCompare(aValue, undefined, {sensitivity: 'base'});
|
||||
});
|
||||
|
||||
// Remove all existing rows
|
||||
while (tbody.firstChild) {
|
||||
tbody.removeChild(tbody.firstChild);
|
||||
}
|
||||
|
||||
// Add sorted rows
|
||||
tbody.append(...rows);
|
||||
}
|
||||
|
||||
// Add event listeners to table headers and initial sort
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const headers = document.querySelectorAll('#phonebookTable th');
|
||||
headers.forEach((header, index) => {
|
||||
header.addEventListener('click', () => sortTable(index));
|
||||
});
|
||||
|
||||
// Initial sort on the first column (index 0) in ascending order
|
||||
sortTable(0);
|
||||
});
|
Reference in New Issue
Block a user