Skip to content
Permalink
Browse files
Web Inspector: introduce an AppController class and shared instance o…
…f it

https://bugs.webkit.org/show_bug.cgi?id=177024

Reviewed by Matt Baker.

WebInspectorUI currently has an app controller singleton that's distributed
among many properties on the WI object, which also serves as a namespace for
classes, enums, and other frontend objects. The singleton should be a proper
class so that we can think more easily about what state is global.

In the process of moving pieces of Main.js into AppController, I intend to move
most UI related code into a view controller class for the top level view.
AppController really shouldn't be doing anything to the view hierarchy or DOM.
It is yet to be determined how responsibility for global DOM events, such as
those for keyboard shortcuts, will be handled.

This larger refactoring project will let us more easily do things like connect
to multiple debuggables in the same Inspector instance, and switch between views
of different debuggable targets. Even if this never comes to pass, the code will
be a lot easier to reason about and maintain in the future.

For the first patch, introduce {AppController, TestAppController} <: AppControllerBase.
Shared code goes in the base class. In the Main.html and Test.html files, first
construct the AppController and then call .initialize() to avoid cyclic dependencies
on the global singleton WI.sharedApp.

* UserInterface/Main.html:
* UserInterface/Test.html:
* UserInterface/Test/Test.js:
(WI.loaded):
* UserInterface/Base/Main.js:
(WI.loaded):
Move some shared code out of here into AppControllerBase.constructor.
Eventually WI.loaded should not exist, and its code will move elsewhere.

(WI.contentLoaded):
Adopt global reference.

* UserInterface/Controllers/AppControllerBase.js: Copied from Source/WebInspectorUI/UserInterface/Protocol/MainTarget.js.
(WI.AppControllerBase):
(WI.AppControllerBase.prototype.get hasExtraDomains):
(WI.AppControllerBase.prototype.get debuggableType):
(WI.AppControllerBase.prototype.initialize):

* UserInterface/Controllers/AppController.js: New.
(WI.AppController):
(WI.AppController.prototype.get hasExtraDomains):
(WI.AppController.prototype.get debuggableType):
(WI.AppController.prototype.activateExtraDomains):

* UserInterface/Test/TestAppController.js: New.
(WI.TestAppController):
(WI.TestAppController.prototype.get hasExtraDomains):
(WI.TestAppController.prototype.get debuggableType):

* UserInterface/Controllers/TimelineManager.js:
(WI.TimelineManager.defaultTimelineTypes):
(WI.TimelineManager.availableTimelineTypes):
(WI.TimelineManager.prototype.scriptProfilerProgrammaticCaptureStarted):
(WI.TimelineManager.prototype.scriptProfilerProgrammaticCaptureStopped):
(WI.TimelineManager.prototype.scriptProfilerTrackingCompleted):
* UserInterface/Models/TimelineRecording.js:
(WI.TimelineRecording.sourceCodeTimelinesSupported):
* UserInterface/Protocol/InspectorObserver.js:
(WI.InspectorObserver.prototype.inspect):
(WI.InspectorObserver.prototype.activateExtraDomains):
(WI.InspectorObserver):
* UserInterface/Protocol/MainTarget.js:
(WI.MainTarget):
(WI.MainTarget.prototype.get displayName):
* UserInterface/Views/ResourceSidebarPanel.js:
(WI.ResourceSidebarPanel):
(WI.ResourceSidebarPanel.prototype.initialLayout):
(WI.ResourceSidebarPanel.prototype._addScript):
(WI.ResourceSidebarPanel.prototype._extraDomainsActivated):
* UserInterface/Views/Toolbar.js:
Use WI.sharedApp.{debuggableType, hasExtraDomains}.


Canonical link: https://commits.webkit.org/193503@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@222181 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
burg committed Sep 18, 2017
1 parent 69975da commit db454b1b5e881684d9c9ce98ad0d4c56a4ba41bc
@@ -1,3 +1,83 @@
2017-09-18 Brian Burg <bburg@apple.com>

Web Inspector: introduce an AppController class and shared instance of it
https://bugs.webkit.org/show_bug.cgi?id=177024

Reviewed by Matt Baker.

WebInspectorUI currently has an app controller singleton that's distributed
among many properties on the WI object, which also serves as a namespace for
classes, enums, and other frontend objects. The singleton should be a proper
class so that we can think more easily about what state is global.

In the process of moving pieces of Main.js into AppController, I intend to move
most UI related code into a view controller class for the top level view.
AppController really shouldn't be doing anything to the view hierarchy or DOM.
It is yet to be determined how responsibility for global DOM events, such as
those for keyboard shortcuts, will be handled.

