summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/helpers/event_hub_factory.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/helpers/event_hub_factory.js')
-rw-r--r--app/assets/javascripts/helpers/event_hub_factory.js109
1 files changed, 95 insertions, 14 deletions
diff --git a/app/assets/javascripts/helpers/event_hub_factory.js b/app/assets/javascripts/helpers/event_hub_factory.js
index 4d7f7550a94..a9c301e3a93 100644
--- a/app/assets/javascripts/helpers/event_hub_factory.js
+++ b/app/assets/javascripts/helpers/event_hub_factory.js
@@ -1,20 +1,101 @@
-import mitt from 'mitt';
+/**
+ * An event hub with a Vue instance like API
+ *
+ * NOTE: There's an [issue open][4] to eventually remove this when some
+ * coupling in our codebase has been fixed.
+ *
+ * NOTE: This is a derivative work from [mitt][1] v1.2.0 which is licensed by
+ * [MIT License][2] © [Jason Miller][3]
+ *
+ * [1]: https://github.com/developit/mitt
+ * [2]: https://opensource.org/licenses/MIT
+ * [3]: https://jasonformat.com/
+ * [4]: https://gitlab.com/gitlab-org/gitlab/-/issues/223864
+ */
+class EventHub {
+ constructor() {
+ this.$_all = new Map();
+ }
-export default () => {
- const emitter = mitt();
+ dispose() {
+ this.$_all.clear();
+ }
+
+ /**
+ * Register an event handler for the given type.
+ *
+ * @param {string|symbol} type Type of event to listen for
+ * @param {Function} handler Function to call in response to given event
+ */
+ $on(type, handler) {
+ const handlers = this.$_all.get(type);
+ const added = handlers && handlers.push(handler);
+
+ if (!added) {
+ this.$_all.set(type, [handler]);
+ }
+ }
+
+ /**
+ * Remove an event handler or all handlers for the given type.
+ *
+ * @param {string|symbol} type Type of event to unregister `handler`
+ * @param {Function} handler Handler function to remove
+ */
+ $off(type, handler) {
+ const handlers = this.$_all.get(type) || [];
- emitter.once = (event, handler) => {
- const wrappedHandler = evt => {
- handler(evt);
- emitter.off(event, wrappedHandler);
+ const newHandlers = handler ? handlers.filter(x => x !== handler) : [];
+
+ if (newHandlers.length) {
+ this.$_all.set(type, newHandlers);
+ } else {
+ this.$_all.delete(type);
+ }
+ }
+
+ /**
+ * Add an event listener to type but only trigger it once
+ *
+ * @param {string|symbol} type Type of event to listen for
+ * @param {Function} handler Handler function to call in response to event
+ */
+ $once(type, handler) {
+ const wrapHandler = (...args) => {
+ this.$off(type, wrapHandler);
+ handler(...args);
};
- emitter.on(event, wrappedHandler);
- };
+ this.$on(type, wrapHandler);
+ }
- emitter.$on = emitter.on;
- emitter.$once = emitter.once;
- emitter.$off = emitter.off;
- emitter.$emit = emitter.emit;
+ /**
+ * Invoke all handlers for the given type.
+ *
+ * @param {string|symbol} type The event type to invoke
+ * @param {Any} [evt] Any value passed to each handler
+ */
+ $emit(type, ...args) {
+ const handlers = this.$_all.get(type) || [];
- return emitter;
+ handlers.forEach(handler => {
+ handler(...args);
+ });
+ }
+}
+
+/**
+ * Return a Vue like event hub
+ *
+ * - $on
+ * - $off
+ * - $once
+ * - $emit
+ *
+ * Please note, this was once implemented with `mitt`, but since then has been reverted
+ * because of some API issues. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35074
+ *
+ * We'd like to shy away from using a full fledged Vue instance from this in the future.
+ */
+export default () => {
+ return new EventHub();
};