[globals] UI.ActionRegistry

[email protected]

Bug: 1058320
Change-Id: I86fdc670c6667f37bfced2d9068106ec553d2210
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2364370
Commit-Queue: Tim van der Lippe <[email protected]>
Reviewed-by: Jack Franklin <[email protected]>
Auto-Submit: Tim van der Lippe <[email protected]>
diff --git a/front_end/console/ConsoleView.js b/front_end/console/ConsoleView.js
index 761e625..d2f020b 100644
--- a/front_end/console/ConsoleView.js
+++ b/front_end/console/ConsoleView.js
@@ -123,12 +123,12 @@
     const rightToolbar = new UI.Toolbar.Toolbar('', this._consoleToolbarContainer);
     toolbar.appendToolbarItem(this._splitWidget.createShowHideSidebarButton(ls`console sidebar`));
     toolbar.appendToolbarItem(UI.Toolbar.Toolbar.createActionButton(
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('console.clear'))));
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action('console.clear'))));
     toolbar.appendSeparator();
     toolbar.appendToolbarItem(this._consoleContextSelector.toolbarItem());
     toolbar.appendSeparator();
     const liveExpressionButton = UI.Toolbar.Toolbar.createActionButton(
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('console.create-pin')));
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action('console.create-pin')));
     toolbar.appendToolbarItem(liveExpressionButton);
     toolbar.appendSeparator();
     toolbar.appendToolbarItem(this._filter._textFilterUI);
diff --git a/front_end/coverage/CoverageView.js b/front_end/coverage/CoverageView.js
index 44a74f9..b58f808 100644
--- a/front_end/coverage/CoverageView.js
+++ b/front_end/coverage/CoverageView.js
@@ -57,7 +57,8 @@
     toolbar.appendToolbarItem(this._coverageTypeComboBox);
 
     this._toggleRecordAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('coverage.toggle-recording'));
+        /** @type {!UI.Action.Action }*/ (
+            UI.ActionRegistry.ActionRegistry.instance().action('coverage.toggle-recording'));
     this._toggleRecordButton = UI.Toolbar.Toolbar.createActionButton(this._toggleRecordAction);
     toolbar.appendToolbarItem(this._toggleRecordButton);
 
@@ -67,7 +68,8 @@
       /** @type {?Element} */
       this._inlineReloadButton = null;
       const startWithReloadAction =
-          /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('coverage.start-with-reload'));
+          /** @type {!UI.Action.Action }*/ (
+              UI.ActionRegistry.ActionRegistry.instance().action('coverage.start-with-reload'));
       this._startWithReloadButton = UI.Toolbar.Toolbar.createActionButton(startWithReloadAction);
       toolbar.appendToolbarItem(this._startWithReloadButton);
       this._toggleRecordButton.setEnabled(false);
diff --git a/front_end/elements/ElementsTreeElement.js b/front_end/elements/ElementsTreeElement.js
index 7ab1ce0..777d323 100644
--- a/front_end/elements/ElementsTreeElement.js
+++ b/front_end/elements/ElementsTreeElement.js
@@ -1870,7 +1870,7 @@
 
   _editAsHTML() {
     const promise = Common.Revealer.reveal(this.node());
-    promise.then(() => self.UI.actionRegistry.action('elements.edit-as-html').execute());
+    promise.then(() => UI.ActionRegistry.ActionRegistry.instance().action('elements.edit-as-html').execute());
   }
 
   // TODO: add unit tests for adorner-related methods after component and TypeScript works are done