This larger refactoring project will let us more easily do things like connect
to multiple debuggables in the same Inspector instance, and switch between views
of different debuggable targets. Even if this never comes to pass, the code will
be a lot easier to reason about and maintain in the future.

For the first patch, introduce {AppController, TestAppController} <: AppControllerBase.
Shared code goes in the base class. In the Main.html and Test.html files, first
construct the AppController and then call .initialize() to avoid cyclic dependencies
on the global singleton WI.sharedApp.

* UserInterface/Main.html:
* UserInterface/Test.html:
* UserInterface/Test/Test.js:
(WI.loaded):
* UserInterface/Base/Main.js:
(WI.loaded):
Move some shared code out of here into AppControllerBase.constructor.
Eventually WI.loaded should not exist, and its code will move elsewhere.

(WI.contentLoaded):
Adopt global reference.

* UserInterface/Controllers/AppControllerBase.js: Copied from Source/WebInspectorUI/UserInterface/Protocol/MainTarget.js.
(WI.AppControllerBase):
(WI.AppControllerBase.prototype.get hasExtraDomains):
(WI.AppControllerBase.prototype.get debuggableType):
(WI.AppControllerBase.prototype.initialize):

* UserInterface/Controllers/AppController.js: New.
(WI.AppController):
(WI.AppController.prototype.get hasExtraDomains):
(WI.AppController.prototype.get debuggableType):
(WI.AppController.prototype.activateExtraDomains):

* UserInterface/Test/TestAppController.js: New.
(WI.TestAppController):
(WI.TestAppController.prototype.get hasExtraDomains):
(WI.TestAppController.prototype.get debuggableType):

* UserInterface/Controllers/TimelineManager.js:
(WI.TimelineManager.defaultTimelineTypes):
(WI.TimelineManager.availableTimelineTypes):
(WI.TimelineManager.prototype.scriptProfilerProgrammaticCaptureStarted):
(WI.TimelineManager.prototype.scriptProfilerProgrammaticCaptureStopped):
(WI.TimelineManager.prototype.scriptProfilerTrackingCompleted):
* UserInterface/Models/TimelineRecording.js:
(WI.TimelineRecording.sourceCodeTimelinesSupported):
* UserInterface/Protocol/InspectorObserver.js:
(WI.InspectorObserver.prototype.inspect):
(WI.InspectorObserver.prototype.activateExtraDomains):
(WI.InspectorObserver):
* UserInterface/Protocol/MainTarget.js:
(WI.MainTarget):
(WI.MainTarget.prototype.get displayName):
* UserInterface/Views/ResourceSidebarPanel.js:
(WI.ResourceSidebarPanel):
(WI.ResourceSidebarPanel.prototype.initialLayout):
(WI.ResourceSidebarPanel.prototype._addScript):
(WI.ResourceSidebarPanel.prototype._extraDomainsActivated):
* UserInterface/Views/Toolbar.js:
Use WI.sharedApp.{debuggableType, hasExtraDomains}.

2017-09-18 Matt Baker <mattbaker@apple.com>

Web Inspector: console.assert messages shouldn't end in an exclamation point
@@ -33,11 +33,6 @@ WI.ContentViewCookieType = {
Timelines: "timelines"
};

WI.DebuggableType = {
Web: "web",
JavaScript: "javascript"
};

WI.SelectedSidebarPanelCookieKey = "selected-sidebar-panel";
WI.TypeIdentifierCookieKey = "represented-object-type";

