Home | History | Annotate | Download | only in sdk
      1 /*
      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.
      5  */
      6 
      7 /**
      8  * @constructor
      9  * @extends {Protocol.Agents}
     10  * @param {string} name
     11  * @param {!InspectorBackendClass.Connection} connection
     12  * @param {function(?WebInspector.Target)=} callback
     13  */
     14 WebInspector.Target = function(name, connection, callback)
     15 {
     16     Protocol.Agents.call(this, connection.agentsMap());
     17     this._name = name;
     18     this._connection = connection;
     19     connection.addEventListener(InspectorBackendClass.Connection.Events.Disconnected, this._onDisconnect, this);
     20     this._id = WebInspector.Target._nextId++;
     21 
     22     /** @type {!Map.<!Function, !WebInspector.SDKModel>} */
     23     this._modelByConstructor = new Map();
     24 
     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);
     34 }
     35 
     36 /**
     37  * @enum {string}
     38  */
     39 WebInspector.Target.Capabilities = {
     40     CanScreencast: "CanScreencast",
     41     HasTouchInputs: "HasTouchInputs",
     42     CanProfilePower: "CanProfilePower",
     43     CanInspectWorkers: "CanInspectWorkers",
     44     CanEmulate: "CanEmulate"
     45 }
     46 
     47 WebInspector.Target._nextId = 1;
     48 
     49 WebInspector.Target.prototype = {
     50 
     51     /**
     52      * @return {number}
     53      */
     54     id: function()
     55     {
     56         return this._id;
     57     },
     58 
     59     /**
     60      *
     61      * @return {string}
     62      */
     63     name: function()
     64     {
     65         return this._name;
     66     },
     67 
     68     /**
     69      * @param {string} name
     70      * @param {function()|null} callback
     71      * @param {?Protocol.Error} error
     72      * @param {boolean} result
     73      */
     74     _initializeCapability: function(name, callback, error, result)
     75     {
     76         this._capabilities[name] = result;
     77         if (callback)
     78             callback();
     79     },
     80 
     81     /**
     82      * @param {string} capability
     83      * @return {boolean}
     84      */
     85     hasCapability: function(capability)
     86     {
     87         return !!this._capabilities[capability];
     88     },
     89 
     90     /**
     91      * @param {function(?WebInspector.Target)=} callback
     92      */
     93     _loadedWithCapabilities: function(callback)
     94     {
     95         if (this._connection.isClosed()) {
     96             callback(null);
     97             return;
     98         }
     99 
    100         /** @type {!WebInspector.ConsoleModel} */
    101         this.consoleModel = new WebInspector.ConsoleModel(this);
    102 
    103         /** @type {!WebInspector.NetworkManager} */
    104         this.networkManager = new WebInspector.NetworkManager(this);
    105 
    106         /** @type {!WebInspector.ResourceTreeModel} */
    107         this.resourceTreeModel = new WebInspector.ResourceTreeModel(this);
    108         if (!WebInspector.resourceTreeModel)
    109             WebInspector.resourceTreeModel = this.resourceTreeModel;
    110 
    111         /** @type {!WebInspector.NetworkLog} */
    112         this.networkLog = new WebInspector.NetworkLog(this);
    113         if (!WebInspector.networkLog)
    114             WebInspector.networkLog = this.networkLog;
    115 
    116         /** @type {!WebInspector.DebuggerModel} */
    117         this.debuggerModel = new WebInspector.DebuggerModel(this);
    118         if (!WebInspector.debuggerModel)
    119             WebInspector.debuggerModel = this.debuggerModel;
    120 
    121         /** @type {!WebInspector.RuntimeModel} */
    122         this.runtimeModel = new WebInspector.RuntimeModel(this);
    123         if (!WebInspector.runtimeModel)
    124             WebInspector.runtimeModel = this.runtimeModel;
    125 
    126         /** @type {!WebInspector.DOMModel} */
    127         this.domModel = new WebInspector.DOMModel(this);
    128 
    129         /** @type {!WebInspector.CSSStyleModel} */
    130         this.cssModel = new WebInspector.CSSStyleModel(this);
    131         if (!WebInspector.cssModel)
    132             WebInspector.cssModel = this.cssModel;
    133 
    134         /** @type {!WebInspector.WorkerManager} */
    135         this.workerManager = new WebInspector.WorkerManager(this, this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers));
    136         if (!WebInspector.workerManager)
    137             WebInspector.workerManager = this.workerManager;
    138 
    139         if (this.hasCapability(WebInspector.Target.Capabilities.CanProfilePower))
    140             WebInspector.powerProfiler = new WebInspector.PowerProfiler(this);
    141 
    142         /** @type {!WebInspector.TimelineManager} */
    143         this.timelineManager = new WebInspector.TimelineManager(this);
    144 
    145         /** @type {!WebInspector.DatabaseModel} */
    146         this.databaseModel = new WebInspector.DatabaseModel(this);
    147         if (!WebInspector.databaseModel)
    148             WebInspector.databaseModel = this.databaseModel;
    149 
    150         /** @type {!WebInspector.DOMStorageModel} */
    151         this.domStorageModel = new WebInspector.DOMStorageModel(this);
    152         if (!WebInspector.domStorageModel)
    153             WebInspector.domStorageModel = this.domStorageModel;
    154 
    155         /** @type {!WebInspector.CPUProfilerModel} */
    156         this.cpuProfilerModel = new WebInspector.CPUProfilerModel(this);
    157         if (!WebInspector.cpuProfilerModel)
    158             WebInspector.cpuProfilerModel = this.cpuProfilerModel;
    159 
    160         /** @type {!WebInspector.HeapProfilerModel} */
    161         this.heapProfilerModel = new WebInspector.HeapProfilerModel(this);
    162 
    163         /** @type {!WebInspector.IndexedDBModel} */
    164         this.indexedDBModel = new WebInspector.IndexedDBModel(this);
    165 
    166         /** @type {!WebInspector.LayerTreeModel} */
    167         this.layerTreeModel = new WebInspector.LayerTreeModel(this);
    168 
    169         if (callback)
    170             callback(this);
    171     },
    172 
    173     /**
    174      * @override
    175      * @param {string} domain
    176      * @param {!Object} dispatcher
    177      */
    178     registerDispatcher: function(domain, dispatcher)
    179     {
    180         this._connection.registerDispatcher(domain, dispatcher);
    181     },
    182 
    183     /**
    184      * @return {boolean}
    185      */
    186     isWorkerTarget: function()
    187     {
    188         return !this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers);
    189     },
    190 
    191     /**
    192      * @return {boolean}
    193      */
    194     canEmulate: function()
    195     {
    196         return this.hasCapability(WebInspector.Target.Capabilities.CanEmulate);
    197     },
    198 
    199     _onDisconnect: function()
    200     {
    201         WebInspector.targetManager.removeTarget(this);
    202         this._dispose();
    203     },
    204 
    205     _dispose: function()
    206     {
    207         this.debuggerModel.dispose();
    208         this.networkManager.dispose();
    209         this.cpuProfilerModel.dispose();
    210     },
    211 
    212     /**
    213      * @return {boolean}
    214      */
    215     isDetached: function()
    216     {
    217         return this._connection.isClosed();
    218     },
    219 
    220     __proto__: Protocol.Agents.prototype
    221 }
    222 
    223 /**
    224  * @constructor
    225  * @extends {WebInspector.Object}
    226  * @param {!WebInspector.Target} target
    227  */
    228 WebInspector.SDKObject = function(target)
    229 {
    230     WebInspector.Object.call(this);
    231     this._target = target;
    232 }
    233 
    234 WebInspector.SDKObject.prototype = {
    235     /**
    236      * @return {!WebInspector.Target}
    237      */
    238     target: function()
    239     {
    240         return this._target;
    241     },
    242 
    243     __proto__: WebInspector.Object.prototype
    244 }
    245 
    246 /**
    247  * @constructor
    248  * @extends {WebInspector.SDKObject}
    249  * @param {!Function} modelClass
    250  * @param {!WebInspector.Target} target
    251  */
    252 WebInspector.SDKModel = function(modelClass, target)
    253 {
    254     WebInspector.SDKObject.call(this, target);
    255     target._modelByConstructor.set(modelClass, this);
    256 }
    257 
    258 WebInspector.SDKModel.prototype = {
    259     __proto__: WebInspector.SDKObject.prototype
    260 }
    261 
    262 /**
    263  * @constructor
    264  * @extends {WebInspector.Object}
    265  */
    266 WebInspector.TargetManager = function()
    267 {
    268     WebInspector.Object.call(this);
    269     /** @type {!Array.<!WebInspector.Target>} */
    270     this._targets = [];
    271     /** @type {!Array.<!WebInspector.TargetManager.Observer>} */
    272     this._observers = [];
    273     /** @type {!Object.<string, !Array.<{modelClass: !Function, thisObject: (!Object|undefined), listener: function(!WebInspector.Event)}>>} */
    274     this._modelListeners = {};
    275 }
    276 
    277 WebInspector.TargetManager.Events = {
    278     InspectedURLChanged: "InspectedURLChanged",
    279     MainFrameNavigated: "MainFrameNavigated",
    280     Load: "Load",
    281     WillReloadPage: "WillReloadPage"
    282 }
    283 
    284 WebInspector.TargetManager.prototype = {
    285     /**
    286      * @return {string}
    287      */
    288     inspectedPageURL: function()
    289     {
    290         if (!this._targets.length)
    291             return "";
    292 
    293         return this._targets[0].resourceTreeModel.inspectedPageURL();
    294     },
    295 
    296     /**
    297      * @return {string}
    298      */
    299     inspectedPageDomain: function()
    300     {
    301         if (!this._targets.length)
    302             return "";
    303 
    304         return this._targets[0].resourceTreeModel.inspectedPageDomain();
    305     },
    306 
    307     /**
    308      * @param {!WebInspector.Event} event
    309      */
    310     _redispatchEvent: function(event)
    311     {
    312         this.dispatchEventToListeners(event.type, event.data);
    313     },
    314 
    315     /**
    316      * @param {boolean=} ignoreCache
    317      */
    318     reloadPage: function(ignoreCache)
    319     {
    320         if (this._targets.length)
    321             this._targets[0].resourceTreeModel.reloadPage(ignoreCache);
    322     },
    323 
    324     /**
    325      * @param {!Function} modelClass
    326      * @param {string} eventType
    327      * @param {function(!WebInspector.Event)} listener
    328      * @param {!Object=} thisObject
    329      */
    330     addModelListener: function(modelClass, eventType, listener, thisObject)
    331     {
    332         for (var i = 0; i < this._targets.length; ++i) {
    333             var model = this._targets[i]._modelByConstructor.get(modelClass);
    334             model.addEventListener(eventType, listener, thisObject);
    335         }
    336         if (!this._modelListeners[eventType])
    337             this._modelListeners[eventType] = [];
    338         this._modelListeners[eventType].push({ modelClass: modelClass, thisObject: thisObject, listener: listener });
    339     },
    340 
    341     /**
    342      * @param {!Function} modelClass
    343      * @param {string} eventType
    344      * @param {function(!WebInspector.Event)} listener
    345      * @param {!Object=} thisObject
    346      */
    347     removeModelListener: function(modelClass, eventType, listener, thisObject)
    348     {
    349         if (!this._modelListeners[eventType])
    350             return;
    351 
    352         for (var i = 0; i < this._targets.length; ++i) {
    353             var model = this._targets[i]._modelByConstructor.get(modelClass);
    354             model.removeEventListener(eventType, listener, thisObject);
    355         }
    356 
    357         var listeners = this._modelListeners[eventType];
    358         for (var i = 0; i < listeners.length; ++i) {
    359             if (listeners[i].modelClass === modelClass && listeners[i].listener === listener && listeners[i].thisObject === thisObject)
    360                 listeners.splice(i--, 1);
    361         }
    362         if (!listeners.length)
    363             delete this._modelListeners[eventType];
    364     },
    365 
    366     /**
    367      * @param {!WebInspector.TargetManager.Observer} targetObserver
    368      */
    369     observeTargets: function(targetObserver)
    370     {
    371         this.targets().forEach(targetObserver.targetAdded.bind(targetObserver));
    372         this._observers.push(targetObserver);
    373     },
    374 
    375     /**
    376      * @param {!WebInspector.TargetManager.Observer} targetObserver
    377      */
    378     unobserveTargets: function(targetObserver)
    379     {
    380         this._observers.remove(targetObserver);
    381     },
    382 
    383     /**
    384      * @param {string} name
    385      * @param {!InspectorBackendClass.Connection} connection
    386      * @param {function(?WebInspector.Target)=} callback
    387      */
    388     createTarget: function(name, connection, callback)
    389     {
    390         var target = new WebInspector.Target(name, connection, callbackWrapper.bind(this));
    391 
    392         /**
    393          * @this {WebInspector.TargetManager}
    394          * @param {?WebInspector.Target} newTarget
    395          */
    396         function callbackWrapper(newTarget)
    397         {
    398             if (newTarget)
    399                 this.addTarget(newTarget);
    400             if (callback)
    401                 callback(newTarget);
    402         }
    403     },
    404 
    405     /**
    406      * @param {!WebInspector.Target} target
    407      */
    408     addTarget: function(target)
    409     {
    410         this._targets.push(target);
    411         if (this._targets.length === 1) {
    412             target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._redispatchEvent, this);
    413             target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._redispatchEvent, this);
    414             target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._redispatchEvent, this);
    415             target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._redispatchEvent, this);
    416         }
    417         var copy = this._observers.slice();
    418         for (var i = 0; i < copy.length; ++i)
    419             copy[i].targetAdded(target);
    420 
    421         for (var eventType in this._modelListeners) {
    422             var listeners = this._modelListeners[eventType];
    423             for (var i = 0; i < listeners.length; ++i) {
    424                 var model = target._modelByConstructor.get(listeners[i].modelClass);
    425                 model.addEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
    426             }
    427         }
    428     },
    429 
    430     /**
    431      * @param {!WebInspector.Target} target
    432      */
    433     removeTarget: function(target)
    434     {
    435         this._targets.remove(target);
    436         if (this._targets.length === 0) {
    437             target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._redispatchEvent, this);
    438             target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._redispatchEvent, this);
    439             target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._redispatchEvent, this);
    440             target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._redispatchEvent, this);
    441         }
    442         var copy = this._observers.slice();
    443         for (var i = 0; i < copy.length; ++i)
    444             copy[i].targetRemoved(target);
    445 
    446         for (var eventType in this._modelListeners) {
    447             var listeners = this._modelListeners[eventType];
    448             for (var i = 0; i < listeners.length; ++i) {
    449                 var model = target._modelByConstructor.get(listeners[i].modelClass);
    450                 model.removeEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
    451             }
    452         }
    453     },
    454 
    455     /**
    456      * @return {boolean}
    457      */
    458     hasTargets: function()
    459     {
    460         return !!this._targets.length;
    461     },
    462 
    463     /**
    464      * @return {!Array.<!WebInspector.Target>}
    465      */
    466     targets: function()
    467     {
    468         return this._targets.slice();
    469     },
    470 
    471     /**
    472      * @return {?WebInspector.Target}
    473      */
    474     mainTarget: function()
    475     {
    476         return this._targets[0];
    477     },
    478 
    479     __proto__: WebInspector.Object.prototype
    480 }
    481 
    482 /**
    483  * @interface
    484  */
    485 WebInspector.TargetManager.Observer = function()
    486 {
    487 }
    488 
    489 WebInspector.TargetManager.Observer.prototype = {
    490     /**
    491      * @param {!WebInspector.Target} target
    492      */
    493     targetAdded: function(target) { },
    494 
    495     /**
    496      * @param {!WebInspector.Target} target
    497      */
    498     targetRemoved: function(target) { },
    499 }
    500 
    501 /**
    502  * @type {!WebInspector.TargetManager}
    503  */
    504 WebInspector.targetManager = new WebInspector.TargetManager();
    505