0.5.10
This commit is contained in:
@@ -15,7 +15,8 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
|
||||
this._search = "";
|
||||
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._detailRepo = null;
|
||||
@@ -562,6 +563,25 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
const root = this.shadowRoot;
|
||||
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");
|
||||
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") {
|
||||
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) {
|
||||
@@ -643,16 +678,40 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
const cat = this._safeText(r?.category) || "";
|
||||
if (this._category !== "all" && this._category !== cat) return false;
|
||||
|
||||
const prov = this._safeText(r?.provider) || "other";
|
||||
if (this._provider !== "all") {
|
||||
if (this._provider === "custom" && r?.source !== "custom") return false;
|
||||
if (this._provider !== "custom" && prov !== this._provider) return false;
|
||||
}
|
||||
const latest = this._safeText(r?.latest_version);
|
||||
const installed = this._asBoolStrict(r?.installed);
|
||||
const installedVersion = this._safeText(r?.installed_version);
|
||||
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;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const an = (this._safeText(a?.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);
|
||||
});
|
||||
|
||||
@@ -660,8 +719,6 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
new Set(repos.map((r) => this._safeText(r?.category)).filter((c) => !!c))
|
||||
).sort();
|
||||
|
||||
const providers = ["github", "gitlab", "gitea", "other"];
|
||||
|
||||
const cards = filtered
|
||||
.map((r) => {
|
||||
const id = this._safeId(r?.id);
|
||||
@@ -705,10 +762,17 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
<option value="all">All categories</option>
|
||||
${categories.map((c) => `<option value="${this._esc(c)}" ${this._category === c ? "selected" : ""}>${this._esc(c)}</option>`).join("")}
|
||||
</select>
|
||||
<select id="prov">
|
||||
<option value="all">All providers</option>
|
||||
<option value="custom" ${this._provider === "custom" ? "selected" : ""}>Custom</option>
|
||||
${providers.map((p) => `<option value="${p}" ${this._provider === p ? "selected" : ""}>${p.toUpperCase()}</option>`).join("")}
|
||||
<select id="filter">
|
||||
<option value="all" ${this._filter === "all" ? "selected" : ""}>All</option>
|
||||
<option value="installed" ${this._filter === "installed" ? "selected" : ""}>Installed</option>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
@@ -725,7 +789,8 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
|
||||
const q = root.getElementById("q");
|
||||
const cat = root.getElementById("cat");
|
||||
const prov = root.getElementById("prov");
|
||||
const filter = root.getElementById("filter");
|
||||
const sort = root.getElementById("sort");
|
||||
|
||||
if (q) {
|
||||
q.addEventListener("input", (e) => {
|
||||
@@ -739,9 +804,15 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
this._update();
|
||||
});
|
||||
}
|
||||
if (prov) {
|
||||
prov.addEventListener("change", (e) => {
|
||||
this._provider = e?.target?.value || "all";
|
||||
if (filter) {
|
||||
filter.addEventListener("change", (e) => {
|
||||
this._filter = e?.target?.value || "all";
|
||||
this._update();
|
||||
});
|
||||
}
|
||||
if (sort) {
|
||||
sort.addEventListener("change", (e) => {
|
||||
this._sort = e?.target?.value || "az";
|
||||
this._update();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user