diff --git a/front_end/elements/InspectElementModeController.js b/front_end/elements/InspectElementModeController.js
index b4e6357..cd77ca4 100644
--- a/front_end/elements/InspectElementModeController.js
+++ b/front_end/elements/InspectElementModeController.js
@@ -46,7 +46,7 @@
    * @suppressGlobalPropertiesCheck
    */
   constructor() {
-    this._toggleSearchAction = self.UI.actionRegistry.action('elements.toggle-element-search');
+    this._toggleSearchAction = UI.ActionRegistry.ActionRegistry.instance().action('elements.toggle-element-search');
     this._mode = Protocol.Overlay.InspectMode.None;
     SDK.SDKModel.TargetManager.instance().addEventListener(
         SDK.SDKModel.Events.SuspendStateChanged, this._suspendStateChanged, this);
diff --git a/front_end/emulation/DeviceModeWrapper.js b/front_end/emulation/DeviceModeWrapper.js
index a44fa16..a7e1d9d 100644
--- a/front_end/emulation/DeviceModeWrapper.js
+++ b/front_end/emulation/DeviceModeWrapper.js
@@ -27,7 +27,7 @@
     this._inspectedPagePlaceholder = inspectedPagePlaceholder;
     /** @type {?DeviceModeView} */
     this._deviceModeView = null;
-    this._toggleDeviceModeAction = self.UI.actionRegistry.action('emulation.toggle-device-mode');
+    this._toggleDeviceModeAction = UI.ActionRegistry.ActionRegistry.instance().action('emulation.toggle-device-mode');
     const model = self.singleton(DeviceModeModel);
     this._showDeviceModeSetting = model.enabledSetting();
     this._showDeviceModeSetting.setRequiresUserAction(!!Root.Runtime.queryParam('hasOtherClients'));
diff --git a/front_end/input/InputTimeline.js b/front_end/input/InputTimeline.js
index a8d87fc..118c5a4 100644
--- a/front_end/input/InputTimeline.js
+++ b/front_end/input/InputTimeline.js
@@ -32,11 +32,11 @@
 
 
     this._toggleRecordAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('input.toggle-recording'));
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action('input.toggle-recording'));
     this._startReplayAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('input.start-replaying'));
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action('input.start-replaying'));
     this._togglePauseAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('input.toggle-pause'));
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action('input.toggle-pause'));
 
     const toolbarContainer = this.contentElement.createChild('div', 'input-timeline-toolbar-container');
     this._panelToolbar = new UI.Toolbar.Toolbar('input-timeline-toolbar', toolbarContainer);
diff --git a/front_end/main/MainImpl.js b/front_end/main/MainImpl.js
index 9637d0b..612fa0f 100644
--- a/front_end/main/MainImpl.js
+++ b/front_end/main/MainImpl.js
@@ -307,8 +307,10 @@
 
     new PauseListener();
 
-    self.UI.actionRegistry = new UI.ActionRegistry.ActionRegistry();
-    self.UI.shortcutRegistry = new UI.ShortcutRegistry.ShortcutRegistry(self.UI.actionRegistry);
+    const actionRegistryInstance = UI.ActionRegistry.ActionRegistry.instance({forceNew: true});
+    // Required for legacy a11y layout tests
+    self.UI.actionRegistry = actionRegistryInstance;
+    self.UI.shortcutRegistry = new UI.ShortcutRegistry.ShortcutRegistry(actionRegistryInstance);
     UI.ShortcutsScreen.ShortcutsScreen.registerShortcuts();
     this._registerMessageSinkListener();
 
@@ -327,7 +329,7 @@
     self.UI.dockController.initialize();
     app.presentUI(document);
 
-    const toggleSearchNodeAction = self.UI.actionRegistry.action('elements.toggle-element-search');
+    const toggleSearchNodeAction = UI.ActionRegistry.ActionRegistry.instance().action('elements.toggle-element-search');
     // TODO: we should not access actions from other modules.
     if (toggleSearchNodeAction) {
       Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
diff --git a/front_end/network/NetworkPanel.js b/front_end/network/NetworkPanel.js
index cf00fb9a..96eece5 100644
--- a/front_end/network/NetworkPanel.js
+++ b/front_end/network/NetworkPanel.js
@@ -64,7 +64,8 @@
     this._networkRecordFilmStripSetting =
         Common.Settings.Settings.instance().createSetting('networkRecordFilmStripSetting', false);
     this._toggleRecordAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('network.toggle-recording'));
+        /** @type {!UI.Action.Action }*/ (
+            UI.ActionRegistry.ActionRegistry.instance().action('network.toggle-recording'));
 
     /** @type {number|undefined} */
     this._pendingStopTimer;
