aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--static/event-hub.ts112
-rw-r--r--static/hub.js59
2 files changed, 114 insertions, 57 deletions
diff --git a/static/event-hub.ts b/static/event-hub.ts
new file mode 100644
index 000000000..3ecaefc41
--- /dev/null
+++ b/static/event-hub.ts
@@ -0,0 +1,112 @@
+// Copyright (c) 2022, Compiler Explorer Authors
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+import GoldenLayout from 'golden-layout';
+import Sentry from '@sentry/browser';
+
+export type EventHubCallback<T extends unknown[]> = (...args: T) => void;
+
+export interface DependencyProxies<T1 extends unknown[], T2 extends unknown[] = T1> {
+ dependencyProxy: EventHubCallback<T1>;
+ dependentProxy: EventHubCallback<T2>;
+}
+
+export interface Event<T extends unknown[], C = any> {
+ evt: string;
+ fn: EventHubCallback<T>;
+ ctx: C;
+}
+
+/**
+ * Event Hub which is enclosed inside a Hub, allowing for dependent calls and
+ * deferred execution based on the parent Hub.
+ */
+export class EventHub {
+ private readonly hub: any; /* typeof Hub */
+ private readonly layoutEventHub: GoldenLayout.EventEmitter;
+ private subscriptions: Event<any>[] = [];
+
+ public constructor(hub: any, layoutEventHub: GoldenLayout.EventEmitter) {
+ this.hub = hub;
+ this.layoutEventHub = layoutEventHub;
+ }
+
+ /**
+ * Emit an event to the layout event hub.
+ *
+ * Events are deferred by the parent hub during initialization to allow all
+ * components to install their listeners before the emission is performed.
+ * This fixes some ordering issues.
+ */
+ public emit(event: string, ...args: unknown[]): void {
+ if (this.hub.deferred) {
+ this.hub.deferredEmissions.push(event, args);
+ } else {
+ this.layoutEventHub.emit(event, ...args);
+ }
+ }
+
+ /** Attach a listener to the layout event hub. */
+ public on<T extends unknown[], C = any>(event: string, callback: EventHubCallback<T>, context: C): void {
+ this.layoutEventHub.on(event, callback, context);
+ this.subscriptions.push({ evt: event, fn: callback, ctx: context });
+ }
+
+ /** Remove all listeners from the layout event hub. */
+ public unsubscribe(): void {
+ for (const subscription of this.subscriptions) {
+ try {
+ this.layoutEventHub.off(subscription.evt, subscription.fn, subscription.ctx);
+ } catch (e) {
+ Sentry.captureMessage(`Can not unsubscribe from ${subscription.evt.toString()}`);
+ Sentry.captureException(e);
+ }
+ }
+ this.subscriptions = [];
+ }
+
+ public mediateDependentCalls<T1 extends unknown[], T2 extends unknown[]= T1>(
+ dependent: EventHubCallback<any>,
+ dependency: EventHubCallback<any>
+ ): DependencyProxies<T1, T2> {
+ let hasDependencyExecuted = false;
+ let lastDependentArguments: unknown[] | null = null;
+ const dependencyProxy = function (this: unknown, ...args: unknown[]) {
+ dependency.apply(this, args);
+ hasDependencyExecuted = true;
+ if (lastDependentArguments) {
+ dependent.apply(this, lastDependentArguments);
+ lastDependentArguments = null;
+ }
+ };
+ const dependentProxy = function (this: unknown, ...args: unknown[]) {
+ if (hasDependencyExecuted) {
+ dependent.apply(this, args);
+ } else {
+ lastDependentArguments = args;
+ }
+ };
+ return { dependencyProxy, dependentProxy };
+ }
+}
diff --git a/static/hub.js b/static/hub.js
index f268ed7b2..122858571 100644
--- a/static/hub.js
+++ b/static/hub.js
@@ -25,7 +25,6 @@
'use strict';
var _ = require('underscore');
-var Sentry = require('@sentry/browser');
var editor = require('./panes/editor');
var compiler = require('./panes/compiler');
var tree = require('./panes/tree');
@@ -51,6 +50,7 @@ var cfgView = require('./panes/cfg-view');
var conformanceView = require('./panes/conformance-view');
var CompilerService = require('compiler-service').CompilerService;
var IdentifierSet = require('./identifier-set').IdentifierSet;
+var EventHub = require('./event-hub').EventHub;
function Hub(layout, subLangId, defaultLangId) {
this.layout = layout;
@@ -353,63 +353,8 @@ Hub.prototype.confomanceFactory = function (container, state) {
return new conformanceView.Conformance(this, container, state);
};
-function WrappedEventHub(hub, eventHub) {
- this.hub = hub;
- this.eventHub = eventHub;
- this.subscriptions = [];
-}
-
-WrappedEventHub.prototype.emit = function () {
- // Events are deferred during initialisation to allow all the components to install their listeners before
- // all the emits are done. This fixes some ordering issues.
- if (this.hub.deferred) {
- this.hub.deferredEmissions.push(arguments);
- } else {
- this.eventHub.emit.apply(this.eventHub, arguments);
- }
-};
-
-WrappedEventHub.prototype.on = function (event, callback, context) {
- this.eventHub.on(event, callback, context);
- this.subscriptions.push({evt: event, fn: callback, ctx: context});
-};
-
-WrappedEventHub.prototype.unsubscribe = function () {
- _.each(this.subscriptions, _.bind(function (obj) {
- try {
- this.eventHub.off(obj.evt, obj.fn, obj.ctx);
- } catch (e) {
- Sentry.captureMessage('Can not unsubscribe from ' + obj.evt.toString());
- Sentry.captureException(e);
- }
- }, this));
- this.subscriptions = [];
-};
-
-WrappedEventHub.prototype.mediateDependentCalls = function (dependent, dependency) {
- var dependencyExecuted = false;
- var lastDependentArgs = null;
- var dependencyProxy = function () {
- dependency.apply(this, arguments);
- dependencyExecuted = true;
- if (lastDependentArgs) {
- dependent.apply(this, lastDependentArgs);
- lastDependentArgs = null;
- }
- };
- var dependentProxy = function () {
- if (dependencyExecuted) {
- dependent.apply(this, arguments);
- } else {
- lastDependentArgs = arguments;
- }
- };
- return {dependencyProxy: dependencyProxy,
- dependentProxy: dependentProxy};
-};
-
Hub.prototype.createEventHub = function () {
- return new WrappedEventHub(this, this.layout.eventHub);
+ return new EventHub(this, this.layout.eventHub);
};
Hub.prototype.findParentRowOrColumn = function (elem) {