NEWS
Vis2 Tabs Widget - Tab per URL anspringen
-
Hallo zusammen,
weiß jemand ob es möglich ist in der VIS2, wenn man auf einer Seite das Tabs Widget verwendet, noch explizit ein bestimmtest Tabs beim aufrufen auszuwählen. In der Adressleiste steht nur die URL von der Hauptseite, in der man das Tabs Widget eingebunden hat. Das Widget selbst öffnet immer automatisch in seinem letzten aktiven Tab. Ich würde aber gerne per URL aufruf immer ein bestimmtes Tab selektiert haben, bzw. je nach bedarf von wo der Trigger kommt, ein bestimmtes Tab direkt mit auswählen beim Seitenaufruf.
Viele Grüße
Flo -
Hallo zusammen,
weiß jemand ob es möglich ist in der VIS2, wenn man auf einer Seite das Tabs Widget verwendet, noch explizit ein bestimmtest Tabs beim aufrufen auszuwählen. In der Adressleiste steht nur die URL von der Hauptseite, in der man das Tabs Widget eingebunden hat. Das Widget selbst öffnet immer automatisch in seinem letzten aktiven Tab. Ich würde aber gerne per URL aufruf immer ein bestimmtes Tab selektiert haben, bzw. je nach bedarf von wo der Trigger kommt, ein bestimmtes Tab direkt mit auswählen beim Seitenaufruf.
Viele Grüße
Flo@Sesamstrasse Meinst du dieses?
http://<iobroker>:8082/vis-2/?<Projekt>#<ViewName> -
Jain. So würde ich es gerne machen. Nur erzeugt das Tabs Widget oben keine Veränderung an der URL, egal welches der 3 Tabs ich wähle, die URL oben bleibt gleich. Und wenn ich die URL woanders aufrufe, dann ist einfach immer das letztgewählte Tab sofort aktiv. Und das würde ich gerne gezielt steuern, also z.b. gezielt per URL die View Strom mit dem Tab Energiefluss aktiv aufrufen, obwohl davor Details gewählt war. Ich befürchte nur, dass das sehr praktische Tabs Widget in der VIS das nicht hergibt und ich doch "echte" einzelne Seiten bauen muss.

-
Jain. So würde ich es gerne machen. Nur erzeugt das Tabs Widget oben keine Veränderung an der URL, egal welches der 3 Tabs ich wähle, die URL oben bleibt gleich. Und wenn ich die URL woanders aufrufe, dann ist einfach immer das letztgewählte Tab sofort aktiv. Und das würde ich gerne gezielt steuern, also z.b. gezielt per URL die View Strom mit dem Tab Energiefluss aktiv aufrufen, obwohl davor Details gewählt war. Ich befürchte nur, dass das sehr praktische Tabs Widget in der VIS das nicht hergibt und ich doch "echte" einzelne Seiten bauen muss.

@Sesamstrasse Beispiel
http://192.168.178.150:8083/vis-2/?main&tab=2#datumIn skripte einfügen WidgetID anpassen