@@ -158,7 +159,9 @@
 
     this._closeButtonElement = createElement('div', 'dt-close-button');
     this._closeButtonElement.addEventListener(
-        'click', async () => await self.UI.actionRegistry.action('network.hide-request-details').execute(), false);
+        'click',
+        async () => await UI.ActionRegistry.ActionRegistry.instance().action('network.hide-request-details').execute(),
+        false);
     this._closeButtonElement.style.margin = '0 5px';
 
     this._networkLogShowOverviewSetting.addChangeListener(this._toggleShowOverview, this);
@@ -243,7 +246,7 @@
    * @param {!Common.EventTarget.EventTargetEvent} event
    */
   async _searchToggleClick(event) {
-    await self.UI.actionRegistry.action('network.search').execute();
+    await UI.ActionRegistry.ActionRegistry.instance().action('network.search').execute();
   }
 
   _setupToolbarButtons(splitWidget) {
diff --git a/front_end/profiler/LiveHeapProfileView.js b/front_end/profiler/LiveHeapProfileView.js
index ec38925..516f438 100644
--- a/front_end/profiler/LiveHeapProfileView.js
+++ b/front_end/profiler/LiveHeapProfileView.js
@@ -27,7 +27,8 @@
     const toolbar = new UI.Toolbar.Toolbar('live-heap-profile-toolbar', this.contentElement);
 
     this._toggleRecordAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('live-heap-profile.toggle-recording'));
+        /** @type {!UI.Action.Action }*/ (
+            UI.ActionRegistry.ActionRegistry.instance().action('live-heap-profile.toggle-recording'));
     this._toggleRecordButton = UI.Toolbar.Toolbar.createActionButton(this._toggleRecordAction);
     this._toggleRecordButton.setToggled(this._setting.get());
     toolbar.appendToolbarItem(this._toggleRecordButton);
@@ -35,7 +36,8 @@
     const mainTarget = SDK.SDKModel.TargetManager.instance().mainTarget();
     if (mainTarget && mainTarget.model(SDK.ResourceTreeModel.ResourceTreeModel)) {
       const startWithReloadAction =
-          /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('live-heap-profile.start-with-reload'));
+          /** @type {!UI.Action.Action }*/ (
+              UI.ActionRegistry.ActionRegistry.instance().action('live-heap-profile.start-with-reload'));
       this._startWithReloadButton = UI.Toolbar.Toolbar.createActionButton(startWithReloadAction);
       toolbar.appendToolbarItem(this._startWithReloadButton);
     }
diff --git a/front_end/profiler/ProfilesPanel.js b/front_end/profiler/ProfilesPanel.js
index 6860e40..c039615 100644
--- a/front_end/profiler/ProfilesPanel.js
+++ b/front_end/profiler/ProfilesPanel.js
@@ -84,7 +84,7 @@
     const toolbar = new UI.Toolbar.Toolbar('', toolbarContainerLeft);
 
     this._toggleRecordAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action(recordingActionId));
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action(recordingActionId));
     this._toggleRecordButton = UI.Toolbar.Toolbar.createActionButton(this._toggleRecordAction);
     toolbar.appendToolbarItem(this._toggleRecordButton);
 
diff --git a/front_end/quick_open/CommandMenu.js b/front_end/quick_open/CommandMenu.js
index 8c97f17..67457bb 100644
--- a/front_end/quick_open/CommandMenu.js
+++ b/front_end/quick_open/CommandMenu.js
@@ -210,7 +210,7 @@
     const allCommands = commandMenu.commands();
 
     // Populate allowlisted actions.
