From e56065d644c3909a82de424d7a52812662f36c63 Mon Sep 17 00:00:00 2001 From: Dominik George <dominik.george@teckids.org> Date: Mon, 16 Jan 2023 14:41:37 +0100 Subject: [PATCH] Add utility method to safely add event listener The handler is unregistered on component destruction. --- .../assets/components/LegacyBaseTemplate.vue | 6 +-- aleksis/core/assets/mixins/aleksis.js | 38 +++++++++++++++++++ aleksis/core/assets/mixins/offline.js | 6 +-- aleksis/core/assets/plugins/aleksis.js | 4 ++ 4 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 aleksis/core/assets/mixins/aleksis.js diff --git a/aleksis/core/assets/components/LegacyBaseTemplate.vue b/aleksis/core/assets/components/LegacyBaseTemplate.vue index ecb534fdb..3f620e7a0 100644 --- a/aleksis/core/assets/components/LegacyBaseTemplate.vue +++ b/aleksis/core/assets/components/LegacyBaseTemplate.vue @@ -73,7 +73,7 @@ export default { }, mounted() { // Subscribe to message channel to receive height from iframe - window.addEventListener("message", this.receiveMessage); + this.safeAddEventListener(window, "message", this.receiveMessage); }, watch: { $route() { @@ -81,10 +81,6 @@ export default { this.$root.contentLoading = true; }, }, - beforeDestroy() { - window.removeEventListener("message", this.receiveMessage); - this.$root.contentLoading = false; - }, name: "LegacyBaseTemplate", }; </script> diff --git a/aleksis/core/assets/mixins/aleksis.js b/aleksis/core/assets/mixins/aleksis.js new file mode 100644 index 000000000..7dc82d67f --- /dev/null +++ b/aleksis/core/assets/mixins/aleksis.js @@ -0,0 +1,38 @@ +/** + * Mixin with utilities for AlekSIS view components. + */ +const aleksisMixin = { + data: () => { + return { + $_aleksis_safeTrackedEvents: new Array(), + }; + }, + methods: { + safeAddEventListener(target, event, handler) { + console.debug("Safely adding handler for %s on %o", event, target); + target.addEventListener(event, handler); + // Add to tracker so we can unregister the handler later + this.$data.$_aleksis_safeTrackedEvents.push({ + target: target, + event: event, + handler: handler, + }); + }, + }, + beforeDestroy() { + // Unregister all safely added event listeners as to not leak them + for (let trackedEvent in this.$data.$_aleksis_safeTrackedEvents) { + console.debug( + "Removing handler for %s on %o", + trackedEvent.event, + trackedEvent.target + ); + trackedEvent.target.removeEventListener( + trackedEvent.event, + trackedEvent.handler + ); + } + }, +}; + +export default aleksisMixin; diff --git a/aleksis/core/assets/mixins/offline.js b/aleksis/core/assets/mixins/offline.js index dfdc03484..6b9aaeba0 100644 --- a/aleksis/core/assets/mixins/offline.js +++ b/aleksis/core/assets/mixins/offline.js @@ -22,15 +22,15 @@ const offlineMixin = { }; }, mounted() { - window.addEventListener("online", () => { + this.safeAddEventListener(window, "online", () => { console.info("Navigator changed status to online."); this.checkOfflineState(); }); - window.addEventListener("offline", () => { + this.safeAddEventListener(window, "offline", () => { console.info("Navigator changed status to offline."); this.checkOfflineState(); }); - document.addEventListener("visibilitychange", () => { + this.safeAddEventListener(document, "visibilitychange", () => { console.info("Visibility changed status to", document.visibilityState); this.checkOfflineState(); }); diff --git a/aleksis/core/assets/plugins/aleksis.js b/aleksis/core/assets/plugins/aleksis.js index 9d511d823..d2c87d40d 100644 --- a/aleksis/core/assets/plugins/aleksis.js +++ b/aleksis/core/assets/plugins/aleksis.js @@ -4,6 +4,7 @@ // aleksisAppImporter is a virtual module defined in Vite config import { appMessages } from "aleksisAppImporter"; +import aleksisMixin from "../mixins/aleksis.js"; console.debug("Defining AleksisVue plugin"); const AleksisVue = {}; @@ -166,6 +167,9 @@ AleksisVue.install = function (Vue) { next(); }); }; + + // Add default behaviour for all components + Vue.mixin(aleksisMixin); }; export default AleksisVue; -- GitLab