blob: dbc085225a33a11444286adfb04999ece6ce77ec [file] [log] [blame]
/*
* Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
WebInspector.ResourceSidebarPanel = class ResourceSidebarPanel extends WebInspector.NavigationSidebarPanel
{
constructor(contentBrowser)
{
super("resource", WebInspector.UIString("Resources"), true);
this.contentBrowser = contentBrowser;
this.filterBar.placeholder = WebInspector.UIString("Filter Resource List");
this._navigationBar = new WebInspector.NavigationBar;
this.element.appendChild(this._navigationBar.element);
var scopeItemPrefix = "resource-sidebar-";
var scopeBarItems = [];
scopeBarItems.push(new WebInspector.ScopeBarItem(scopeItemPrefix + "type-all", WebInspector.UIString("All Resources"), true));
for (var key in WebInspector.Resource.Type) {
var value = WebInspector.Resource.Type[key];
var scopeBarItem = new WebInspector.ScopeBarItem(scopeItemPrefix + value, WebInspector.Resource.displayNameForType(value, true));
scopeBarItem.__resourceType = value;
scopeBarItems.push(scopeBarItem);
}
this._scopeBar = new WebInspector.ScopeBar("resource-sidebar-scope-bar", scopeBarItems, scopeBarItems[0], true);
this._scopeBar.addEventListener(WebInspector.ScopeBar.Event.SelectionChanged, this._scopeBarSelectionDidChange, this);
this._navigationBar.addNavigationItem(this._scopeBar);
WebInspector.Frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
WebInspector.frameResourceManager.addEventListener(WebInspector.FrameResourceManager.Event.MainFrameDidChange, this._mainFrameDidChange, this);
WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, this._scriptWasAdded, this);
WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptsCleared, this._scriptsCleared, this);
WebInspector.notifications.addEventListener(WebInspector.Notification.ExtraDomainsActivated, this._extraDomainsActivated, this);
this.contentTreeOutline.onselect = this._treeElementSelected.bind(this);
this.contentTreeOutline.includeSourceMapResourceChildren = true;
if (WebInspector.debuggableType === WebInspector.DebuggableType.JavaScript)
this.contentTreeOutline.element.classList.add(WebInspector.NavigationSidebarPanel.HideDisclosureButtonsStyleClassName);
if (WebInspector.frameResourceManager.mainFrame)
this._mainFrameMainResourceDidChange(WebInspector.frameResourceManager.mainFrame);
}
// Public
closed()
{
super.closed();
WebInspector.Frame.removeEventListener(null, null, this);
WebInspector.frameResourceManager.removeEventListener(null, null, this);
WebInspector.debuggerManager.removeEventListener(null, null, this);
WebInspector.notifications.removeEventListener(null, null, this);
}
showDefaultContentView()
{
if (WebInspector.frameResourceManager.mainFrame) {
this.contentBrowser.showContentViewForRepresentedObject(WebInspector.frameResourceManager.mainFrame);
return;
}
var firstTreeElement = this.contentTreeOutline.children[0];
if (firstTreeElement)
this.showDefaultContentViewForTreeElement(firstTreeElement);
}
treeElementForRepresentedObject(representedObject)
{
// A custom implementation is needed for this since the frames are populated lazily.
if (!this._mainFrameTreeElement && (representedObject instanceof WebInspector.Resource || representedObject instanceof WebInspector.Frame)) {
// All resources are under the main frame, so we need to return early if we don't have the main frame yet.
return null;
}
// The Frame is used as the representedObject instead of the main resource in our tree.
if (representedObject instanceof WebInspector.Resource && representedObject.parentFrame && representedObject.parentFrame.mainResource === representedObject)
representedObject = representedObject.parentFrame;
function isAncestor(ancestor, resourceOrFrame)
{
// SourceMapResources are descendants of another SourceCode object.
if (resourceOrFrame instanceof WebInspector.SourceMapResource) {
if (resourceOrFrame.sourceMap.originalSourceCode === ancestor)
return true;
// Not a direct ancestor, so check the ancestors of the parent SourceCode object.
resourceOrFrame = resourceOrFrame.sourceMap.originalSourceCode;
}
var currentFrame = resourceOrFrame.parentFrame;
while (currentFrame) {
if (currentFrame === ancestor)
return true;
currentFrame = currentFrame.parentFrame;
}
return false;
}
function getParent(resourceOrFrame)
{
// SourceMapResources are descendants of another SourceCode object.
if (resourceOrFrame instanceof WebInspector.SourceMapResource)
return resourceOrFrame.sourceMap.originalSourceCode;
return resourceOrFrame.parentFrame;
}
var treeElement = this.contentTreeOutline.findTreeElement(representedObject, isAncestor, getParent);
if (treeElement)
return treeElement;
// Only special case Script objects.
if (!(representedObject instanceof WebInspector.Script)) {
console.error("Didn't find a TreeElement for representedObject", representedObject);
return null;
}
// If the Script has a URL we should have found it earlier.
if (representedObject.url) {
console.error("Didn't find a ScriptTreeElement for a Script with a URL.");
return null;
}
// Since the Script does not have a URL we consider it an 'anonymous' script. These scripts happen from calls to
// window.eval() or browser features like Auto Fill and Reader. They are not normally added to the sidebar, but since
// we have a ScriptContentView asking for the tree element we will make a ScriptTreeElement on demand and add it.
if (!this._anonymousScriptsFolderTreeElement)
this._anonymousScriptsFolderTreeElement = new WebInspector.FolderTreeElement(WebInspector.UIString("Anonymous Scripts"));
if (!this._anonymousScriptsFolderTreeElement.parent) {
var index = insertionIndexForObjectInListSortedByFunction(this._anonymousScriptsFolderTreeElement, this.contentTreeOutline.children, this._compareTreeElements);
this.contentTreeOutline.insertChild(this._anonymousScriptsFolderTreeElement, index);
}
var scriptTreeElement = new WebInspector.ScriptTreeElement(representedObject);
this._anonymousScriptsFolderTreeElement.appendChild(scriptTreeElement);
return scriptTreeElement;
}
// Protected
hasCustomFilters()
{
console.assert(this._scopeBar.selectedItems.length === 1);
var selectedScopeBarItem = this._scopeBar.selectedItems[0];
return selectedScopeBarItem && !selectedScopeBarItem.exclusive;
}
matchTreeElementAgainstCustomFilters(treeElement, flags)
{
console.assert(this._scopeBar.selectedItems.length === 1);
var selectedScopeBarItem = this._scopeBar.selectedItems[0];
// Show everything if there is no selection or "All Resources" is selected (the exclusive item).
if (!selectedScopeBarItem || selectedScopeBarItem.exclusive)
return true;
// Folders are hidden on the first pass, but visible childen under the folder will force the folder visible again.
if (treeElement instanceof WebInspector.FolderTreeElement)
return false;
function match()
{
if (treeElement instanceof WebInspector.FrameTreeElement)
return selectedScopeBarItem.__resourceType === WebInspector.Resource.Type.Document;
if (treeElement instanceof WebInspector.ScriptTreeElement)
return selectedScopeBarItem.__resourceType === WebInspector.Resource.Type.Script;
console.assert(treeElement instanceof WebInspector.ResourceTreeElement, "Unknown treeElement", treeElement);
if (!(treeElement instanceof WebInspector.ResourceTreeElement))
return false;
return treeElement.resource.type === selectedScopeBarItem.__resourceType;
}
var matched = match();
if (matched)
flags.expandTreeElement = true;
return matched;
}
// Private
_mainResourceDidChange(event)
{
if (!event.target.isMainFrame())
return;
this._mainFrameMainResourceDidChange(event.target);
}
_mainFrameDidChange(event)
{
this._mainFrameMainResourceDidChange(WebInspector.frameResourceManager.mainFrame);
}
_mainFrameMainResourceDidChange(mainFrame)
{
this.contentBrowser.contentViewContainer.closeAllContentViews();
if (this._mainFrameTreeElement) {
this.contentTreeOutline.removeChild(this._mainFrameTreeElement);
this._mainFrameTreeElement = null;
}
if (!mainFrame)
return;
this._mainFrameTreeElement = new WebInspector.FrameTreeElement(mainFrame);
this.contentTreeOutline.insertChild(this._mainFrameTreeElement, 0);
function delayedWork()
{
if (!this.contentTreeOutline.selectedTreeElement) {
var currentContentView = this.contentBrowser.currentContentView;
var treeElement = currentContentView ? this.treeElementForRepresentedObject(currentContentView.representedObject) : null;
if (!treeElement)
treeElement = this._mainFrameTreeElement;
this.showDefaultContentViewForTreeElement(treeElement);
}
}
// Cookie restoration will attempt to re-select the resource we were showing.
// Give it time to do that before selecting the main frame resource.
setTimeout(delayedWork.bind(this));
}
_scriptWasAdded(event)
{
var script = event.data.script;
// We don't add scripts without URLs here. Those scripts can quickly clutter the interface and
// are usually more transient. They will get added if/when they need to be shown in a content view.
if (!script.url)
return;
// Exclude inspector scripts.
if (script.url.startsWith("__WebInspector"))
return;
// If the script URL matches a resource we can assume it is part of that resource and does not need added.
if (script.resource)
return;
var insertIntoTopLevel = false;
if (script.injected) {
if (!this._extensionScriptsFolderTreeElement)
this._extensionScriptsFolderTreeElement = new WebInspector.FolderTreeElement(WebInspector.UIString("Extension Scripts"));
var parentFolderTreeElement = this._extensionScriptsFolderTreeElement;
} else {
if (WebInspector.debuggableType === WebInspector.DebuggableType.JavaScript && !WebInspector.hasExtraDomains)
insertIntoTopLevel = true;
else {
if (!this._extraScriptsFolderTreeElement)
this._extraScriptsFolderTreeElement = new WebInspector.FolderTreeElement(WebInspector.UIString("Extra Scripts"));
var parentFolderTreeElement = this._extraScriptsFolderTreeElement;
}
}
var scriptTreeElement = new WebInspector.ScriptTreeElement(script);
if (insertIntoTopLevel) {
var index = insertionIndexForObjectInListSortedByFunction(scriptTreeElement, this.contentTreeOutline.children, this._compareTreeElements);
this.contentTreeOutline.insertChild(scriptTreeElement, index);
} else {
if (!parentFolderTreeElement.parent) {
var index = insertionIndexForObjectInListSortedByFunction(parentFolderTreeElement, this.contentTreeOutline.children, this._compareTreeElements);
this.contentTreeOutline.insertChild(parentFolderTreeElement, index);
}
parentFolderTreeElement.appendChild(scriptTreeElement);
}
}
_scriptsCleared(event)
{
if (this._extensionScriptsFolderTreeElement) {
if (this._extensionScriptsFolderTreeElement.parent)
this._extensionScriptsFolderTreeElement.parent.removeChild(this._extensionScriptsFolderTreeElement);
this._extensionScriptsFolderTreeElement = null;
}
if (this._extraScriptsFolderTreeElement) {
if (this._extraScriptsFolderTreeElement.parent)
this._extraScriptsFolderTreeElement.parent.removeChild(this._extraScriptsFolderTreeElement);
this._extraScriptsFolderTreeElement = null;
}
if (this._anonymousScriptsFolderTreeElement) {
if (this._anonymousScriptsFolderTreeElement.parent)
this._anonymousScriptsFolderTreeElement.parent.removeChild(this._anonymousScriptsFolderTreeElement);
this._anonymousScriptsFolderTreeElement = null;
}
}
_treeElementSelected(treeElement, selectedByUser)
{
if (treeElement instanceof WebInspector.FolderTreeElement)
return;
if (treeElement instanceof WebInspector.ResourceTreeElement || treeElement instanceof WebInspector.ScriptTreeElement) {
WebInspector.showRepresentedObject(treeElement.representedObject);
return;
}
console.error("Unknown tree element", treeElement);
}
_compareTreeElements(a, b)
{
// Always sort the main frame element first.
if (a instanceof WebInspector.FrameTreeElement)
return -1;
if (b instanceof WebInspector.FrameTreeElement)
return 1;
console.assert(a.mainTitle);
console.assert(b.mainTitle);
return (a.mainTitle || "").localeCompare(b.mainTitle || "");
}
_extraDomainsActivated()
{
if (WebInspector.debuggableType === WebInspector.DebuggableType.JavaScript)
this.contentTreeOutline.element.classList.remove(WebInspector.NavigationSidebarPanel.HideDisclosureButtonsStyleClassName);
}
_scopeBarSelectionDidChange(event)
{
this.updateFilter();
}
};