-    const actions = self.UI.actionRegistry.availableActions();
+    const actions = UI.ActionRegistry.ActionRegistry.instance().availableActions();
     for (const action of actions) {
       const category = action.category();
       if (!category) {
diff --git a/front_end/resources/BackgroundServiceView.js b/front_end/resources/BackgroundServiceView.js
index 2306497..5798c4a 100644
--- a/front_end/resources/BackgroundServiceView.js
+++ b/front_end/resources/BackgroundServiceView.js
@@ -67,7 +67,8 @@
 
     /** @const {!UI.Action.Action} */
     this._recordAction =
-        /** @type {!UI.Action.Action} */ (self.UI.actionRegistry.action('background-service.toggle-recording'));
+        /** @type {!UI.Action.Action} */ (
+            UI.ActionRegistry.ActionRegistry.instance().action('background-service.toggle-recording'));
     /** @type {?UI.Toolbar.ToolbarButton} */
     this._recordButton = null;
 
diff --git a/front_end/settings/KeybindsSettingsTab.js b/front_end/settings/KeybindsSettingsTab.js
index bad162b..44a97e3 100644
--- a/front_end/settings/KeybindsSettingsTab.js
+++ b/front_end/settings/KeybindsSettingsTab.js
@@ -133,7 +133,7 @@
    * @returns {!Array.<!KeybindsItem>}
    */
   _createListItems() {
-    const actions = self.UI.actionRegistry.actions().sort((actionA, actionB) => {
+    const actions = UI.ActionRegistry.ActionRegistry.instance().actions().sort((actionA, actionB) => {
       if (actionA.category() < actionB.category()) {
         return -1;
       }
diff --git a/front_end/sources/SourcesPanel.js b/front_end/sources/SourcesPanel.js
index 4c0c978..9437956 100644
--- a/front_end/sources/SourcesPanel.js
+++ b/front_end/sources/SourcesPanel.js
@@ -62,16 +62,18 @@
     this._workspace = Workspace.Workspace.WorkspaceImpl.instance();
 
     this._togglePauseAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('debugger.toggle-pause'));
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action('debugger.toggle-pause'));
     this._stepOverAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('debugger.step-over'));
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action('debugger.step-over'));
     this._stepIntoAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('debugger.step-into'));
-    this._stepOutAction = /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('debugger.step-out'));
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action('debugger.step-into'));
+    this._stepOutAction =
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action('debugger.step-out'));
     this._stepAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('debugger.step'));
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action('debugger.step'));
     this._toggleBreakpointsActiveAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('debugger.toggle-breakpoints-active'));
+        /** @type {!UI.Action.Action }*/ (
+            UI.ActionRegistry.ActionRegistry.instance().action('debugger.toggle-breakpoints-active'));
 
     this._debugToolbar = this._createDebugToolbar();
     this._debugToolbarDrawer = this._createDebugToolbarDrawer();
diff --git a/front_end/sources/SourcesView.js b/front_end/sources/SourcesView.js
index da993a5..709970d 100644
--- a/front_end/sources/SourcesView.js
+++ b/front_end/sources/SourcesView.js
@@ -148,7 +148,7 @@
       } else {
         row.createChild('div', 'tabbed-pane-no-shortcut').textContent = shortcut.description;
       }
-      const action = self.UI.actionRegistry.action(shortcut.actionId);
+      const action = UI.ActionRegistry.ActionRegistry.instance().action(shortcut.actionId);
       const actionHandler = action.execute.bind(action);
       this._placeholderOptionArray.push({element: row, handler: actionHandler});
     }
diff --git a/front_end/timeline/TimelineHistoryManager.js b/front_end/timeline/TimelineHistoryManager.js
index c1f9ad2..098e8bc 100644
--- a/front_end/timeline/TimelineHistoryManager.js
+++ b/front_end/timeline/TimelineHistoryManager.js
@@ -15,7 +15,8 @@
   constructor() {
     /** @type {!Array<!PerformanceModel>} */
     this._recordings = [];
-    this._action = /** @type {!UI.Action.Action} */ (self.UI.actionRegistry.action('timeline.show-history'));
+    this._action =
+        /** @type {!UI.Action.Action} */ (UI.ActionRegistry.ActionRegistry.instance().action('timeline.show-history'));
     /** @type {!Map<string, number>} */
     this._nextNumberByDomain = new Map();
     this._button = new ToolbarButton(this._action);
diff --git a/front_end/timeline/TimelinePanel.js b/front_end/timeline/TimelinePanel.js
index 2d0b7b2..702be8f 100644
--- a/front_end/timeline/TimelinePanel.js
+++ b/front_end/timeline/TimelinePanel.js
@@ -73,9 +73,10 @@
     this._recordingPageReload = false;
     this._millisecondsToRecordAfterLoadEvent = 5000;
     this._toggleRecordAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('timeline.toggle-recording'));
