From db225d526782b702b62d3968cdd137645bae162b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Sun, 15 Sep 2024 08:28:49 +0200 Subject: [PATCH] Fix several issues around browser back navigation (#825) --- bookmarks/frontend/behaviors/bulk-edit.js | 9 ++++-- .../frontend/behaviors/confirm-button.js | 10 +++++-- bookmarks/frontend/behaviors/dropdown.js | 4 +++ .../frontend/behaviors/global-shortcuts.js | 7 ++++- bookmarks/frontend/behaviors/index.js | 6 +++- .../frontend/behaviors/tag-autocomplete.js | 28 +++++++++++++------ .../templates/bookmarks/bulk_edit/bar.html | 5 ++-- bookmarks/templates/bookmarks/form.html | 4 +-- bookmarks/templates/bookmarks/search.html | 12 ++++++-- bookmarks/tests/test_bookmark_edit_view.py | 2 +- 10 files changed, 64 insertions(+), 23 deletions(-) diff --git a/bookmarks/frontend/behaviors/bulk-edit.js b/bookmarks/frontend/behaviors/bulk-edit.js index 6d9d0bc..45ee131 100644 --- a/bookmarks/frontend/behaviors/bulk-edit.js +++ b/bookmarks/frontend/behaviors/bulk-edit.js @@ -4,8 +4,9 @@ class BulkEdit extends Behavior { constructor(element) { super(element); - this.active = false; + this.active = element.classList.contains("active"); + this.init = this.init.bind(this); this.onToggleActive = this.onToggleActive.bind(this); this.onToggleAll = this.onToggleAll.bind(this); this.onToggleBookmark = this.onToggleBookmark.bind(this); @@ -13,7 +14,11 @@ class BulkEdit extends Behavior { this.init(); // Reset when bookmarks are refreshed - document.addEventListener("refresh-bookmark-list-done", () => this.init()); + document.addEventListener("refresh-bookmark-list-done", this.init); + } + + destroy() { + document.removeEventListener("refresh-bookmark-list-done", this.init); } init() { diff --git a/bookmarks/frontend/behaviors/confirm-button.js b/bookmarks/frontend/behaviors/confirm-button.js index 059e938..454c3cf 100644 --- a/bookmarks/frontend/behaviors/confirm-button.js +++ b/bookmarks/frontend/behaviors/confirm-button.js @@ -13,7 +13,10 @@ class ConfirmButtonBehavior extends Behavior { } destroy() { - Behavior.interacting = false; + this.reset(); + this.element.setAttribute("type", this.element.dataset.type); + this.element.setAttribute("name", this.element.dataset.name); + this.element.setAttribute("value", this.element.dataset.value); } onClick(event) { @@ -70,7 +73,10 @@ class ConfirmButtonBehavior extends Behavior { reset() { setTimeout(() => { Behavior.interacting = false; - this.container.remove(); + if (this.container) { + this.container.remove(); + this.container = null; + } this.element.classList.remove("d-none"); }); } diff --git a/bookmarks/frontend/behaviors/dropdown.js b/bookmarks/frontend/behaviors/dropdown.js index 60a4787..73b03c2 100644 --- a/bookmarks/frontend/behaviors/dropdown.js +++ b/bookmarks/frontend/behaviors/dropdown.js @@ -16,6 +16,10 @@ class DropdownBehavior extends Behavior { }); } + destroy() { + this.close(); + } + open() { this.element.classList.add("active"); document.addEventListener("click", this.onOutsideClick); diff --git a/bookmarks/frontend/behaviors/global-shortcuts.js b/bookmarks/frontend/behaviors/global-shortcuts.js index fba6ab1..68e16f7 100644 --- a/bookmarks/frontend/behaviors/global-shortcuts.js +++ b/bookmarks/frontend/behaviors/global-shortcuts.js @@ -4,7 +4,12 @@ class GlobalShortcuts extends Behavior { constructor(element) { super(element); - document.addEventListener("keydown", this.onKeyDown.bind(this)); + this.onKeyDown = this.onKeyDown.bind(this); + document.addEventListener("keydown", this.onKeyDown); + } + + destroy() { + document.removeEventListener("keydown", this.onKeyDown); } onKeyDown(event) { diff --git a/bookmarks/frontend/behaviors/index.js b/bookmarks/frontend/behaviors/index.js index 3368f7e..0dfe49c 100644 --- a/bookmarks/frontend/behaviors/index.js +++ b/bookmarks/frontend/behaviors/index.js @@ -16,7 +16,7 @@ const mutationObserver = new MutationObserver((mutations) => { }); }); -window.addEventListener("turbo:load", () => { +document.addEventListener("turbo:load", () => { mutationObserver.observe(document.body, { childList: true, subtree: true, @@ -25,6 +25,10 @@ window.addEventListener("turbo:load", () => { applyBehaviors(document.body); }); +document.addEventListener("turbo:before-cache", () => { + destroyBehaviors(document.body); +}); + export class Behavior { constructor(element) { this.element = element; diff --git a/bookmarks/frontend/behaviors/tag-autocomplete.js b/bookmarks/frontend/behaviors/tag-autocomplete.js index 58e8e97..755ba3c 100644 --- a/bookmarks/frontend/behaviors/tag-autocomplete.js +++ b/bookmarks/frontend/behaviors/tag-autocomplete.js @@ -5,23 +5,35 @@ import { ApiClient } from "../api"; class TagAutocomplete extends Behavior { constructor(element) { super(element); - const wrapper = document.createElement("div"); + const input = element.querySelector("input"); + if (!input) { + console.warning("TagAutocomplete: input element not found"); + return; + } + + const container = document.createElement("div"); const apiBaseUrl = document.documentElement.dataset.apiBaseUrl || ""; const apiClient = new ApiClient(apiBaseUrl); new TagAutoCompleteComponent({ - target: wrapper, + target: container, props: { - id: element.id, - name: element.name, - value: element.value, - placeholder: element.getAttribute("placeholder") || "", + id: input.id, + name: input.name, + value: input.value, + placeholder: input.getAttribute("placeholder") || "", apiClient: apiClient, - variant: element.getAttribute("variant"), + variant: input.getAttribute("variant"), }, }); - element.replaceWith(wrapper.firstElementChild); + this.input = input; + this.autocomplete = container.firstElementChild; + input.replaceWith(this.autocomplete); + } + + destroy() { + this.autocomplete.replaceWith(this.input); } } diff --git a/bookmarks/templates/bookmarks/bulk_edit/bar.html b/bookmarks/templates/bookmarks/bulk_edit/bar.html index 847b998..9f5d8a9 100644 --- a/bookmarks/templates/bookmarks/bulk_edit/bar.html +++ b/bookmarks/templates/bookmarks/bulk_edit/bar.html @@ -23,9 +23,8 @@ {% endif %} -
- +
+
-
+
- {{ form.tag_string|add_class:"form-input"|attr:"ld-tag-autocomplete"|attr:"autocomplete:off"|attr:"autocapitalize:off" }} + {{ form.tag_string|add_class:"form-input"|attr:"autocomplete:off"|attr:"autocapitalize:off" }}
Enter any number of tags separated by space and without the hash (#). If a tag does not exist it will be automatically created. diff --git a/bookmarks/templates/bookmarks/search.html b/bookmarks/templates/bookmarks/search.html index c9e5868..266416f 100644 --- a/bookmarks/templates/bookmarks/search.html +++ b/bookmarks/templates/bookmarks/search.html @@ -89,9 +89,9 @@ } const apiClient = new linkding.ApiClient('{% url 'bookmarks:api-root' %}') const input = document.querySelector('#search input[name="q"]') - const wrapper = document.createElement('div') + const container = document.createElement('div') new linkding.SearchAutoComplete({ - target: wrapper, + target: container, props: { name: 'q', placeholder: 'Search for words or #tags', @@ -103,6 +103,12 @@ search, } }) - input.replaceWith(wrapper.firstElementChild); + + const autoComplete = container.firstElementChild; + input.replaceWith(autoComplete); + + document.addEventListener("turbo:before-cache", () => { + autoComplete.replaceWith(input); + }, {once: true}); })(); \ No newline at end of file diff --git a/bookmarks/tests/test_bookmark_edit_view.py b/bookmarks/tests/test_bookmark_edit_view.py index ee5de9f..68fbafb 100644 --- a/bookmarks/tests/test_bookmark_edit_view.py +++ b/bookmarks/tests/test_bookmark_edit_view.py @@ -98,7 +98,7 @@ class BookmarkEditViewTestCase(TestCase, BookmarkFactoryMixin): tag_string = build_tag_string(bookmark.tag_names, " ") self.assertInHTML( f""" - """, html,