Add clear buttons in bookmark form (#846)

This commit is contained in:
Sascha Ißbrücker 2024-09-23 11:02:30 +02:00 committed by GitHub
parent c5c5949d20
commit ed57da3c99
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 101 additions and 41 deletions

View file

@ -0,0 +1,42 @@
import { Behavior, registerBehavior } from "./index";
class ClearButtonBehavior extends Behavior {
constructor(element) {
super(element);
this.field = document.getElementById(element.dataset.for);
if (!this.field) {
console.error(`Field with ID ${element.dataset.for} not found`);
return;
}
this.update = this.update.bind(this);
this.clear = this.clear.bind(this);
this.element.addEventListener("click", this.clear);
this.field.addEventListener("input", this.update);
this.field.addEventListener("value-changed", this.update);
this.update();
}
destroy() {
if (!this.field) {
return;
}
this.element.removeEventListener("click", this.clear);
this.field.removeEventListener("input", this.update);
this.field.removeEventListener("value-changed", this.update);
}
update() {
this.element.style.display = this.field.value ? "inline-flex" : "none";
}
clear() {
this.field.value = "";
this.field.focus();
this.update();
}
}
registerBehavior("ld-clear-button", ClearButtonBehavior);

View file

@ -16,7 +16,24 @@ const mutationObserver = new MutationObserver((mutations) => {
}); });
}); });
document.addEventListener("turbo:load", () => { // Update behaviors on Turbo events
// - turbo:load: initial page load, only listen once, afterward can rely on turbo:render
// - turbo:render: after page navigation, including back/forward, and failed form submissions
// - turbo:before-cache: before page navigation, reset DOM before caching
document.addEventListener(
"turbo:load",
() => {
mutationObserver.observe(document.body, {
childList: true,
subtree: true,
});
applyBehaviors(document.body);
},
{ once: true },
);
document.addEventListener("turbo:render", () => {
mutationObserver.observe(document.body, { mutationObserver.observe(document.body, {
childList: true, childList: true,
subtree: true, subtree: true,
@ -41,7 +58,6 @@ Behavior.interacting = false;
export function registerBehavior(name, behavior) { export function registerBehavior(name, behavior) {
behaviorRegistry[name] = behavior; behaviorRegistry[name] = behavior;
applyBehaviors(document, [name]);
} }
export function applyBehaviors(container, behaviorNames = null) { export function applyBehaviors(container, behaviorNames = null) {

View file

@ -1,6 +1,7 @@
import "@hotwired/turbo"; import "@hotwired/turbo";
import "./behaviors/bookmark-page"; import "./behaviors/bookmark-page";
import "./behaviors/bulk-edit"; import "./behaviors/bulk-edit";
import "./behaviors/clear-button";
import "./behaviors/confirm-button"; import "./behaviors/confirm-button";
import "./behaviors/dropdown"; import "./behaviors/dropdown";
import "./behaviors/form"; import "./behaviors/form";

View file

@ -1,48 +1,38 @@
.bookmarks-form-page { .bookmarks-form-page {
section { section {
max-width: 550px; max-width: 550px;
margin: 0 auto; margin: 0 auto;
} }
} }
.bookmarks-form { .bookmarks-form {
& .btn.btn-link.form-icon { & .has-icon-right > input, & .has-icon-right > textarea {
padding: 0; padding-right: 30px;
width: 20px;
height: 20px;
visibility: hidden;
--btn-icon-color: var(--tertiary-text-color);
& > svg {
width: 20px;
height: 20px;
} }
}
& .has-icon-right > input, & .has-icon-right > textarea { & .form-icon.loading {
padding-right: 30px; visibility: hidden;
} }
& .has-icon-right > input:placeholder-shown ~ .btn.form-icon, & .form-group .clear-button {
& .has-icon-right > textarea:placeholder-shown ~ .btn.form-icon { display: none;
visibility: visible; padding: 0;
} border: none;
height: auto;
font-size: var(--font-size-sm);
}
& .form-icon.loading { & .form-input-hint.bookmark-exists {
visibility: hidden; display: none;
} color: var(--warning-color);
}
& .form-input-hint.bookmark-exists { & .form-input-hint.auto-tags {
display: none; display: none;
color: var(--warning-color); color: var(--success-color);
} }
& .form-input-hint.auto-tags { & details.notes textarea {
display: none; box-sizing: border-box;
color: var(--success-color); }
}
& details.notes textarea {
box-sizing: border-box;
}
} }

View file

@ -31,12 +31,22 @@
{{ form.tag_string.errors }} {{ form.tag_string.errors }}
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="{{ form.title.id_for_label }}" class="form-label">Title</label> <div class="d-flex justify-between align-baseline">
<label for="{{ form.title.id_for_label }}" class="form-label">Title</label>
<button ld-clear-button data-for="{{ form.title.id_for_label }}" class="btn btn-link clear-button"
type="button">Clear
</button>
</div>
{{ form.title|add_class:"form-input"|attr:"autocomplete:off" }} {{ form.title|add_class:"form-input"|attr:"autocomplete:off" }}
{{ form.title.errors }} {{ form.title.errors }}
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="{{ form.description.id_for_label }}" class="form-label">Description</label> <div class="d-flex justify-between align-baseline">
<label for="{{ form.description.id_for_label }}" class="form-label">Description</label>
<button ld-clear-button data-for="{{ form.description.id_for_label }}" class="btn btn-link clear-button"
type="button">Clear
</button>
</div>
{{ form.description|add_class:"form-input"|attr:"rows:3" }} {{ form.description|add_class:"form-input"|attr:"rows:3" }}
{{ form.description.errors }} {{ form.description.errors }}
</div> </div>
@ -116,6 +126,7 @@
return; return;
} }
input.value = value; input.value = value;
input.dispatchEvent(new Event('value-changed'));
} }
function updateCheckbox(input, value) { function updateCheckbox(input, value) {