custom_components/bahmcloud_store/panel/panel.js aktualisiert

This commit is contained in:
2026-01-15 09:56:53 +00:00
parent 8cee9e5e4d
commit adb117672c

View File

@@ -21,6 +21,9 @@ class BahmcloudStorePanel extends HTMLElement {
this._readmeLoading = false; this._readmeLoading = false;
this._readmeText = null; this._readmeText = null;
this._readmeError = null; this._readmeError = null;
// Prevent multiple concurrent markdown mounts
this._mdMountToken = 0;
} }
set hass(hass) { set hass(hass) {
@@ -335,6 +338,11 @@ class BahmcloudStorePanel extends HTMLElement {
details{ margin-top: 10px; } details{ margin-top: 10px; }
summary{ cursor:pointer; color: var(--bcs-accent); font-weight: 800; } summary{ cursor:pointer; color: var(--bcs-accent); font-weight: 800; }
/* Make HA markdown look nice inside our card */
ha-markdown{
display:block;
}
</style> </style>
<div class="mobilebar"> <div class="mobilebar">
@@ -388,9 +396,7 @@ class BahmcloudStorePanel extends HTMLElement {
tag === "select" || tag === "select" ||
t.isContentEditable; t.isContentEditable;
if (isEditable) { if (isEditable) e.stopPropagation();
e.stopPropagation();
}
}; };
root.addEventListener("keydown", stopIfFormField, true); root.addEventListener("keydown", stopIfFormField, true);
@@ -406,13 +412,12 @@ class BahmcloudStorePanel extends HTMLElement {
const supported = new Set(["searchInput", "categorySelect", "addUrl", "addName"]); const supported = new Set(["searchInput", "categorySelect", "addUrl", "addName"]);
if (!supported.has(ae.id)) return null; if (!supported.has(ae.id)) return null;
const state = { return {
id: ae.id, id: ae.id,
value: ae.value, value: ae.value,
selectionStart: typeof ae.selectionStart === "number" ? ae.selectionStart : null, selectionStart: typeof ae.selectionStart === "number" ? ae.selectionStart : null,
selectionEnd: typeof ae.selectionEnd === "number" ? ae.selectionEnd : null, selectionEnd: typeof ae.selectionEnd === "number" ? ae.selectionEnd : null,
}; };
return state;
} }
_restoreFocusState(state) { _restoreFocusState(state) {
@@ -431,7 +436,6 @@ class BahmcloudStorePanel extends HTMLElement {
_update() { _update() {
const root = this.shadowRoot; const root = this.shadowRoot;
const focusState = this._captureFocusState(); const focusState = this._captureFocusState();
const content = root.getElementById("content"); const content = root.getElementById("content");
@@ -515,13 +519,11 @@ class BahmcloudStorePanel extends HTMLElement {
: `<span class="badge">Index</span>`; : `<span class="badge">Index</span>`;
const desc = r.description || "No description available."; const desc = r.description || "No description available.";
const creator = r.owner ? `Creator: ${r.owner}` : "Creator: -"; const creator = r.owner ? `Creator: ${r.owner}` : "Creator: -";
const latest = r.latest_version ? `Latest: ${r.latest_version}` : "Latest: unknown";
const cat = r.category ? `Category: ${r.category}` : null; const cat = r.category ? `Category: ${r.category}` : null;
const metaSrc = r.meta_source ? `Meta: ${r.meta_source}` : null; const metaSrc = r.meta_source ? `Meta: ${r.meta_source}` : null;
const latest = r.latest_version ? `Latest: ${r.latest_version}` : "Latest: unknown";
const lineBits = [creator, latest, cat, metaSrc].filter(Boolean); const lineBits = [creator, latest, cat, metaSrc].filter(Boolean);
return ` return `
@@ -552,7 +554,6 @@ class BahmcloudStorePanel extends HTMLElement {
_wireStore() { _wireStore() {
const root = this.shadowRoot; const root = this.shadowRoot;
const search = root.getElementById("searchInput"); const search = root.getElementById("searchInput");
const cat = root.getElementById("categorySelect"); const cat = root.getElementById("categorySelect");
@@ -587,7 +588,6 @@ class BahmcloudStorePanel extends HTMLElement {
: `<span class="badge">Index</span>`; : `<span class="badge">Index</span>`;
const desc = r.description || "No description available."; const desc = r.description || "No description available.";
const latest = r.latest_version ? `Latest: ${r.latest_version}` : "Latest: unknown"; const latest = r.latest_version ? `Latest: ${r.latest_version}` : "Latest: unknown";
const infoBits = [ const infoBits = [
@@ -659,6 +659,60 @@ class BahmcloudStorePanel extends HTMLElement {
`; `;
} }
async _mountPrettyMarkdown(container, markdown) {
// token prevents race conditions when switching repos fast
const token = ++this._mdMountToken;
container.innerHTML = "";
// If user switched views/repo while we were waiting
const stillValid = () => token === this._mdMountToken && this._view === "detail" && !!this._readmeText;
// Wait until HA registers the component
try {
await customElements.whenDefined("ha-markdown");
} catch (_) {
// ignored
}
if (!stillValid()) return;
// Create markdown element
let el;
try {
el = document.createElement("ha-markdown");
} catch (_) {
el = null;
}
// If creation failed, fallback to plain pre
if (!el) {
const pre = document.createElement("pre");
pre.className = "readme";
pre.textContent = markdown;
container.appendChild(pre);
return;
}
// Attach first (some HA internals react after connection)
container.appendChild(el);
// Set hass + content
try { el.hass = this._hass; } catch (_) {}
try { el.content = markdown; } catch (_) {
// some builds used `markdown` property in the past
try { el.markdown = markdown; } catch (_) {}
}
// Nudge render (some builds need a microtask/frame after setting properties)
await new Promise((resolve) => requestAnimationFrame(resolve));
if (!stillValid()) return;
try { el.hass = this._hass; } catch (_) {}
try { el.content = markdown; } catch (_) {
try { el.markdown = markdown; } catch (_) {}
}
}
_wireDetail() { _wireDetail() {
const root = this.shadowRoot; const root = this.shadowRoot;
const container = root.getElementById("readmeContainer"); const container = root.getElementById("readmeContainer");
@@ -668,26 +722,8 @@ class BahmcloudStorePanel extends HTMLElement {
if (!this._readmeText) return; if (!this._readmeText) return;
// Only attempt ha-markdown if the custom element exists // Always try pretty markdown; raw fallback is already available in <details>
const hasHaMarkdown = typeof customElements !== "undefined" && !!customElements.get("ha-markdown"); this._mountPrettyMarkdown(container, this._readmeText);
if (hasHaMarkdown) {
try {
const el = document.createElement("ha-markdown");
try { el.hass = this._hass; } catch (_) {}
el.content = this._readmeText;
container.appendChild(el);
return;
} catch (_) {
// fall through to raw fallback (details already exists)
}
}
// If ha-markdown is missing, show a minimal rendered area:
const pre = document.createElement("pre");
pre.className = "readme";
pre.textContent = this._readmeText;
container.appendChild(pre);
} }
_renderFabs() { _renderFabs() {