diff --git a/frontend/src/html/pages/test.html b/frontend/src/html/pages/test.html
index 95ad7beed..f2d8f33c8 100644
--- a/frontend/src/html/pages/test.html
+++ b/frontend/src/html/pages/test.html
@@ -417,7 +417,7 @@
0s
-
diff --git a/frontend/src/ts/pages/account-settings.ts b/frontend/src/ts/pages/account-settings.ts
index ab7ea2378..66de98e1a 100644
--- a/frontend/src/ts/pages/account-settings.ts
+++ b/frontend/src/ts/pages/account-settings.ts
@@ -12,7 +12,7 @@ import * as BlockedUserTable from "../elements/account-settings/blocked-user-tab
import * as Notifications from "../elements/notifications";
import { z } from "zod";
import * as AuthEvent from "../observables/auth-event";
-import { qs, qsr, onWindowLoad } from "../utils/dom";
+import { qs, qsa, qsr, onWindowLoad } from "../utils/dom";
const pageElement = qsr(".page.pageAccountSettings");
@@ -165,7 +165,7 @@ qs(".page.pageAccountSettings")?.onChild("click", ".tabs button", (event) => {
page.setUrlParams(state);
});
-qs(
+qsa(
".page.pageAccountSettings .section.discordIntegration .getLinkAndGoToOauth",
)?.on("click", () => {
Loader.show();
diff --git a/frontend/src/ts/utils/dom.ts b/frontend/src/ts/utils/dom.ts
index 2e063a1d4..531c7477c 100644
--- a/frontend/src/ts/utils/dom.ts
+++ b/frontend/src/ts/utils/dom.ts
@@ -4,6 +4,7 @@ import {
JSAnimation,
} from "animejs";
+// Implementation
/**
* Query Selector
*
@@ -13,6 +14,7 @@ import {
export function qs(
selector: string,
): ElementWithUtils | null {
+ checkUniqueSelector(selector);
const el = document.querySelector(selector);
return el ? new ElementWithUtils(el) : null;
}
@@ -44,6 +46,7 @@ export function qsa(
export function qsr(
selector: string,
): ElementWithUtils {
+ checkUniqueSelector(selector);
const el = document.querySelector(selector);
if (el === null) {
throw new Error(`Required element not found: ${selector}`);
@@ -349,6 +352,7 @@ export class ElementWithUtils {
* Query the element for a child element matching the selector
*/
qs(selector: string): ElementWithUtils | null {
+ checkUniqueSelector(selector, this);
const found = this.native.querySelector(selector);
return found ? new ElementWithUtils(found) : null;
}
@@ -372,6 +376,7 @@ export class ElementWithUtils {
* @throws Error if the element is not found.
*/
qsr(selector: string): ElementWithUtils {
+ checkUniqueSelector(selector, this);
const found = this.native.querySelector(selector);
if (found === null) {
throw new Error(`Required element not found: ${selector}`);
@@ -703,3 +708,33 @@ export class ElementsWithUtils<
return this;
}
}
+
+function checkUniqueSelector(
+ selector: string,
+ parent?: ElementWithUtils,
+): void {
+ if (!import.meta.env.DEV) return;
+ const elements = parent ? parent.qsa(selector) : qsa(selector);
+ if (elements.length > 1) {
+ console.warn(
+ `Multiple elements found for selector "${selector}". Did you mean to use QSA? If not, try making the query more specific.`,
+ elements.native,
+ );
+ console.trace("Stack trace for qs/qsr call:");
+ if (document.querySelector("#domUtilsQsWarning") !== null) return;
+
+ const bannerCenter = document.querySelector("#bannerCenter");
+ const warning = document.createElement("div");
+ warning.classList.add("psa", "bad", "content-grid");
+ warning.id = "domUtilsQsWarning";
+ warning.innerHTML = `
+
+
+
+ "Warning: qs/qsr detected selector(s) matching multiple elements, check console for details."
+
+
+ `;
+ bannerCenter?.appendChild(warning);
+ }
+}