+        /** @type {!UI.Action.Action }*/ (
+            UI.ActionRegistry.ActionRegistry.instance().action('timeline.toggle-recording'));
     this._recordReloadAction =
-        /** @type {!UI.Action.Action }*/ (self.UI.actionRegistry.action('timeline.record-reload'));
+        /** @type {!UI.Action.Action }*/ (UI.ActionRegistry.ActionRegistry.instance().action('timeline.record-reload'));
 
     this._historyManager = new TimelineHistoryManager();
 
diff --git a/front_end/ui/ActionRegistry.js b/front_end/ui/ActionRegistry.js
index e3d8f7a..dbe5b7b 100644
--- a/front_end/ui/ActionRegistry.js
+++ b/front_end/ui/ActionRegistry.js
@@ -7,6 +7,9 @@
 import {Action} from './Action.js';
 import {Context} from './Context.js';  // eslint-disable-line no-unused-vars
 
+/** @type {!ActionRegistry} */
+let actionRegistryInstance;
+
 export class ActionRegistry {
   constructor() {
     /** @type {!Map.<string, !Action>} */
@@ -14,6 +17,18 @@
     this._registerActions();
   }
 
+  /**
+   * @param {{forceNew: ?boolean}} opts
+   */
+  static instance(opts = {forceNew: null}) {
+    const {forceNew} = opts;
+    if (!actionRegistryInstance || forceNew) {
+      actionRegistryInstance = new ActionRegistry();
+    }
+
+    return actionRegistryInstance;
+  }
+
   _registerActions() {
     // @ts-ignore
     // TODO(crbug.com/1058320): Use Runtime.instance() once it no longer crashes at this point.
diff --git a/front_end/ui/ContextMenu.js b/front_end/ui/ContextMenu.js
index 08cd54d..5b7875e 100644
--- a/front_end/ui/ContextMenu.js
+++ b/front_end/ui/ContextMenu.js
@@ -34,6 +34,7 @@
 import * as Common from '../common/common.js';  // eslint-disable-line no-unused-vars
 import * as Host from '../host/host.js';
 
+import {ActionRegistry} from './ActionRegistry.js';
 import {SoftContextMenu} from './SoftContextMenu.js';
 
 /**
@@ -169,7 +170,7 @@
    * @param {boolean=} optional
    */
   appendAction(actionId, label, optional) {
-    const action = self.UI.actionRegistry.action(actionId);
+    const action = ActionRegistry.instance().action(actionId);
     if (!action) {
       if (!optional) {
         console.error(`Action ${actionId} was not defined`);
diff --git a/front_end/ui/Toolbar.js b/front_end/ui/Toolbar.js
index e364fd4..6f92ccc 100644
--- a/front_end/ui/Toolbar.js
+++ b/front_end/ui/Toolbar.js
@@ -35,6 +35,7 @@
 import * as Host from '../host/host.js';
 
 import {Action, Events as ActionEvents} from './Action.js';  // eslint-disable-line no-unused-vars
+import {ActionRegistry} from './ActionRegistry.js';
 import * as ARIAUtils from './ARIAUtils.js';
 import {ContextMenu} from './ContextMenu.js';
 import {GlassPane, PointerEventsBehavior} from './GlassPane.js';
@@ -256,7 +257,7 @@
    * @return {!ToolbarButton}
    */
   static createActionButtonForId(actionId, options = TOOLBAR_BUTTON_DEFAULT_OPTIONS) {
-    const action = self.UI.actionRegistry.action(actionId);
+    const action = ActionRegistry.instance().action(actionId);
     return Toolbar.createActionButton(/** @type {!Action} */ (action), options);
   }