Einstellungsseite: Reiter, Kachelwerte und Geraeteliste
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>
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
<?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>";
|
||||
}
|
||||
Reference in New Issue
Block a user