2 * Copyright 2014 The Chromium Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
9 * @extends {Protocol.Agents}
10 * @param {string} name
11 * @param {!InspectorBackendClass.Connection} connection
12 * @param {function(?WebInspector.Target)=} callback
14 WebInspector.Target = function(name, connection, callback)
16 Protocol.Agents.call(this, connection.agentsMap());
18 this._connection = connection;
19 connection.addEventListener(InspectorBackendClass.Connection.Events.Disconnected, this._onDisconnect, this);
20 this._id = WebInspector.Target._nextId++;
22 /** @type {!Map.<!Function, !WebInspector.SDKModel>} */
23 this._modelByConstructor = new Map();
25 /** @type {!Object.<string, boolean>} */
26 this._capabilities = {};
27 this.pageAgent().canScreencast(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanScreencast, null));
28 this.pageAgent().canEmulate(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanEmulate, null));
29 if (Runtime.experiments.isEnabled("timelinePowerProfiler"))
30 this.powerAgent().canProfilePower(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanProfilePower, null));
31 this.workerAgent().canInspectWorkers(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanInspectWorkers, this._loadedWithCapabilities.bind(this, callback)));
32 if (Runtime.experiments.isEnabled("timelineOnTraceEvents"))
33 this.consoleAgent().setTracingBasedTimeline(true);
39 WebInspector.Target.Capabilities = {
40 CanScreencast: "CanScreencast",
41 HasTouchInputs: "HasTouchInputs",
42 CanProfilePower: "CanProfilePower",
43 CanInspectWorkers: "CanInspectWorkers",
44 CanEmulate: "CanEmulate"
47 WebInspector.Target._nextId = 1;
49 WebInspector.Target.prototype = {
52 if (!Runtime.experiments.isEnabled("disableAgentsWhenProfile")) {
53 this.debuggerModel.asyncStackTracesStateChanged();
56 this.debuggerModel.suspendModel();
57 this.cssModel.suspendModel();
58 this.domModel.suspendModel();
63 if (Runtime.experiments.isEnabled("disableAgentsWhenProfile")) {
64 this.domModel.resumeModel();
65 this.cssModel.resumeModel();
66 this.debuggerModel.resumeModel();
68 this.debuggerModel.asyncStackTracesStateChanged();
90 * @param {string} name
91 * @param {function()|null} callback
92 * @param {?Protocol.Error} error
93 * @param {boolean} result
95 _initializeCapability: function(name, callback, error, result)
97 this._capabilities[name] = result;
103 * @param {string} capability
106 hasCapability: function(capability)
108 return !!this._capabilities[capability];
112 * @param {function(?WebInspector.Target)=} callback
114 _loadedWithCapabilities: function(callback)
116 if (this._connection.isClosed()) {
121 /** @type {!WebInspector.ConsoleModel} */
122 this.consoleModel = new WebInspector.ConsoleModel(this);
124 /** @type {!WebInspector.NetworkManager} */
125 this.networkManager = new WebInspector.NetworkManager(this);
127 /** @type {!WebInspector.ResourceTreeModel} */
128 this.resourceTreeModel = new WebInspector.ResourceTreeModel(this);
129 if (!WebInspector.resourceTreeModel)
130 WebInspector.resourceTreeModel = this.resourceTreeModel;
132 /** @type {!WebInspector.NetworkLog} */
133 this.networkLog = new WebInspector.NetworkLog(this);
134 if (!WebInspector.networkLog)
135 WebInspector.networkLog = this.networkLog;
137 /** @type {!WebInspector.DebuggerModel} */
138 this.debuggerModel = new WebInspector.DebuggerModel(this);
139 if (!WebInspector.debuggerModel)
140 WebInspector.debuggerModel = this.debuggerModel;
142 /** @type {!WebInspector.RuntimeModel} */
143 this.runtimeModel = new WebInspector.RuntimeModel(this);
144 if (!WebInspector.runtimeModel)
145 WebInspector.runtimeModel = this.runtimeModel;
147 /** @type {!WebInspector.DOMModel} */
148 this.domModel = new WebInspector.DOMModel(this);
150 /** @type {!WebInspector.CSSStyleModel} */
151 this.cssModel = new WebInspector.CSSStyleModel(this);
152 if (!WebInspector.cssModel)
153 WebInspector.cssModel = this.cssModel;
155 /** @type {!WebInspector.WorkerManager} */
156 this.workerManager = new WebInspector.WorkerManager(this, this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers));
157 if (!WebInspector.workerManager)
158 WebInspector.workerManager = this.workerManager;
160 if (this.hasCapability(WebInspector.Target.Capabilities.CanProfilePower))
161 WebInspector.powerProfiler = new WebInspector.PowerProfiler(this);
163 /** @type {!WebInspector.TimelineManager} */
164 this.timelineManager = new WebInspector.TimelineManager(this);
166 /** @type {!WebInspector.DatabaseModel} */
167 this.databaseModel = new WebInspector.DatabaseModel(this);
168 if (!WebInspector.databaseModel)
169 WebInspector.databaseModel = this.databaseModel;
171 /** @type {!WebInspector.DOMStorageModel} */
172 this.domStorageModel = new WebInspector.DOMStorageModel(this);
173 if (!WebInspector.domStorageModel)
174 WebInspector.domStorageModel = this.domStorageModel;
176 /** @type {!WebInspector.CPUProfilerModel} */
177 this.cpuProfilerModel = new WebInspector.CPUProfilerModel(this);
178 if (!WebInspector.cpuProfilerModel)
179 WebInspector.cpuProfilerModel = this.cpuProfilerModel;
181 /** @type {!WebInspector.HeapProfilerModel} */
182 this.heapProfilerModel = new WebInspector.HeapProfilerModel(this);
184 /** @type {!WebInspector.IndexedDBModel} */
185 this.indexedDBModel = new WebInspector.IndexedDBModel(this);
187 /** @type {!WebInspector.LayerTreeModel} */
188 this.layerTreeModel = new WebInspector.LayerTreeModel(this);
190 /** @type {!WebInspector.AnimationModel} */
191 this.animationModel = new WebInspector.AnimationModel(this);
199 * @param {string} domain
200 * @param {!Object} dispatcher
202 registerDispatcher: function(domain, dispatcher)
204 this._connection.registerDispatcher(domain, dispatcher);
210 isWorkerTarget: function()
212 return !this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers);
218 canEmulate: function()
220 return this.hasCapability(WebInspector.Target.Capabilities.CanEmulate);
223 _onDisconnect: function()
225 WebInspector.targetManager.removeTarget(this);
231 this.debuggerModel.dispose();
232 this.networkManager.dispose();
233 this.cpuProfilerModel.dispose();
239 isDetached: function()
241 return this._connection.isClosed();
244 __proto__: Protocol.Agents.prototype
249 * @extends {WebInspector.Object}
250 * @param {!WebInspector.Target} target
252 WebInspector.SDKObject = function(target)
254 WebInspector.Object.call(this);
255 this._target = target;
258 WebInspector.SDKObject.prototype = {
260 * @return {!WebInspector.Target}
267 __proto__: WebInspector.Object.prototype
272 * @extends {WebInspector.SDKObject}
273 * @param {!Function} modelClass
274 * @param {!WebInspector.Target} target
276 WebInspector.SDKModel = function(modelClass, target)
278 WebInspector.SDKObject.call(this, target);
279 target._modelByConstructor.set(modelClass, this);
282 WebInspector.SDKModel.prototype = {
283 __proto__: WebInspector.SDKObject.prototype
288 * @extends {WebInspector.Object}
290 WebInspector.TargetManager = function()
292 WebInspector.Object.call(this);
293 /** @type {!Array.<!WebInspector.Target>} */
295 /** @type {!Array.<!WebInspector.TargetManager.Observer>} */
296 this._observers = [];
297 /** @type {!Object.<string, !Array.<{modelClass: !Function, thisObject: (!Object|undefined), listener: function(!WebInspector.Event)}>>} */
298 this._modelListeners = {};
299 /** @type {boolean} */
300 this._allTargetsSuspended = false;
303 WebInspector.TargetManager.Events = {
304 InspectedURLChanged: "InspectedURLChanged",
305 MainFrameNavigated: "MainFrameNavigated",
307 WillReloadPage: "WillReloadPage",
308 SuspendStateChanged: "SuspendStateChanged"
311 WebInspector.TargetManager.prototype = {
312 suspendAllTargets: function()
314 console.assert(!this._allTargetsSuspended);
315 if (this._allTargetsSuspended)
317 this._allTargetsSuspended = true;
318 this._targets.forEach(function(target)
322 this.dispatchEventToListeners(WebInspector.TargetManager.Events.SuspendStateChanged);
325 resumeAllTargets: function()
327 console.assert(this._allTargetsSuspended);
328 if (!this._allTargetsSuspended)
330 this._allTargetsSuspended = false;
331 this._targets.forEach(function(target)
335 this.dispatchEventToListeners(WebInspector.TargetManager.Events.SuspendStateChanged);
341 allTargetsSuspended: function()
343 return this._allTargetsSuspended;
349 inspectedPageURL: function()
351 if (!this._targets.length)
354 return this._targets[0].resourceTreeModel.inspectedPageURL();
360 inspectedPageDomain: function()
362 if (!this._targets.length)
365 return this._targets[0].resourceTreeModel.inspectedPageDomain();
369 * @param {!WebInspector.Event} event
371 _redispatchEvent: function(event)
373 this.dispatchEventToListeners(event.type, event.data);
377 * @param {boolean=} ignoreCache
379 reloadPage: function(ignoreCache)
381 if (this._targets.length)
382 this._targets[0].resourceTreeModel.reloadPage(ignoreCache);
386 * @param {!Function} modelClass
387 * @param {string} eventType
388 * @param {function(!WebInspector.Event)} listener
389 * @param {!Object=} thisObject
391 addModelListener: function(modelClass, eventType, listener, thisObject)
393 for (var i = 0; i < this._targets.length; ++i) {
394 var model = this._targets[i]._modelByConstructor.get(modelClass);
395 model.addEventListener(eventType, listener, thisObject);
397 if (!this._modelListeners[eventType])
398 this._modelListeners[eventType] = [];
399 this._modelListeners[eventType].push({ modelClass: modelClass, thisObject: thisObject, listener: listener });
403 * @param {!Function} modelClass
404 * @param {string} eventType
405 * @param {function(!WebInspector.Event)} listener
406 * @param {!Object=} thisObject
408 removeModelListener: function(modelClass, eventType, listener, thisObject)
410 if (!this._modelListeners[eventType])
413 for (var i = 0; i < this._targets.length; ++i) {
414 var model = this._targets[i]._modelByConstructor.get(modelClass);
415 model.removeEventListener(eventType, listener, thisObject);
418 var listeners = this._modelListeners[eventType];
419 for (var i = 0; i < listeners.length; ++i) {
420 if (listeners[i].modelClass === modelClass && listeners[i].listener === listener && listeners[i].thisObject === thisObject)
421 listeners.splice(i--, 1);
423 if (!listeners.length)
424 delete this._modelListeners[eventType];
428 * @param {!WebInspector.TargetManager.Observer} targetObserver
430 observeTargets: function(targetObserver)
432 this.targets().forEach(targetObserver.targetAdded.bind(targetObserver));
433 this._observers.push(targetObserver);
437 * @param {!WebInspector.TargetManager.Observer} targetObserver
439 unobserveTargets: function(targetObserver)
441 this._observers.remove(targetObserver);
445 * @param {string} name
446 * @param {!InspectorBackendClass.Connection} connection
447 * @param {function(?WebInspector.Target)=} callback
449 createTarget: function(name, connection, callback)
451 var target = new WebInspector.Target(name, connection, callbackWrapper.bind(this));
454 * @this {WebInspector.TargetManager}
455 * @param {?WebInspector.Target} newTarget
457 function callbackWrapper(newTarget)
460 this.addTarget(newTarget);
467 * @param {!WebInspector.Target} target
469 addTarget: function(target)
471 this._targets.push(target);
472 if (this._targets.length === 1) {
473 target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._redispatchEvent, this);
474 target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._redispatchEvent, this);
475 target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._redispatchEvent, this);
476 target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._redispatchEvent, this);
478 var copy = this._observers.slice();
479 for (var i = 0; i < copy.length; ++i)
480 copy[i].targetAdded(target);
482 for (var eventType in this._modelListeners) {
483 var listeners = this._modelListeners[eventType];
484 for (var i = 0; i < listeners.length; ++i) {
485 var model = target._modelByConstructor.get(listeners[i].modelClass);
486 model.addEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
492 * @param {!WebInspector.Target} target
494 removeTarget: function(target)
496 this._targets.remove(target);
497 if (this._targets.length === 0) {
498 target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._redispatchEvent, this);
499 target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._redispatchEvent, this);
500 target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._redispatchEvent, this);
501 target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._redispatchEvent, this);
503 var copy = this._observers.slice();
504 for (var i = 0; i < copy.length; ++i)
505 copy[i].targetRemoved(target);
507 for (var eventType in this._modelListeners) {
508 var listeners = this._modelListeners[eventType];
509 for (var i = 0; i < listeners.length; ++i) {
510 var model = target._modelByConstructor.get(listeners[i].modelClass);
511 model.removeEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
519 hasTargets: function()
521 return !!this._targets.length;
525 * @return {!Array.<!WebInspector.Target>}
529 return this._targets.slice();
533 * @return {?WebInspector.Target}
535 mainTarget: function()
537 return this._targets[0] || null;
540 __proto__: WebInspector.Object.prototype
546 WebInspector.TargetManager.Observer = function()
550 WebInspector.TargetManager.Observer.prototype = {
552 * @param {!WebInspector.Target} target
554 targetAdded: function(target) { },
557 * @param {!WebInspector.Target} target
559 targetRemoved: function(target) { },
563 * @type {!WebInspector.TargetManager}
565 WebInspector.targetManager = new WebInspector.TargetManager();