@@ -55,9 +50,6 @@ WI.LayoutDirection = {

WI.loaded = function()
{
this.debuggableType = InspectorFrontendHost.debuggableType() === "web" ? WI.DebuggableType.Web : WI.DebuggableType.JavaScript;
this.hasExtraDomains = false;

// Register observers for events from the InspectorBackend.
if (InspectorBackend.registerInspectorDispatcher)
InspectorBackend.registerInspectorDispatcher(new WI.InspectorObserver);
@@ -247,7 +239,7 @@ WI.contentLoaded = function()
document.body.classList.add("legacy-mac");
}

document.body.classList.add(this.debuggableType);
document.body.classList.add(WI.sharedApp.debuggableType);
document.body.setAttribute("dir", this.resolvedLayoutDirection());

function setTabSize() {
@@ -378,7 +370,7 @@ WI.contentLoaded = function()
this._togglePreviousDockConfigurationKeyboardShortcut = new WI.KeyboardShortcut(WI.KeyboardShortcut.Modifier.CommandOrControl | WI.KeyboardShortcut.Modifier.Shift, "D", this._togglePreviousDockConfiguration.bind(this));

var toolTip;
if (WI.debuggableType === WI.DebuggableType.JavaScript)
if (WI.sharedApp.debuggableType === WI.DebuggableType.JavaScript)
toolTip = WI.UIString("Restart (%s)").format(this._reloadPageKeyboardShortcut.displayName);
else
toolTip = WI.UIString("Reload this page (%s)\nReload ignoring cache (%s)").format(this._reloadPageKeyboardShortcut.displayName, this._reloadPageIgnoringCacheKeyboardShortcut.displayName);
@@ -704,14 +696,6 @@ WI.registerTabClass = function(tabClass)

WI.activateExtraDomains = function(domains)
{
this.hasExtraDomains = true;

for (var domain of domains) {
var agent = InspectorBackend.activateDomain(domain);
if (agent.enable)
agent.enable();
}

this.notifications.dispatchEventToListeners(WI.Notification.ExtraDomainsActivated, {"domains": domains});

WI.CSSCompletions.requestCSSCompletions();
@@ -1859,7 +1843,7 @@ WI._updateReloadToolbarButton = function()
WI._updateDownloadToolbarButton = function()
{
// COMPATIBILITY (iOS 7): Page.archive did not exist yet.
if (!window.PageAgent || !PageAgent.archive || this.debuggableType !== WI.DebuggableType.Web) {
if (!window.PageAgent || !PageAgent.archive || this.sharedApp.debuggableType !== WI.DebuggableType.Web) {
this._downloadToolbarButton.hidden = true;
return;
}
@@ -2589,7 +2573,7 @@ WI.archiveMainFrame = function()
WI.canArchiveMainFrame = function()
{
// COMPATIBILITY (iOS 7): Page.archive did not exist yet.
if (!PageAgent.archive || this.debuggableType !== WI.DebuggableType.Web)
if (!PageAgent.archive || this.sharedApp.debuggableType !== WI.DebuggableType.Web)
return false;

if (!WI.frameResourceManager.mainFrame || !WI.frameResourceManager.mainFrame.mainResource)
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
*/

WI.AppController = class AppController extends WI.AppControllerBase
{
constructor()
{
super();

this._hasExtraDomains = false;
this._debuggableType = InspectorFrontendHost.debuggableType() === "web" ? WI.DebuggableType.Web : WI.DebuggableType.JavaScript;
}

// Properties.

get hasExtraDomains() { return this._hasExtraDomains; }
get debuggableType() { return this._debuggableType; }

// API.

activateExtraDomains(domains)
{
if (this._hasExtraDomains)
throw new Error("Extra domains have already been activated, cannot activate again.");

this._hasExtraDomains = true;

for (let domain of domains) {
let agent = InspectorBackend.activateDomain(domain);
if (agent.enable)
agent.enable();
}

// FIXME: all code within WI.activateExtraDomains should be distributed elsewhere.
WI.activateExtraDomains();
}
};
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
*/

WI.DebuggableType = {
Web: "web",
JavaScript: "javascript"
};

WI.NotImplementedError = class NotImplementedError extends Error
{
constructor(message="This method is not implemented.")
{
super(message);
}

static subclassMustOverride()
{
return new WI.NotImplementedError("This method must be overridden by a subclass.");
}
};

WI.AppControllerBase = class AppControllerBase
{
constructor()
{
this._initialized = false;
}

get hasExtraDomains() { throw WI.NotImplementedError.subclassMustOverride(); }
get debuggableType() { throw WI.NotImplementedError.subclassMustOverride(); }

// Since various members of the app controller depend on the global singleton to exist,
// some initialization needs to happen after the app controller has been constructed.
initialize()
{
if (this._initialized)
throw new Error("App controller is already initialized.");

this._initialized = true;

// FIXME: eventually all code within WI.loaded should be distributed elsewhere.
WI.loaded();
}
};
@@ -66,7 +66,7 @@ WI.TimelineManager = class TimelineManager extends WI.Object

static defaultTimelineTypes()
{
if (WI.debuggableType === WI.DebuggableType.JavaScript) {
if (WI.sharedApp.debuggableType === WI.DebuggableType.JavaScript) {
let defaultTypes = [WI.TimelineRecord.Type.Script];
if (WI.HeapAllocationsInstrument.supported())
defaultTypes.push(WI.TimelineRecord.Type.HeapAllocations);
@@ -88,7 +88,7 @@ WI.TimelineManager = class TimelineManager extends WI.Object
static availableTimelineTypes()
{
let types = WI.TimelineManager.defaultTimelineTypes();
if (WI.debuggableType === WI.DebuggableType.JavaScript)
if (WI.sharedApp.debuggableType === WI.DebuggableType.JavaScript)
return types;

if (WI.MemoryInstrument.supported())
@@ -878,7 +878,7 @@ WI.TimelineManager = class TimelineManager extends WI.Object
scriptProfilerProgrammaticCaptureStarted()
{
// FIXME: <https://webkit.org/b/158753> Generalize the concept of Instruments on the backend to work equally for JSContext and Web inspection
console.assert(WI.debuggableType === WI.DebuggableType.JavaScript);
console.assert(WI.sharedApp.debuggableType === WI.DebuggableType.JavaScript);
console.assert(!this._isCapturing);

this.programmaticCaptureStarted();
@@ -887,7 +887,7 @@ WI.TimelineManager = class TimelineManager extends WI.Object
scriptProfilerProgrammaticCaptureStopped()
{
// FIXME: <https://webkit.org/b/158753> Generalize the concept of Instruments on the backend to work equally for JSContext and Web inspection
console.assert(WI.debuggableType === WI.DebuggableType.JavaScript);
console.assert(WI.sharedApp.debuggableType === WI.DebuggableType.JavaScript);
console.assert(this._isCapturing);

this.programmaticCaptureStopped();
@@ -977,7 +977,7 @@ WI.TimelineManager = class TimelineManager extends WI.Object

// Associate the ScriptProfiler created records with Web Timeline records.
// Filter out the already added ScriptProfiler events which should not have been wrapped.
if (WI.debuggableType !== WI.DebuggableType.JavaScript) {
if (WI.sharedApp.debuggableType !== WI.DebuggableType.JavaScript) {
this._scriptProfilerRecords = this._scriptProfilerRecords.filter((x) => x.__scriptProfilerType === ScriptProfilerAgent.EventType.Other);
this._mergeScriptProfileRecords();
}
@@ -817,14 +817,17 @@
<script src="Workers/Formatter/FormatterContentBuilder.js"></script>

<script src="Base/Main.js"></script>
<script src="Controllers/AppControllerBase.js"></script>
<script src="Controllers/AppController.js"></script>

<script src="Debug/Bootstrap.js"></script>
<script src="Debug/CapturingProtocolTracer.js"></script>
<script src="Debug/ProtocolTrace.js"></script>
<script src="Debug/DebugContentView.js"></script>

<script>
WI.loaded();
WI.sharedApp = new WI.AppController;
WI.sharedApp.initialize();
</script>
</head>
<body>
@@ -56,7 +56,7 @@ WI.TimelineRecording = class TimelineRecording extends WI.Object

static sourceCodeTimelinesSupported()
{
return WI.debuggableType === WI.DebuggableType.Web;
return WI.sharedApp.debuggableType === WI.DebuggableType.Web;
}

// Public
@@ -55,7 +55,7 @@ WI.InspectorObserver = class InspectorObserver
}
});
remoteObject.release();
return;
return;
}

if (hints.databaseId)
@@ -68,6 +68,6 @@ WI.InspectorObserver = class InspectorObserver

activateExtraDomains(domains)
{
WI.activateExtraDomains(domains);
WI.sharedApp.activateExtraDomains(domains);
}
};
@@ -29,21 +29,21 @@ WI.MainTarget = class MainTarget extends WI.Target
{
super("main", "", WI.Target.Type.Main, InspectorBackend.mainConnection);

let displayName = WI.debuggableType === WI.DebuggableType.Web ? WI.UIString("Main Frame") : this.displayName;
let displayName = WI.sharedApp.debuggableType === WI.DebuggableType.Web ? WI.UIString("Main Frame") : this.displayName;
this._executionContext = new WI.ExecutionContext(this, WI.RuntimeManager.TopLevelContextExecutionIdentifier, displayName, true, null);
}

// Protected (Target)

get displayName()
{
switch (WI.debuggableType) {
switch (WI.sharedApp.debuggableType) {
case WI.DebuggableType.Web:
return WI.UIString("Page");
case WI.DebuggableType.JavaScript:
return WI.UIString("JavaScript Context");
default:
console.error("Unexpected debuggable type: ", WI.debuggableType);
console.error("Unexpected debuggable type: ", WI.sharedApp.debuggableType);
return WI.UIString("Main");
}
}

0 comments on commit db454b1

Please sign in to comment.