• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @constructor
33 * @extends {WebInspector.TargetAwareObject}
34 * @param {!WebInspector.Target} target
35 */
36WebInspector.ResourceTreeModel = function(target)
37{
38    WebInspector.TargetAwareObject.call(this, target);
39
40    target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestFinished, this);
41    target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestUpdateDropped, this._onRequestUpdateDropped, this);
42
43    target.consoleModel.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._consoleMessageAdded, this);
44    target.consoleModel.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this);
45
46    this._agent = target.pageAgent();
47    this._agent.enable();
48
49    this._fetchResourceTree();
50
51    target.registerPageDispatcher(new WebInspector.PageDispatcher(this));
52
53    this._pendingConsoleMessages = {};
54    this._securityOriginFrameCount = {};
55    this._inspectedPageURL = "";
56}
57
58WebInspector.ResourceTreeModel.EventTypes = {
59    FrameAdded: "FrameAdded",
60    FrameNavigated: "FrameNavigated",
61    FrameDetached: "FrameDetached",
62    FrameResized: "FrameResized",
63    MainFrameNavigated: "MainFrameNavigated",
64    ResourceAdded: "ResourceAdded",
65    WillLoadCachedResources: "WillLoadCachedResources",
66    CachedResourcesLoaded: "CachedResourcesLoaded",
67    DOMContentLoaded: "DOMContentLoaded",
68    Load: "Load",
69    WillReloadPage: "WillReloadPage",
70    InspectedURLChanged: "InspectedURLChanged",
71    SecurityOriginAdded: "SecurityOriginAdded",
72    SecurityOriginRemoved: "SecurityOriginRemoved",
73    ScreencastFrame: "ScreencastFrame",
74    ScreencastVisibilityChanged: "ScreencastVisibilityChanged"
75}
76
77WebInspector.ResourceTreeModel.prototype = {
78    _fetchResourceTree: function()
79    {
80        /** @type {!Object.<string, !WebInspector.ResourceTreeFrame>} */
81        this._frames = {};
82        delete this._cachedResourcesProcessed;
83        this._agent.getResourceTree(this._processCachedResources.bind(this));
84    },
85
86    _processCachedResources: function(error, mainFramePayload)
87    {
88        if (error) {
89            console.error(JSON.stringify(error));
90            return;
91        }
92
93        this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.WillLoadCachedResources);
94        this._inspectedPageURL = mainFramePayload.frame.url;
95        this._addFramesRecursively(null, mainFramePayload);
96        this._dispatchInspectedURLChanged();
97        this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.CachedResourcesLoaded);
98        this._cachedResourcesProcessed = true;
99    },
100
101    /**
102     * @return {string}
103     */
104    inspectedPageURL: function()
105    {
106        return this._inspectedPageURL;
107    },
108
109    /**
110     * @return {string}
111     */
112    inspectedPageDomain: function()
113    {
114        var parsedURL = this._inspectedPageURL ? this._inspectedPageURL.asParsedURL() : null;
115        return parsedURL ? parsedURL.host : "";
116    },
117
118    /**
119     * @return {boolean}
120     */
121    cachedResourcesLoaded: function()
122    {
123        return this._cachedResourcesProcessed;
124    },
125
126    _dispatchInspectedURLChanged: function()
127    {
128        InspectorFrontendHost.inspectedURLChanged(this._inspectedPageURL);
129        this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._inspectedPageURL);
130    },
131
132    /**
133     * @param {!WebInspector.ResourceTreeFrame} frame
134     * @param {boolean=} aboutToNavigate
135     */
136    _addFrame: function(frame, aboutToNavigate)
137    {
138        this._frames[frame.id] = frame;
139        if (frame.isMainFrame())
140            this.mainFrame = frame;
141        this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, frame);
142        if (!aboutToNavigate)
143            this._addSecurityOrigin(frame.securityOrigin);
144    },
145
146    /**
147     * @param {string} securityOrigin
148     */
149    _addSecurityOrigin: function(securityOrigin)
150    {
151        if (!this._securityOriginFrameCount[securityOrigin]) {
152            this._securityOriginFrameCount[securityOrigin] = 1;
153            this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginAdded, securityOrigin);
154            return;
155        }
156        this._securityOriginFrameCount[securityOrigin] += 1;
157    },
158
159    /**
160     * @param {string|undefined} securityOrigin
161     */
162    _removeSecurityOrigin: function(securityOrigin)
163    {
164        if (typeof securityOrigin === "undefined")
165            return;
166        if (this._securityOriginFrameCount[securityOrigin] === 1) {
167            delete this._securityOriginFrameCount[securityOrigin];
168            this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginRemoved, securityOrigin);
169            return;
170        }
171        this._securityOriginFrameCount[securityOrigin] -= 1;
172    },
173
174    /**
175     * @return {!Array.<string>}
176     */
177    securityOrigins: function()
178    {
179        return Object.keys(this._securityOriginFrameCount);
180    },
181
182    /**
183     * @param {!WebInspector.ResourceTreeFrame} mainFrame
184     */
185    _handleMainFrameDetached: function(mainFrame)
186    {
187        /**
188         * @param {!WebInspector.ResourceTreeFrame} frame
189         * @this {WebInspector.ResourceTreeModel}
190         */
191        function removeOriginForFrame(frame)
192        {
193            for (var i = 0; i < frame.childFrames.length; ++i)
194                removeOriginForFrame.call(this, frame.childFrames[i]);
195            if (!frame.isMainFrame())
196                this._removeSecurityOrigin(frame.securityOrigin);
197        }
198        removeOriginForFrame.call(this, WebInspector.resourceTreeModel.mainFrame);
199    },
200
201    /**
202     * @param {!PageAgent.FrameId} frameId
203     * @param {?PageAgent.FrameId} parentFrameId
204     * @return {?WebInspector.ResourceTreeFrame}
205     */
206    _frameAttached: function(frameId, parentFrameId)
207    {
208        // Do nothing unless cached resource tree is processed - it will overwrite everything.
209        if (!this._cachedResourcesProcessed)
210            return null;
211        if (this._frames[frameId])
212            return null;
213
214        var parentFrame = parentFrameId ? this._frames[parentFrameId] : null;
215        var frame = new WebInspector.ResourceTreeFrame(this, parentFrame, frameId);
216        if (frame.isMainFrame() && this.mainFrame) {
217            this._handleMainFrameDetached(this.mainFrame);
218            // Navigation to the new backend process.
219            this._frameDetached(this.mainFrame.id);
220        }
221        this._addFrame(frame, true);
222        return frame;
223    },
224
225    /**
226     * @param {!PageAgent.Frame} framePayload
227     */
228    _frameNavigated: function(framePayload)
229    {
230        // Do nothing unless cached resource tree is processed - it will overwrite everything.
231        if (!this._cachedResourcesProcessed)
232            return;
233        var frame = this._frames[framePayload.id];
234        if (!frame) {
235            // Simulate missed "frameAttached" for a main frame navigation to the new backend process.
236            console.assert(!framePayload.parentId, "Main frame shouldn't have parent frame id.");
237            frame = this._frameAttached(framePayload.id, framePayload.parentId || "");
238            console.assert(frame);
239        }
240        this._removeSecurityOrigin(frame.securityOrigin);
241        frame._navigate(framePayload);
242        var addedOrigin = frame.securityOrigin;
243
244        if (frame.isMainFrame())
245            this._inspectedPageURL = frame.url;
246
247        this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, frame);
248        if (frame.isMainFrame())
249            this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, frame);
250        if (addedOrigin)
251            this._addSecurityOrigin(addedOrigin);
252
253        // Fill frame with retained resources (the ones loaded using new loader).
254        var resources = frame.resources();
255        for (var i = 0; i < resources.length; ++i)
256            this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resources[i]);
257
258        if (frame.isMainFrame())
259            this._dispatchInspectedURLChanged();
260    },
261
262    /**
263     * @param {!PageAgent.FrameId} frameId
264     */
265    _frameDetached: function(frameId)
266    {
267        // Do nothing unless cached resource tree is processed - it will overwrite everything.
268        if (!this._cachedResourcesProcessed)
269            return;
270
271        var frame = this._frames[frameId];
272        if (!frame)
273            return;
274
275        this._removeSecurityOrigin(frame.securityOrigin);
276        if (frame.parentFrame)
277            frame.parentFrame._removeChildFrame(frame);
278        else
279            frame._remove();
280    },
281
282    /**
283     * @param {!WebInspector.Event} event
284     */
285    _onRequestFinished: function(event)
286    {
287        if (!this._cachedResourcesProcessed)
288            return;
289
290        var request = /** @type {!WebInspector.NetworkRequest} */ (event.data);
291        if (request.failed || request.type === WebInspector.resourceTypes.XHR)
292            return;
293
294        var frame = this._frames[request.frameId];
295        if (frame) {
296            var resource = frame._addRequest(request);
297            this._addPendingConsoleMessagesToResource(resource);
298        }
299    },
300
301    /**
302     * @param {!WebInspector.Event} event
303     */
304    _onRequestUpdateDropped: function(event)
305    {
306        if (!this._cachedResourcesProcessed)
307            return;
308
309        var frameId = event.data.frameId;
310        var frame = this._frames[frameId];
311        if (!frame)
312            return;
313
314        var url = event.data.url;
315        if (frame._resourcesMap[url])
316            return;
317
318        var resource = new WebInspector.Resource(null, url, frame.url, frameId, event.data.loaderId, WebInspector.resourceTypes[event.data.resourceType], event.data.mimeType);
319        frame.addResource(resource);
320    },
321
322    /**
323     * @param {!PageAgent.FrameId} frameId
324     * @return {!WebInspector.ResourceTreeFrame}
325     */
326    frameForId: function(frameId)
327    {
328        return this._frames[frameId];
329    },
330
331    /**
332     * @param {function(!WebInspector.Resource)} callback
333     * @return {boolean}
334     */
335    forAllResources: function(callback)
336    {
337        if (this.mainFrame)
338            return this.mainFrame._callForFrameResources(callback);
339        return false;
340    },
341
342    /**
343     * @return {!Array.<!WebInspector.ResourceTreeFrame>}
344     */
345    frames: function()
346    {
347        return Object.values(this._frames);
348    },
349
350    /**
351     * @param {!WebInspector.Event} event
352     */
353    _consoleMessageAdded: function(event)
354    {
355        var msg = /** @type {!WebInspector.ConsoleMessage} */ (event.data);
356        var resource = msg.url ? this.resourceForURL(msg.url) : null;
357        if (resource)
358            this._addConsoleMessageToResource(msg, resource);
359        else
360            this._addPendingConsoleMessage(msg);
361    },
362
363    /**
364     * @param {!WebInspector.ConsoleMessage} msg
365     */
366    _addPendingConsoleMessage: function(msg)
367    {
368        if (!msg.url)
369            return;
370        if (!this._pendingConsoleMessages[msg.url])
371            this._pendingConsoleMessages[msg.url] = [];
372        this._pendingConsoleMessages[msg.url].push(msg);
373    },
374
375    /**
376     * @param {!WebInspector.Resource} resource
377     */
378    _addPendingConsoleMessagesToResource: function(resource)
379    {
380        var messages = this._pendingConsoleMessages[resource.url];
381        if (messages) {
382            for (var i = 0; i < messages.length; i++)
383                this._addConsoleMessageToResource(messages[i], resource);
384            delete this._pendingConsoleMessages[resource.url];
385        }
386    },
387
388    /**
389     * @param {!WebInspector.ConsoleMessage} msg
390     * @param {!WebInspector.Resource} resource
391     */
392    _addConsoleMessageToResource: function(msg, resource)
393    {
394        switch (msg.level) {
395        case WebInspector.ConsoleMessage.MessageLevel.Warning:
396            resource.warnings++;
397            break;
398        case WebInspector.ConsoleMessage.MessageLevel.Error:
399            resource.errors++;
400            break;
401        }
402        resource.addMessage(msg);
403    },
404
405    _consoleCleared: function()
406    {
407        function callback(resource)
408        {
409            resource.clearErrorsAndWarnings();
410        }
411
412        this._pendingConsoleMessages = {};
413        this.forAllResources(callback);
414    },
415
416    /**
417     * @param {string} url
418     * @return {?WebInspector.Resource}
419     */
420    resourceForURL: function(url)
421    {
422        // Workers call into this with no frames available.
423        return this.mainFrame ? this.mainFrame.resourceForURL(url) : null;
424    },
425
426    /**
427     * @param {?WebInspector.ResourceTreeFrame} parentFrame
428     * @param {!PageAgent.FrameResourceTree} frameTreePayload
429     */
430    _addFramesRecursively: function(parentFrame, frameTreePayload)
431    {
432        var framePayload = frameTreePayload.frame;
433        var frame = new WebInspector.ResourceTreeFrame(this, parentFrame, framePayload.id, framePayload);
434        this._addFrame(frame);
435
436        var frameResource = this._createResourceFromFramePayload(framePayload, framePayload.url, WebInspector.resourceTypes.Document, framePayload.mimeType);
437        if (frame.isMainFrame())
438            this._inspectedPageURL = frameResource.url;
439        frame.addResource(frameResource);
440
441        for (var i = 0; frameTreePayload.childFrames && i < frameTreePayload.childFrames.length; ++i)
442            this._addFramesRecursively(frame, frameTreePayload.childFrames[i]);
443
444        for (var i = 0; i < frameTreePayload.resources.length; ++i) {
445            var subresource = frameTreePayload.resources[i];
446            var resource = this._createResourceFromFramePayload(framePayload, subresource.url, WebInspector.resourceTypes[subresource.type], subresource.mimeType);
447            frame.addResource(resource);
448        }
449    },
450
451    /**
452     * @param {!PageAgent.Frame} frame
453     * @param {string} url
454     * @param {!WebInspector.ResourceType} type
455     * @param {string} mimeType
456     * @return {!WebInspector.Resource}
457     */
458    _createResourceFromFramePayload: function(frame, url, type, mimeType)
459    {
460        return new WebInspector.Resource(null, url, frame.url, frame.id, frame.loaderId, type, mimeType);
461    },
462
463    /**
464     * @param {boolean=} ignoreCache
465     * @param {string=} scriptToEvaluateOnLoad
466     * @param {string=} scriptPreprocessor
467     */
468    reloadPage: function(ignoreCache, scriptToEvaluateOnLoad, scriptPreprocessor)
469    {
470        this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage);
471        this._agent.reload(ignoreCache, scriptToEvaluateOnLoad, scriptPreprocessor);
472    },
473
474    __proto__: WebInspector.TargetAwareObject.prototype
475}
476
477/**
478 * @constructor
479 * @param {!WebInspector.ResourceTreeModel} model
480 * @param {?WebInspector.ResourceTreeFrame} parentFrame
481 * @param {!PageAgent.FrameId} frameId
482 * @param {!PageAgent.Frame=} payload
483 */
484WebInspector.ResourceTreeFrame = function(model, parentFrame, frameId, payload)
485{
486    this._model = model;
487    this._parentFrame = parentFrame;
488    this._id = frameId;
489    this._url = "";
490
491    if (payload) {
492        this._loaderId = payload.loaderId;
493        this._name = payload.name;
494        this._url = payload.url;
495        this._securityOrigin = payload.securityOrigin;
496        this._mimeType = payload.mimeType;
497    }
498
499    /**
500     * @type {!Array.<!WebInspector.ResourceTreeFrame>}
501     */
502    this._childFrames = [];
503
504    /**
505     * @type {!Object.<string, !WebInspector.Resource>}
506     */
507    this._resourcesMap = {};
508
509    if (this._parentFrame)
510        this._parentFrame._childFrames.push(this);
511}
512
513WebInspector.ResourceTreeFrame.prototype = {
514    /**
515     * @return {!WebInspector.Target}
516     */
517    target: function()
518    {
519        return this._model.target();
520    },
521
522    /**
523     * @return {string}
524     */
525    get id()
526    {
527        return this._id;
528    },
529
530    /**
531     * @return {string}
532     */
533    get name()
534    {
535        return this._name || "";
536    },
537
538    /**
539     * @return {string}
540     */
541    get url()
542    {
543        return this._url;
544    },
545
546    /**
547     * @return {string}
548     */
549    get securityOrigin()
550    {
551        return this._securityOrigin;
552    },
553
554    /**
555     * @return {string}
556     */
557    get loaderId()
558    {
559        return this._loaderId;
560    },
561
562    /**
563     * @return {?WebInspector.ResourceTreeFrame}
564     */
565    get parentFrame()
566    {
567        return this._parentFrame;
568    },
569
570    /**
571     * @return {!Array.<!WebInspector.ResourceTreeFrame>}
572     */
573    get childFrames()
574    {
575        return this._childFrames;
576    },
577
578    /**
579     * @return {boolean}
580     */
581    isMainFrame: function()
582    {
583        return !this._parentFrame;
584    },
585
586    /**
587     * @param {!PageAgent.Frame} framePayload
588     */
589    _navigate: function(framePayload)
590    {
591        this._loaderId = framePayload.loaderId;
592        this._name = framePayload.name;
593        this._url = framePayload.url;
594        this._securityOrigin = framePayload.securityOrigin;
595        this._mimeType = framePayload.mimeType;
596
597        var mainResource = this._resourcesMap[this._url];
598        this._resourcesMap = {};
599        this._removeChildFrames();
600        if (mainResource && mainResource.loaderId === this._loaderId)
601            this.addResource(mainResource);
602    },
603
604    /**
605     * @return {!WebInspector.Resource}
606     */
607    get mainResource()
608    {
609        return this._resourcesMap[this._url];
610    },
611
612    /**
613     * @param {!WebInspector.ResourceTreeFrame} frame
614     */
615    _removeChildFrame: function(frame)
616    {
617        this._childFrames.remove(frame);
618        frame._remove();
619    },
620
621    _removeChildFrames: function()
622    {
623        var frames = this._childFrames;
624        this._childFrames = [];
625        for (var i = 0; i < frames.length; ++i)
626            frames[i]._remove();
627    },
628
629    _remove: function()
630    {
631        this._removeChildFrames();
632        delete this._model._frames[this.id];
633        this._model.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this);
634    },
635
636    /**
637     * @param {!WebInspector.Resource} resource
638     */
639    addResource: function(resource)
640    {
641        if (this._resourcesMap[resource.url] === resource) {
642            // Already in the tree, we just got an extra update.
643            return;
644        }
645        this._resourcesMap[resource.url] = resource;
646        this._model.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resource);
647    },
648
649    /**
650     * @param {!WebInspector.NetworkRequest} request
651     * @return {!WebInspector.Resource}
652     */
653    _addRequest: function(request)
654    {
655        var resource = this._resourcesMap[request.url];
656        if (resource && resource.request === request) {
657            // Already in the tree, we just got an extra update.
658            return resource;
659        }
660        resource = new WebInspector.Resource(request, request.url, request.documentURL, request.frameId, request.loaderId, request.type, request.mimeType);
661        this._resourcesMap[resource.url] = resource;
662        this._model.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resource);
663        return resource;
664    },
665
666    /**
667     * @return {!Array.<!WebInspector.Resource>}
668     */
669    resources: function()
670    {
671        var result = [];
672        for (var url in this._resourcesMap)
673            result.push(this._resourcesMap[url]);
674        return result;
675    },
676
677    /**
678     * @param {string} url
679     * @return {?WebInspector.Resource}
680     */
681    resourceForURL: function(url)
682    {
683        var result;
684        function filter(resource)
685        {
686            if (resource.url === url) {
687                result = resource;
688                return true;
689            }
690        }
691        this._callForFrameResources(filter);
692        return result || null;
693    },
694
695    /**
696     * @param {function(!WebInspector.Resource)} callback
697     * @return {boolean}
698     */
699    _callForFrameResources: function(callback)
700    {
701        for (var url in this._resourcesMap) {
702            if (callback(this._resourcesMap[url]))
703                return true;
704        }
705
706        for (var i = 0; i < this._childFrames.length; ++i) {
707            if (this._childFrames[i]._callForFrameResources(callback))
708                return true;
709        }
710        return false;
711    },
712
713    /**
714     * @return {string}
715     */
716    displayName: function()
717    {
718        if (!this._parentFrame)
719            return WebInspector.UIString("<top frame>");
720        var subtitle = new WebInspector.ParsedURL(this._url).displayName;
721        if (subtitle) {
722            if (!this._name)
723                return subtitle;
724            return this._name + "( " + subtitle + " )";
725        }
726        return WebInspector.UIString("<iframe>");
727    }
728}
729
730/**
731 * @constructor
732 * @implements {PageAgent.Dispatcher}
733 */
734WebInspector.PageDispatcher = function(resourceTreeModel)
735{
736    this._resourceTreeModel = resourceTreeModel;
737}
738
739WebInspector.PageDispatcher.prototype = {
740    domContentEventFired: function(time)
741    {
742        this._resourceTreeModel.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, time);
743    },
744
745    loadEventFired: function(time)
746    {
747        this._resourceTreeModel.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.Load, time);
748    },
749
750    frameAttached: function(frameId, parentFrameId)
751    {
752        this._resourceTreeModel._frameAttached(frameId, parentFrameId);
753    },
754
755    frameNavigated: function(frame)
756    {
757        this._resourceTreeModel._frameNavigated(frame);
758    },
759
760    frameDetached: function(frameId)
761    {
762        this._resourceTreeModel._frameDetached(frameId);
763    },
764
765    frameStartedLoading: function(frameId)
766    {
767    },
768
769    frameStoppedLoading: function(frameId)
770    {
771    },
772
773    frameScheduledNavigation: function(frameId, delay)
774    {
775    },
776
777    frameClearedScheduledNavigation: function(frameId)
778    {
779    },
780
781    frameResized: function()
782    {
783        this._resourceTreeModel.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameResized, null);
784    },
785
786    javascriptDialogOpening: function(message)
787    {
788    },
789
790    javascriptDialogClosed: function()
791    {
792    },
793
794    scriptsEnabled: function(isEnabled)
795    {
796        WebInspector.settings.javaScriptDisabled.set(!isEnabled);
797    },
798
799    /**
800     * @param {string} data
801     * @param {!PageAgent.ScreencastFrameMetadata=} metadata
802     */
803    screencastFrame: function(data, metadata)
804    {
805        this._resourceTreeModel.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ScreencastFrame, {data:data, metadata:metadata});
806    },
807
808    /**
809     * @param {boolean} visible
810     */
811    screencastVisibilityChanged: function(visible)
812    {
813        this._resourceTreeModel.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ScreencastVisibilityChanged, {visible:visible});
814    }
815}
816
817/**
818 * @type {!WebInspector.ResourceTreeModel}
819 */
820WebInspector.resourceTreeModel;
821