blob: 6066f7048124722d14af2210b71b389893c9e1ae [file] [log] [blame]
/*
* Copyright 2014 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**
* @constructor
* @extends {Protocol.Agents}
* @param {string} name
* @param {!InspectorBackendClass.Connection} connection
* @param {function(!WebInspector.Target)=} callback
*/
WebInspector.Target = function(name, connection, callback)
{
Protocol.Agents.call(this, connection.agentsMap());
/** @type {!WeakReference.<!WebInspector.Target>} */
this._weakReference = new WeakReference(this);
this._name = name;
this._connection = connection;
connection.addEventListener(InspectorBackendClass.Connection.Events.Disconnected, this._onDisconnect, this);
this._id = WebInspector.Target._nextId++;
/** @type {!Map.<!Function, !WebInspector.SDKModel>} */
this._modelByConstructor = new Map();
/** @type {!Object.<string, boolean>} */
this._capabilities = {};
this.pageAgent().canScreencast(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanScreencast, null));
if (WebInspector.experimentsSettings.timelinePowerProfiler.isEnabled())
this.powerAgent().canProfilePower(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanProfilePower, null));
this.workerAgent().canInspectWorkers(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanInspectWorkers, this._loadedWithCapabilities.bind(this, callback)));
if (WebInspector.experimentsSettings.timelineOnTraceEvents.isEnabled())
this.consoleAgent().setTracingBasedTimeline(true);
}
/**
* @enum {string}
*/
WebInspector.Target.Capabilities = {
CanScreencast: "CanScreencast",
HasTouchInputs: "HasTouchInputs",
CanProfilePower: "CanProfilePower",
CanInspectWorkers: "CanInspectWorkers"
}
WebInspector.Target._nextId = 1;
WebInspector.Target.prototype = {
/**
* @return {number}
*/
id: function()
{
return this._id;
},
/**
*
* @return {string}
*/
name: function()
{
return this._name;
},
/**
* @return {!WeakReference.<!WebInspector.Target>}
*/
weakReference: function()
{
return this._weakReference;
},
/**
* @param {string} name
* @param {function()|null} callback
* @param {?Protocol.Error} error
* @param {boolean} result
*/
_initializeCapability: function(name, callback, error, result)
{
this._capabilities[name] = result;
if (callback)
callback();
},
/**
* @param {string} capability
* @return {boolean}
*/
hasCapability: function(capability)
{
return !!this._capabilities[capability];
},
/**
* @param {function(!WebInspector.Target)=} callback
*/
_loadedWithCapabilities: function(callback)
{
/** @type {!WebInspector.ConsoleModel} */
this.consoleModel = new WebInspector.ConsoleModel(this);
/** @type {!WebInspector.NetworkManager} */
this.networkManager = new WebInspector.NetworkManager(this);
/** @type {!WebInspector.ResourceTreeModel} */
this.resourceTreeModel = new WebInspector.ResourceTreeModel(this);
if (!WebInspector.resourceTreeModel)
WebInspector.resourceTreeModel = this.resourceTreeModel;
/** @type {!WebInspector.NetworkLog} */
this.networkLog = new WebInspector.NetworkLog(this);
if (!WebInspector.networkLog)
WebInspector.networkLog = this.networkLog;
/** @type {!WebInspector.DebuggerModel} */
this.debuggerModel = new WebInspector.DebuggerModel(this);
if (!WebInspector.debuggerModel)
WebInspector.debuggerModel = this.debuggerModel;
/** @type {!WebInspector.RuntimeModel} */
this.runtimeModel = new WebInspector.RuntimeModel(this);
if (!WebInspector.runtimeModel)
WebInspector.runtimeModel = this.runtimeModel;
/** @type {!WebInspector.DOMModel} */
this.domModel = new WebInspector.DOMModel(this);
/** @type {!WebInspector.CSSStyleModel} */
this.cssModel = new WebInspector.CSSStyleModel(this);
if (!WebInspector.cssModel)
WebInspector.cssModel = this.cssModel;
/** @type {!WebInspector.WorkerManager} */
this.workerManager = new WebInspector.WorkerManager(this, this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers));
if (!WebInspector.workerManager)
WebInspector.workerManager = this.workerManager;
if (this.hasCapability(WebInspector.Target.Capabilities.CanProfilePower))
WebInspector.powerProfiler = new WebInspector.PowerProfiler();
/** @type {!WebInspector.TimelineManager} */
this.timelineManager = new WebInspector.TimelineManager(this);
/** @type {!WebInspector.DatabaseModel} */
this.databaseModel = new WebInspector.DatabaseModel(this);
if (!WebInspector.databaseModel)
WebInspector.databaseModel = this.databaseModel;
/** @type {!WebInspector.DOMStorageModel} */
this.domStorageModel = new WebInspector.DOMStorageModel(this);
if (!WebInspector.domStorageModel)
WebInspector.domStorageModel = this.domStorageModel;
/** @type {!WebInspector.CPUProfilerModel} */
this.cpuProfilerModel = new WebInspector.CPUProfilerModel(this);
if (!WebInspector.cpuProfilerModel)
WebInspector.cpuProfilerModel = this.cpuProfilerModel;
/** @type {!WebInspector.HeapProfilerModel} */
this.heapProfilerModel = new WebInspector.HeapProfilerModel(this);
if (callback)
callback(this);
},
/**
* @override
* @param {string} domain
* @param {!Object} dispatcher
*/
registerDispatcher: function(domain, dispatcher)
{
this._connection.registerDispatcher(domain, dispatcher);
},
/**
* @return {boolean}
*/
isWorkerTarget: function()
{
return !this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers);
},
/**
* @return {boolean}
*/
isMobile: function()
{
// FIXME: either add a separate capability or rename CanScreencast to IsMobile.
return this.hasCapability(WebInspector.Target.Capabilities.CanScreencast);
},
_onDisconnect: function()
{
WebInspector.targetManager.removeTarget(this);
this._dispose();
},
_dispose: function()
{
this._weakReference.clear();
this.debuggerModel.dispose();
this.networkManager.dispose();
this.cpuProfilerModel.dispose();
},
/**
* @return {boolean}
*/
isDetached: function()
{
return this._connection.isClosed();
},
__proto__: Protocol.Agents.prototype
}
/**
* @constructor
* @extends {WebInspector.Object}
* @param {!WebInspector.Target} target
*/
WebInspector.SDKObject = function(target)
{
WebInspector.Object.call(this);
this._target = target;
}
WebInspector.SDKObject.prototype = {
/**
* @return {!WebInspector.Target}
*/
target: function()
{
return this._target;
},
__proto__: WebInspector.Object.prototype
}
/**
* @constructor
* @extends {WebInspector.SDKObject}
* @param {!Function} modelClass
* @param {!WebInspector.Target} target
*/
WebInspector.SDKModel = function(modelClass, target)
{
WebInspector.SDKObject.call(this, target);
target._modelByConstructor.put(modelClass, this);
}
WebInspector.SDKModel.prototype = {
__proto__: WebInspector.SDKObject.prototype
}
/**
* @constructor
*/
WebInspector.TargetManager = function()
{
/** @type {!Array.<!WebInspector.Target>} */
this._targets = [];
/** @type {!Array.<!WebInspector.TargetManager.Observer>} */
this._observers = [];
/** @type {!Object.<string, !Array.<{modelClass: !Function, thisObject: (!Object|undefined), listener: function(!WebInspector.Event)}>>} */
this._listeners = {};
}
WebInspector.TargetManager.prototype = {
/**
* @param {!Function} modelClass
* @param {string} eventType
* @param {function(!WebInspector.Event)} listener
* @param {!Object=} thisObject
*/
addModelListener: function(modelClass, eventType, listener, thisObject)
{
for (var i = 0; i < this._targets.length; ++i) {
var model = this._targets[i]._modelByConstructor.get(modelClass);
model.addEventListener(eventType, listener, thisObject);
}
if (!this._listeners[eventType])
this._listeners[eventType] = [];
this._listeners[eventType].push({ modelClass: modelClass, thisObject: thisObject, listener: listener });
},
/**
* @param {!Function} modelClass
* @param {string} eventType
* @param {function(!WebInspector.Event)} listener
* @param {!Object=} thisObject
*/
removeModelListener: function(modelClass, eventType, listener, thisObject)
{
if (!this._listeners[eventType])
return;
for (var i = 0; i < this._targets.length; ++i) {
var model = this._targets[i]._modelByConstructor.get(modelClass);
model.removeEventListener(eventType, listener, thisObject);
}
var listeners = this._listeners[eventType];
for (var i = 0; i < listeners.length; ++i) {
if (listeners[i].modelClass === modelClass && listeners[i].listener === listener && listeners[i].thisObject === thisObject)
listeners.splice(i--, 1);
}
if (!listeners.length)
delete this._listeners[eventType];
},
/**
* @param {!WebInspector.TargetManager.Observer} targetObserver
*/
observeTargets: function(targetObserver)
{
this.targets().forEach(targetObserver.targetAdded.bind(targetObserver));
this._observers.push(targetObserver);
},
/**
* @param {!WebInspector.TargetManager.Observer} targetObserver
*/
unobserveTargets: function(targetObserver)
{
this._observers.remove(targetObserver);
},
/**
* @param {string} name
* @param {!InspectorBackendClass.Connection} connection
* @param {function(!WebInspector.Target)=} callback
*/
createTarget: function(name, connection, callback)
{
var target = new WebInspector.Target(name, connection, callbackWrapper.bind(this));
/**
* @this {WebInspector.TargetManager}
* @param {!WebInspector.Target} newTarget
*/
function callbackWrapper(newTarget)
{
this.addTarget(newTarget);
if (callback)
callback(newTarget);
}
},
/**
* @param {!WebInspector.Target} target
*/
addTarget: function(target)
{
this._targets.push(target);
var copy = this._observers.slice();
for (var i = 0; i < copy.length; ++i)
copy[i].targetAdded(target);
for (var eventType in this._listeners) {
var listeners = this._listeners[eventType];
for (var i = 0; i < listeners.length; ++i) {
var model = target._modelByConstructor.get(listeners[i].modelClass);
model.addEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
}
}
},
/**
* @param {!WebInspector.Target} target
*/
removeTarget: function(target)
{
this._targets.remove(target);
var copy = this._observers.slice();
for (var i = 0; i < copy.length; ++i)
copy[i].targetRemoved(target);
for (var eventType in this._listeners) {
var listeners = this._listeners[eventType];
for (var i = 0; i < listeners.length; ++i) {
var model = target._modelByConstructor.get(listeners[i].modelClass);
model.removeEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
}
}
},
/**
* @return {!Array.<!WebInspector.Target>}
*/
targets: function()
{
return this._targets.slice();
},
/**
* @return {?WebInspector.Target}
*/
mainTarget: function()
{
return this._targets[0];
}
}
/**
* @interface
*/
WebInspector.TargetManager.Observer = function()
{
}
WebInspector.TargetManager.Observer.prototype = {
/**
* @param {!WebInspector.Target} target
*/
targetAdded: function(target) { },
/**
* @param {!WebInspector.Target} target
*/
targetRemoved: function(target) { },
}
/**
* @type {!WebInspector.TargetManager}
*/
WebInspector.targetManager = new WebInspector.TargetManager();