WebInspector.SourceFile = function(id, script, contentChangedDelegate)
{
this._scripts = [script];
this._contentChangedDelegate = contentChangedDelegate;
if (script.sourceURL)
this._resource = WebInspector.networkManager.inflightResourceForURL(script.sourceURL) || WebInspector.resourceForURL(script.sourceURL);
this._requestContentCallbacks = [];
this.id = id;
this.url = script.sourceURL;
this.isContentScript = script.isContentScript;
this.messages = [];
this.breakpoints = {};
if (this._hasPendingResource())
this._resource.addEventListener("finished", this.reload.bind(this));
}
WebInspector.SourceFile.prototype = {
addScript: function(script)
{
this._scripts.push(script);
},
requestContent: function(callback)
{
if (this._contentLoaded) {
callback(this._mimeType, this._content);
return;
}
this._requestContentCallbacks.push(callback);
this._requestContent();
},
get displayName()
{
return this.url ? WebInspector.displayNameForURL(this.url) : WebInspector.UIString("(program)");
},
get content()
{
return this._content;
},
set content(content)
{
this._content = content;
},
requestSourceMapping: function(callback)
{
if (!this._mapping)
this._mapping = new WebInspector.SourceMapping(this._scripts);
callback(this._mapping);
},
forceLoadContent: function(script)
{
if (!this._hasPendingResource())
return;
if (!this._concatenatedScripts)
this._concatenatedScripts = {};
if (this._concatenatedScripts[script.sourceID])
return;
for (var i = 0; i < this._scripts.length; ++i)
this._concatenatedScripts[this._scripts[i].sourceID] = true;
this.reload();
if (!this._contentRequested) {
this._contentRequested = true;
this._loadAndConcatenateScriptsContent();
}
},
reload: function()
{
if (this._contentLoaded) {
this._contentLoaded = false;
this._contentChangedDelegate();
} else if (this._contentRequested)
this._reloadContent = true;
else if (this._requestContentCallbacks.length)
this._requestContent();
},
_requestContent: function()
{
if (this._contentRequested)
return;
this._contentRequested = true;
if (this._resource && this._resource.finished)
this._loadResourceContent(this._resource);
else if (!this._resource)
this._loadScriptContent();
else if (this._concatenatedScripts)
this._loadAndConcatenateScriptsContent();
else
this._contentRequested = false;
},
_loadResourceContent: function(resource)
{
function didRequestContent(text)
{
if (!text) {
this._loadAndConcatenateScriptsContent();
return;
}
var mimeType = resource.type === WebInspector.Resource.Type.Script ? "text/javascript" : "text/html";
this._didRequestContent(mimeType, text);
}
resource.requestContent(didRequestContent.bind(this));
},
_loadScriptContent: function()
{
this._scripts[0].requestSource(this._didRequestContent.bind(this, "text/javascript"));
},
_loadAndConcatenateScriptsContent: function()
{
var scripts = this._scripts.slice();
scripts.sort(function(x, y) { return x.lineOffset - y.lineOffset || x.columnOffset - y.columnOffset; });
var sources = [];
function didRequestSource(source)
{
sources.push(source);
if (sources.length < scripts.length)
return;
if (scripts.length === 1 && !scripts[0].lineOffset && !scripts[0].columnOffset)
this._didRequestContent("text/javascript", source);
else
this._concatenateScriptsContent(scripts, sources);
}
for (var i = 0; i < scripts.length; ++i)
scripts[i].requestSource(didRequestSource.bind(this));
},
_concatenateScriptsContent: function(scripts, sources)
{
var content = "";
var lineNumber = 0;
var columnNumber = 0;
var scriptRanges = [];
function appendChunk(chunk, script)
{
var start = { lineNumber: lineNumber, columnNumber: columnNumber };
content += chunk;
var lineEndings = chunk.lineEndings();
var lineCount = lineEndings.length;
if (lineCount === 1)
columnNumber += chunk.length;
else {
lineNumber += lineCount - 1;
columnNumber = lineEndings[lineCount - 1] - lineEndings[lineCount - 2] - 1;
}
var end = { lineNumber: lineNumber, columnNumber: columnNumber };
if (script)
scriptRanges.push({ start: start, end: end, sourceID: script.sourceID });
}
var scriptOpenTag = "<script>";
var scriptCloseTag = "</script>";
for (var i = 0; i < scripts.length; ++i) {
while (lineNumber < scripts[i].lineOffset)
appendChunk("\n");
while (columnNumber < scripts[i].columnOffset - scriptOpenTag.length)
appendChunk(" ");
appendChunk(scriptOpenTag);
appendChunk(sources[i], scripts[i]);
appendChunk(scriptCloseTag);
}
this._didRequestContent("text/html", content);
},
_didRequestContent: function(mimeType, content)
{
this._contentLoaded = true;
this._contentRequested = false;
this._mimeType = mimeType;
this._content = content;
for (var i = 0; i < this._requestContentCallbacks.length; ++i)
this._requestContentCallbacks[i](mimeType, content);
this._requestContentCallbacks = [];
if (this._reloadContent)
this.reload();
},
_hasPendingResource: function()
{
return this._resource && !this._resource.finished;
}
}
WebInspector.FormattedSourceFile = function(sourceFileId, script, contentChangedDelegate, formatter)
{
WebInspector.SourceFile.call(this, sourceFileId, script, contentChangedDelegate);
this._formatter = formatter;
}
WebInspector.FormattedSourceFile.prototype = {
requestSourceMapping: function(callback)
{
function didRequestContent()
{
callback(this._mapping);
}
this.requestContent(didRequestContent.bind(this));
},
_didRequestContent: function(mimeType, text)
{
function didFormatContent(formattedText, mapping)
{
this._mapping = new WebInspector.SourceMappingForFormattedSourceFile(this._scripts, mapping);
WebInspector.SourceFile.prototype._didRequestContent.call(this, mimeType, formattedText);
}
this._formatter.formatContent(mimeType, text, didFormatContent.bind(this));
}
}
WebInspector.FormattedSourceFile.prototype.__proto__ = WebInspector.SourceFile.prototype;
WebInspector.SourceMapping = function(scripts)
{
this._sortedScripts = scripts.slice();
this._sortedScripts.sort(function(x, y) { return x.lineOffset - y.lineOffset || x.columnOffset - y.columnOffset; });
}
WebInspector.SourceMapping.prototype = {
scriptLocationToSourceLine: function(location)
{
return location.lineNumber;
},
sourceLineToScriptLocation: function(lineNumber)
{
return this._sourceLocationToScriptLocation(lineNumber, 0);
},
_sourceLocationToScriptLocation: function(lineNumber, columnNumber)
{
var closestScript = this._sortedScripts[0];
for (var i = 1; i < this._sortedScripts.length; ++i) {
script = this._sortedScripts[i];
if (script.lineOffset > lineNumber || (script.lineOffset === lineNumber && script.columnOffset > columnNumber))
break;
closestScript = script;
}
return { sourceID: closestScript.sourceID, lineNumber: lineNumber, columnNumber: columnNumber };
}
}
WebInspector.SourceMappingForFormattedSourceFile = function(scripts, mapping)
{
WebInspector.SourceMapping.call(this, scripts);
this._mapping = mapping;
}
WebInspector.SourceMappingForFormattedSourceFile.prototype = {
scriptLocationToSourceLine: function(location)
{
return this._mapping.originalToFormatted(location).lineNumber;
},
sourceLineToScriptLocation: function(lineNumber)
{
var originalLocation = this._mapping.formattedToOriginal({ lineNumber: lineNumber, columnNumber: 0 });
return WebInspector.SourceMapping.prototype._sourceLocationToScriptLocation.call(this, originalLocation.lineNumber, originalLocation.columnNumber);
}
}
WebInspector.SourceMappingForFormattedSourceFile.prototype.__proto__ = WebInspector.SourceMapping.prototype;