atom-nuclide
Version:
A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.
499 lines (446 loc) • 16.9 kB
JavaScript
/*
* Copyright (C) 2012 Google 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* OWNER OR 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.
*/
/**
* @constructor
* @extends {WebInspector.ContentProviderBasedProjectDelegate}
* @param {!WebInspector.Target} target
* @param {!WebInspector.Workspace} workspace
* @param {string} projectId
* @param {string} projectURL
* @param {!WebInspector.projectTypes} projectType
*/
WebInspector.NetworkProjectDelegate = function(target, workspace, projectId, projectURL, projectType)
{
this._url = projectURL;
this._target = target;
this._id = projectId;
WebInspector.ContentProviderBasedProjectDelegate.call(this, workspace, projectId, projectType);
}
WebInspector.NetworkProjectDelegate.prototype = {
/**
* @return {!WebInspector.Target}
*/
target: function()
{
return this._target;
},
/**
* @return {string}
*/
id: function()
{
return this._id;
},
/**
* @override
* @return {string}
*/
displayName: function()
{
if (typeof this._displayName !== "undefined")
return this._displayName;
var targetSuffix = this._target.isPage() ? "" : " \u2014 " + this._target.name();
if (!this._url) {
this._displayName = WebInspector.UIString("(no domain)") + targetSuffix;
return this._displayName;
}
var parsedURL = new WebInspector.ParsedURL(this._url);
var prettyURL = parsedURL.isValid ? parsedURL.host + (parsedURL.port ? (":" + parsedURL.port) : "") : "";
this._displayName = (prettyURL || this._url) + targetSuffix;
return this._displayName;
},
/**
* @override
* @return {string}
*/
url: function()
{
return this._url;
},
/**
* @param {string} parentPath
* @param {string} name
* @param {string} url
* @param {!WebInspector.ContentProvider} contentProvider
* @return {string}
*/
addFile: function(parentPath, name, url, contentProvider)
{
return this.addContentProvider(parentPath, name, url, url, contentProvider);
},
__proto__: WebInspector.ContentProviderBasedProjectDelegate.prototype
}
/**
* @constructor
* @param {!WebInspector.TargetManager} targetManager
* @param {!WebInspector.Workspace} workspace
* @param {!WebInspector.NetworkMapping} networkMapping
* @implements {WebInspector.TargetManager.Observer}
*/
WebInspector.NetworkProjectManager = function(targetManager, workspace, networkMapping)
{
this._workspace = workspace;
this._networkMapping = networkMapping;
this._projectSymbol = Symbol("networkProject");
targetManager.observeTargets(this);
}
WebInspector.NetworkProjectManager.prototype = {
/**
* @override
* @param {!WebInspector.Target} target
*/
targetAdded: function(target)
{
new WebInspector.NetworkProject(target, this._workspace, this._networkMapping);
},
/**
* @override
* @param {!WebInspector.Target} target
*/
targetRemoved: function(target)
{
WebInspector.NetworkProject.forTarget(target)._dispose();
}
}
/**
* @constructor
* @extends {WebInspector.SDKObject}
* @param {!WebInspector.Target} target
* @param {!WebInspector.Workspace} workspace
* @param {!WebInspector.NetworkMapping} networkMapping
*/
WebInspector.NetworkProject = function(target, workspace, networkMapping)
{
WebInspector.SDKObject.call(this, target);
this._workspace = workspace;
this._networkMapping = networkMapping;
this._projectDelegates = {};
this._processedURLs = {};
target[WebInspector.NetworkProject._networkProjectSymbol] = this;
target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, this._resourceAdded, this);
target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this);
target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this);
target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, this._parsedScriptSource, this);
target.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
target.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
}
WebInspector.NetworkProject._networkProjectSymbol = Symbol("networkProject");
WebInspector.NetworkProject._targetSymbol = Symbol("target");
WebInspector.NetworkProject._contentTypeSymbol = Symbol("networkContentType");
/**
* @param {!WebInspector.Target} target
* @param {string} projectURL
* @param {boolean} isContentScripts
* @return {string}
*/
WebInspector.NetworkProject.projectId = function(target, projectURL, isContentScripts)
{
return target.id() + ":" + (isContentScripts ? "contentscripts:" : "") + projectURL;
}
/**
* @param {!WebInspector.Target} target
* @return {!WebInspector.NetworkProject}
*/
WebInspector.NetworkProject.forTarget = function(target)
{
return target[WebInspector.NetworkProject._networkProjectSymbol];
}
/**
* @param {!WebInspector.UISourceCode} uiSourceCode
* @return {?WebInspector.Target} target
*/
WebInspector.NetworkProject.targetForUISourceCode = function(uiSourceCode)
{
return uiSourceCode[WebInspector.NetworkProject._targetSymbol];
}
/**
* @param {!WebInspector.UISourceCode} uiSourceCode
* @return {(!WebInspector.ResourceType|undefined)}
*/
WebInspector.NetworkProject.uiSourceCodeContentType = function(uiSourceCode)
{
return uiSourceCode[WebInspector.NetworkProject._contentTypeSymbol];
}
WebInspector.NetworkProject.prototype = {
/**
* @param {string} projectURL
* @param {boolean} isContentScripts
* @return {!WebInspector.NetworkProjectDelegate}
*/
_projectDelegate: function(projectURL, isContentScripts)
{
var projectId = WebInspector.NetworkProject.projectId(this.target(), projectURL, isContentScripts);
var projectType = isContentScripts ? WebInspector.projectTypes.ContentScripts : WebInspector.projectTypes.Network;
if (this._projectDelegates[projectId])
return this._projectDelegates[projectId];
var projectDelegate = new WebInspector.NetworkProjectDelegate(this.target(), this._workspace, projectId, projectURL, projectType);
this._projectDelegates[projectId] = projectDelegate;
return projectDelegate;
},
/**
* @param {string} url
* @param {!WebInspector.ContentProvider} contentProvider
* @param {boolean=} isContentScript
* @return {!WebInspector.UISourceCode}
*/
addFileForURL: function(url, contentProvider, isContentScript)
{
var splitURL = WebInspector.ParsedURL.splitURLIntoPathComponents(url);
var projectURL = splitURL[0];
var parentPath = splitURL.slice(1, -1).join("/");
var name = splitURL.peekLast() || "";
var projectDelegate = this._projectDelegate(projectURL, isContentScript || false);
var path = projectDelegate.addFile(parentPath, name, url, contentProvider);
var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (this._workspace.uiSourceCode(projectDelegate.id(), path));
uiSourceCode[WebInspector.NetworkProject._targetSymbol] = this.target();
console.assert(uiSourceCode);
return uiSourceCode;
},
/**
* @param {string} url
*/
_removeFileForURL: function(url)
{
var splitURL = WebInspector.ParsedURL.splitURLIntoPathComponents(url);
var projectURL = splitURL[0];
var path = splitURL.slice(1).join("/");
var projectDelegate = this._projectDelegates[WebInspector.NetworkProject.projectId(this.target(), projectURL, false)];
projectDelegate.removeFile(path);
},
_populate: function()
{
/**
* @param {!WebInspector.ResourceTreeFrame} frame
* @this {WebInspector.NetworkProject}
*/
function populateFrame(frame)
{
for (var i = 0; i < frame.childFrames.length; ++i)
populateFrame.call(this, frame.childFrames[i]);
var resources = frame.resources();
for (var i = 0; i < resources.length; ++i)
this._addFile(resources[i].url, new WebInspector.NetworkProject.FallbackResource(resources[i]));
}
var mainFrame = this.target().resourceTreeModel.mainFrame;
if (mainFrame)
populateFrame.call(this, mainFrame);
},
/**
* @param {!WebInspector.Event} event
*/
_parsedScriptSource: function(event)
{
var script = /** @type {!WebInspector.Script} */ (event.data);
if (!script.sourceURL || (script.isInlineScript() && !script.hasSourceURL))
return;
// Filter out embedder injected content scripts.
if (script.isContentScript() && !script.hasSourceURL) {
var parsedURL = new WebInspector.ParsedURL(script.sourceURL);
if (!parsedURL.isValid)
return;
}
this._addFile(script.sourceURL, script, script.isContentScript());
},
/**
* @param {!WebInspector.Event} event
*/
_styleSheetAdded: function(event)
{
var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
if (header.isInline && header.origin !== "inspector")
return;
this._addFile(header.resourceURL(), header, false);
},
/**
* @param {!WebInspector.Event} event
*/
_styleSheetRemoved: function(event)
{
var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
if (header.isInline && header.origin !== "inspector")
return;
this._removeFile(header.resourceURL());
},
/**
* @param {!WebInspector.Event} event
*/
_resourceAdded: function(event)
{
var resource = /** @type {!WebInspector.Resource} */ (event.data);
this._addFile(resource.url, new WebInspector.NetworkProject.FallbackResource(resource));
},
/**
* @param {!WebInspector.Event} event
*/
_mainFrameNavigated: function(event)
{
this._reset();
this._populate();
},
/**
* @param {string} url
* @param {!WebInspector.ContentProvider} contentProvider
* @param {boolean=} isContentScript
*/
_addFile: function(url, contentProvider, isContentScript)
{
if (this._networkMapping.hasMappingForURL(url))
return;
var type = contentProvider.contentType();
if (type !== WebInspector.resourceTypes.Stylesheet && type !== WebInspector.resourceTypes.Document && type !== WebInspector.resourceTypes.Script)
return;
if (this._processedURLs[url])
return;
this._processedURLs[url] = true;
var uiSourceCode = this.addFileForURL(url, contentProvider, isContentScript);
uiSourceCode[WebInspector.NetworkProject._contentTypeSymbol] = type;
},
/**
* @param {string} url
*/
_removeFile: function(url)
{
if (!this._processedURLs[url])
return;
delete this._processedURLs[url];
this._removeFileForURL(url);
},
_dispose: function()
{
this._reset();
var target = this.target();
target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, this._resourceAdded, this);
target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this);
target.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this);
target.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, this._parsedScriptSource, this);
target.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
target.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
},
_reset: function()
{
this._processedURLs = {};
for (var projectId in this._projectDelegates)
this._projectDelegates[projectId].reset();
this._projectDelegates = {};
},
__proto__: WebInspector.SDKObject.prototype
}
/**
* @constructor
* @implements {WebInspector.ContentProvider}
* @param {!WebInspector.Resource} resource
*/
WebInspector.NetworkProject.FallbackResource = function(resource)
{
this._resource = resource;
}
WebInspector.NetworkProject.FallbackResource.prototype = {
/**
* @override
* @return {string}
*/
contentURL: function()
{
return this._resource.contentURL();
},
/**
* @override
* @return {!WebInspector.ResourceType}
*/
contentType: function()
{
return this._resource.resourceType();
},
/**
* @override
* @param {function(?string)} callback
*/
requestContent: function(callback)
{
/**
* @this {WebInspector.NetworkProject.FallbackResource}
*/
function loadFallbackContent()
{
var scripts = this._resource.target().debuggerModel.scriptsForSourceURL(this._resource.url);
if (!scripts.length) {
callback(null);
return;
}
var contentProvider;
var type = this._resource.resourceType();
if (type === WebInspector.resourceTypes.Document)
contentProvider = new WebInspector.ConcatenatedScriptsContentProvider(scripts);
else if (type === WebInspector.resourceTypes.Script)
contentProvider = scripts[0];
console.assert(contentProvider, "Resource content request failed. " + this._resource.url);
contentProvider.requestContent(callback);
}
/**
* @param {?string} content
* @this {WebInspector.NetworkProject.FallbackResource}
*/
function requestContentLoaded(content)
{
if (content)
callback(content)
else
loadFallbackContent.call(this);
}
this._resource.requestContent(requestContentLoaded.bind(this));
},
/**
* @override
* @param {string} query
* @param {boolean} caseSensitive
* @param {boolean} isRegex
* @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
*/
searchInContent: function(query, caseSensitive, isRegex, callback)
{
/**
* @param {?string} content
*/
function documentContentLoaded(content)
{
if (content === null) {
callback([]);
return;
}
var result = WebInspector.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex);
callback(result);
}
if (this.contentType() === WebInspector.resourceTypes.Document) {
this.requestContent(documentContentLoaded);
return;
}
this._resource.searchInContent(query, caseSensitive, isRegex, callback);
}
}