// VIS2: Tab beim Laden per URL wählen // URL-Beispiele: // .../vis-2/?tab=Heizung#visview_datum // .../vis-2/?tab=2#visview_datum (1-basiert: 2 => zweiter Tab) const TABS_WIDGET_ID = "w000016"; // <- aus deinem DOM const PARAM_NAME = "tab"; // ?tab=Heizung oder ?tab=2 const MAX_TRIES = 60; // ~15s bei 250ms const INTERVAL_MS = 250; function getUrlParam(name) { // Query-String (vor #) const sp = new URLSearchParams(window.location.search); let v = sp.get(name); if (v) return v; // optional: auch aus Hash (#view?tab=...) const hash = window.location.hash || ""; const qPos = hash.indexOf("?"); if (qPos !== -1) { const hp = new URLSearchParams(hash.slice(qPos + 1)); v = hp.get(name); if (v) return v; } return null; } function getTabButtons() { const root = document.getElementById(TABS_WIDGET_ID); if (!root) return []; return Array.from(root.querySelectorAll('button[role="tab"]')); } function isSelected(btn) { return btn?.getAttribute("aria-selected") === "true" || btn?.classList?.contains("Mui-selected"); } function selectTabByIndex(index) { const tabs = getTabButtons(); if (!tabs.length) return false; if (index < 0 || index >= tabs.length) return false; const btn = tabs[index]; if (isSelected(btn)) return true; // schon aktiv btn.click(); return true; } function selectTabByName(name) { const tabs = getTabButtons(); if (!tabs.length) return false; const needle = String(name).trim().toLowerCase(); const btn = tabs.find(b => (b.textContent || "").trim().toLowerCase() === needle); if (!btn) return false; if (isSelected(btn)) return true; btn.click(); return true; } function applyTabFromUrl() { const tabParam = getUrlParam(PARAM_NAME); if (!tabParam) return; // Nummer? -> 1-basiert (2 => index 1). "0" bleibt 0. if (/^\d+$/.test(tabParam)) { const n = parseInt(tabParam, 10); const idx = (n === 0) ? 0 : (n - 1); selectTabByIndex(idx); return; } // sonst Name selectTabByName(tabParam); } function waitAndApply() { let tries = 0; const timer = setInterval(() => { tries++; const tabs = getTabButtons(); if (tabs.length) { applyTabFromUrl(); clearInterval(timer); } if (tries >= MAX_TRIES) clearInterval(timer); }, INTERVAL_MS); } // Beim ersten Laden waitAndApply(); // Wenn die App ohne Reload navigiert (z. B. Back/Forward) window.addEventListener("popstate", () => waitAndApply()); window.addEventListener("hashchange", () => waitAndApply()); -
Jain. So würde ich es gerne machen. Nur erzeugt das Tabs Widget oben keine Veränderung an der URL, egal welches der 3 Tabs ich wähle, die URL oben bleibt gleich. Und wenn ich die URL woanders aufrufe, dann ist einfach immer das letztgewählte Tab sofort aktiv. Und das würde ich gerne gezielt steuern, also z.b. gezielt per URL die View Strom mit dem Tab Energiefluss aktiv aufrufen, obwohl davor Details gewählt war. Ich befürchte nur, dass das sehr praktische Tabs Widget in der VIS das nicht hergibt und ich doch "echte" einzelne Seiten bauen muss.

