Proper history navigation for searches
authorMarcel Werk <burntime@woltlab.com>
Sat, 7 May 2022 16:51:22 +0000 (18:51 +0200)
committerMarcel Werk <burntime@woltlab.com>
Sat, 7 May 2022 16:51:22 +0000 (18:51 +0200)
ts/WoltLabSuite/Core/Ui/Search/Extended.ts
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Search/Extended.js

index c342995f3af0322dec90d67d4a11e698513583d5..655d787486b785c46cb56a363b66b7fc13acd9c8 100644 (file)
@@ -29,6 +29,11 @@ type ResponseSearchResults = {
   template: string;
 };
 
+const enum SearchAction {
+  Modify,
+  Init,
+}
+
 export class UiSearchExtended {
   private readonly form: HTMLFormElement;
   private readonly queryInput: HTMLInputElement;
@@ -62,9 +67,13 @@ export class UiSearchExtended {
     this.form.addEventListener("submit", (event) => {
       event.preventDefault();
       this.activePage = 1;
-      void this.search();
+      void this.search(SearchAction.Modify);
     });
     this.typeInput.addEventListener("change", () => this.changeType());
+
+    window.addEventListener("popstate", () => {
+      this.initQueryString();
+    });
   }
 
   private initKeywordSuggestions(): void {
@@ -82,12 +91,12 @@ export class UiSearchExtended {
     });
   }
 
-  private async search(): Promise<void> {
+  private async search(searchAction: SearchAction): Promise<void> {
     if (!this.queryInput.value.trim() && !this.usernameInput.value.trim()) {
       return;
     }
 
-    this.updateQueryString();
+    this.updateQueryString(searchAction);
 
     this.lastSearchRequest?.abort();
 
@@ -107,7 +116,7 @@ export class UiSearchExtended {
     }
   }
 
-  private updateQueryString(): void {
+  private updateQueryString(searchAction: SearchAction): void {
     const url = new URL(this.form.action);
     url.search += url.search !== "" ? "&" : "?";
 
@@ -122,7 +131,11 @@ export class UiSearchExtended {
     }
     url.search += new URLSearchParams(parameters);
 
-    window.history.replaceState({}, document.title, url.toString());
+    if (searchAction === SearchAction.Init) {
+      window.history.replaceState({}, document.title, url.toString());
+    } else {
+      window.history.pushState({}, document.title, url.toString());
+    }
   }
 
   private getFormData(): Record<string, unknown> {
@@ -173,7 +186,7 @@ export class UiSearchExtended {
     });
 
     this.typeInput.dispatchEvent(new Event("change"));
-    void this.search();
+    void this.search(SearchAction.Init);
   }
 
   private initPagination(position: "top" | "bottom"): void {
index 953ec3d66f6c8f36add61b81c8496810a0cc7e0a..4beb670ba304c30d36206a931ccd25c18aa85f84 100644 (file)
@@ -39,9 +39,12 @@ define(["require", "exports", "tslib", "../../Ajax", "../../Date/Picker", "../..
             this.form.addEventListener("submit", (event) => {
                 event.preventDefault();
                 this.activePage = 1;
-                void this.search();
+                void this.search(0 /* Modify */);
             });
             this.typeInput.addEventListener("change", () => this.changeType());
+            window.addEventListener("popstate", () => {
+                this.initQueryString();
+            });
         }
         initKeywordSuggestions() {
             new Input_1.default(this.queryInput, {
@@ -56,12 +59,12 @@ define(["require", "exports", "tslib", "../../Ajax", "../../Date/Picker", "../..
                 filter.hidden = filter.dataset.objectType !== this.typeInput.value;
             });
         }
-        async search() {
+        async search(searchAction) {
             var _a;
             if (!this.queryInput.value.trim() && !this.usernameInput.value.trim()) {
                 return;
             }
-            this.updateQueryString();
+            this.updateQueryString(searchAction);
             (_a = this.lastSearchRequest) === null || _a === void 0 ? void 0 : _a.abort();
             const request = (0, Ajax_1.dboAction)("search", "wcf\\data\\search\\SearchAction").payload(this.getFormData());
             this.lastSearchRequest = request.getAbortController();
@@ -75,7 +78,7 @@ define(["require", "exports", "tslib", "../../Ajax", "../../Date/Picker", "../..
                 this.showSearchResults(template);
             }
         }
-        updateQueryString() {
+        updateQueryString(searchAction) {
             const url = new URL(this.form.action);
             url.search += url.search !== "" ? "&" : "?";
             const parameters = [];
@@ -88,7 +91,12 @@ define(["require", "exports", "tslib", "../../Ajax", "../../Date/Picker", "../..
                 parameters.push(["pageNo", this.activePage.toString()]);
             }
             url.search += new URLSearchParams(parameters);
-            window.history.replaceState({}, document.title, url.toString());
+            if (searchAction === 1 /* Init */) {
+                window.history.replaceState({}, document.title, url.toString());
+            }
+            else {
+                window.history.pushState({}, document.title, url.toString());
+            }
         }
         getFormData() {
             const data = {};
@@ -138,7 +146,7 @@ define(["require", "exports", "tslib", "../../Ajax", "../../Date/Picker", "../..
                 }
             });
             this.typeInput.dispatchEvent(new Event("change"));
-            void this.search();
+            void this.search(1 /* Init */);
         }
         initPagination(position) {
             const wrapperDiv = document.createElement("div");