0.5.10
This commit is contained in:
@@ -15,7 +15,8 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
|
|
||||||
this._search = "";
|
this._search = "";
|
||||||
this._category = "all";
|
this._category = "all";
|
||||||
this._provider = "all"; // all|github|gitea|gitlab|other|custom
|
this._filter = "all"; // all|installed|not_installed|updates|custom
|
||||||
|
this._sort = "az"; // az|updates_first|installed_first
|
||||||
|
|
||||||
this._detailRepoId = null;
|
this._detailRepoId = null;
|
||||||
this._detailRepo = null;
|
this._detailRepo = null;
|
||||||
@@ -562,6 +563,25 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
const root = this.shadowRoot;
|
const root = this.shadowRoot;
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
|
|
||||||
|
// Preserve focus & cursor position for inputs that trigger a re-render (e.g. search).
|
||||||
|
// Without this, mobile browsers may drop focus after each keystroke.
|
||||||
|
const active = root.activeElement;
|
||||||
|
const restore = {
|
||||||
|
id: active && active.id ? String(active.id) : null,
|
||||||
|
start: null,
|
||||||
|
end: null,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
if (active && (active.tagName === "INPUT" || active.tagName === "TEXTAREA")) {
|
||||||
|
if (typeof active.selectionStart === "number" && typeof active.selectionEnd === "number") {
|
||||||
|
restore.start = active.selectionStart;
|
||||||
|
restore.end = active.selectionEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
const subtitle = root.getElementById("subtitle");
|
const subtitle = root.getElementById("subtitle");
|
||||||
if (subtitle) subtitle.textContent = this._view === "detail" ? "Details" : this._view[0].toUpperCase() + this._view.slice(1);
|
if (subtitle) subtitle.textContent = this._view === "detail" ? "Details" : this._view[0].toUpperCase() + this._view.slice(1);
|
||||||
|
|
||||||
@@ -604,6 +624,21 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
if (this._view === "detail") {
|
if (this._view === "detail") {
|
||||||
this._wireDetail(); // now always wires buttons
|
this._wireDetail(); // now always wires buttons
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore focus and cursor for the search field after re-render.
|
||||||
|
if (restore.id && this._view === "store") {
|
||||||
|
const el = root.getElementById(restore.id);
|
||||||
|
if (el && (el.tagName === "INPUT" || el.tagName === "TEXTAREA")) {
|
||||||
|
try {
|
||||||
|
el.focus({ preventScroll: true });
|
||||||
|
if (restore.start !== null && restore.end !== null && typeof el.setSelectionRange === "function") {
|
||||||
|
el.setSelectionRange(restore.start, restore.end);
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_safeText(v) {
|
_safeText(v) {
|
||||||
@@ -643,16 +678,40 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
const cat = this._safeText(r?.category) || "";
|
const cat = this._safeText(r?.category) || "";
|
||||||
if (this._category !== "all" && this._category !== cat) return false;
|
if (this._category !== "all" && this._category !== cat) return false;
|
||||||
|
|
||||||
const prov = this._safeText(r?.provider) || "other";
|
const latest = this._safeText(r?.latest_version);
|
||||||
if (this._provider !== "all") {
|
const installed = this._asBoolStrict(r?.installed);
|
||||||
if (this._provider === "custom" && r?.source !== "custom") return false;
|
const installedVersion = this._safeText(r?.installed_version);
|
||||||
if (this._provider !== "custom" && prov !== this._provider) return false;
|
const updateAvailable = installed && !!latest && (!installedVersion || latest !== installedVersion);
|
||||||
}
|
|
||||||
|
if (this._filter === "installed" && !installed) return false;
|
||||||
|
if (this._filter === "not_installed" && installed) return false;
|
||||||
|
if (this._filter === "updates" && !updateAvailable) return false;
|
||||||
|
if (this._filter === "custom" && r?.source !== "custom") return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
const an = (this._safeText(a?.name) || "").toLowerCase();
|
const an = (this._safeText(a?.name) || "").toLowerCase();
|
||||||
const bn = (this._safeText(b?.name) || "").toLowerCase();
|
const bn = (this._safeText(b?.name) || "").toLowerCase();
|
||||||
|
|
||||||
|
const alatest = this._safeText(a?.latest_version);
|
||||||
|
const ainstalled = this._asBoolStrict(a?.installed);
|
||||||
|
const ainstalledVersion = this._safeText(a?.installed_version);
|
||||||
|
const aupdate = ainstalled && !!alatest && (!ainstalledVersion || alatest !== ainstalledVersion);
|
||||||
|
|
||||||
|
const blatest = this._safeText(b?.latest_version);
|
||||||
|
const binstalled = this._asBoolStrict(b?.installed);
|
||||||
|
const binstalledVersion = this._safeText(b?.installed_version);
|
||||||
|
const bupdate = binstalled && !!blatest && (!binstalledVersion || blatest !== binstalledVersion);
|
||||||
|
|
||||||
|
if (this._sort === "updates_first") {
|
||||||
|
if (aupdate !== bupdate) return aupdate ? -1 : 1;
|
||||||
|
return an.localeCompare(bn);
|
||||||
|
}
|
||||||
|
if (this._sort === "installed_first") {
|
||||||
|
if (ainstalled !== binstalled) return ainstalled ? -1 : 1;
|
||||||
|
return an.localeCompare(bn);
|
||||||
|
}
|
||||||
return an.localeCompare(bn);
|
return an.localeCompare(bn);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -660,8 +719,6 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
new Set(repos.map((r) => this._safeText(r?.category)).filter((c) => !!c))
|
new Set(repos.map((r) => this._safeText(r?.category)).filter((c) => !!c))
|
||||||
).sort();
|
).sort();
|
||||||
|
|
||||||
const providers = ["github", "gitlab", "gitea", "other"];
|
|
||||||
|
|
||||||
const cards = filtered
|
const cards = filtered
|
||||||
.map((r) => {
|
.map((r) => {
|
||||||
const id = this._safeId(r?.id);
|
const id = this._safeId(r?.id);
|
||||||
@@ -705,10 +762,17 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
<option value="all">All categories</option>
|
<option value="all">All categories</option>
|
||||||
${categories.map((c) => `<option value="${this._esc(c)}" ${this._category === c ? "selected" : ""}>${this._esc(c)}</option>`).join("")}
|
${categories.map((c) => `<option value="${this._esc(c)}" ${this._category === c ? "selected" : ""}>${this._esc(c)}</option>`).join("")}
|
||||||
</select>
|
</select>
|
||||||
<select id="prov">
|
<select id="filter">
|
||||||
<option value="all">All providers</option>
|
<option value="all" ${this._filter === "all" ? "selected" : ""}>All</option>
|
||||||
<option value="custom" ${this._provider === "custom" ? "selected" : ""}>Custom</option>
|
<option value="installed" ${this._filter === "installed" ? "selected" : ""}>Installed</option>
|
||||||
${providers.map((p) => `<option value="${p}" ${this._provider === p ? "selected" : ""}>${p.toUpperCase()}</option>`).join("")}
|
<option value="not_installed" ${this._filter === "not_installed" ? "selected" : ""}>Not installed</option>
|
||||||
|
<option value="updates" ${this._filter === "updates" ? "selected" : ""}>Updates available</option>
|
||||||
|
<option value="custom" ${this._filter === "custom" ? "selected" : ""}>Custom repos</option>
|
||||||
|
</select>
|
||||||
|
<select id="sort">
|
||||||
|
<option value="az" ${this._sort === "az" ? "selected" : ""}>A–Z</option>
|
||||||
|
<option value="updates_first" ${this._sort === "updates_first" ? "selected" : ""}>Updates first</option>
|
||||||
|
<option value="installed_first" ${this._sort === "installed_first" ? "selected" : ""}>Installed first</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -725,7 +789,8 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
|
|
||||||
const q = root.getElementById("q");
|
const q = root.getElementById("q");
|
||||||
const cat = root.getElementById("cat");
|
const cat = root.getElementById("cat");
|
||||||
const prov = root.getElementById("prov");
|
const filter = root.getElementById("filter");
|
||||||
|
const sort = root.getElementById("sort");
|
||||||
|
|
||||||
if (q) {
|
if (q) {
|
||||||
q.addEventListener("input", (e) => {
|
q.addEventListener("input", (e) => {
|
||||||
@@ -739,9 +804,15 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
this._update();
|
this._update();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (prov) {
|
if (filter) {
|
||||||
prov.addEventListener("change", (e) => {
|
filter.addEventListener("change", (e) => {
|
||||||
this._provider = e?.target?.value || "all";
|
this._filter = e?.target?.value || "all";
|
||||||
|
this._update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (sort) {
|
||||||
|
sort.addEventListener("change", (e) => {
|
||||||
|
this._sort = e?.target?.value || "az";
|
||||||
this._update();
|
this._update();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user