2193 lines
118 KiB
PHP
2193 lines
118 KiB
PHP
<?php
|
|
|
|
ini_set('display_errors', 1);
|
|
ini_set('display_startup_errors', 1);
|
|
// Show all errors except deprecation notices (these come from vendor libraries
|
|
// that aren't yet typed for newer PHP versions). Long-term fix: update
|
|
// dependencies to versions compatible with your PHP runtime.
|
|
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
|
|
|
|
if (!isset($baseDir)) {
|
|
$baseDir = $_SERVER['DOCUMENT_ROOT'];
|
|
}
|
|
|
|
require_once $baseDir . '/../scripts/session_functions.php';
|
|
|
|
ini_wkvs_session(true);
|
|
|
|
$csrf_token = $_SESSION['csrf_token'] ?? '';
|
|
|
|
$access_granted_wkl = check_user_permission('wk_leitung', true) ?? false;
|
|
|
|
if (!$access_granted_wkl):
|
|
|
|
$logintype = 'wk_leitung';
|
|
|
|
require $baseDir . '/../scripts/login/login.php';
|
|
|
|
$logintype = '';
|
|
|
|
else:
|
|
$saveDir = '/../private-files/config-uploads/';
|
|
|
|
$uploadConfigDir = $baseDir . $saveDir;
|
|
|
|
$allConfigFiles = glob($uploadConfigDir . '*.json');
|
|
|
|
$presetUsed = false;
|
|
|
|
if (count($allConfigFiles) > 0) {
|
|
|
|
$timestamps = array_map(function ($file) {
|
|
$jsonContent = file_get_contents($file) ?? '';
|
|
|
|
$data = json_decode($jsonContent, true) ?? [];
|
|
|
|
return $data['added_timestamp'] ?? 0;
|
|
}, $allConfigFiles);
|
|
|
|
if (count($timestamps) > 0) {
|
|
array_multisort($timestamps, SORT_DESC, $allConfigFiles);
|
|
|
|
$json = json_decode(file_get_contents($allConfigFiles[0]), true) ?? [];
|
|
|
|
if (isset($json['metadata']['titel'])) {
|
|
$presetUsed = true;
|
|
$usedpreset = $json['metadata']['titel'];
|
|
}
|
|
}
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="de">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<link rel="icon" type="png" href="/intern/img/icon.png">
|
|
<title>WK-leitung - Einstellungen</title>
|
|
|
|
|
|
<link rel="stylesheet" href="/intern/css/einstellungen-ai.css">
|
|
<link rel="stylesheet" href="/intern/css/sidebar.css">
|
|
<script src="/intern/js/jquery/jquery-3.7.1.min.js"></script>
|
|
<script src="/intern/js/custom-msg-display.js"></script>
|
|
<link rel="stylesheet" href="/intern/css/custom-msg-display.css">
|
|
<script src="/intern/js/custom-select.js"></script>
|
|
<link rel="stylesheet" href="/intern/css/custom-select.css">
|
|
<link rel="stylesheet" href="/files/fonts/fonts.css">
|
|
<link rel="stylesheet" href="/intern/css/user.css">
|
|
<link rel="stylesheet" href="/externe-geraete/css/display.css">
|
|
|
|
<script src="/intern/js/ace/ace.js"></script>
|
|
|
|
<link rel="stylesheet" href="/intern/css/coloris/coloris.min.css" />
|
|
<script src="/intern/js/coloris/coloris.min.js"></script>
|
|
|
|
</head>
|
|
|
|
<body class="einstellungen">
|
|
<?php
|
|
|
|
|
|
require $baseDir . '/../scripts/db/db-functions.php';
|
|
require $baseDir . '/../scripts/db/db-tables.php';
|
|
|
|
require $baseDir . '/../scripts/websocket/ws-create-token.php';
|
|
|
|
|
|
$type = 'wkl';
|
|
|
|
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
|
|
|
|
if ($dbconnection['success'] !== true) {
|
|
echo 'Critical DB Error.';
|
|
exit;
|
|
}
|
|
|
|
$currentPage = 'einstellungen';
|
|
|
|
require $baseDir . '/../scripts/sidebar/sidebar.php';
|
|
|
|
$keysNeeded = [
|
|
'wkName',
|
|
'displayColourLogo',
|
|
'displayTextColourLogo',
|
|
'displayColorScoringBg',
|
|
'displayColorScoringBgSoft',
|
|
'displayColorScoringPanel',
|
|
'displayColorScoringPanelSoft',
|
|
'displayColorScoringBorderColor',
|
|
'displayColorScoringShadowColor',
|
|
'displayColorScoringPanelText',
|
|
'displayColorScoringPanelTextSoft',
|
|
'displayColorScoringPanelTextNoteL',
|
|
'displayColorScoringPanelTextNoteR',
|
|
'displayIdNoteL',
|
|
'displayIdNoteR',
|
|
'rechnungenName',
|
|
'rechnungenVorname',
|
|
'rechnungenStrasse',
|
|
'rechnungenHausnummer',
|
|
'rechnungenPostleitzahl',
|
|
'rechnungenOrt',
|
|
'rechnungenIBAN',
|
|
'linkWebseite',
|
|
'rechnungenPostversand',
|
|
'rechnungenPostversandKosten',
|
|
'rangNote',
|
|
'orderBestRang',
|
|
'displayCTextLogo',
|
|
'displayCTextWKName',
|
|
'personEinzahl',
|
|
'personMehrzahl',
|
|
'rankLivePublic',
|
|
'riegeneinteilungPublic'
|
|
];
|
|
|
|
$placeholders = implode(',', array_fill(0, count($keysNeeded), '?'));
|
|
|
|
$query = "SELECT `name`, `value` FROM $db_tabelle_var WHERE `name` IN ($placeholders)";
|
|
|
|
$stmt = $mysqli->prepare($query);
|
|
$params = str_repeat("s", count($keysNeeded));
|
|
$stmt->bind_param($params, ...$keysNeeded);
|
|
$stmt->execute();
|
|
$result = $stmt->get_result();
|
|
|
|
$config = [];
|
|
while ($row = $result->fetch_assoc()) {
|
|
$config[$row['name']] = $row['value'];
|
|
}
|
|
|
|
$wkName = $config['wkName'] ?? null;
|
|
$displayCTextDisplayLogo = $config['displayCTextLogo'] ?? null;
|
|
$displayCTextDisplayWKName = $config['displayCTextWKName'] ?? null;
|
|
$displayColor = $config['displayColourLogo'] ?? null;
|
|
$textColor = $config['displayTextColourLogo'] ?? null;
|
|
$displayColorScoringBg = $config['displayColorScoringBg'] ?? null;
|
|
$displayColorScoringBgSoft = $config['displayColorScoringBgSoft'] ?? null;
|
|
$displayColorScoringPanel = $config['displayColorScoringPanel'] ?? null;
|
|
$displayColorScoringPanelSoft = $config['displayColorScoringPanelSoft'] ?? null;
|
|
$displayColorScoringShadowColor = $config['displayColorScoringShadowColor'] ?? null;
|
|
$displayColorScoringBorderColor = $config['displayColorScoringBorderColor'] ?? null;
|
|
$displayColorScoringPanelText = $config['displayColorScoringPanelText'] ?? null;
|
|
$displayColorScoringPanelTextSoft = $config['displayColorScoringPanelTextSoft'] ?? null;
|
|
$displayColorScoringPanelTextNoteL = $config['displayColorScoringPanelTextNoteL'] ?? null;
|
|
$displayColorScoringPanelTextNoteR = $config['displayColorScoringPanelTextNoteR'] ?? null;
|
|
$displayIdNoteL = $config['displayIdNoteL'] ?? null;
|
|
$displayIdNoteR = $config['displayIdNoteR'] ?? null;
|
|
$rechnungenName = $config['rechnungenName'] ?? null;
|
|
$rechnungenVorname = $config['rechnungenVorname'] ?? null;
|
|
$rechnungenStrasse = $config['rechnungenStrasse'] ?? null;
|
|
$rechnungenHausnummer = $config['rechnungenHausnummer'] ?? null;
|
|
$rechnungenPostleitzahl = $config['rechnungenPostleitzahl'] ?? null;
|
|
$rechnungenOrt = $config['rechnungenOrt'] ?? null;
|
|
$rechnungenIBAN = $config['rechnungenIBAN'] ?? null;
|
|
$linkWebseite = $config['linkWebseite'] ?? null;
|
|
$rechnungenPostversand = $config['rechnungenPostversand'] ?? null;
|
|
$rechnungenPostversandKosten = $config['rechnungenPostversandKosten'] ?? null;
|
|
$rangNote = $config['rangNote'] ?? null;
|
|
$orderBestRang = $config['orderBestRang'] ?? null;
|
|
$personEinzahl = $config['personEinzahl'] ?? null;
|
|
$personMehrzahl = $config['personMehrzahl'] ?? null;
|
|
$rankLivePublic = $config['rankLivePublic'] ?? null;
|
|
$riegeneinteilungPublic = $config['riegeneinteilungPublic'] ?? null;
|
|
|
|
|
|
$stmt->close();
|
|
|
|
$geraete = db_select($mysqli, $db_tabelle_disziplinen, '*', '', [], 'start_index ASC');
|
|
$noten = db_select($mysqli, $db_tabelle_wertungstypen, '*', '', [], '`id` ASC');
|
|
|
|
$indexedNoten = array_column($noten, 'name', 'id');
|
|
|
|
$zeitplanTypes = db_select($mysqli, $db_tabelle_zeitplan_types, '*', '', [], '`id` ASC');
|
|
|
|
setlocale(LC_TIME, 'de_DE.UTF-8');
|
|
|
|
$WSaccesstype = "wk_leitung";
|
|
$WSaccess = "einstellungen";
|
|
$WSaccessPermission = "W";
|
|
|
|
?>
|
|
<section class="bgSection">
|
|
<?php sidebarRender('modal'); ?>
|
|
<div class="headerDivTrainer">
|
|
<div class="headingPanelDiv">
|
|
<h2 class="headingPanel">Einstellungen</h2>
|
|
</div>
|
|
<div class="menuWrapper">
|
|
<?php sidebarRender('button'); ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="dashboardGrid">
|
|
<div class="twoColumDiv">
|
|
<div>
|
|
<div class="containerDiv firstDiv">
|
|
<h3 class="containerHeading">Wettkampf:</h3>
|
|
<div class="settingsGrid">
|
|
<div class="settingsRowGroup">
|
|
<div class="settingsRow"><span>Wettkampfname: </span><input type="text"
|
|
class="ajaxInput" data-key="wkName" placeholder="Test WKVS"
|
|
value="<?= $wkName ?>"></div>
|
|
<div class="settingsRow"><span>Link Webseite: </span><input type="text"
|
|
class="ajaxInput" data-key="linkWebseite" placeholder="www.wkvs.ch"
|
|
value="<?= $linkWebseite ?>"></div>
|
|
</div>
|
|
<div class="settingsRowGroup">
|
|
<div class="settingsRow"><span>Bezeichnung eines Wettkampfteilnehmenden: </span><input
|
|
type="text" class="ajaxInput" data-key="personEinzahl"
|
|
placeholder="Bsp. Turnerin oder Athlet" value="<?= $personEinzahl ?>"></div>
|
|
<div class="settingsRow"><span>Bezeichnung mehrer Wettkampfteilnehmenden: </span><input
|
|
type="text" class="ajaxInput" data-key="personMehrzahl"
|
|
placeholder="Bsp. Turnerinnen oder Athleten" value="<?= $personMehrzahl ?>">
|
|
</div>
|
|
</div>
|
|
<div class="settingsRowGroup">
|
|
<div class="settingsRow">
|
|
<span>Riegeneinteilung öffentlich einsehbar: </span>
|
|
<label class="checkbox">
|
|
<input type="checkbox" class="ajaxInputCheckbox"
|
|
data-key="riegeneinteilungPublic" <?= ($riegeneinteilungPublic) ? 'checked' : '' ?>>
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</div>
|
|
<div class="settingsRow">
|
|
<span>RankLive öffentlich einsehbar: </span>
|
|
<label class="checkbox">
|
|
<input type="checkbox" class="ajaxInputCheckbox"
|
|
data-key="rankLivePublic" <?= ($rankLivePublic) ? 'checked' : '' ?>>
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="containerDiv secondDiv">
|
|
<h3 class="containerHeading">Daten für Rechnungserstellung: <span class="light">(Schweiz)</span>
|
|
</h3>
|
|
<div class="settingsGrid">
|
|
<div class="settingsRowGroup">
|
|
<div class="settingsRow"><span>Name: </span><input type="text" class="ajaxInput"
|
|
data-key="rechnungenName" placeholder="Mustermann"
|
|
value="<?= $rechnungenName ?>"></div>
|
|
<div class="settingsRow"><span>Vorname: </span><input type="text" class="ajaxInput"
|
|
data-key="rechnungenVorname" placeholder="Max"
|
|
value="<?= $rechnungenVorname ?>"></div>
|
|
<div class="settingsRow"><span>Strasse: </span><input type="text" class="ajaxInput"
|
|
data-key="rechnungenStrasse" placeholder="Musterstrasse"
|
|
value="<?= $rechnungenStrasse ?>"></div>
|
|
<div class="settingsRow"><span>Hausnummer: </span><input type="text" class="ajaxInput"
|
|
data-key="rechnungenHausnummer" placeholder="123"
|
|
value="<?= $rechnungenHausnummer ?>"></div>
|
|
<div class="settingsRow"><span>Postleitzahl: </span><input type="text" class="ajaxInput"
|
|
data-key="rechnungenPostleitzahl" placeholder="4000"
|
|
value="<?= $rechnungenPostleitzahl ?>"></div>
|
|
<div class="settingsRow"><span>Ort: </span><input type="text" class="ajaxInput"
|
|
data-key="rechnungenOrt" placeholder="Basel" value="<?= $rechnungenOrt ?>">
|
|
</div>
|
|
<div class="settingsRow"><span>IBAN: </span><input type="text" class="ajaxInput"
|
|
data-key="rechnungenIBAN" placeholder="CH44 3199 9123 0008 8901 2"
|
|
value="<?= $rechnungenIBAN ?>"></div>
|
|
<div class="settingsRow">
|
|
<span>Postversand erlauben: </span>
|
|
<label class="checkbox">
|
|
<input type="checkbox" class="ajaxInputCheckbox"
|
|
data-key="rechnungenPostversand" <?= ($rechnungenPostversand) ? 'checked' : '' ?>>
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</div>
|
|
<div class="settingsRow"><span>Zusatzkosten Postversand: </span><input type="nubmer"
|
|
class="ajaxInput" data-key="rechnungenPostversandKosten" placeholder="0.00"
|
|
value="<?= $rechnungenPostversandKosten ?>"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="containerDiv">
|
|
<div>
|
|
<h3 class="containerHeading">Alters- und Leistungsklassen</h3>
|
|
|
|
<table id="programmTable" class="wkvsTabelle trainer">
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Bezeichnung</th>
|
|
<th>Aktiv</th>
|
|
<th>Startgebüren</th>
|
|
<th>Index</th>
|
|
<th>Löschen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php
|
|
$programme = db_select($mysqli, $db_tabelle_kategorien, "*", '', [], 'order_index ASC');
|
|
if (isset($programme) && is_array($programme) && count($programme) > 0) {
|
|
foreach ($programme as $entry) {
|
|
$aktiv = ($entry['aktiv'] == 1) ? 'checked' : ''; ?>
|
|
<tr>
|
|
<td><?= (int) $entry['id'] ?></td>
|
|
<td><?= htmlspecialchars($entry['programm']) ?></td>
|
|
<td>
|
|
<label class="checkbox">
|
|
<input type="checkbox" class="anmeldencheckbox inputAktivProgramm ajaxProgramm"
|
|
<?= $aktiv ?> data-field-id="<?= (int) $entry['id'] ?>" data-type="aktiv" />
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</td>
|
|
<td><label class="tdDiv labelStartgebuerenWraper">CHF <input type="number"
|
|
class="inputPreisProgramm ajaxProgramm"
|
|
data-field-id="<?= (int) $entry['id'] ?>"
|
|
value="<?= floatval($entry['preis']) ?>" data-type="preis"></label></td>
|
|
<td>
|
|
<div class="tdDiv"><input type="number" class="inputOrderIndexProgramm ajaxProgramm"
|
|
data-field-id="<?= (int) $entry['id'] ?>"
|
|
value="<?= (int) $entry['order_index'] ?>" data-type="order_index"></div>
|
|
</td>
|
|
<td>
|
|
<button class="deleteProgramm deleteBtn" data-id="<?= (int) $entry['id'] ?>">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22"
|
|
viewBox="0 0 24 24" fill="none" stroke="var(--ui-danger)"
|
|
stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="3 6 5 6 21 6"></polyline>
|
|
<path
|
|
d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2">
|
|
</path>
|
|
<line x1="10" y1="11" x2="10" y2="17"></line>
|
|
<line x1="14" y1="11" x2="14" y2="17"></line>
|
|
</svg>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<?php }
|
|
}
|
|
?>
|
|
<tr class="addRow">
|
|
<td></td>
|
|
<td><input type="text" required placeholder="Bezeichnung" class="inputProgrammName">
|
|
</td>
|
|
<td colspan="4"><button type="submit" class="blackBtn neuProgrammBtn">Neue Alters- /
|
|
Leistungsklasse
|
|
erstellen</button></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="containerDiv">
|
|
<h3 class="containerHeading">Bilder:</h3>
|
|
<div class="containerImages">
|
|
<div><label for="imgKampfrichter"><span>Kampfrichter</span><input type="file"
|
|
data-key="Kampfrichter" accept="image/png, image/jpeg" id="imgKampfrichter"><img
|
|
src="/intern/img/login/bgKampfrichter.webp"></label></div>
|
|
<div><label for="imgTrainer"><span>Trainer</span><input type="file" data-key="Trainer"
|
|
accept="image/png, image/jpeg" id="imgTrainer"><img
|
|
src="/intern/img/login/bgTrainer.webp"></label></div>
|
|
<div><label for="imgWk_leitung"><span>WK-Leitung</span><input type="file" data-key="Wk_leitung"
|
|
accept="image/png, image/jpeg" id="imgWk_leitung"><img
|
|
src="/intern/img/login/bgWk_leitung.webp"></label></div>
|
|
<div><label for="imgOtl"><span>Einmal Login</span><input type="file" data-key="Otl"
|
|
accept="image/png, image/jpeg" id="imgOtl"><img
|
|
src="/intern/img/login/bgOtl.webp"></label>
|
|
</div>
|
|
<div><label for="imgIcon"><span>Icon Webseite</span><input type="file" data-key="icon"
|
|
accept="image/png, image/jpeg" id="imgIcon"><img src="/intern/img/icon.png"></label>
|
|
</div>
|
|
<div><label for="imgLogo_normal"><span>Logo</span><input type="file" data-key="logo-normal"
|
|
accept="image/png, image/jpeg" id="imgLogo_normal"><img
|
|
src="/intern/img/logo-normal.png"></label></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="containerDiv">
|
|
<h3 class="containerHeading">Einstellungen Display:</h3>
|
|
<div class="oneOneGridDisplay">
|
|
<div class="displayDiv displayDivSettings">
|
|
<?php /* Akuell noch nicht Custom
|
|
<div class="errorws">
|
|
<svg xmlns="http://www.w3.org/2000/svg" id="errorSvg" viewBox="0 0 800 200">
|
|
<defs>
|
|
<filter id="a" x="-50%" y="-50%" width="200%" height="200%">
|
|
<feGaussianBlur stdDeviation="8" result="blur"/>
|
|
<feMerge>
|
|
<feMergeNode in="blur"/>
|
|
<feMergeNode in="SourceGraphic"/>
|
|
</feMerge>
|
|
</filter>
|
|
<linearGradient id="myLinearGradient" x1="0%" y1="5%" x2="100%" y2="0%">
|
|
<stop offset="0%" stop-color="#22c55e00" />
|
|
<stop offset="100%" stop-color="#22c55e90" />
|
|
</linearGradient>
|
|
</defs>
|
|
<path d="M150 100h200m100 0h200" id="errorLine" opacity=".3" stroke="#3b82f6" stroke-width="4" stroke-dasharray="10,15" stroke-linecap="round"/>
|
|
<g transform="translate(150 100)">
|
|
<circle r="45" fill="#1e293b" stroke="#3b82f6" stroke-width="3"/>
|
|
<circle r="45" fill="#1e293b" stroke="#3b82f6" stroke-width="3"/>
|
|
|
|
<rect x="-30" y="-19" width="60" height="38" rx="2" fill="#334155"/>
|
|
<rect x="-28" y="-17" width="56" height="10" rx="2" fill="#555"/>
|
|
<rect x="-28" y="-5" width="56" height="10" rx="2" fill="#555"/>
|
|
<rect x="-28" y="7" width="56" height="10" rx="2" fill="#555"/>
|
|
<text x="-26" y="-11" fill="#94a3b8" font-size="4" font-family="monospace" letter-spacing="0.5">Test WKVS</text>
|
|
|
|
<text x="-26" y="-1" fill="#94a3b8" font-size="2.5" font-family="monospace" letter-spacing="0">WKVS,</text>
|
|
<text x="-26" y="2.5" fill="#94a3b8" font-size="2" font-family="monospace" letter-spacing="0">EP</text>
|
|
<rect x="0" y="-5" width="28" rx="2" height="10" fill="url(#myLinearGradient)" />
|
|
|
|
<text x="10" y="1" fill="#22c55e" font-size="4" font-family="monospace" letter-spacing="0.5">START</text>
|
|
|
|
<text x="-26" y="13" fill="#94a3b8" font-size="4" font-family="monospace" letter-spacing="0.5">D 1.40</text>
|
|
<text x="15" y="13" fill="#94a3b8" font-size="4" font-family="monospace" letter-spacing="0.5">9.40</text>
|
|
|
|
|
|
|
|
<text y="70" text-anchor="middle" fill="#94a3b8" font-size="12" font-family="monospace" letter-spacing="1.5">Anzeige</text>
|
|
</g>
|
|
<g transform="translate(650 100)">
|
|
<circle r="45" fill="#1e293b" stroke="#3b82f6" stroke-width="3"/>
|
|
<rect x="-18" y="-15" width="36" height="10" rx="2" fill="#334155"/>
|
|
<rect x="-18" y="2" width="36" height="10" rx="2" fill="#334155"/>
|
|
<circle cx="10" cy="-10" r="2" fill="#10b981"/>
|
|
<circle cx="10" cy="7" r="2" fill="#10b981"/>
|
|
<text y="70" text-anchor="middle" fill="#94a3b8" font-size="12" font-family="monospace" letter-spacing="1.5">WKVS Server</text>
|
|
</g>
|
|
<path fill="#f43f5e" class="opacity0gsap" opacity=".4" d="m-14.142-70.71 5.657 5.656-5.657 5.657-5.657-5.657z" transform="translate(400 100)"/>
|
|
<path fill="#f43f5e" class="opacity0gsap" opacity=".4" d="m42.67 39.74 5.869 1.247-1.248 5.87-5.868-1.248z" transform="translate(400 100)"/>
|
|
<path fill="#3b82f6" class="opacity0gsap" opacity=".4" d="m-50.98 28.301 8.66 5-5 8.66-8.66-5z" transform="translate(400 100)"/>
|
|
<g filter="url(#a)" transform="translate(400 100)">
|
|
<path id="cross"
|
|
d="M-30,-30 L30,30 M30,-30 L-30,30"
|
|
stroke="#f43f5e"
|
|
stroke-width="8"
|
|
stroke-linecap="round"
|
|
fill="none"/>
|
|
</g>
|
|
</svg>
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" id="okSvg" viewBox="0 0 800 200" style="display: none">
|
|
<defs>
|
|
<filter id="a" x="-50%" y="-50%" width="200%" height="200%">
|
|
<feGaussianBlur stdDeviation="8" result="blur"/>
|
|
<feMerge>
|
|
<feMergeNode in="blur"/>
|
|
<feMergeNode in="SourceGraphic"/>
|
|
</feMerge>
|
|
</filter>
|
|
<linearGradient id="myLinearGradient" x1="0%" y1="5%" x2="100%" y2="0%">
|
|
<stop offset="0%" stop-color="#22c55e00" />
|
|
<stop offset="100%" stop-color="#22c55e90" />
|
|
</linearGradient>
|
|
</defs>
|
|
<path d="M150 100 h500" opacity=".3" stroke="#3b82f6" stroke-width="4" stroke-dasharray="10, 15" stroke-linecap="round"/>
|
|
<g transform="translate(150 100)">
|
|
<circle r="45" fill="#1e293b" stroke="#3b82f6" stroke-width="3"/>
|
|
<circle r="45" fill="#1e293b" stroke="#3b82f6" stroke-width="3"/>
|
|
|
|
<rect x="-30" y="-19" width="60" height="38" rx="2" fill="#334155"/>
|
|
<rect x="-28" y="-17" width="56" height="10" rx="2" fill="#555"/>
|
|
<rect x="-28" y="-5" width="56" height="10" rx="2" fill="#555"/>
|
|
<rect x="-28" y="7" width="56" height="10" rx="2" fill="#555"/>
|
|
<text x="-26" y="-11" fill="#94a3b8" font-size="4" font-family="monospace" letter-spacing="0.5">Test WKVS</text>
|
|
|
|
<text x="-26" y="-1" fill="#94a3b8" font-size="2.5" font-family="monospace" letter-spacing="0">WKVS,</text>
|
|
<text x="-26" y="2.5" fill="#94a3b8" font-size="2" font-family="monospace" letter-spacing="0">EP</text>
|
|
<rect x="0" y="-5" width="28" rx="2" height="10" fill="url(#myLinearGradient)" />
|
|
|
|
<text x="10" y="1" fill="#22c55e" font-size="4" font-family="monospace" letter-spacing="0.5">START</text>
|
|
|
|
<text x="-26" y="13" fill="#94a3b8" font-size="4" font-family="monospace" letter-spacing="0.5">D 1.40</text>
|
|
<text x="15" y="13" fill="#94a3b8" font-size="4" font-family="monospace" letter-spacing="0.5">9.40</text>
|
|
|
|
|
|
|
|
<text y="70" text-anchor="middle" fill="#94a3b8" font-size="12" font-family="monospace" letter-spacing="1.5">Anzeige</text>
|
|
</g>
|
|
<g transform="translate(650 100)">
|
|
<circle r="45" fill="#1e293b" stroke="#3b82f6" stroke-width="3"/>
|
|
<rect x="-18" y="-15" width="36" height="10" rx="2" fill="#334155"/>
|
|
<rect x="-18" y="2" width="36" height="10" rx="2" fill="#334155"/>
|
|
<circle cx="10" cy="-10" r="2" fill="#10b981"/>
|
|
<circle cx="10" cy="7" r="2" fill="#10b981"/>
|
|
<text y="70" text-anchor="middle" fill="#94a3b8" font-size="12" font-family="monospace" letter-spacing="1.5">WKVS Server</text>
|
|
</g>
|
|
|
|
<g filter="url(#a)" transform="translate(400 100)">
|
|
<path d="m-15-60 15 30 m30-60 -30 60" stroke="#0e0" stroke-width="8" stroke-linecap="round"/>
|
|
</g>
|
|
</svg>
|
|
|
|
|
|
<div class="divErrorTextWs">
|
|
<p class="errortext">Keine WebSocket Verbindung</p>
|
|
<p class="errortextSmall">Versuche Verbindung... (Versuch <span id="counterTries"></span> / <span id="counterMaxTries"></span>)</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="noWsConnection">
|
|
<div class="rotator">
|
|
<p>Keine WebSocket Verbindung, Syncronisation via FETCH</p>
|
|
</div>
|
|
</div> */ ?>
|
|
|
|
<div class="logobg hidden">
|
|
<img id="jsImgLogo" class="logoimg <?= (!$displayCTextDisplayLogo) ? 'cTextHidden' : '' ?>"
|
|
src="/intern/img/logo-normal.png">
|
|
<p class="logotext <?= (!$displayCTextDisplayWKName) ? 'cTextHidden' : '' ?>"><?= $wkName ?>
|
|
</p>
|
|
<p class="logoctext">Benutzerdefinierter Text</p>
|
|
</div>
|
|
|
|
<div class="pagediv">
|
|
<div class="display-row row1">
|
|
<p class="row1text normalText">Vorname Nachname</p>
|
|
</div>
|
|
<div class="display-row row2">
|
|
<div class="row2text">
|
|
<p class="row2_1text sds">Verein</p>
|
|
<p class="row2_2text normalText">Programm</p>
|
|
</div>
|
|
<div class="start_div">
|
|
<p class="start_text normalText" data-type="stop">START</p>
|
|
</div>
|
|
</div>
|
|
<div class="display-row row3">
|
|
<p class="row3_1text">NOTE L</p>
|
|
<p class="row3_2text">NOTE R</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settingsGrid optionsDisplay">
|
|
<div class="settingsRowGroup settingsRowGroupDisplay" data-type="ctext">
|
|
<div class="subSettingsRowGroup">
|
|
<div class="settingsRow"><span>Hintergrundfarbe Displays: </span><input type="text"
|
|
data-coloris class="ajaxInput" data-key="displayColourLogo"
|
|
value="<?= $displayColor ?>"></div>
|
|
<div class="settingsRow"><span>Textfarbe Displays: </span><input type="text"
|
|
data-coloris class="ajaxInput" data-key="displayTextColourLogo"
|
|
value="<?= $textColor ?>"></div>
|
|
</div>
|
|
<div class="subSettingsRowGroup">
|
|
<div class="settingsRow">
|
|
<span>Logo anzeigen: </span>
|
|
<label class="checkbox">
|
|
<input type="checkbox" class="ajaxInputCheckbox" data-key="displayCTextLogo"
|
|
<?= ($displayCTextDisplayLogo) ? 'checked' : '' ?>>
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</div>
|
|
<div class="settingsRow">
|
|
<span>Wettkampfname anzeigen: </span>
|
|
<label class="checkbox">
|
|
<input type="checkbox" class="ajaxInputCheckbox" data-key="displayCTextWKName"
|
|
<?= ($displayCTextDisplayWKName) ? 'checked' : '' ?>>
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="subSettingsRowGroup">
|
|
<button class="btn" onclick="switchMode('scoring')">Scoring</button>
|
|
<button class="btn" onclick="switchMode('logo')">Logo</button>
|
|
</div>
|
|
</div>
|
|
<div class="settingsRowGroup settingsRowGroupDisplay" data-type="logo">
|
|
<div class="subSettingsRowGroup">
|
|
<div class="settingsRow"><span>Hintergrundfarbe Displays: </span><input type="text"
|
|
data-coloris class="ajaxInput" data-key="displayColourLogo"
|
|
value="<?= $displayColor ?>"></div>
|
|
<div class="settingsRow"><span>Textfarbe Displays: </span><input type="text"
|
|
data-coloris class="ajaxInput" data-key="displayTextColourLogo"
|
|
value="<?= $textColor ?>"></div>
|
|
</div>
|
|
<div class="subSettingsRowGroup">
|
|
<button class="btn" onclick="switchMode('ctext')">Benutzerdefinierter Text</button>
|
|
<button class="btn" onclick="switchMode('logo')">Logo</button>
|
|
</div>
|
|
</div>
|
|
<div class="settingsRowGroup settingsRowGroupDisplay" data-type="scoring">
|
|
<div class="subSettingsRowGroup">
|
|
<button class="btn" onclick="switchStart()">Start Wechseln</button>
|
|
</div>
|
|
<div class="subSettingsRowGroup">
|
|
<div class="settingsRow"><span>Hintergrundfarbe Displays primär: </span><input
|
|
type="text" data-coloris class="ajaxInput" data-key="displayColorScoringBg"
|
|
data-assoc-el="pagediv" value="<?= $displayColorScoringBg ?>"></div>
|
|
<div class="settingsRow"><span>Hintergrundfarbe Displays sekundär: </span><input
|
|
type="text" data-coloris class="ajaxInput" data-key="displayColorScoringBgSoft"
|
|
data-assoc-el="pagediv" value="<?= $displayColorScoringBgSoft ?>"></div>
|
|
</div>
|
|
<div class="subSettingsRowGroup">
|
|
<div class="settingsRow"><span>Schattenfarben: </span><input type="text" data-coloris
|
|
class="ajaxInput" data-key="displayColorScoringShadowColor"
|
|
data-assoc-el="pagediv" value="<?= $displayColorScoringShadowColor ?>"></div>
|
|
<div class="settingsRow"><span>Farbe Linie unter Kacheln: </span><input type="text"
|
|
data-coloris class="ajaxInput" data-key="displayColorScoringBorderColor"
|
|
data-assoc-el="pagediv" value="<?= $displayColorScoringBorderColor ?>"></div>
|
|
<div class="settingsRow"><span>Hintergrundfarbe Kacheln Displays primär: </span><input
|
|
type="text" data-coloris class="ajaxInput" data-key="displayColorScoringPanel"
|
|
data-assoc-el="display-row" value="<?= $displayColorScoringPanel ?>"></div>
|
|
<div class="settingsRow"><span>Hintergrundfarbe Kacheln Displays sekundär: </span><input
|
|
type="text" data-coloris class="ajaxInput"
|
|
data-key="displayColorScoringPanelSoft" data-assoc-el="display-row"
|
|
value="<?= $displayColorScoringPanelSoft ?>"></div>
|
|
</div>
|
|
<div class="subSettingsRowGroup">
|
|
<div class="settingsRow"><span>Textfarbe Displays: </span><input type="text"
|
|
data-coloris class="ajaxInput" data-key="displayColorScoringPanelText"
|
|
data-assoc-el="normalText" value="<?= $displayColorScoringPanelText ?>"></div>
|
|
<div class="settingsRow"><span>Sekundäre Textfarbe Displays: </span><input type="text"
|
|
data-coloris class="ajaxInput" data-key="displayColorScoringPanelTextSoft"
|
|
data-assoc-el="sds" value="<?= $displayColorScoringPanelTextSoft ?>"></div>
|
|
<div class="settingsRow"><span>Textfarbe Note Links Displays: </span><input type="text"
|
|
data-coloris class="ajaxInput" data-key="displayColorScoringPanelTextNoteL"
|
|
data-assoc-el="row3_1text" value="<?= $displayColorScoringPanelTextNoteL ?>">
|
|
</div>
|
|
<div class="settingsRow"><span>Textfarbe Note Rechts Displays: </span><input type="text"
|
|
data-coloris class="ajaxInput" data-key="displayColorScoringPanelTextNoteR"
|
|
data-assoc-el="row3_2text" value="<?= $displayColorScoringPanelTextNoteR ?>">
|
|
</div>
|
|
</div>
|
|
<div class="subSettingsRowGroup">
|
|
<div class="settingsRow"><span>Id Note links auf Display: </span><input type="number"
|
|
class="ajaxInput" data-key="displayIdNoteL" placeholder="10"
|
|
value="<?= $displayIdNoteL ?>"></div>
|
|
<div class="settingsRow"><span>Id Note rechts auf Display: </span><input type="number"
|
|
class="ajaxInput" data-key="displayIdNoteR" placeholder="10"
|
|
value="<?= $displayIdNoteR ?>"></div>
|
|
</div>
|
|
<div class="subSettingsRowGroup">
|
|
<button class="btn" onclick="switchMode('logo')">Logo</button>
|
|
<button class="btn" onclick="switchMode('ctext')">Benutzerdefinierter Text</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="settingsGrid">
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="containerDiv">
|
|
<h3 class="containerHeading">Zeittypen: <span class="light">(auf Riegeneinteilung)</span></h3>
|
|
<div class="tableWraperOverflowY">
|
|
<table class="wkvsTabelle trainer" id="zeitplanTable">
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Name</th>
|
|
<th>Endzeit</th>
|
|
<th>Index</th>
|
|
<th>Löschen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($zeitplanTypes as $t): ?>
|
|
<tr data-id="<?= $t['id'] ?>">
|
|
<td><?= $t['id'] ?></td>
|
|
<td><input type="text" class="ajaxZeitplan" data-field="name"
|
|
value="<?= htmlspecialchars($t['name'] ?? '') ?>"
|
|
style="width: 100%; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td>
|
|
<label class="checkbox">
|
|
<input type="checkbox" class="ajaxZeitplan" data-field="has_endtime"
|
|
<?= $t['has_endtime'] ? 'checked' : '' ?>>
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</td>
|
|
<td><input type="number" class="ajaxZeitplan" data-field="index"
|
|
value="<?= htmlspecialchars($t['display_index'] ?? '') ?>"
|
|
style="width: 100%; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td>
|
|
<button class="deleteZeitplanType deleteBtn" data-id="<?= $t['id'] ?>"
|
|
style="border:none; background:none; cursor:pointer;">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"
|
|
viewBox="0 0 24 24" fill="none" stroke="#b91c1c" stroke-width="2"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="3 6 5 6 21 6"></polyline>
|
|
<path
|
|
d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2">
|
|
</path>
|
|
</svg>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<tr class="addRow">
|
|
<td></td>
|
|
<td><input type="text" id="newZeitplanName" placeholder="Neuer Zeittyp..."
|
|
style="width: 100%; padding: 6px; border: 1px solid #777; border-radius: 4px;">
|
|
</td>
|
|
<td>
|
|
<label class="checkbox">
|
|
<input type="checkbox" id="newZeitplanHasEndtime">
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</td>
|
|
<td><input type="number" id="newZeitplanIndex" placeholder="Index"
|
|
style="width: 100%; padding: 6px; border: 1px solid #777; border-radius: 4px;">
|
|
</td>
|
|
<td><button id="addZeitplanTypeBtn"
|
|
style="padding: 6px 12px; background: var(--bg-top); color: #fff; border: none; border-radius: 4px; cursor: pointer;">Hinzufügen</button>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="containerDiv">
|
|
<h3 class="containerHeading">WKVS Presets:</h3>
|
|
<p>WKVS Presets sind Dateien, welche eine einfache Konfiguration von WKVS ermöglichen. In diesen Presets
|
|
werden folgende Dinge gespeichert:</p>
|
|
<ul>
|
|
<li>Disziplinen</li>
|
|
<li>Notenkonfigurationen</li>
|
|
<li>Zeittypen</li>
|
|
<li>Alters- und Leistungsklassen</li>
|
|
</ul>
|
|
<p>WKVS Presets können für manche Sportarten unter <a
|
|
href="https://wkvs.ch/downloads/configs">https://wkvs.ch/downloads/configs</a> heruntergeladen
|
|
werden.<br>
|
|
Diese Version von WKVS unterstützt nur WKVS Presets der Version 1.0.0</p>
|
|
|
|
<?php if ($presetUsed): ?>
|
|
<p><b>Aktuell benutztes Preset:</b> <?= $usedpreset ?></p>
|
|
<?php endif; ?>
|
|
|
|
<div class="gridWKVSConfig">
|
|
<div>
|
|
<h3>Preset importieren:</h3>
|
|
<div class="importWKVSConfigDiv">
|
|
<input type="file" id="importPresetInput" accept=".json">
|
|
<button for="importPresetInput" class="btn newBtn" id="submitWKVSConfig">Preset importieren
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 74 74" height="34"
|
|
width="34">
|
|
<circle stroke-width="3" stroke="currentColor" r="35.5" cy="37" cx="37"></circle>
|
|
<path fill="currentColor"
|
|
d="M38.5 49C38.5 49.8284 37.8284 50.5 37 50.5C36.1716 50.5 35.5 49.8284 35.5 49H38.5ZM35.9393 24.9393C36.5251 24.3536 37.4749 24.3536 38.0607 24.9393L47.6066 34.4853C48.1924 35.0711 48.1924 36.0208 47.6066 36.6066C47.0208 37.1924 46.0711 37.1924 45.4853 36.6066L37 28.1213L28.5147 36.6066C27.9289 37.1924 26.9792 37.1924 26.3934 36.6066C25.8076 36.0208 25.8076 35.0711 26.3934 34.4853L35.9393 24.9393ZM35.5 49L35.5 26H38.5L38.5 49H35.5Z">
|
|
</path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<p><b>Hinweis:</b> Ein Import überschreibt die aktuelle Konfiguration.</p>
|
|
</div>
|
|
<div>
|
|
<h3>Aktuelle Einstellungen als Preset exportieren:</h3>
|
|
<button for="importPresetInput" class="btn newBtn" onclick="downloadPresetConfig()">Preset
|
|
exportieren
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 74 74" height="34"
|
|
width="34">
|
|
<circle stroke-width="3" stroke="currentColor" r="35.5" cy="37" cx="37"></circle>
|
|
<path fill="currentColor"
|
|
d="M35.5 25C35.5 24.1716 36.1716 23.5 37 23.5C37.8284 23.5 38.5 24.1716 38.5 25H35.5ZM38.0607 49.0607C37.4749 49.6464 36.5251 49.6464 35.9393 49.0607L26.3934 39.5147C25.8076 38.9289 25.8076 37.9792 26.3934 37.3934C26.9792 36.8076 27.9289 36.8076 28.5147 37.3934L37 45.8787L45.4853 37.3934C46.0711 36.8076 47.0208 36.8076 47.6066 37.3934C48.1924 37.9792 48.1924 38.9289 47.6066 39.5147L38.0607 49.0607ZM38.5 25L38.5 48H35.5L35.5 25H38.5Z">
|
|
</path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="containerDiv">
|
|
<h3 class="containerHeading">Disziplinen: <span class="light">(fortgeschrittene Einstellungen)</span>
|
|
</h3>
|
|
<div class="tableWraperOverflowY">
|
|
<table class="wkvsTabelle trainer" id="geraeteTable">
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Name</th>
|
|
<th>Startindex</th>
|
|
<th>Farbe Kampfrichter</th>
|
|
<th>Audiofiles</th>
|
|
<th>Max Dauer Audiofiles</th>
|
|
<th>Löschen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($geraete as $g): ?>
|
|
<tr data-id="<?= $g['id'] ?>">
|
|
<td><?= $g['id'] ?></td>
|
|
<td><input type="text" class="ajaxGeraete" data-field="name"
|
|
value="<?= htmlspecialchars($g['name'] ?? '') ?>"
|
|
style="width: 100%; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td><input type="number" class="ajaxGeraete" data-field="start_index"
|
|
value="<?= $g['start_index'] ?>"
|
|
style="width: 80px; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td><input type="text" data-coloris class="ajaxGeraete" data-field="color_kampfrichter"
|
|
value="<?= $g['color_kampfrichter'] ?>"
|
|
style="width: 100px; height: 35px; padding: 2px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td>
|
|
<label class="checkbox">
|
|
<input type="checkbox" class="ajaxGeraete" data-field="audiofile"
|
|
<?= $g['audiofile'] ? 'checked' : '' ?>>
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</td>
|
|
<td><input type="number" class="ajaxGeraete" data-field="audiofile_max_duration"
|
|
value="<?= $g['audiofile_max_duration'] ?>"
|
|
style="width: 80px; padding: 2px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td>
|
|
<button class="deleteGeraete deleteBtn" data-id="<?= $g['id'] ?>"
|
|
style="border:none; background:none; cursor:pointer;">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"
|
|
viewBox="0 0 24 24" fill="none" stroke="#b91c1c" stroke-width="2"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="3 6 5 6 21 6"></polyline>
|
|
<path
|
|
d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2">
|
|
</path>
|
|
</svg>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<tr class="addRow">
|
|
<td></td>
|
|
<td><input type="text" id="newGeraeteName" placeholder="Neues Gerät..."
|
|
style="width: 100%; padding: 6px; border: 1px solid #777; border-radius: 4px;">
|
|
</td>
|
|
<td><input type="number" id="newGeraeteIndex" value="0"
|
|
style="width: 80px; padding: 6px; border: 1px solid #777; border-radius: 4px;">
|
|
</td>
|
|
<td><input type="text" data-coloris id="newGeraeteColor" value="#424242"
|
|
style="width: 100px; height: 35px; padding: 2px; border: 1px solid #777; border-radius: 4px;">
|
|
</td>
|
|
<td>
|
|
<label class="checkbox">
|
|
<input type="checkbox" id="newGeraeteAudiofile">
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</td>
|
|
<td><input type="number" class="newGeraeteAudiofileDuration" data-field="audiofile_max_duration"
|
|
value="300"
|
|
style="width: 80px; padding: 2px; border: 1px sdashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td><button id="addGeraeteBtn"
|
|
style="padding: 6px 12px; background: var(--bg-top); color: #fff; border: none; border-radius: 4px; cursor: pointer;">Hinzufügen</button>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="containerDiv" style="z-index: 2;">
|
|
<h3 class="containerHeading">Konfiguration Noten: <span class="light">(fortgeschrittene
|
|
Einstellungen)</span></h3>
|
|
<div class="settingsGrid">
|
|
<div class="tableWraperOverflowY">
|
|
<table class="wkvsTabelle trainer tableNoten" id="notenTable">
|
|
<thead>
|
|
<tr class="notenRow">
|
|
<th>ID</th>
|
|
<th>Name</th>
|
|
<th>Typ</th>
|
|
<th>Standardwert</th>
|
|
<th>Berechnung</th>
|
|
<th>Min Wert</th>
|
|
<th>Max Wert</th>
|
|
<th>Pro Gerät</th>
|
|
<th>Gerät</th>
|
|
<th>Läufe (JSON)</th>
|
|
<th>Auf Rangliste</th>
|
|
<th>Grösse Rangliste</th>
|
|
<th>Nullstellen</th>
|
|
<th>Darstellung Display</th>
|
|
<th>Löschen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($noten as $n): ?>
|
|
<tr class="notenRow" data-id="<?= $n['id'] ?>">
|
|
<td><?= htmlspecialchars($n['id'] ?? '') ?></td>
|
|
<td><input type="text" class="ajaxNoten" data-field="name"
|
|
value="<?= htmlspecialchars($n['name'] ?? '') ?>"
|
|
style="width: 100%; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td>
|
|
<select class="ajaxNoten" data-field="type"
|
|
style="padding: 6px; border: 1px dashed #777; border-radius: 4px; width: 130px;">
|
|
<option value="input" <?= $n['type'] === 'input' ? 'selected' : '' ?>>Input
|
|
</option>
|
|
<option value="berechnung" <?= $n['type'] === 'berechnung' ? 'selected' : '' ?>>
|
|
Berechnung</option>
|
|
</select>
|
|
</td>
|
|
<td><input type="number" class="ajaxNoten" data-field="default_value"
|
|
value="<?= htmlspecialchars($n['default_value'] ?? '') ?>"
|
|
placeholder="<?= htmlspecialchars(($n['default_value'] === null) ? 'Kein Standartwert' : '') ?>"
|
|
style="width: 100%; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td><input type="text" class="ajaxNoten" data-field="berechnung"
|
|
value="<?= htmlspecialchars($n['berechnung'] ?? '') ?>"
|
|
style="min-width: 300px; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td><input type="number" class="ajaxNoten" data-field="min_value"
|
|
value="<?= htmlspecialchars($n['min_value'] ?? '') ?>"
|
|
placeholder="<?= htmlspecialchars(($n['min_value'] === null) ? '-' : '') ?>"
|
|
style="width: 100%; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td><input type="number" class="ajaxNoten" data-field="max_value"
|
|
value="<?= htmlspecialchars($n['max_value'] ?? '') ?>"
|
|
placeholder="<?= htmlspecialchars(($n['max_value'] === null) ? '-' : '') ?>"
|
|
style="width: 100%; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td>
|
|
<label class="checkbox">
|
|
<input type="checkbox" class="ajaxNoten" data-field="pro_geraet"
|
|
<?= $n['pro_geraet'] ? 'checked' : '' ?>>
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</td>
|
|
<td>
|
|
<?php
|
|
// 1. JSON sicher decodieren.
|
|
// json_decode gibt null zurück, wenn null übergeben wird, daher der erste Teil.
|
|
$arrayGerateJson = !empty($n['geraete_json']) ? json_decode($n['geraete_json'], true) : [];
|
|
|
|
// Sicherheit: Stelle sicher, dass es ein Array ist
|
|
if (!is_array($arrayGerateJson)) {
|
|
$arrayGerateJson = [];
|
|
}
|
|
|
|
$arrayGerateJsonNamen = [];
|
|
|
|
$geraeteIdName = array_column($geraete, 'name', 'id');
|
|
$geraeteIdName[0] = 'Keine Gerätezuweisung';
|
|
|
|
foreach ($arrayGerateJson as $id) {
|
|
$arrayGerateJsonNamen[$id] = $geraeteIdName[$id] ?? '';
|
|
}
|
|
?>
|
|
<div class="customSelect" id="selectedOption"
|
|
data-value="[<?= implode(",", $arrayGerateJsonNamen) ?>]">
|
|
<button type="button" id="selectTriggergeraete_json" class="selectTriggerBulk"
|
|
aria-expanded="false">
|
|
<span
|
|
class="selectLabel placeholder"><?= ($arrayGerateJsonNamen !== []) ? implode(", ", $arrayGerateJsonNamen) : 'Bitte auswählen…' ?></span>
|
|
<svg class="selectArrow" xmlns='http://www.w3.org/2000/svg'
|
|
viewBox='0 0 24 24' fill='none' height="14" width="14">
|
|
<path d='M6 9L12 15L18 9' stroke='currentColor' stroke-width='2'
|
|
stroke-linecap='round' stroke-linejoin='round' />
|
|
</svg>
|
|
</button>
|
|
<ul class="selectOptionsBulk">
|
|
<?php foreach ($geraete as $g): ?>
|
|
<?php
|
|
// 2. ID als String umwandeln für den sicheren Vergleich
|
|
$currentId = (int) $g['id'];
|
|
|
|
// 3. Prüfen, ob die aktuelle ID im Array der zugewiesenen Geräte enthalten ist
|
|
$isSelected = in_array($currentId, $arrayGerateJson);
|
|
?>
|
|
|
|
<li data-value="<?= $g['id'] ?>"
|
|
class="<?= $isSelected ? 'selected' : '' ?>">
|
|
<?= $g['name'] ?>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
|
|
<?php $isSelected = in_array(0, $arrayGerateJson); ?>
|
|
|
|
<li data-value="0" class="<?= $isSelected ? 'selected' : '' ?>">Keine
|
|
Gerätezuweisung</li>
|
|
</ul>
|
|
<input type="hidden" name="geraete_json" class="selectValue ajaxNoten"
|
|
data-field="geraete_json" value="[<?= implode(",", $arrayGerateJson) ?>]">
|
|
</div>
|
|
</td>
|
|
<td><input type="text" class="ajaxNoten" data-field="anzahl_laeufe_json"
|
|
value="<?= htmlspecialchars($n['anzahl_laeufe_json'] ?? '') ?>"
|
|
placeholder='{"default": 1, "ID": 2}'
|
|
style="min-width: 200px; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td>
|
|
<label class="checkbox">
|
|
<input type="checkbox" class="ajaxNoten" data-field="zeige_auf_rangliste"
|
|
<?= $n['zeige_auf_rangliste'] ? 'checked' : '' ?>>
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</td>
|
|
<td><input type="number" class="ajaxNoten" data-field="groesse_auf_rangliste"
|
|
value="<?= htmlspecialchars($n['groesse_auf_rangliste'] ?? '') ?>"
|
|
placeholder='normal'
|
|
style="padding: 6px; border: 1px dashed #777; border-radius: 4px;"></td>
|
|
<td><input type="number" class="ajaxNoten" data-field="nullstellen"
|
|
value="<?= htmlspecialchars($n['nullstellen'] ?? '') ?>"
|
|
style="width: 100%; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td><input type="text" class="ajaxNoten" data-field="display_string"
|
|
value="<?= htmlspecialchars($n['display_string'] ?? '') ?>"
|
|
style="width: 100%; padding: 6px; border: 1px dashed #777; border-radius: 4px;">
|
|
</td>
|
|
<td>
|
|
<button class="deleteNoten deleteBtn" data-id="<?= $n['id'] ?>"
|
|
style="border:none; background:none; cursor:pointer;">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"
|
|
viewBox="0 0 24 24" fill="none" stroke="#b91c1c" stroke-width="2"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="3 6 5 6 21 6"></polyline>
|
|
<path
|
|
d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2">
|
|
</path>
|
|
</svg>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<tr class="addRow">
|
|
<td><input type="number" id="newNotenId" placeholder="Neue einzigartige ID..."
|
|
style="width: 100%; padding: 6px; border: 1px solid #777; border-radius: 4px; width: 200px">
|
|
</td>
|
|
<td><input type="text" id="newNotenName" placeholder="Neue Note..."
|
|
style="width: 100%; padding: 6px; border: 1px solid #777; border-radius: 4px; width: 200px">
|
|
</td>
|
|
|
|
<td><button id="addNotenBtn"
|
|
style="padding: 6px 12px; background: var(--bg-top); color: #fff; border: none; border-radius: 4px; cursor: pointer;">Hinzufügen</button>
|
|
</td>
|
|
<td colspan="15"></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="settingsRow">
|
|
<div class="horizontalLabelWrapper">
|
|
<span>Note welche für die Berechnung der Ränge verwendet wird: </span>
|
|
<span class="light">(Es wird das Gerät 0, Run 1 dieser Note verwendet)</span>
|
|
</div>
|
|
<div class="customSelect" id="selectedOption" data-value="">
|
|
<button type="button" id="selectTrigger" class="selectTrigger paddingNormal"
|
|
aria-expanded="false">
|
|
<?php $hasValue = $rangNote != null && isset($indexedNoten[intval($rangNote)]); ?>
|
|
<span
|
|
class="selectLabel <?= $hasValue ? '' : 'placeholder' ?>"><?= $hasValue ? $indexedNoten[intval($rangNote)] : 'Bitte auswählen…' ?></span>
|
|
<svg class="selectArrow" xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'
|
|
height="14" width="14">
|
|
<path d='M6 9L12 15L18 9' stroke='currentColor' stroke-width='2' stroke-linecap='round'
|
|
stroke-linejoin='round' />
|
|
</svg>
|
|
</button>
|
|
<ul class="selectOptions">
|
|
|
|
<?php foreach ($indexedNoten as $snid => $snname):
|
|
$isSelected = (intval($rangNote) === $snid) ? 'selected' : '';
|
|
?>
|
|
<li data-value="<?= intval($snid) ?>" class="<?= $isSelected ? 'selected' : '' ?>">
|
|
<?= $snname ?>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
|
|
</ul>
|
|
<input type="hidden" name="rangNote" class="selectValue ajaxInput" data-key="rangNote"
|
|
value="<?= $rangNote ?? '' ?>">
|
|
</div>
|
|
</div>
|
|
<div class="settingsRow">
|
|
<span>Wert, welcher Rang 1 erhält: </span>
|
|
<div class="customSelect" id="selectedOption" data-value="">
|
|
<button type="button" id="selectTrigger" class="selectTrigger paddingNormal"
|
|
aria-expanded="false">
|
|
<?php
|
|
|
|
$all_possible_orders = [
|
|
'ASC' => 'Niedrigster Wert',
|
|
'DESC' => 'Höchster Wert'
|
|
];
|
|
|
|
$hasValue = $orderBestRang != null && isset($all_possible_orders[$orderBestRang]);
|
|
|
|
?>
|
|
<span
|
|
class="selectLabel <?= $hasValue ? '' : 'placeholder' ?>"><?= $hasValue ? $all_possible_orders[$orderBestRang] : 'Bitte auswählen…' ?></span>
|
|
<svg class="selectArrow" xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'
|
|
height="14" width="14">
|
|
<path d='M6 9L12 15L18 9' stroke='currentColor' stroke-width='2' stroke-linecap='round'
|
|
stroke-linejoin='round' />
|
|
</svg>
|
|
</button>
|
|
<ul class="selectOptions">
|
|
|
|
<?php foreach ($all_possible_orders as $val => $text):
|
|
$isSelected = ($orderBestRang === $val) ? 'selected' : '';
|
|
?>
|
|
<li data-value="<?= htmlspecialchars($val) ?>" class="<?= $isSelected ? 'selected' : '' ?>">
|
|
<?= htmlspecialchars($text) ?>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
|
|
</ul>
|
|
<input type="hidden" name="rangNote" class="selectValue ajaxInput" data-key="orderBestRang"
|
|
value="<?= $orderBestRang ?? '' ?>">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="containerDiv">
|
|
<h3 class="containerHeading">CSS Editor: <span class="light">(fortgeschrittene Einstellungen)</span>
|
|
</h3>
|
|
|
|
<style type="text/css" media="screen">
|
|
/* Give the editor container a defined size */
|
|
#csseditor {
|
|
width: 100%;
|
|
height: 400px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
font-family: monospace !important;
|
|
}
|
|
|
|
#csseditor,
|
|
#csseditor * {
|
|
font-family: monospace !important;
|
|
font-size: 14px !important;
|
|
letter-spacing: 0px !important;
|
|
line-height: normal !important;
|
|
}
|
|
</style>
|
|
|
|
<div id="csseditor"></div>
|
|
<div style="text-align: right; margin-top: 10px;">
|
|
<button onclick="saveCssCode()" class="cssCodeSaveBtn">CSS-Code speichern</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const editor = ace.edit("csseditor");
|
|
|
|
editor.setTheme("ace/theme/monokai");
|
|
|
|
editor.session.setMode("ace/mode/css");
|
|
|
|
editor.setOptions({
|
|
fontSize: "14px",
|
|
showPrintMargin: false,
|
|
enableLiveAutocompletion: true
|
|
});
|
|
|
|
const fileContents = <?= json_encode(file_get_contents($baseDir . '/intern/css/user.css') ?? '', JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_QUOT) ?>;
|
|
|
|
editor.setValue(fileContents, -1);
|
|
|
|
// Force Ace to recalculate font metrics
|
|
setTimeout(function () {
|
|
editor.renderer.updateFull();
|
|
}, 200);
|
|
|
|
editor.resize();
|
|
|
|
function saveCssCode() {
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-save-user-css.php',
|
|
type: 'POST',
|
|
data: {
|
|
css_content: editor.getValue(),
|
|
csrf_token
|
|
},
|
|
success: function (response) {
|
|
if (response.success) {
|
|
displayMsg(1, "CSS gespeichert");
|
|
} else {
|
|
displayMsg(0, "Fehler: " + response.message);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
|
|
</div>
|
|
|
|
<div class="msgDiv"></div>
|
|
|
|
</section>
|
|
|
|
<script>
|
|
|
|
document.addEventListener('keydown', function (event) {
|
|
if (event.key === 's' && (event.ctrlKey || event.metaKey)) {
|
|
event.preventDefault();
|
|
displayMsg(1, "Speichere CSS code...");
|
|
saveCssCode();
|
|
}
|
|
});
|
|
|
|
let ws;
|
|
|
|
const $inputAnzahlTage = $('#anzahlTageWK');
|
|
const $divTageInputs = $('#divTageInputs');
|
|
|
|
const csrf_token = "<?= $csrf_token ?>";
|
|
|
|
function displayNDayFields() {
|
|
console.log('ja');
|
|
const anzTageRoh = parseInt($inputAnzahlTage.val(), 10);
|
|
const anzTage = anzTageRoh + 1;
|
|
const $children = $divTageInputs.children();
|
|
const anzChildren = $children.length + 1;
|
|
|
|
if (anzChildren < anzTage) {
|
|
for (let i = anzChildren; i < anzTage; i++) {
|
|
$divTageInputs.append($('<div class="settingsRow"><span for="' + i + '-wk-date">' + i + '. Wettkampftag: </span><input type="date" id="' + i + '-wk-date"></div>'));
|
|
}
|
|
} else if (anzChildren > anzTage) {
|
|
for (let i = anzChildren; i > anzTage; i--) {
|
|
$divTageInputs.find('div:last-child').remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
displayNDayFields();
|
|
|
|
$inputAnzahlTage.on('change', displayNDayFields);
|
|
|
|
const arrayWSSend = [
|
|
'wkName',
|
|
'displayCTextLogo',
|
|
'displayCTextWKName',
|
|
'displayColourLogo',
|
|
'displayTextColourLogo',
|
|
'displayColorScoringBg',
|
|
'displayColorScoringBgSoft',
|
|
'displayColorScoringPanel',
|
|
'displayColorScoringPanelSoft',
|
|
'displayColorScoringPanelText',
|
|
'displayColorScoringShadowColor',
|
|
'displayColorScoringBorderColor',
|
|
'displayColorScoringPanelTextSoft',
|
|
'displayColorScoringPanelTextNoteL',
|
|
'displayColorScoringPanelTextNoteR'
|
|
];
|
|
|
|
$('input[type="file"][data-key]').on('change', function () {
|
|
const $input = $(this);
|
|
const file = this.files[0];
|
|
const type = $input.data('key');
|
|
|
|
if (!file) return;
|
|
|
|
const formData = new FormData();
|
|
formData.append('image', file);
|
|
formData.append('type', type);
|
|
formData.append('csrf_token', csrf_token);
|
|
|
|
$('.msgDiv').html('<p style="color: #007bff; font-weight: 500;">Wird hochgeladen...</p>');
|
|
$input.closest('div').css('opacity', '0.5');
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-upload-image.php',
|
|
type: 'POST',
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
success: function (response) {
|
|
$input.closest('div').css('opacity', '1');
|
|
if (response.success) {
|
|
$('.msgDiv').html('<p style="color: #28a745; font-weight: 500;">Bild "' + type + '" erfolgreich aktualisiert!</p>');
|
|
setTimeout(() => { $('.msgDiv').fadeOut(500, function () { $(this).empty().show(); }); }, 3000);
|
|
const timestamp = new Date().getTime();
|
|
|
|
if (type === 'icon') {
|
|
$input.parent().find('img').attr('src', '/intern/img/icon.png?t=' + timestamp);
|
|
} else if (type === 'logo-normal') {
|
|
$input.parent().find('img').attr('src', '/intern/img/logo-normal.png?t=' + timestamp);
|
|
ws.send(JSON.stringify({ type: 'EINSTELLUNGEN_DISPLAY_UPDATE', payload: { key: type, value: null } }));
|
|
} else {
|
|
$input.parent().find('img').attr('src', '/intern/img/login/bg' + type + '.webp?t=' + timestamp);
|
|
}
|
|
} else {
|
|
$('.msgDiv').html('<p style="color: #dc3545; font-weight: 500;">Fehler: ' + response.message + '</p>');
|
|
}
|
|
},
|
|
error: function (xhr) {
|
|
$input.closest('div').css('opacity', '1');
|
|
$('.msgDiv').html('<p style="color: #dc3545; font-weight: 500;">Kritischer Fehler beim Hochladen.</p>');
|
|
console.error(xhr);
|
|
}
|
|
});
|
|
});
|
|
|
|
function sendAjaxUpdate($input, value) {
|
|
const type = $input.data('key');
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-change-value.php',
|
|
type: 'POST',
|
|
data: {
|
|
csrf_token,
|
|
type: type,
|
|
value: value
|
|
},
|
|
success: function (response) {
|
|
|
|
if (response.success) {
|
|
|
|
displayMsg(1, 'Wert erfolgreich gespeichert!');
|
|
|
|
if (arrayWSSend.includes(type)) {
|
|
ws.send(JSON.stringify({ type: 'EINSTELLUNGEN_DISPLAY_UPDATE', payload: { key: type, value: value } }));
|
|
}
|
|
}
|
|
},
|
|
error: function (xhr) {
|
|
$input.closest('div').css('opacity', '1');
|
|
$('.msgDiv').html('<p style="color: #dc3545; font-weight: 500;">Kritischer Fehler beim Hochladen.</p>');
|
|
console.error(xhr);
|
|
}
|
|
});
|
|
}
|
|
|
|
$('.ajaxInput').on('change', function () {
|
|
const $input = $(this);
|
|
const value = $input.val();
|
|
sendAjaxUpdate($input, value);
|
|
});
|
|
|
|
$('.ajaxInputCheckbox').on('change', function () {
|
|
const $input = $(this);
|
|
const value = $input.is(':checked') ? 1 : 0;
|
|
sendAjaxUpdate($input, value);
|
|
});
|
|
|
|
// Gerate management
|
|
$(document).on('change', '.ajaxGeraete', function () {
|
|
const $input = $(this);
|
|
const id = $input.closest('tr').data('id');
|
|
const field = $input.data('field');
|
|
let value = $input.val();
|
|
|
|
if (field === 'audiofile') {
|
|
value = ($input.prop("checked")) ? 1 : 0;
|
|
}
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-gereate-management.php',
|
|
type: 'POST',
|
|
data: { action: 'update', id: id, field: field, value: value, csrf_token },
|
|
success: function (response) {
|
|
if (response.success) {
|
|
displayMsg(1, "Gerät aktualisiert");
|
|
} else {
|
|
displayMsg(0, "Fehler: " + response.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
$(document).on('click', '#addGeraeteBtn', function () {
|
|
const name = $('#newGeraeteName').val();
|
|
const index = $('#newGeraeteIndex').val();
|
|
const color = $('#newGeraeteColor').val();
|
|
const audiofile = $('#newGeraeteAudiofile').val();
|
|
const audiofileMaxDuration = $('newGeraeteAudiofileDuration').val();
|
|
|
|
if (!name) {
|
|
displayMsg(0, "Name erforderlich");
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-gereate-management.php',
|
|
type: 'POST',
|
|
data: { action: 'add', name: name, start_index: index, color: color, audiofile, audiofileMaxDuration, csrf_token },
|
|
success: function (response) {
|
|
if (response.success) {
|
|
window.location.reload();
|
|
} else {
|
|
displayMsg(0, "Fehler: " + response.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
$(document).on('click', '.deleteGeraete', async function () {
|
|
if (!await displayConfirm("Gerät wirklich löschen?")) return;
|
|
const id = $(this).data('id');
|
|
const $tr = $(this).closest('tr');
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-gereate-management.php',
|
|
type: 'POST',
|
|
data: { action: 'delete', id: id, csrf_token },
|
|
success: function (response) {
|
|
if (response.success) {
|
|
$tr.remove();
|
|
displayMsg(1, "Gerät gelöscht");
|
|
} else {
|
|
displayMsg(0, "Fehler: " + response.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Zeitplan management
|
|
$(document).on('change', '.ajaxZeitplan', function () {
|
|
const $input = $(this);
|
|
const id = $input.closest('tr').data('id');
|
|
const field = $input.data('field');
|
|
let value = $input.val();
|
|
|
|
if (field === 'has_endtime') {
|
|
value = ($input.prop("checked")) ? 1 : 0;
|
|
}
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-zeitplan-management.php',
|
|
type: 'POST',
|
|
data: { action: 'update', id: id, field: field, value: value, csrf_token },
|
|
success: function (response) {
|
|
if (response.success) {
|
|
displayMsg(1, "Zeitplan aktualisiert");
|
|
} else {
|
|
displayMsg(0, "Fehler: " + response.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
$(document).on('click', '#addZeitplanTypeBtn', function () {
|
|
const name = $('#newZeitplanName').val();
|
|
const has_endtime = $('#newZeitplanHasEndtime').is(':checked') ? 1 : 0;
|
|
const index = $('#newZeitplanIndex').val();
|
|
|
|
if (!name) {
|
|
displayMsg(0, "Name erforderlich");
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-zeitplan-management.php',
|
|
type: 'POST',
|
|
data: { action: 'add', name: name, has_endtime: has_endtime, index: index, csrf_token },
|
|
success: function (response) {
|
|
if (response.success) {
|
|
window.location.reload();
|
|
} else {
|
|
displayMsg(0, "Fehler: " + response.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
$(document).on('click', '.deleteZeitplan', async function () {
|
|
if (!await displayConfirm("Zeitplan wirklich löschen?")) return;
|
|
const id = $(this).data('id');
|
|
const $tr = $(this).closest('tr');
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-zeitplan-management.php',
|
|
type: 'POST',
|
|
data: { action: 'delete', id: id, csrf_token },
|
|
success: function (response) {
|
|
if (response.success) {
|
|
$tr.remove();
|
|
displayMsg(1, "Zeitplan gelöscht");
|
|
} else {
|
|
displayMsg(0, "Fehler: " + response.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Noten management
|
|
$(document).on('change', '.ajaxNoten', function () {
|
|
const $input = $(this);
|
|
const id = $input.closest('tr').data('id');
|
|
const field = $input.data('field');
|
|
let value = $input.val();
|
|
|
|
if ($input.attr('type') === 'checkbox') {
|
|
value = $input.is(':checked') ? 1 : 0;
|
|
}
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-noten-management.php',
|
|
type: 'POST',
|
|
data: { action: 'update', id: id, field: field, value: value, csrf_token },
|
|
success: function (response) {
|
|
if (response.success) {
|
|
displayMsg(1, "Note aktualisiert");
|
|
} else {
|
|
displayMsg(0, "Fehler: " + response.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
$(document).on('click', '#addNotenBtn', function () {
|
|
const id = $('#newNotenId').val();
|
|
const name = $('#newNotenName').val();
|
|
const type_val = $('#newNotenType').val();
|
|
const berechnung = $('#newNotenBerechnung').val();
|
|
const pro_geraet = $('#newNotenProGeraet').is(':checked') ? 1 : 0;
|
|
|
|
if (!name) {
|
|
displayMsg(0, "Name erforderlich");
|
|
return;
|
|
}
|
|
|
|
if (!id) {
|
|
displayMsg(0, "Id erforderlich");
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-noten-management.php',
|
|
type: 'POST',
|
|
data: { action: 'add', id: id, name: name, type_val: type_val, berechnung: berechnung, pro_geraet: pro_geraet, csrf_token },
|
|
success: function (response) {
|
|
if (response.success) {
|
|
window.location.reload();
|
|
} else {
|
|
displayMsg(0, "Fehler: " + response.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
$(document).on('click', '.deleteNoten', async function () {
|
|
if (!await displayConfirm("Note wirklich löschen?")) return;
|
|
const id = $(this).data('id');
|
|
const $tr = $(this).closest('tr');
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/ajax-noten-management.php',
|
|
type: 'POST',
|
|
data: { action: 'delete', id: id, csrf_token },
|
|
success: function (response) {
|
|
if (response.success) {
|
|
$tr.remove();
|
|
displayMsg(1, "Note gelöscht");
|
|
} else {
|
|
displayMsg(0, "Fehler: " + response.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
let firstConnect = true;
|
|
const RETRY_DELAY = 2000;
|
|
|
|
const WSaccesstype = "<?= $WSaccesstype ?>";
|
|
const WSaccess = "<?= $WSaccess ?>";
|
|
const WSaccessPermission = "<?= $WSaccessPermission ?>"
|
|
|
|
const urlAjaxNewWSToken = '/intern/scripts/ajax-create-ws-token.php';
|
|
|
|
async function fetchNewWSToken(accesstype, access, accessPermission) {
|
|
try {
|
|
const response = await fetch(urlAjaxNewWSToken, {
|
|
method: "POST",
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: new URLSearchParams({
|
|
csrf_token,
|
|
accesstype,
|
|
access,
|
|
accessPermission
|
|
})
|
|
});
|
|
|
|
if (response.status === 403) {
|
|
console.warn("Please Re-Autenithicate. Reloading page...");
|
|
location.reload();
|
|
return null;
|
|
}
|
|
|
|
if (!response.ok) return null;
|
|
|
|
const data = await response.json();
|
|
return data.success ? data.token : null;
|
|
} catch (error) {
|
|
console.error("Token fetch failed:", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function startWebSocket() {
|
|
console.log("Attempting WebSocket connection...");
|
|
|
|
let token;
|
|
if (firstConnect) {
|
|
token = '<?= generateWSAdminToken($WSaccesstype, $WSaccess) ?>';
|
|
} else {
|
|
token = await fetchNewWSToken(WSaccesstype, WSaccess, WSaccessPermission);
|
|
}
|
|
|
|
if (!token) {
|
|
console.error("No valid token available. Retrying...");
|
|
scheduleRetry();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
ws = new WebSocket(`wss://${window.location.hostname}/ws/?access=token&token=${token}`);
|
|
} catch (err) {
|
|
console.error("Malformed WebSocket URL", err);
|
|
scheduleRetry();
|
|
return;
|
|
}
|
|
|
|
ws.onopen = () => {
|
|
console.log("WebSocket connected!");
|
|
if (!firstConnect) {
|
|
displayMsg(1, "Live Syncronisation wieder verfügbar");
|
|
}
|
|
firstConnect = true;
|
|
};
|
|
|
|
ws.onerror = (event) => {
|
|
console.error("WebSocket error observed.");
|
|
};
|
|
|
|
ws.onclose = (event) => {
|
|
displayMsg(0, "Live Syncronisation verloren");
|
|
console.log(event);
|
|
firstConnect = false;
|
|
|
|
scheduleRetry();
|
|
};
|
|
|
|
ws.addEventListener("message", msg => {
|
|
let msgJSON;
|
|
try {
|
|
msgJSON = JSON.parse(msg.data);
|
|
} catch (error) {
|
|
return; // Ignore malformed messages
|
|
}
|
|
|
|
switch (msgJSON.type) {
|
|
case "EINSTELLUNGEN_DISPLAY_UPDATE":
|
|
updateSettings(msgJSON.payload.key, msgJSON.payload.value);
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
function scheduleRetry() {
|
|
console.log(`Retrying in ${RETRY_DELAY}ms...`);
|
|
setTimeout(startWebSocket, RETRY_DELAY);
|
|
}
|
|
|
|
const $presetUploadBtn = $('#importPresetInput');
|
|
|
|
function updatePresetUploadBtn() {
|
|
const hasFile = $presetUploadBtn[0].files && $presetUploadBtn[0].files.length > 0;
|
|
$('#submitWKVSConfig').prop('disabled', !hasFile);
|
|
}
|
|
|
|
$presetUploadBtn.on('change', updatePresetUploadBtn);
|
|
|
|
updatePresetUploadBtn();
|
|
|
|
$('#submitWKVSConfig').on('click', async function () {
|
|
|
|
if (!await displayConfirm("Die aktuelle Konfiguration wird durch die ausgewählte Datei vollständig überschrieben!")) {
|
|
return;
|
|
}
|
|
const $button = $(this);
|
|
const input = $button.siblings('#importPresetInput')[0];
|
|
|
|
const formData = new FormData();
|
|
|
|
formData.append('csrf_token', csrf_token);
|
|
formData.append('configFile', input.files[0]);
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/einstellungen/upload-config-file.php',
|
|
type: 'POST',
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
success: function (response) {
|
|
response = response ? JSON.parse(response) : {};
|
|
if (response.success) {
|
|
window.location.reload();
|
|
} else {
|
|
if (response.message) {
|
|
displayMsg(0, response.message);
|
|
} else {
|
|
displayMsg(0, "Unbekannter Fehler beim Hochladen der Config-Datei.");
|
|
}
|
|
}
|
|
},
|
|
error: function (xhr, status, errorThrown) {
|
|
let errorMsg = "Kritischer Fehler beim Hochladen der Config-Datei.";
|
|
|
|
if (xhr.responseText) {
|
|
try {
|
|
const response = JSON.parse(xhr.responseText);
|
|
if (response.message) {
|
|
errorMsg = response.message;
|
|
}
|
|
} catch (e) {
|
|
console.error("Could not parse JSON error response:", e);
|
|
}
|
|
}
|
|
|
|
displayMsg(0, errorMsg);
|
|
|
|
console.error(xhr);
|
|
}
|
|
});
|
|
|
|
});
|
|
|
|
function downloadPresetConfig() {
|
|
const form = document.createElement('form');
|
|
form.method = 'POST';
|
|
form.action = '/intern/scripts/einstellungen/export-config-file.php';
|
|
form.style.display = 'none';
|
|
|
|
const csrfInput = document.createElement('input');
|
|
csrfInput.type = 'hidden';
|
|
csrfInput.name = 'csrf_token';
|
|
csrfInput.value = csrf_token;
|
|
form.appendChild(csrfInput);
|
|
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
document.body.removeChild(form);
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
:root {
|
|
/* Brand */
|
|
--display-panelBgLogo:
|
|
<?= $displayColor ?>
|
|
;
|
|
--display-text-color:
|
|
<?= $textColor ?>
|
|
;
|
|
|
|
/* Backgrounds */
|
|
--display-bg:
|
|
<?= $displayColorScoringBg ?>
|
|
;
|
|
--display-bg-soft:
|
|
<?= $displayColorScoringBgSoft ?>
|
|
;
|
|
--display-panel:
|
|
<?= $displayColorScoringPanel ?>
|
|
;
|
|
--display-panel-soft:
|
|
<?= $displayColorScoringPanelSoft ?>
|
|
;
|
|
|
|
/* Shadow */
|
|
--display-shadow:
|
|
<?= $displayColorScoringShadowColor ?>
|
|
;
|
|
|
|
/* Border */
|
|
--display-border:
|
|
<?= $displayColorScoringBorderColor ?>
|
|
;
|
|
|
|
/* Typography */
|
|
--display-text-main:
|
|
<?= $displayColorScoringPanelText ?>
|
|
;
|
|
--display-text-muted:
|
|
<?= $displayColorScoringPanelTextSoft ?>
|
|
;
|
|
|
|
/* Noten */
|
|
--display-color-note-l:
|
|
<?= $displayColorScoringPanelTextNoteL ?>
|
|
;
|
|
--display-color-note-r:
|
|
<?= $displayColorScoringPanelTextNoteR ?>
|
|
;
|
|
|
|
|
|
}
|
|
</style>
|
|
|
|
|
|
<script>
|
|
|
|
// --- Settings & UI Handlers ---
|
|
function updateSettings(type, value) {
|
|
|
|
const sanitizeHex = (val) => val.replace(/[^0-9a-fA-F#]/g, '');
|
|
|
|
switch (type) {
|
|
case 'wkName':
|
|
const logotext = document.querySelector('.logotext');
|
|
if (logotext) logotext.innerHTML = value;
|
|
break;
|
|
case 'displayColourLogo':
|
|
document.documentElement.style.setProperty('--display-panelBgLogo', sanitizeHex(value));
|
|
break;
|
|
case 'displayTextColourLogo':
|
|
document.documentElement.style.setProperty('--display-text-color', sanitizeHex(value));
|
|
break;
|
|
case 'displayCTextLogo':
|
|
document.querySelector('.logoimg').classList.toggle('cTextHidden');
|
|
break;
|
|
case 'displayCTextWKName':
|
|
document.querySelector('.logotext').classList.toggle('cTextHidden');
|
|
break;
|
|
case 'displayColorScoringBg':
|
|
document.documentElement.style.setProperty('--display-bg', sanitizeHex(value));
|
|
break;
|
|
case 'displayColorScoringBgSoft':
|
|
document.documentElement.style.setProperty('--display-bg-soft', sanitizeHex(value));
|
|
break;
|
|
case 'displayColorScoringShadowColor':
|
|
document.documentElement.style.setProperty('--display-shadow', sanitizeHex(value));
|
|
break;
|
|
case 'displayColorScoringBorderColor':
|
|
document.documentElement.style.setProperty('--display-border', sanitizeHex(value));
|
|
break;
|
|
case 'displayColorScoringPanel':
|
|
document.documentElement.style.setProperty('--display-panel', sanitizeHex(value));
|
|
break;
|
|
case 'displayColorScoringPanelSoft':
|
|
document.documentElement.style.setProperty('--display-panel-soft', sanitizeHex(value));
|
|
break;
|
|
case 'displayColorScoringPanelText':
|
|
document.documentElement.style.setProperty('--display-text-main', sanitizeHex(value));
|
|
break;
|
|
case 'displayColorScoringPanelTextSoft':
|
|
document.documentElement.style.setProperty('--display-text-muted', sanitizeHex(value));
|
|
break;
|
|
case 'displayColorScoringPanelTextNoteL': // Matching your PHP typo
|
|
document.documentElement.style.setProperty('--display-color-note-l', sanitizeHex(value));
|
|
break;
|
|
case 'displayColorScoringPanelTextNoteR': // Matching your PHP typo
|
|
document.documentElement.style.setProperty('--display-color-note-r', sanitizeHex(value));
|
|
break;
|
|
case 'logo-normal':
|
|
const jsImgLogo = document.getElementById('jsImgLogo');
|
|
if (jsImgLogo) jsImgLogo.src = '/intern/img/logo-normal.png?' + Date.now();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// --- Text Resizing Engine ---
|
|
function isOverflown(parent, elem, heightscale, widthscale, paddingtext) {
|
|
return (
|
|
(elem.scrollWidth + paddingtext) > (parent.clientWidth / widthscale) ||
|
|
(elem.scrollHeight + paddingtext) > (parent.clientHeight / heightscale)
|
|
);
|
|
}
|
|
|
|
function fitTextElement(elem, { minSize = 10, maxSize = 1000, step = 1, unit = 'px' } = {}) {
|
|
if (!elem) return;
|
|
const parent = elem.parentElement;
|
|
if (!parent) return;
|
|
|
|
// FIXED: Declare variables properly so they don't leak into the global scope
|
|
let heightscale = 1;
|
|
let widthscale = 1;
|
|
let paddingtext = 60;
|
|
|
|
if (parent.classList.contains('row2text')) {
|
|
heightscale = 2;
|
|
paddingtext = 0;
|
|
}
|
|
|
|
if (parent.classList.contains('start_div')) {
|
|
paddingtext = 0;
|
|
}
|
|
|
|
if (parent.classList.contains('row3')) {
|
|
widthscale = 2;
|
|
}
|
|
|
|
let size = minSize;
|
|
elem.style.whiteSpace = 'nowrap';
|
|
elem.style.fontSize = size + unit;
|
|
|
|
while (size < maxSize && !isOverflown(parent, elem, heightscale, widthscale, paddingtext)) {
|
|
size += step;
|
|
elem.style.fontSize = size + unit;
|
|
}
|
|
|
|
elem.style.fontSize = (size - step) + unit;
|
|
}
|
|
|
|
const ctext = document.querySelector('.logoctext');
|
|
const logobg = document.querySelector('.logobg');
|
|
|
|
function resizeCText() {
|
|
ctext.style.fontSize = '';
|
|
if (isOverflown(logobg, ctext, 1, 1, 0)) fitTextElement(ctext);
|
|
}
|
|
|
|
function fitTextAll() {
|
|
const paragraphs = document.querySelectorAll('.pagediv p');
|
|
paragraphs.forEach(p => fitTextElement(p));
|
|
resizeCText();
|
|
}
|
|
|
|
function switchStart() {
|
|
const starttext = document.querySelector('.start_text');
|
|
const row2El = document.querySelector('.row2');
|
|
if (starttext && row2El) {
|
|
const rootStyles = getComputedStyle(document.documentElement);
|
|
const dangerColor = rootStyles.getPropertyValue('--display-danger').trim();
|
|
const successColor = rootStyles.getPropertyValue('--display-success').trim();
|
|
|
|
const isStop = starttext.dataset.type === 'stop';
|
|
|
|
row2El.style.setProperty('--display-colorStartDiv', isStop ? successColor : dangerColor);
|
|
|
|
starttext.innerHTML = isStop ? 'Start' : 'Stop';
|
|
starttext.dataset.type = isStop ? 'start' : 'stop';
|
|
|
|
}
|
|
}
|
|
|
|
function switchMode(mode) {
|
|
switch (mode) {
|
|
case 'scoring':
|
|
document.querySelector('.pagediv').classList.remove('hidden');
|
|
logobg.classList.add('hidden');
|
|
document.querySelector('.settingsRowGroupDisplay[data-type="logo"]').classList.add('hidden');
|
|
document.querySelector('.settingsRowGroupDisplay[data-type="ctext"]').classList.add('hidden');
|
|
document.querySelector('.settingsRowGroupDisplay[data-type="scoring"]').classList.remove('hidden');
|
|
break;
|
|
case 'logo':
|
|
document.querySelector('.pagediv').classList.add('hidden');
|
|
logobg.classList.remove('hidden');
|
|
logobg.classList.remove('ctext');
|
|
ctext.classList.add('hidden');
|
|
document.querySelector('.settingsRowGroupDisplay[data-type="logo"]').classList.remove('hidden');
|
|
document.querySelector('.settingsRowGroupDisplay[data-type="ctext"]').classList.add('hidden');
|
|
document.querySelector('.settingsRowGroupDisplay[data-type="scoring"]').classList.add('hidden');
|
|
break;
|
|
case 'ctext':
|
|
document.querySelector('.pagediv').classList.add('hidden');
|
|
logobg.classList.remove('hidden');
|
|
logobg.classList.add('ctext');
|
|
ctext.classList.remove('hidden');
|
|
resizeCText();
|
|
document.querySelector('.settingsRowGroupDisplay[data-type="logo"]').classList.add('hidden');
|
|
document.querySelector('.settingsRowGroupDisplay[data-type="ctext"]').classList.remove('hidden');
|
|
document.querySelector('.settingsRowGroupDisplay[data-type="scoring"]').classList.add('hidden');
|
|
break;
|
|
}
|
|
}
|
|
|
|
$('.optionsDisplay').on('click', 'input', function (e) {
|
|
// e.stopPropagation();
|
|
|
|
$('.displayDiv .scaled').removeClass("scaled");
|
|
|
|
const $el = $(this);
|
|
const notHiddenElName = $el.data("assoc-el") ?? null;
|
|
|
|
if (!notHiddenElName) return;
|
|
|
|
const $notHiddenEl = $('.' + notHiddenElName);
|
|
|
|
if (!$notHiddenEl.length) return;
|
|
|
|
$notHiddenEl.addClass("scaled");
|
|
// $el.click();
|
|
});
|
|
|
|
$(document).on('click', function () {
|
|
$('.displayDiv .scaled').removeClass("scaled");
|
|
});
|
|
|
|
window.addEventListener('resize', fitTextAll);
|
|
|
|
// --- Initialize ---
|
|
startWebSocket();
|
|
|
|
fitTextAll();
|
|
|
|
switchStart();
|
|
|
|
Coloris({
|
|
swatches: [
|
|
'DarkSlateGray',
|
|
'#2a9d8f',
|
|
'#e9c46a',
|
|
'coral',
|
|
'rgb(231, 111, 81)',
|
|
'Crimson',
|
|
'#023e8a',
|
|
'#0077b6',
|
|
'hsl(194, 100%, 39%)',
|
|
'#00b4d8',
|
|
'#ffffff'
|
|
]
|
|
});
|
|
|
|
switchMode('scoring');
|
|
|
|
$(document).on('change', '.ajaxProgramm', function () {
|
|
const $input = $(this);
|
|
const type = $input.data('type');
|
|
const url = `/intern/scripts/logindata/ajax-update_programm_value.php`;
|
|
|
|
const value = (type === 'aktiv') ? ($input.is(':checked') ? 1 : 0) : $input.val();
|
|
|
|
fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: new URLSearchParams({
|
|
csrf_token,
|
|
id: $input.data('field-id'),
|
|
type: $input.data('type'),
|
|
value
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
displayMsg(1, 'Programm erfolgreich aktualisiert');
|
|
} else {
|
|
displayMsg(0, 'Programm konnte nicht aktualisiert werden');
|
|
}
|
|
})
|
|
.catch(err => {
|
|
displayMsg(0, 'Programm konnte nicht aktualisiert werden');
|
|
console.error('AJAX fetch error:', err);
|
|
});
|
|
});
|
|
|
|
/*function rebuildProgrammeTable(programmes) {
|
|
const $tableBody = $('#programmTable tbody');
|
|
const $inputRow = $tableBody.find('tr.addRow');
|
|
const $input = $inputRow.find('.inputProgrammName');
|
|
$input.val('');
|
|
$tableBody.empty();
|
|
|
|
programmes.forEach(entry => {
|
|
const aktiv = entry.aktiv === 1 ? 'checked' : '';
|
|
|
|
const row = `
|
|
<tr>
|
|
<td>${entry.programm}</td>
|
|
<td>
|
|
<label class="checkbox">
|
|
<input type="checkbox" class="anmeldencheckbox inputAktivProgramm" ${aktiv} data-field-id="${entry.id}"/>
|
|
<span class="checkbox-ui"></span>
|
|
</label>
|
|
</td>
|
|
<td>
|
|
CHF <input type="number" class="inputPreisProgramm"
|
|
data-field-id="${entry.id}" step="0.01"
|
|
value="${entry.preis}">
|
|
</td>
|
|
<td><input type="number" class="inputOrderIndexProgramm ajaxProgramm" data-field-id="${entry.id}" value="${entry.orderIndex}" data-type="order_index"></td>
|
|
<td>
|
|
<button class="deleteProgramm"
|
|
data-field-id="${entry.id}'">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="3 6 5 6 21 6"></polyline>
|
|
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
|
<line x1="10" y1="11" x2="10" y2="17"></line>
|
|
<line x1="14" y1="11" x2="14" y2="17"></line>
|
|
</svg>
|
|
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
|
|
$tableBody.append(row);
|
|
});
|
|
$tableBody.append($inputRow);
|
|
} */
|
|
|
|
$(document).on('click', '.neuProgrammBtn', async function (e) {
|
|
e.preventDefault();
|
|
|
|
const $input = $(this).closest('tr').find('.inputProgrammName');
|
|
|
|
let value = $input.val();
|
|
|
|
if (!value) {
|
|
displayMsg(0, 'Bitte Bezeichnung eingeben');
|
|
return;
|
|
}
|
|
|
|
const url = `/intern/scripts/logindata/ajax-neu_programm.php`;
|
|
|
|
fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: new URLSearchParams({
|
|
csrf_token,
|
|
value
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
displayMsg(1, 'Alters-/ Leistungsklasse erfolgreich hinzugefügt');
|
|
location.reload();
|
|
/*if (data.output) {
|
|
rebuildProgrammeTable(data.output);
|
|
}*/
|
|
} else {
|
|
displayMsg(0, 'Alters-/ Leistungsklasse konnte nicht hinzugefügt werden');
|
|
}
|
|
})
|
|
.catch(err => {
|
|
displayMsg(0, 'Alters-/ Leistungsklasse konnte nicht hinzugefügt werden');
|
|
console.error('AJAX fetch error:', err);
|
|
});
|
|
});
|
|
|
|
$(document).on('click', '.deleteProgramm', async function () {
|
|
const $btn = $(this);
|
|
|
|
if (!await displayConfirm("Alters-/ Leistungsklasse wirklich löschen?")) return;
|
|
|
|
const id = $btn.attr('data-id');
|
|
|
|
$.ajax({
|
|
url: '/intern/scripts/logindata/ajax-remove_programm.php',
|
|
type: "DELETE",
|
|
data: {
|
|
csrf_token,
|
|
id
|
|
},
|
|
success: function (response) {
|
|
if (!response.success) {
|
|
displayMsg(0, response.message || 'Fehler beim Löschen');
|
|
return;
|
|
}
|
|
|
|
const $row = $btn.closest('tr');
|
|
if ($row.length !== 1) return;
|
|
|
|
$row.remove();
|
|
|
|
displayMsg(1, 'Alters-/ Leistungsklasse gelöscht');
|
|
|
|
},
|
|
error: function (xhr, status, error) {
|
|
displayMsg(0, 'Fehler beim Löschen: ' + error);
|
|
}
|
|
});
|
|
});
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|
|
<?php endif; ?>
|