2 * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
26 WebInspector.FrameTreeElement = class FrameTreeElement extends WebInspector.ResourceTreeElement
28 constructor(frame, representedObject)
30 console.assert(frame instanceof WebInspector.Frame);
32 super(frame.mainResource, representedObject || frame);
36 this._updateExpandedSetting();
38 frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
39 frame.addEventListener(WebInspector.Frame.Event.ResourceWasAdded, this._resourceWasAdded, this);
40 frame.addEventListener(WebInspector.Frame.Event.ResourceWasRemoved, this._resourceWasRemoved, this);
41 frame.addEventListener(WebInspector.Frame.Event.ChildFrameWasAdded, this._childFrameWasAdded, this);
42 frame.addEventListener(WebInspector.Frame.Event.ChildFrameWasRemoved, this._childFrameWasRemoved, this);
44 frame.domTree.addEventListener(WebInspector.DOMTree.Event.ContentFlowWasAdded, this._childContentFlowWasAdded, this);
45 frame.domTree.addEventListener(WebInspector.DOMTree.Event.ContentFlowWasRemoved, this._childContentFlowWasRemoved, this);
46 frame.domTree.addEventListener(WebInspector.DOMTree.Event.RootDOMNodeInvalidated, this._rootDOMNodeInvalidated, this);
48 if (this._frame.isMainFrame())
49 this._downloadingPage = false;
51 this.shouldRefreshChildren = true;
52 this.folderSettingsKey = this._frame.url.hash;
54 this.registerFolderizeSettings("frames", WebInspector.UIString("Frames"),
55 function(representedObject) { return representedObject instanceof WebInspector.Frame; },
56 function() { return this.frame.childFrames.length; }.bind(this),
57 WebInspector.FrameTreeElement
60 this.registerFolderizeSettings("flows", WebInspector.UIString("Flows"),
61 function(representedObject) { return representedObject instanceof WebInspector.ContentFlow; },
62 function() { return this.frame.domTree.flowsCount; }.bind(this),
63 WebInspector.ContentFlowTreeElement
66 this.registerFolderizeSettings("canvases", WebInspector.UIString("Canvases"),
67 function(representedObject) { return representedObject instanceof WebInspector.Canvas; },
68 function() { return WebInspector.canvasManager.canvasesForFrame(this._frame).length; }.bind(this),
69 WebInspector.CanvasTreeElement
72 function makeValidateCallback(resourceType) {
73 return function(representedObject) {
74 return representedObject instanceof WebInspector.Resource && representedObject.type === resourceType;
78 function makeChildCountCallback(frame, resourceType) {
80 return frame.resourcesWithType(resourceType).length;
84 for (var key in WebInspector.Resource.Type) {
85 var value = WebInspector.Resource.Type[key];
86 var folderName = WebInspector.Resource.displayNameForType(value, true);
87 this.registerFolderizeSettings(key, folderName,
88 makeValidateCallback(value),
89 makeChildCountCallback(this.frame, value),
90 WebInspector.ResourceTreeElement
94 this.updateParentStatus();
104 descendantResourceTreeElementTypeDidChange(resourceTreeElement, oldType)
106 // Called by descendant ResourceTreeElements.
108 // Add the tree element again, which will move it to the new location
109 // based on sorting and possible folder changes.
110 this._addTreeElement(resourceTreeElement);
113 descendantResourceTreeElementMainTitleDidChange(resourceTreeElement, oldMainTitle)
115 // Called by descendant ResourceTreeElements.
117 // Add the tree element again, which will move it to the new location
118 // based on sorting and possible folder changes.
119 this._addTreeElement(resourceTreeElement);
122 // Overrides from SourceCodeTreeElement.
124 updateSourceMapResources()
126 // Frames handle their own SourceMapResources.
128 if (!this.treeOutline || !this.treeOutline.includeSourceMapResourceChildren)
134 this.updateParentStatus();
136 if (this.resource && this.resource.sourceMaps.length)
137 this.shouldRefreshChildren = true;
142 // Immediate superclasses are skipped, since Frames handle their own SourceMapResources.
143 WebInspector.GeneralTreeElement.prototype.onattach.call(this);
145 WebInspector.canvasManager.addEventListener(WebInspector.CanvasManager.Event.CanvasesAvailable, this._canvasesAvailable, this);
146 WebInspector.canvasManager.addEventListener(WebInspector.CanvasManager.Event.CanvasWasAdded, this._canvasWasAdded, this);
147 WebInspector.canvasManager.addEventListener(WebInspector.CanvasManager.Event.CanvasWasRemoved, this._canvasWasRemoved, this);
149 if (this._frame.isMainFrame()) {
150 WebInspector.notifications.addEventListener(WebInspector.Notification.PageArchiveStarted, this._pageArchiveStarted, this);
151 WebInspector.notifications.addEventListener(WebInspector.Notification.PageArchiveEnded, this._pageArchiveEnded, this);
157 WebInspector.ResourceTreeElement.prototype.ondetach.call(this);
159 WebInspector.canvasManager.removeEventListener(WebInspector.CanvasManager.Event.CanvasesAvailable, this._canvasesAvailable, this);
160 WebInspector.canvasManager.removeEventListener(WebInspector.CanvasManager.Event.CanvasWasAdded, this._canvasWasAdded, this);
161 WebInspector.canvasManager.removeEventListener(WebInspector.CanvasManager.Event.CanvasWasRemoved, this._canvasWasRemoved, this);
163 if (this._frame.isMainFrame()) {
164 WebInspector.notifications.removeEventListener(WebInspector.Notification.PageArchiveStarted, this._pageArchiveStarted, this);
165 WebInspector.notifications.removeEventListener(WebInspector.Notification.PageArchiveEnded, this._pageArchiveEnded, this);
169 // Overrides from FolderizedTreeElement (Protected).
171 compareChildTreeElements(a, b)
176 var aIsResource = a instanceof WebInspector.ResourceTreeElement;
177 var bIsResource = b instanceof WebInspector.ResourceTreeElement;
179 if (aIsResource && bIsResource)
180 return WebInspector.ResourceTreeElement.compareResourceTreeElements(a, b);
182 if (!aIsResource && !bIsResource) {
183 // When both components are not resources then default to base class comparison.
184 return super.compareChildTreeElements(a, b);
187 // Non-resources should appear before the resources.
188 // FIXME: There should be a better way to group the elements by their type.
189 return aIsResource ? 1 : -1;
192 // Called from ResourceTreeElement.
194 updateStatusForMainFrame()
196 function loadedImages()
198 if (!this._reloadButton || !this._downloadButton)
201 var fragment = document.createDocumentFragment("div");
202 fragment.appendChild(this._downloadButton.element);
203 fragment.appendChild(this._reloadButton.element);
204 this.status = fragment;
206 delete this._loadingMainFrameButtons;
209 if (this._reloadButton && this._downloadButton) {
210 loadedImages.call(this);
214 if (!this._loadingMainFrameButtons) {
215 this._loadingMainFrameButtons = true;
218 if (WebInspector.debuggableType === WebInspector.DebuggableType.JavaScript)
219 tooltip = WebInspector.UIString("Restart (%s)").format(WebInspector._reloadPageKeyboardShortcut.displayName);
221 tooltip = WebInspector.UIString("Reload page (%s)\nReload ignoring cache (%s)").format(WebInspector._reloadPageKeyboardShortcut.displayName, WebInspector._reloadPageIgnoringCacheKeyboardShortcut.displayName);
223 wrappedSVGDocument(platformImagePath("Reload.svg"), null, tooltip, function(element) {
224 this._reloadButton = new WebInspector.TreeElementStatusButton(element);
225 this._reloadButton.addEventListener(WebInspector.TreeElementStatusButton.Event.Clicked, this._reloadPageClicked, this);
226 loadedImages.call(this);
229 wrappedSVGDocument(platformImagePath("DownloadArrow.svg"), null, WebInspector.UIString("Download Web Archive"), function(element) {
230 this._downloadButton = new WebInspector.TreeElementStatusButton(element);
231 this._downloadButton.addEventListener(WebInspector.TreeElementStatusButton.Event.Clicked, this._downloadButtonClicked, this);
232 this._updateDownloadButton();
233 loadedImages.call(this);
238 // Overrides from TreeElement (Private).
242 if (this.children.length && !this.shouldRefreshChildren)
244 this.shouldRefreshChildren = false;
246 this.removeChildren();
247 this.updateParentStatus();
248 this.prepareToPopulate();
250 for (var i = 0; i < this._frame.childFrames.length; ++i)
251 this.addChildForRepresentedObject(this._frame.childFrames[i]);
253 for (var i = 0; i < this._frame.resources.length; ++i)
254 this.addChildForRepresentedObject(this._frame.resources[i]);
256 var sourceMaps = this.resource && this.resource.sourceMaps;
257 for (var i = 0; i < sourceMaps.length; ++i) {
258 var sourceMap = sourceMaps[i];
259 for (var j = 0; j < sourceMap.resources.length; ++j)
260 this.addChildForRepresentedObject(sourceMap.resources[j]);
263 var flowMap = this._frame.domTree.flowMap;
264 for (var flowKey in flowMap)
265 this.addChildForRepresentedObject(flowMap[flowKey]);
267 var canvases = WebInspector.canvasManager.canvasesForFrame(this._frame);
268 for (var canvas of canvases)
269 this.addChildForRepresentedObject(canvas);
274 this._expandedSetting.value = true;
275 this._frame.domTree.requestContentFlowList();
280 // Only store the setting if we have children, since setting hasChildren to false will cause a collapse,
281 // and we only care about user triggered collapses.
282 if (this.hasChildren)
283 this._expandedSetting.value = false;
288 _updateExpandedSetting()
290 this._expandedSetting = new WebInspector.Setting("frame-expanded-" + this._frame.url.hash, this._frame.isMainFrame() ? true : false);
291 if (this._expandedSetting.value)
297 _mainResourceDidChange(event)
299 this._updateResource(this._frame.mainResource);
301 this.updateParentStatus();
302 this.removeChildren();
304 // Change the expanded setting since the frame URL has changed. Do this before setting shouldRefreshChildren, since
305 // shouldRefreshChildren will call onpopulate if expanded is true.
306 this._updateExpandedSetting();
308 if (this._frame.isMainFrame())
309 this._updateDownloadButton();
311 this.shouldRefreshChildren = true;
314 _resourceWasAdded(event)
316 this.addRepresentedObjectToNewChildQueue(event.data.resource);
319 _resourceWasRemoved(event)
321 this.removeChildForRepresentedObject(event.data.resource);
324 _childFrameWasAdded(event)
326 this.addRepresentedObjectToNewChildQueue(event.data.childFrame);
329 _childFrameWasRemoved(event)
331 this.removeChildForRepresentedObject(event.data.childFrame);
334 _childContentFlowWasAdded(event)
336 this.addRepresentedObjectToNewChildQueue(event.data.flow);
339 _childContentFlowWasRemoved(event)
341 this.removeChildForRepresentedObject(event.data.flow);
344 _canvasesAvailable(event)
346 this.updateParentStatus();
347 this.removeChildren();
349 this.shouldRefreshChildren = true;
352 _canvasWasAdded(event)
354 var canvas = event.data.canvas;
355 if (canvas.parentFrame == this._frame)
356 this.addRepresentedObjectToNewChildQueue(canvas);
359 _canvasWasRemoved(event)
361 var canvas = event.data.canvas;
362 if (canvas.parentFrame == this._frame)
363 this.removeChildForRepresentedObject(canvas);
366 _rootDOMNodeInvalidated()
369 this._frame.domTree.requestContentFlowList();
372 _reloadPageClicked(event)
374 // Ignore cache when the shift key is pressed.
375 PageAgent.reload(event.data.shiftKey);
378 _downloadButtonClicked(event)
380 WebInspector.archiveMainFrame();
383 _updateDownloadButton()
385 console.assert(this._frame.isMainFrame());
386 if (!this._downloadButton)
389 if (!PageAgent.archive || WebInspector.debuggableType !== WebInspector.DebuggableType.Web) {
390 this._downloadButton.hidden = true;
394 if (this._downloadingPage) {
395 this._downloadButton.enabled = false;
399 this._downloadButton.enabled = WebInspector.canArchiveMainFrame();
402 _pageArchiveStarted(event)
404 this._downloadingPage = true;
405 this._updateDownloadButton();
408 _pageArchiveEnded(event)
410 this._downloadingPage = false;
411 this._updateDownloadButton();