@Sesamstrasse Mit dieser Variante wird die URL bei Tabwechsel neu geschrieben
// VIS-2: Tabs per URL (?…&tab=) setzen + URL bei Tabwechsel aktualisieren const TABS_WIDGET_ID = "w000016"; // deine Tabs-Widget-ID const PARAM = "tab"; // true => Back/Forward pro Tab, false => URL nur ersetzen (empfohlen) const USE_PUSHSTATE = false; const OBSERVE_TIMEOUT_MS = 15000; let suppressUntil = 0; function suppress(ms = 350) { suppressUntil = Date.now() + ms; } function isSuppressed() { return Date.now() < suppressUntil; } function norm(s) { return String(s ?? "").trim().toLowerCase(); } // -------- URL: nur Query-Teil (?main&tab=...) -------- function getTabParamFromSearch() { const sp = new URLSearchParams(window.location.search); const v = sp.get(PARAM); return v || null; } function setTabParamInSearch(tabValue) { if (!tabValue) return; const path = window.location.pathname; const hash = window.location.hash || ""; const raw = window.location.search || ""; // z.B. "?main&tab=Heizung" // tab ersetzen oder anhängen, OHNE main zu "main=" umzuschreiben let next = raw; if (/[?&]tab=/.test(next)) { next = next.replace(/([?&]tab=)[^&]*/i, `$1${encodeURIComponent(tabValue)}`); } else { next += (next.includes("?") ? "&" : "?") + `tab=${encodeURIComponent(tabValue)}`; } const newUrl = `${path}${next}${hash}`; // optional: pushState / replaceState wie vorher history.replaceState(null, "", newUrl); } // -------- Tabs Zugriff -------- function getTabButtons() { const root = document.getElementById(TABS_WIDGET_ID); if (!root) return []; return Array.from(root.querySelectorAll('button[role="tab"]')); } function isSelected(btn) { return ( btn?.getAttribute("aria-selected") === "true" || btn?.classList?.contains("Mui-selected") ); } function getSelectedTabName() { const tabs = getTabButtons(); const sel = tabs.find(isSelected); return sel ? (sel.textContent || "").trim() : ""; } function trySelectTab(tabParam) { if (!tabParam) return false; const tabs = getTabButtons(); if (!tabs.length) return false; let target = null; // Zahl => 1-basiert (tab=1 => erster Tab). tab=0 erlaubt auch ersten Tab. if (/^\d+$/.test(tabParam)) { const n = parseInt(tabParam, 10); const idx = (n === 0) ? 0 : (n - 1); target = tabs[idx]; } else { // Name const needle = norm(tabParam); target = tabs.find(b => norm(b.textContent) === needle); } if (!target) return false; if (!isSelected(target)) { suppress(450); target.click(); } return true; } // -------- URL -> Tab (beim Laden / Navigation) -------- function applyTabFromUrl() { if (isSuppressed()) return; const tabParam = getTabParamFromSearch(); if (!tabParam) return; // sofort versuchen if (trySelectTab(tabParam)) return; // warten bis gerendert const obs = new MutationObserver(() => { if (trySelectTab(tabParam)) obs.disconnect(); }); obs.observe(document.body, { childList: true, subtree: true }); setTimeout(() => obs.disconnect(), OBSERVE_TIMEOUT_MS); } // -------- Tab -> URL (bei Tabwechsel) -------- let lastWritten = ""; function writeUrlFromSelection() { if (isSuppressed()) return; const name = getSelectedTabName(); if (!name) return; if (name === lastWritten) return; lastWritten = name; setTabParamInSearch(name); } function wireTabHandlers() { const tabs = getTabButtons(); if (!tabs.length) return false; tabs.forEach(btn => { if (btn.__vis2TabUrlWired) return; btn.__vis2TabUrlWired = true; const handler = () => setTimeout(writeUrlFromSelection, 0); btn.addEventListener("click", handler); btn.addEventListener("keydown", (e) => { if (e.key === "Enter" || e.key === " " || e.key === "Spacebar") handler(); }); }); return true; } function observeTabChanges() { const root = document.getElementById(TABS_WIDGET_ID); if (!root) return false; const obs = new MutationObserver(() => { wireTabHandlers(); writeUrlFromSelection(); }); obs.observe(root, { subtree: true, childList: true, attributes: true, attributeFilter: ["aria-selected", "class"], }); wireTabHandlers(); writeUrlFromSelection(); return true; } // -------- Init -------- (function init() { applyTabFromUrl(); if (!observeTabChanges()) { const obs = new MutationObserver(() => { if (observeTabChanges()) obs.disconnect(); }); obs.observe(document.body, { childList: true, subtree: true }); setTimeout(() => obs.disconnect(), OBSERVE_TIMEOUT_MS); } // Wenn du URL manuell änderst / Back-Forward window.addEventListener("popstate", applyTabFromUrl); })(); -
ufff... alter falter... jetzt bin ich erstmal beschäftigt, dass zu verstehen :) Vielen Dank für die schnelle Antwort!
-
ufff... alter falter... jetzt bin ich erstmal beschäftigt, dass zu verstehen :) Vielen Dank für die schnelle Antwort!
@Sesamstrasse Also man kann die Umschaltung auch per DP steuern, so dass man von ioBroker aus auf unterschiedlichen Geräte die Tab festlegen kann.
Interesse? -
Wenn das einfacher ist, klar. :D dann kann ich mir überlegen, wie ich es am besten mache.
-
Wenn das einfacher ist, klar. :D dann kann ich mir überlegen, wie ich es am besten mache.
@Sesamstrasse Einfach ist relativ. DPs anlegen und den Code in Skripte austauschen.
- DPs in ioBroker anlegen mit dem Skript
Beispiele für DP setzen sind ausgeklammert, da die Werte angepasst werden müssen
- Script in VIS2 unter Skripte austauschen

- DPs in ioBroker anlegen mit dem Skript