commit c82b401b63d6d5a9a097a4383092487df2e79bd9
parent b8b6cc4d54aaaae543dcba98ea13593c5e04996f
Author: breadcat <breadcat@users.noreply.github.com>
Date: Tue, 30 Jun 2026 09:17:29 +0100
Update tag list via Ajax when amending
Diffstat:
2 files changed, 98 insertions(+), 3 deletions(-)
diff --git a/static/ajax-tags.js b/static/ajax-tags.js
@@ -0,0 +1,93 @@
+
+function initAjaxTagForms() {
+ document.querySelectorAll('.ajax-tag-form').forEach((form) => {
+ if (form.dataset.ajaxBound) return; // avoid double-binding after a swap
+ form.dataset.ajaxBound = 'true';
+ form.addEventListener('submit', handleAjaxTagSubmit);
+ });
+}
+
+async function handleAjaxTagSubmit(e) {
+ e.preventDefault();
+ const form = e.target;
+ const submitButton = form.querySelector('button[type="submit"]');
+ if (submitButton) submitButton.disabled = true;
+
+ const action = form.getAttribute('action') || window.location.pathname;
+
+ try {
+ const response = await fetch(action, {
+ method: 'POST',
+ body: new FormData(form),
+ });
+
+ if (!response.ok) {
+ throw new Error('Request failed with status ' + response.status);
+ }
+
+ const html = await response.text();
+ const doc = new DOMParser().parseFromString(html, 'text/html');
+
+ // Swap the tag list
+ const newTagsList = doc.getElementById('tags-list');
+ const currentTagsList = document.getElementById('tags-list');
+ if (newTagsList && currentTagsList) {
+ currentTagsList.innerHTML = newTagsList.innerHTML;
+ }
+
+ // Swap the category datalist (new categories may have been created)
+ const newCategories = doc.getElementById('categories');
+ const currentCategories = document.getElementById('categories');
+ if (newCategories && currentCategories) {
+ currentCategories.innerHTML = newCategories.innerHTML;
+ }
+
+ // Show success/error message, pulled from the redirected URL's query params
+ const finalUrl = new URL(response.url, window.location.origin);
+ const statusEl = document.getElementById('tag-status');
+ const success = finalUrl.searchParams.get('success');
+ const error = finalUrl.searchParams.get('error');
+ if (statusEl) {
+ if (error) {
+ statusEl.textContent = error;
+ statusEl.className = 'tag-status-error';
+ } else if (success) {
+ statusEl.textContent = success;
+ statusEl.className = 'tag-status-success';
+ } else {
+ statusEl.textContent = '';
+ statusEl.className = '';
+ }
+ if (success || error) {
+ setTimeout(() => {
+ statusEl.textContent = '';
+ statusEl.className = '';
+ }, 4000);
+ }
+ }
+
+ // Clear the "Add Tag" inputs after a successful add
+ if (!error) {
+ const catInput = form.querySelector('input[name="category"]');
+ const valInput = form.querySelector('input[name="value"]');
+ if (catInput && form.querySelector('button[type="submit"]').textContent.includes('Add')) {
+ catInput.value = '';
+ valInput.value = '';
+ }
+ }
+
+ // Re-bind the delete buttons that just got swapped in
+ initAjaxTagForms();
+ } catch (err) {
+ console.error('Tag update failed:', err);
+ const statusEl = document.getElementById('tag-status');
+ if (statusEl) {
+ statusEl.textContent = 'Failed to update tag. Please try again.';
+ statusEl.className = 'tag-status-error';
+ }
+ } finally {
+ if (submitButton) submitButton.disabled = false;
+ }
+}
+
+document.addEventListener('DOMContentLoaded', initAjaxTagForms);
diff --git a/templates/file.html b/templates/file.html
@@ -7,13 +7,13 @@
<details open>
<summary>Tags</summary>
- <ul>
+ <ul id="tags-list">
{{range $k, $vs := .Data.File.Tags}}
<li>
<span class="file-tag-category">{{$k}}:</span><br>
{{range $i, $v := $vs}}
{{if $i}}<br> {{end}}
- <form method="post" action="/file/{{$.Data.File.ID}}/tag/delete"><input type="hidden" name="category" value="{{$k}}"><input type="hidden" name="value" value="{{$v}}"><button class="text-button" type="submit">x</button></form>
+ <form method="post" action="/file/{{$.Data.File.ID}}/tag/delete" class="ajax-tag-form"><input type="hidden" name="category" value="{{$k}}"><input type="hidden" name="value" value="{{$v}}"><button class="text-button" type="submit">x</button></form>
<a href="/tag/{{pathEscape $k}}/{{pathEscape $v}}">{{$v}}</a>
{{end}}
</li>
@@ -25,13 +25,15 @@
<details>
<summary>Add Tags</summary>
- <form method="post">
+ <form method="post" class="ajax-tag-form">
<input type="text" name="category" list="categories" placeholder="Category"><br>
<datalist id="categories">{{range .Data.Categories}}<option value="{{.}}">{{end}}</datalist>
<input type="text" name="value" placeholder="Value"><br>
<button class="text-button" type="submit">Add Tag</button>
</form>
</details>
+ <div id="tag-status"></div>
+ <script src="/static/ajax-tags.js" defer></script>
<details>
<summary>Properties</summary>