Die Einstellungen bestanden aus einer einzigen langen Spalte mit den Preistabellen. Sie bekommt Reiter, und darin zwei neue Flaechen: was die Kacheln der Startseite anzeigen, und welche Geraete es ueberhaupt gibt. Reiter gab es vorher dreimal in drei Ausfuehrungen - die Etagen ueber den Automatismen mit eigenem switchTab(), die Geraetegruppen im Raum-Modal mit eigener CSS-Klasse, und die Einstellungsseite noch einmal anders. Jetzt baut restricted/reiter.php alle drei; umgeschaltet wird von Bootstrap, den offenen Reiter merkt reiterMerken() in der Adresse. Kachelwerte: was auf einer Kachel steht, stand fest in rooms.php. Die neue Tabelle kachelWerte (solarLog_kacheln.sql) ueberschreibt das je Raum, die Maske waehlt die Messwerte aus demselben Katalog wie der Automatik-Editor - nach Etage sortiert, die Geraete des eigenen Raums oben. Fehlt die Tabelle, zeigt jede Kachel weiter ihre Vorgabe. Geraete: die Zuordnung Geraet -> Raum war ein Modal, erreichbar ueber ein Zahnrad neben den Automatismen. Sie ist eine Einstellung und steht jetzt dort, zusammen mit dem, was fehlte: seit wann ein Geraet nichts mehr meldet, in welchen Automatiken es steckt, und ein Loeschknopf. Letzterer ist noetig, weil der Suchlauf nichts loescht - er legt an und frischt auf, damit die Automatiken ihre Zustands-Ids behalten; ein abgebautes Geraet bliebe sonst fuer immer stehen. Geloescht wird nur, was in keiner Automatik vorkommt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
129 lines
5.2 KiB
PHP
129 lines
5.2 KiB
PHP
<?php
|
|
/**
|
|
* Reiter - eine Bauart für die ganze Seite.
|
|
*
|
|
* Vorher gab es drei: die Etagenreiter über den Automatiken (Home) mit einem
|
|
* eigenen switchTab() in JavaScript, die Gerätegruppen im Raum-Modal als
|
|
* Bootstrap-Reiter mit eigener CSS-Klasse, und die Einstellungsseite noch
|
|
* einmal anders. Drei Markups, zwei Verhaltensweisen, ein Sonderaussehen -
|
|
* und jede Änderung am Erscheinungsbild wäre dreimal zu machen gewesen.
|
|
*
|
|
* Hier steht nur noch, wie ein Reiter aussieht und heißt. Umgeschaltet wird
|
|
* von Bootstrap (data-bs-toggle="tab"); eigenes JavaScript dafür gibt es
|
|
* nicht mehr. Wer sich den offenen Reiter merken will, setzt "merken" - das
|
|
* übernimmt reiterMerken() in js/solar/common.js für alle Leisten der Seite.
|
|
*
|
|
* Ein Reiter ist:
|
|
*
|
|
* id Kürzel, taucht in den Element-Ids und in der Adresse auf
|
|
* titel Beschriftung
|
|
* symbol optional ein Bootstrap-Icon ("bi-currency-euro")
|
|
* titel2 optional der lange Name als Sprechblase (Etagenkürzel!)
|
|
* inhalt nur für reiterBlock(): der fertige Inhalt der Fläche
|
|
*
|
|
* Aufrufarten - je nachdem, ob der Inhalt schon als Text vorliegt:
|
|
*
|
|
* reiterBlock($reiter, $opt) Leiste und Flächen am Stück
|
|
* reiterLeiste($reiter, $opt) nur die Leiste ...
|
|
* reiterFlaecheAuf($id, $opt) ... und die Flächen einzeln, wenn der
|
|
* reiterFlaecheZu() Inhalt im Template steht
|
|
*/
|
|
|
|
/**
|
|
* Die Kennung eines Reiters. Der Name der Leiste steht davor, damit zwei
|
|
* Leisten auf derselben Seite sich nicht dieselben Ids teilen.
|
|
*/
|
|
function reiterId($opt, $id, $anhang = "")
|
|
{
|
|
return ($opt["name"] ?? "reiter") . "-" . $id . $anhang;
|
|
}
|
|
|
|
/**
|
|
* Welcher Reiter offen ist: der ausdrücklich genannte, sonst der erste.
|
|
*
|
|
* Als eigene Funktion, weil Leiste und Flächen dieselbe Antwort brauchen -
|
|
* und weil "der erste" bei den Flächen sonst noch einmal ausgerechnet würde.
|
|
*/
|
|
function reiterAktiv($reiter, $opt)
|
|
{
|
|
$ids = array_column($reiter, "id");
|
|
$aktiv = $opt["aktiv"] ?? null;
|
|
return ($aktiv !== null && in_array($aktiv, $ids, true)) ? $aktiv : ($ids[0] ?? null);
|
|
}
|
|
|
|
/**
|
|
* Die Leiste.
|
|
*
|
|
* $opt:
|
|
* name Namensraum der Ids; sollte gesetzt sein, sonst "reiter"
|
|
* aktiv id des offenen Reiters (Vorgabe: der erste)
|
|
* merken true: der offene Reiter steht in der Adresse und übersteht ein
|
|
* Neuladen. Nur eine Leiste je Seite sollte das tun.
|
|
* schmal true: kleinere Reiter, die waagerecht scrollen statt umzubrechen
|
|
* - für enge Stellen wie das Raum-Modal
|
|
* klasse zusätzliche Klassen für die Leiste
|
|
*/
|
|
function reiterLeiste($reiter, $opt = [])
|
|
{
|
|
if (count($reiter) < 2 && empty($opt["immer"])) {
|
|
// Ein einzelner Reiter beschriftet nur sich selbst. Das Raum-Modal
|
|
// hat oft nur eine Gerätegruppe - dort ist die Leiste dann weg.
|
|
return "";
|
|
}
|
|
$aktiv = reiterAktiv($reiter, $opt);
|
|
$klassen = "nav nav-tabs reiter"
|
|
. (!empty($opt["schmal"]) ? " reiter-schmal" : "")
|
|
. (isset($opt["klasse"]) ? " " . $opt["klasse"] : "");
|
|
|
|
$html = "<ul class='" . $klassen . "' role='tablist'"
|
|
. (!empty($opt["merken"]) ? " data-reiter-merken='" . htmlspecialchars($opt["name"] ?? "reiter") . "'" : "")
|
|
. ">";
|
|
foreach ($reiter as $r) {
|
|
$offen = $r["id"] === $aktiv;
|
|
$html .= "<li class='nav-item' role='presentation'>"
|
|
. "<button class='nav-link" . ($offen ? " active" : "") . "' type='button' role='tab'"
|
|
. " id='" . reiterId($opt, $r["id"], "-tab") . "'"
|
|
. " data-bs-toggle='tab' data-bs-target='#" . reiterId($opt, $r["id"]) . "'"
|
|
. " data-reiter='" . htmlspecialchars($r["id"]) . "'"
|
|
. " aria-controls='" . reiterId($opt, $r["id"]) . "'"
|
|
. " aria-selected='" . ($offen ? "true" : "false") . "'"
|
|
. (isset($r["titel2"]) ? " title='" . htmlspecialchars($r["titel2"]) . "'" : "")
|
|
. ">"
|
|
// Der Abstand zum Text kommt aus dem Stylesheet, nicht aus
|
|
// einer Hilfsklasse: in der schmalen Fassung ist er kleiner.
|
|
. (isset($r["symbol"]) ? "<i class='bi " . htmlspecialchars($r["symbol"]) . "'></i>" : "")
|
|
. htmlspecialchars($r["titel"])
|
|
. "</button></li>";
|
|
}
|
|
return $html . "</ul>";
|
|
}
|
|
|
|
/** Anfang einer Fläche - der Inhalt steht danach im Template. */
|
|
function reiterFlaecheAuf($id, $opt = [])
|
|
{
|
|
$offen = ($opt["aktiv"] ?? null) === $id;
|
|
return "<div class='tab-pane fade" . ($offen ? " show active" : "") . "'"
|
|
. " id='" . reiterId($opt, $id) . "' role='tabpanel'"
|
|
. " aria-labelledby='" . reiterId($opt, $id, "-tab") . "'>";
|
|
}
|
|
|
|
/** Ende einer Fläche. Eigene Funktion, damit im Template kein nacktes </div> steht. */
|
|
function reiterFlaecheZu()
|
|
{
|
|
return "</div>";
|
|
}
|
|
|
|
/**
|
|
* Leiste und Flächen am Stück - für Aufrufer, die den Inhalt schon als Text
|
|
* haben (siehe zeichneGruppen() im Raum-Modal).
|
|
*/
|
|
function reiterBlock($reiter, $opt = [])
|
|
{
|
|
$opt["aktiv"] = reiterAktiv($reiter, $opt);
|
|
$html = reiterLeiste($reiter, $opt) . "<div class='tab-content'>";
|
|
foreach ($reiter as $r) {
|
|
$html .= reiterFlaecheAuf($r["id"], $opt) . ($r["inhalt"] ?? "") . reiterFlaecheZu();
|
|
}
|
|
return $html . "</div>";
|
|
}
|