mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2026-02-04 10:35:30 +00:00
Almanach list
This commit is contained in:
@@ -491,13 +491,17 @@ class Ge extends HTMLElement {
|
||||
static get observedAttributes() {
|
||||
}
|
||||
constructor() {
|
||||
super(), this._showall = !1, this.shown = -1, this._headings = [], this._contents = [], this._checkbox = null;
|
||||
super(), this._showall = !1, this.shown = -1, this._headings = [], this._contents = [], this._checkbox = null, this._disabled = /* @__PURE__ */ new Set(), this._defaultIndex = null;
|
||||
}
|
||||
connectedCallback() {
|
||||
this._headings = Array.from(this.querySelectorAll(".tab-list-head")), this._contents = Array.from(this.querySelectorAll(".tab-list-panel")), this.hookupEvtHandlers(), this.hideDependent(), this._headings.length === 1 && this.expand(0);
|
||||
if (this._headings = Array.from(this.querySelectorAll(".tab-list-head")), this._contents = Array.from(this.querySelectorAll(".tab-list-panel")), this._readConfig(), this.hookupEvtHandlers(), this._applyDisabled(), this.hideDependent(), this._headings.length === 1) {
|
||||
this.expand(0);
|
||||
return;
|
||||
}
|
||||
this._defaultIndex !== null && this._expandFirstAvailable(this._defaultIndex);
|
||||
}
|
||||
expand(t) {
|
||||
t < 0 || t >= this._headings.length || (this.shown = t, this._contents.forEach((e, i) => {
|
||||
t < 0 || t >= this._headings.length || this._disabled.has(t) || (this.shown = t, this._contents.forEach((e, i) => {
|
||||
i === t ? (e.classList.remove("hidden"), this._headings[i].setAttribute("aria-pressed", "true")) : (e.classList.add("hidden"), this._headings[i].setAttribute("aria-pressed", "false"));
|
||||
}));
|
||||
}
|
||||
@@ -512,6 +516,32 @@ class Ge extends HTMLElement {
|
||||
for (let t of this._contents)
|
||||
t.classList.add("hidden");
|
||||
}
|
||||
_readConfig() {
|
||||
const t = (this.getAttribute("data-disabled-indices") || "").trim(), e = (this.getAttribute("data-default-index") || "").trim();
|
||||
if (this._disabled.clear(), t && t.split(",").map((i) => parseInt(i.trim(), 10)).filter((i) => Number.isFinite(i)).forEach((i) => this._disabled.add(i)), e !== "") {
|
||||
const i = parseInt(e, 10);
|
||||
this._defaultIndex = Number.isFinite(i) ? i : null;
|
||||
} else
|
||||
this._defaultIndex = null;
|
||||
}
|
||||
_applyDisabled() {
|
||||
this._headings.forEach((t, e) => {
|
||||
this._disabled.has(e) ? t.classList.add("pointer-events-none", "opacity-60") : t.classList.remove("pointer-events-none", "opacity-60");
|
||||
});
|
||||
}
|
||||
_expandFirstAvailable(t) {
|
||||
if (this._headings.length !== 0) {
|
||||
if (!this._disabled.has(t)) {
|
||||
this.expand(t);
|
||||
return;
|
||||
}
|
||||
for (let e = 0; e < this._headings.length; e += 1)
|
||||
if (!this._disabled.has(e)) {
|
||||
this.expand(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
restore() {
|
||||
for (let t of this._headings)
|
||||
t.classList.add("cursor-pointer"), t.classList.add("select-none"), t.setAttribute("role", "button"), t.setAttribute("aria-pressed", "false"), t.setAttribute("tabindex", "0"), t.classList.remove("pointer-events-none"), t.classList.remove("!text-slate-900");
|
||||
@@ -2966,9 +2996,44 @@ class li extends HTMLElement {
|
||||
connectedCallback() {
|
||||
setTimeout(() => {
|
||||
const t = this.querySelector("form");
|
||||
t && typeof window.FormLoad == "function" && window.FormLoad(t);
|
||||
t && typeof window.FormLoad == "function" && window.FormLoad(t), this._setupDelete();
|
||||
}, 0);
|
||||
}
|
||||
_setupDelete() {
|
||||
const t = this.querySelector("form");
|
||||
if (!t)
|
||||
return;
|
||||
const e = t.getAttribute("data-delete-endpoint");
|
||||
if (!e)
|
||||
return;
|
||||
const i = this.querySelector("[data-role='edit-delete-dialog']"), s = this.querySelector("[data-role='edit-delete']"), n = this.querySelector("[data-role='edit-delete-confirm']"), a = this.querySelector("[data-role='edit-delete-cancel']");
|
||||
if (!i || !s || !n || !a)
|
||||
return;
|
||||
s.addEventListener("click", (o) => {
|
||||
o.preventDefault(), typeof i.showModal == "function" && i.showModal();
|
||||
});
|
||||
const r = (o) => {
|
||||
o && o.preventDefault(), i.open && i.close();
|
||||
};
|
||||
a.addEventListener("click", r), i.addEventListener("cancel", r), n.addEventListener("click", async (o) => {
|
||||
o.preventDefault(), r();
|
||||
const d = new FormData(t), c = {
|
||||
csrf_token: d.get("csrf_token") || "",
|
||||
last_edited: d.get("last_edited") || ""
|
||||
}, h = await fetch(e, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json"
|
||||
},
|
||||
body: JSON.stringify(c)
|
||||
});
|
||||
if (!h.ok)
|
||||
return;
|
||||
const u = await h.json().catch(() => null), m = (u == null ? void 0 : u.redirect) || "/";
|
||||
window.location.assign(m);
|
||||
});
|
||||
}
|
||||
}
|
||||
const ri = "filter-list", oi = "scroll-button", di = "tool-tip", hi = "abbrev-tooltips", ci = "int-link", ui = "popup-image", mi = "tab-list", _i = "filter-pill", pi = "image-reel", fi = "multi-select-places", gi = "multi-select-simple", bi = "single-select-remote", Me = "reset-button", Ei = "div-manager", Si = "items-editor", vi = "almanach-edit-page", Li = "relations-editor", yi = "edit-page";
|
||||
customElements.define(ci, je);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -31,6 +31,35 @@
|
||||
<div class="">{{ $agent.Id }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-end gap-y-6 pr-6">
|
||||
<div class="">
|
||||
<div class="font-bold text-sm">
|
||||
<i class="ri-navigation-line"></i> Navigation
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
{{- if $model.result.Prev -}}
|
||||
<tool-tip position="top" class="!inline">
|
||||
<div class="data-tip">{{ $model.result.Prev.Name }}</div>
|
||||
<a
|
||||
href="/person/{{ $model.result.Prev.Id }}/edit"
|
||||
class="text-gray-700 hover:text-slate-950 no-underline">
|
||||
<i class="ri-arrow-left-s-line"></i>
|
||||
</a>
|
||||
</tool-tip>
|
||||
{{- end -}}
|
||||
{{- if $model.result.Next -}}
|
||||
<tool-tip position="top" class="!inline">
|
||||
<div class="data-tip">{{ $model.result.Next.Name }}</div>
|
||||
<a
|
||||
href="/person/{{ $model.result.Next.Id }}/edit"
|
||||
class="text-gray-700 hover:text-slate-950 no-underline">
|
||||
<i class="ri-arrow-right-s-line"></i>
|
||||
</a>
|
||||
</tool-tip>
|
||||
{{- end -}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-end gap-y-6 pr-4">
|
||||
<div class="">
|
||||
<div class="font-bold text-sm mb-1"><i class="ri-calendar-line"></i> Zuletzt bearbeitet</div>
|
||||
@@ -122,6 +151,85 @@
|
||||
<label for="edit_comment" class="inputlabel">Bearbeitungsvermerk</label>
|
||||
<textarea name="edit_comment" id="edit_comment" class="inputinput" autocomplete="off" rows="1">{{- $agent.Comment -}}</textarea>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<tab-list
|
||||
data-default-index="{{ if gt (len $model.result.Entries) 0 }}0{{ else if gt (len $model.result.Contents) 0 }}1{{ end }}"
|
||||
data-disabled-indices="{{ if and (eq (len $model.result.Entries) 0) (eq (len $model.result.Contents) 0) }}0,1{{ else if eq (len $model.result.Entries) 0 }}0{{ else if eq (len $model.result.Contents) 0 }}1{{ end }}">
|
||||
<div class="flex items-center gap-3 text-sm font-bold text-gray-700">
|
||||
<div class="tab-list-head flex items-center gap-2">
|
||||
<i class="ri-book-2-line"></i>
|
||||
<span>Verknüpfte Bände</span>
|
||||
<span class="text-xs bg-stone-200 text-gray-700 px-2 py-0.5 rounded-sm">{{ len $model.result.Entries }}</span>
|
||||
</div>
|
||||
<div class="tab-list-head flex items-center gap-2">
|
||||
<i class="ri-article-line"></i>
|
||||
<span>Verknüpfte Inhalte</span>
|
||||
<span class="text-xs bg-stone-200 text-gray-700 px-2 py-0.5 rounded-sm">{{ len $model.result.Contents }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="border-slate-400 mt-2 mb-3" />
|
||||
<div class="tab-list-panel text-sm text-gray-700 max-h-96 overflow-auto pr-1 pl-0 ml-0">
|
||||
{{- if $model.result.Entries -}}
|
||||
<ul class="flex flex-col gap-3 pl-0 pr-0 m-0 ml-0 list-none">
|
||||
{{- range $entry := $model.result.Entries -}}
|
||||
{{- $entryTypes := index $model.result.EntryTypes $entry.Id -}}
|
||||
<li class="flex items-baseline justify-between gap-3 ml-0 pl-0">
|
||||
<div class="flex flex-col gap-1">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}" class="no-underline hover:text-slate-900">
|
||||
{{- $entry.PreferredTitle -}}
|
||||
</a>
|
||||
{{- if $entryTypes -}}
|
||||
<div class="text-xs text-gray-600">
|
||||
Rolle:
|
||||
{{- range $i, $t := $entryTypes -}}
|
||||
{{- if $i }}, {{ end -}}{{ $t -}}
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
<span class="text-xs text-gray-500">{{ $entry.Year }}</span>
|
||||
</li>
|
||||
{{- end -}}
|
||||
</ul>
|
||||
{{- else -}}
|
||||
<div class="italic text-gray-500">Keine Bände verknüpft.</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
<div class="tab-list-panel text-sm text-gray-700 max-h-96 overflow-auto pr-1 pl-0 ml-0">
|
||||
{{- if $model.result.Contents -}}
|
||||
<ul class="flex flex-col gap-3 pl-0 pr-0 m-0 ml-0 list-none">
|
||||
{{- range $content := $model.result.Contents -}}
|
||||
{{- $entry := index $model.result.ContentEntries $content.Entry -}}
|
||||
{{- $types := index $model.result.ContentTypes $content.Id -}}
|
||||
<li class="flex flex-col gap-1 ml-0 pl-0">
|
||||
<a href="/beitrag/{{ $content.MusenalmID }}" class="no-underline hover:text-slate-900 font-semibold">
|
||||
{{- if $content.PreferredTitle -}}{{ $content.PreferredTitle }}{{- else -}}Inhalt #{{ $content.MusenalmID }}{{- end -}}
|
||||
</a>
|
||||
<div class="text-xs text-gray-600 flex flex-wrap gap-3">
|
||||
{{- if $entry -}}
|
||||
<span>Band: <a href="/almanach/{{ $entry.MusenalmID }}" class="no-underline hover:text-slate-900">{{ $entry.PreferredTitle }}</a></span>
|
||||
{{- end -}}
|
||||
{{- if $types -}}
|
||||
<span>
|
||||
Rolle:
|
||||
{{- range $i, $t := $types -}}
|
||||
{{- if $i }}, {{ end -}}{{ $t -}}
|
||||
{{- end -}}
|
||||
</span>
|
||||
{{- end -}}
|
||||
{{- if $content.MusenalmPagination -}}
|
||||
<span>Seite: {{ $content.MusenalmPagination }}</span>
|
||||
{{- end -}}
|
||||
</div>
|
||||
</li>
|
||||
{{- end -}}
|
||||
</ul>
|
||||
{{- else -}}
|
||||
<div class="italic text-gray-500">Keine Inhalte verknüpft.</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
</tab-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -31,6 +31,35 @@
|
||||
<div class="">{{ $series.Id }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-end gap-y-6 pr-6">
|
||||
<div class="">
|
||||
<div class="font-bold text-sm">
|
||||
<i class="ri-navigation-line"></i> Navigation
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
{{- if $model.result.Prev -}}
|
||||
<tool-tip position="top" class="!inline">
|
||||
<div class="data-tip">{{ $model.result.Prev.Title }}</div>
|
||||
<a
|
||||
href="/reihe/{{ $model.result.Prev.MusenalmID }}/edit"
|
||||
class="text-gray-700 hover:text-slate-950 no-underline">
|
||||
<i class="ri-arrow-left-s-line"></i>
|
||||
</a>
|
||||
</tool-tip>
|
||||
{{- end -}}
|
||||
{{- if $model.result.Next -}}
|
||||
<tool-tip position="top" class="!inline">
|
||||
<div class="data-tip">{{ $model.result.Next.Title }}</div>
|
||||
<a
|
||||
href="/reihe/{{ $model.result.Next.MusenalmID }}/edit"
|
||||
class="text-gray-700 hover:text-slate-950 no-underline">
|
||||
<i class="ri-arrow-right-s-line"></i>
|
||||
</a>
|
||||
</tool-tip>
|
||||
{{- end -}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-end gap-y-6 pr-4">
|
||||
<div class="">
|
||||
<div class="font-bold text-sm mb-1"><i class="ri-calendar-line"></i> Zuletzt bearbeitet</div>
|
||||
@@ -58,7 +87,8 @@
|
||||
class="w-full dbform"
|
||||
id="changeseriesform"
|
||||
method="POST"
|
||||
action="/reihe/{{ $series.MusenalmID }}/edit">
|
||||
action="/reihe/{{ $series.MusenalmID }}/edit"
|
||||
data-delete-endpoint="/reihe/{{ $series.MusenalmID }}/edit/delete">
|
||||
<input type="hidden" name="csrf_token" value="{{ $model.csrf_token }}" />
|
||||
<input type="hidden" name="last_edited" value="{{ $series.Updated }}" />
|
||||
|
||||
@@ -101,6 +131,74 @@
|
||||
<label for="edit_comment" class="inputlabel">Bearbeitungsvermerk</label>
|
||||
<textarea name="edit_comment" id="edit_comment" class="inputinput" autocomplete="off" rows="1">{{- $series.Comment -}}</textarea>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<tab-list
|
||||
data-default-index="{{ if gt (len $model.result.Entries) 0 }}0{{ else if gt (len $model.result.Contents) 0 }}1{{ end }}"
|
||||
data-disabled-indices="{{ if and (eq (len $model.result.Entries) 0) (eq (len $model.result.Contents) 0) }}0,1{{ else if eq (len $model.result.Entries) 0 }}0{{ else if eq (len $model.result.Contents) 0 }}1{{ end }}">
|
||||
<div class="flex items-center gap-3 text-sm font-bold text-gray-700">
|
||||
<div class="tab-list-head flex items-center gap-2">
|
||||
<i class="ri-book-2-line"></i>
|
||||
<span>Verknüpfte Bände</span>
|
||||
<span class="text-xs bg-stone-200 text-gray-700 px-2 py-0.5 rounded-sm">{{ len $model.result.Entries }}</span>
|
||||
</div>
|
||||
<div class="tab-list-head flex items-center gap-2">
|
||||
<i class="ri-article-line"></i>
|
||||
<span>Verknüpfte Inhalte</span>
|
||||
<span class="text-xs bg-stone-200 text-gray-700 px-2 py-0.5 rounded-sm">{{ len $model.result.Contents }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="border-slate-400 mt-2 mb-3" />
|
||||
<div class="tab-list-panel text-sm text-gray-700 max-h-96 overflow-auto pr-1 pl-0 ml-0">
|
||||
{{- if $model.result.Entries -}}
|
||||
<ul class="flex flex-col gap-2 pl-0 pr-0 m-0 ml-0 list-none">
|
||||
{{- range $entry := $model.result.Entries -}}
|
||||
<li class="flex items-baseline justify-between gap-3 ml-0 pl-0">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}" class="no-underline hover:text-slate-900">
|
||||
{{- $entry.PreferredTitle -}}
|
||||
</a>
|
||||
<span class="text-xs text-gray-500">{{ $entry.Year }}</span>
|
||||
</li>
|
||||
{{- end -}}
|
||||
</ul>
|
||||
{{- else -}}
|
||||
<div class="italic text-gray-500">Keine Bände verknüpft.</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
<div class="tab-list-panel text-sm text-gray-700 max-h-96 overflow-auto pr-1 pl-0 ml-0">
|
||||
{{- if $model.result.Contents -}}
|
||||
<ul class="flex flex-col gap-3 pl-0 pr-0 m-0 ml-0 list-none">
|
||||
{{- range $content := $model.result.Contents -}}
|
||||
{{- $entry := index $model.result.ContentEntries $content.Entry -}}
|
||||
{{- $types := index $model.result.ContentTypes $content.Id -}}
|
||||
<li class="flex flex-col gap-1 ml-0 pl-0">
|
||||
<a href="/beitrag/{{ $content.MusenalmID }}" class="no-underline hover:text-slate-900 font-semibold">
|
||||
{{- if $content.PreferredTitle -}}{{ $content.PreferredTitle }}{{- else -}}Inhalt #{{ $content.MusenalmID }}{{- end -}}
|
||||
</a>
|
||||
<div class="text-xs text-gray-600 flex flex-wrap gap-3">
|
||||
{{- if $entry -}}
|
||||
<span>Band: <a href="/almanach/{{ $entry.MusenalmID }}" class="no-underline hover:text-slate-900">{{ $entry.PreferredTitle }}</a></span>
|
||||
{{- end -}}
|
||||
{{- if $types -}}
|
||||
<span>
|
||||
Typ:
|
||||
{{- range $i, $t := $types -}}
|
||||
{{- if $i }}, {{ end -}}{{ $t -}}
|
||||
{{- end -}}
|
||||
</span>
|
||||
{{- end -}}
|
||||
{{- if $content.MusenalmPagination -}}
|
||||
<span>Seite: {{ $content.MusenalmPagination }}</span>
|
||||
{{- end -}}
|
||||
</div>
|
||||
</li>
|
||||
{{- end -}}
|
||||
</ul>
|
||||
{{- else -}}
|
||||
<div class="italic text-gray-500">Keine Inhalte verknüpft.</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
</tab-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -115,6 +213,13 @@
|
||||
<i class="ri-loop-left-line"></i>
|
||||
<span>Reset</span>
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
class="resetbutton w-40 flex items-center gap-2 justify-center bg-red-50 text-red-800 hover:bg-red-100 hover:text-red-900"
|
||||
data-role="edit-delete">
|
||||
<i class="ri-delete-bin-line"></i>
|
||||
<span>Reihe löschen</span>
|
||||
</button>
|
||||
<button type="submit" class="submitbutton w-40 flex items-center gap-2 justify-center">
|
||||
<i class="ri-save-line"></i>
|
||||
<span>Speichern</span>
|
||||
@@ -123,4 +228,36 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<dialog data-role="edit-delete-dialog" class="fixed inset-0 m-auto rounded-md border border-slate-200 p-0 shadow-xl backdrop:bg-black/40">
|
||||
<div class="p-5 w-[26rem]">
|
||||
<div class="text-base font-bold text-gray-900">Reihe löschen?</div>
|
||||
<div class="text-sm font-bold text-gray-900 mt-1">{{ $series.Title }}</div>
|
||||
<p class="text-sm text-gray-700 mt-2">
|
||||
Alle Bände, Inhalte und Verknüpfungen der bevorzugten Reihentitel werden gelöscht.
|
||||
</p>
|
||||
<div class="mt-3">
|
||||
<div class="text-sm font-semibold text-gray-700">Betroffene Bände</div>
|
||||
<div class="mt-2 max-h-40 overflow-auto pr-1">
|
||||
{{- if $model.result.PreferredEntries -}}
|
||||
<ul class="flex flex-col gap-2 pl-0 pr-0 m-0 list-none">
|
||||
{{- range $entry := $model.result.PreferredEntries -}}
|
||||
<li class="flex items-baseline justify-between gap-3 ml-0 pl-0 text-sm text-gray-700">
|
||||
<span>{{ $entry.PreferredTitle }}</span>
|
||||
<span class="text-xs text-gray-500">{{ $entry.Year }}</span>
|
||||
</li>
|
||||
{{- end -}}
|
||||
</ul>
|
||||
{{- else -}}
|
||||
<div class="italic text-gray-500">Keine Bände betroffen.</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-end gap-3 mt-4">
|
||||
<button type="button" class="resetbutton w-auto px-3 py-1 text-sm" data-role="edit-delete-cancel">Abbrechen</button>
|
||||
<button type="button" class="submitbutton w-auto bg-red-700 hover:bg-red-800 px-3 py-1 text-sm" data-role="edit-delete-confirm">
|
||||
Löschen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
</edit-page>
|
||||
|
||||
@@ -5,6 +5,69 @@ export class EditPage extends HTMLElement {
|
||||
if (form && typeof window.FormLoad === "function") {
|
||||
window.FormLoad(form);
|
||||
}
|
||||
this._setupDelete();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
_setupDelete() {
|
||||
const form = this.querySelector("form");
|
||||
if (!form) {
|
||||
return;
|
||||
}
|
||||
const deleteEndpoint = form.getAttribute("data-delete-endpoint");
|
||||
if (!deleteEndpoint) {
|
||||
return;
|
||||
}
|
||||
const dialog = this.querySelector("[data-role='edit-delete-dialog']");
|
||||
const deleteButton = this.querySelector("[data-role='edit-delete']");
|
||||
const confirmButton = this.querySelector("[data-role='edit-delete-confirm']");
|
||||
const cancelButton = this.querySelector("[data-role='edit-delete-cancel']");
|
||||
|
||||
if (!dialog || !deleteButton || !confirmButton || !cancelButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
deleteButton.addEventListener("click", (event) => {
|
||||
event.preventDefault();
|
||||
if (typeof dialog.showModal === "function") {
|
||||
dialog.showModal();
|
||||
}
|
||||
});
|
||||
|
||||
const closeDialog = (event) => {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if (dialog.open) {
|
||||
dialog.close();
|
||||
}
|
||||
};
|
||||
|
||||
cancelButton.addEventListener("click", closeDialog);
|
||||
dialog.addEventListener("cancel", closeDialog);
|
||||
|
||||
confirmButton.addEventListener("click", async (event) => {
|
||||
event.preventDefault();
|
||||
closeDialog();
|
||||
const formData = new FormData(form);
|
||||
const payload = {
|
||||
csrf_token: formData.get("csrf_token") || "",
|
||||
last_edited: formData.get("last_edited") || "",
|
||||
};
|
||||
const response = await fetch(deleteEndpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!response.ok) {
|
||||
return;
|
||||
}
|
||||
const data = await response.json().catch(() => null);
|
||||
const redirect = data?.redirect || "/";
|
||||
window.location.assign(redirect);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,18 @@
|
||||
@apply px-1.5 italic text-gray-600;
|
||||
}
|
||||
|
||||
/* Reset global list indentation inside tab panels */
|
||||
.tab-list-panel ul {
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tab-list-panel li {
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
/* Disabled form controls in deleted relations */
|
||||
[data-rel-row].bg-red-50 select:disabled,
|
||||
[data-rel-row].bg-red-50 input[type="checkbox"]:disabled:not([data-delete-toggle]) {
|
||||
|
||||
@@ -8,16 +8,25 @@ export class TabList extends HTMLElement {
|
||||
this._headings = [];
|
||||
this._contents = [];
|
||||
this._checkbox = null;
|
||||
this._disabled = new Set();
|
||||
this._defaultIndex = null;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this._headings = Array.from(this.querySelectorAll(".tab-list-head"));
|
||||
this._contents = Array.from(this.querySelectorAll(".tab-list-panel"));
|
||||
this._readConfig();
|
||||
this.hookupEvtHandlers();
|
||||
this._applyDisabled();
|
||||
this.hideDependent();
|
||||
|
||||
if (this._headings.length === 1) {
|
||||
this.expand(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._defaultIndex !== null) {
|
||||
this._expandFirstAvailable(this._defaultIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +34,9 @@ export class TabList extends HTMLElement {
|
||||
if (index < 0 || index >= this._headings.length) {
|
||||
return;
|
||||
}
|
||||
if (this._disabled.has(index)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.shown = index;
|
||||
|
||||
@@ -67,6 +79,53 @@ export class TabList extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
_readConfig() {
|
||||
const disabledRaw = (this.getAttribute("data-disabled-indices") || "").trim();
|
||||
const defaultRaw = (this.getAttribute("data-default-index") || "").trim();
|
||||
|
||||
this._disabled.clear();
|
||||
if (disabledRaw) {
|
||||
disabledRaw
|
||||
.split(",")
|
||||
.map((value) => parseInt(value.trim(), 10))
|
||||
.filter((value) => Number.isFinite(value))
|
||||
.forEach((value) => this._disabled.add(value));
|
||||
}
|
||||
|
||||
if (defaultRaw !== "") {
|
||||
const parsed = parseInt(defaultRaw, 10);
|
||||
this._defaultIndex = Number.isFinite(parsed) ? parsed : null;
|
||||
} else {
|
||||
this._defaultIndex = null;
|
||||
}
|
||||
}
|
||||
|
||||
_applyDisabled() {
|
||||
this._headings.forEach((heading, index) => {
|
||||
if (this._disabled.has(index)) {
|
||||
heading.classList.add("pointer-events-none", "opacity-60");
|
||||
} else {
|
||||
heading.classList.remove("pointer-events-none", "opacity-60");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_expandFirstAvailable(preferredIndex) {
|
||||
if (this._headings.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (!this._disabled.has(preferredIndex)) {
|
||||
this.expand(preferredIndex);
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < this._headings.length; i += 1) {
|
||||
if (!this._disabled.has(i)) {
|
||||
this.expand(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
restore() {
|
||||
for (let heading of this._headings) {
|
||||
heading.classList.add("cursor-pointer");
|
||||
|
||||
Reference in New Issue
Block a user