diff --git a/planet/js/__tests__/helper.test.js b/planet/js/__tests__/helper.test.js
index 500311b9c4..2c430c4fb4 100644
--- a/planet/js/__tests__/helper.test.js
+++ b/planet/js/__tests__/helper.test.js
@@ -231,6 +231,24 @@ describe("helper.js", () => {
expect(document.getElementById("target").style.display).toBe("block");
});
+
+ it("should remove previous listener when hideOnClickOutside is called again for the same anchor element", () => {
+ document.body.innerHTML = `
+
+ Target
+ `;
+
+ const container = document.getElementById("container");
+ const spyRemove = jest.spyOn(document, "removeEventListener");
+
+ hideOnClickOutside([container], "target");
+ hideOnClickOutside([container], "target");
+ hideOnClickOutside([container], "target");
+
+ expect(spyRemove).toHaveBeenCalledTimes(2);
+
+ spyRemove.mockRestore();
+ });
});
describe("updateCheckboxes", () => {
diff --git a/planet/js/helper.js b/planet/js/helper.js
index 07c014d2e5..6a68e0a790 100644
--- a/planet/js/helper.js
+++ b/planet/js/helper.js
@@ -92,19 +92,37 @@ function toggleExpandable(id, c) {
el.className = el.className === `${c} open` ? c : `${c} open`;
}
+const outsideClickListeners = new WeakMap();
+
function hideOnClickOutside(eles, other) {
+ const validEles = (Array.isArray(eles) ? eles : [eles]).filter(Boolean);
+ if (validEles.length === 0) return;
+
+ const anchor = validEles[0];
+
+ if (anchor && outsideClickListeners.has(anchor)) {
+ const prevListener = outsideClickListeners.get(anchor);
+ document.removeEventListener("click", prevListener);
+ outsideClickListeners.delete(anchor);
+ }
+
// if click not in id, hide
const outsideClickListener = event => {
- const path =
- event.path ||
- (event.composedPath && event.composedPath()) ||
- event.composedPath(event.target);
+ const path = event.path || (event.composedPath && event.composedPath()) || [];
let ok = false;
- for (let i = 0; i < eles.length; i++) if (path.includes(eles[i])) ok = true;
+ for (let i = 0; i < validEles.length; i++) {
+ if (path.includes(validEles[i])) {
+ ok = true;
+ break;
+ }
+ }
if (ok === false) {
- document.getElementById(other).style.display = "none";
+ const otherEl = document.getElementById(other);
+ if (otherEl) {
+ otherEl.style.display = "none";
+ }
removeClickListener();
}
@@ -112,8 +130,15 @@ function hideOnClickOutside(eles, other) {
const removeClickListener = () => {
document.removeEventListener("click", outsideClickListener);
+ if (anchor) {
+ outsideClickListeners.delete(anchor);
+ }
};
+ if (anchor) {
+ outsideClickListeners.set(anchor, outsideClickListener);
+ }
+
document.addEventListener("click", outsideClickListener);
}