monaca-lib
Version:
Monaca cloud API bindings for JavaScript
448 lines (402 loc) • 16.9 kB
JavaScript
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @constructor
* @implements {WebInspector.DebuggerSourceMapping}
* @param {!WebInspector.Target} target
* @param {!WebInspector.ScriptFormatterEditorAction} editorAction
*/
WebInspector.FormatterScriptMapping = function(target, editorAction)
{
this._target = target;
this._editorAction = editorAction;
}
WebInspector.FormatterScriptMapping.prototype = {
/**
* @override
* @param {!WebInspector.DebuggerModel.Location} rawLocation
* @return {?WebInspector.UILocation}
*/
rawLocationToUILocation: function(rawLocation)
{
var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (rawLocation);
var script = debuggerModelLocation.script();
var uiSourceCode = this._editorAction._uiSourceCodes.get(script);
if (!uiSourceCode)
return null;
var formatData = this._editorAction._formatData.get(uiSourceCode);
if (!formatData)
return null;
var mapping = formatData.mapping;
var lineNumber = debuggerModelLocation.lineNumber;
var columnNumber = debuggerModelLocation.columnNumber || 0;
var formattedLocation = mapping.originalToFormatted(lineNumber, columnNumber);
return uiSourceCode.uiLocation(formattedLocation[0], formattedLocation[1]);
},
/**
* @override
* @param {!WebInspector.UISourceCode} uiSourceCode
* @param {number} lineNumber
* @param {number} columnNumber
* @return {?WebInspector.DebuggerModel.Location}
*/
uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber)
{
var formatData = this._editorAction._formatData.get(uiSourceCode);
if (!formatData)
return null;
var originalLocation = formatData.mapping.formattedToOriginal(lineNumber, columnNumber);
for (var i = 0; i < formatData.scripts.length; ++i) {
if (formatData.scripts[i].target() === this._target)
return this._target.debuggerModel.createRawLocation(formatData.scripts[i], originalLocation[0], originalLocation[1]);
}
return null;
},
/**
* @override
* @return {boolean}
*/
isIdentity: function()
{
return false;
},
/**
* @override
* @param {!WebInspector.UISourceCode} uiSourceCode
* @param {number} lineNumber
* @return {boolean}
*/
uiLineHasMapping: function(uiSourceCode, lineNumber)
{
return true;
}
}
/**
* @constructor
* @param {string} projectId
* @param {string} path
* @param {!WebInspector.FormatterSourceMapping} mapping
* @param {!Array.<!WebInspector.Script>} scripts
*/
WebInspector.FormatterScriptMapping.FormatData = function(projectId, path, mapping, scripts)
{
this.projectId = projectId;
this.path = path;
this.mapping = mapping;
this.scripts = scripts;
}
/**
* @constructor
* @param {!WebInspector.Workspace} workspace
* @param {string} id
* @extends {WebInspector.ContentProviderBasedProjectDelegate}
*/
WebInspector.FormatterProjectDelegate = function(workspace, id)
{
WebInspector.ContentProviderBasedProjectDelegate.call(this, workspace, id, WebInspector.projectTypes.Formatter);
}
WebInspector.FormatterProjectDelegate.prototype = {
/**
* @override
* @return {string}
*/
displayName: function()
{
return "formatter";
},
/**
* @param {string} name
* @param {string} sourceURL
* @param {!WebInspector.ResourceType} contentType
* @param {string} content
* @return {string}
*/
_addFormatted: function(name, sourceURL, contentType, content)
{
var contentProvider = new WebInspector.StaticContentProvider(contentType, content);
return this.addContentProvider(sourceURL, name + ":formatted", sourceURL, "deobfuscated:" + sourceURL, contentProvider);
},
/**
* @param {string} path
*/
_removeFormatted: function(path)
{
this.removeFile(path);
},
__proto__: WebInspector.ContentProviderBasedProjectDelegate.prototype
}
/**
* @constructor
* @implements {WebInspector.SourcesView.EditorAction}
* @implements {WebInspector.TargetManager.Observer}
*/
WebInspector.ScriptFormatterEditorAction = function()
{
this._projectId = "formatter:";
this._projectDelegate = new WebInspector.FormatterProjectDelegate(WebInspector.workspace, this._projectId);
/** @type {!Map.<!WebInspector.Script, !WebInspector.UISourceCode>} */
this._uiSourceCodes = new Map();
/** @type {!Map.<string, string>} */
this._formattedPaths = new Map();
/** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.FormatterScriptMapping.FormatData>} */
this._formatData = new Map();
/** @type {!Set.<string>} */
this._pathsToFormatOnLoad = new Set();
/** @type {!Map.<!WebInspector.Target, !WebInspector.FormatterScriptMapping>} */
this._scriptMappingByTarget = new Map();
this._workspace = WebInspector.workspace;
WebInspector.targetManager.observeTargets(this);
}
WebInspector.ScriptFormatterEditorAction.prototype = {
/**
* @override
* @param {!WebInspector.Target} target
*/
targetAdded: function(target)
{
this._scriptMappingByTarget.set(target, new WebInspector.FormatterScriptMapping(target, this));
target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
},
/**
* @override
* @param {!WebInspector.Target} target
*/
targetRemoved: function(target)
{
this._scriptMappingByTarget.remove(target);
this._cleanForTarget(target);
target.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
},
/**
* @param {!WebInspector.Event} event
*/
_editorSelected: function(event)
{
var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
this._updateButton(uiSourceCode);
var path = uiSourceCode.project().id() + ":" + uiSourceCode.path();
var networkURL = WebInspector.networkMapping.networkURL(uiSourceCode);
if (this._isFormatableScript(uiSourceCode) && networkURL && this._pathsToFormatOnLoad.has(path) && !this._formattedPaths.get(path))
this._formatUISourceCodeScript(uiSourceCode);
},
/**
* @param {!WebInspector.Event} event
*/
_editorClosed: function(event)
{
var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data.uiSourceCode);
var wasSelected = /** @type {boolean} */ (event.data.wasSelected);
if (wasSelected)
this._updateButton(null);
this._discardFormattedUISourceCodeScript(uiSourceCode);
},
/**
* @param {?WebInspector.UISourceCode} uiSourceCode
*/
_updateButton: function(uiSourceCode)
{
this._button.element.classList.toggle("hidden", !this._isFormatableScript(uiSourceCode));
},
/**
* @override
* @param {!WebInspector.SourcesView} sourcesView
* @return {!WebInspector.StatusBarButton}
*/
button: function(sourcesView)
{
if (this._button)
return this._button;
this._sourcesView = sourcesView;
this._sourcesView.addEventListener(WebInspector.SourcesView.Events.EditorSelected, this._editorSelected.bind(this));
this._sourcesView.addEventListener(WebInspector.SourcesView.Events.EditorClosed, this._editorClosed.bind(this));
this._button = new WebInspector.StatusBarButton(WebInspector.UIString("Pretty print"), "format-status-bar-item");
this._button.setToggled(false);
this._button.addEventListener("click", this._toggleFormatScriptSource, this);
this._updateButton(sourcesView.currentUISourceCode());
return this._button;
},
/**
* @param {?WebInspector.UISourceCode} uiSourceCode
* @return {boolean}
*/
_isFormatableScript: function(uiSourceCode)
{
if (!uiSourceCode)
return false;
var supportedProjectTypes = [WebInspector.projectTypes.Network, WebInspector.projectTypes.Debugger, WebInspector.projectTypes.ContentScripts];
if (supportedProjectTypes.indexOf(uiSourceCode.project().type()) === -1)
return false;
var contentType = uiSourceCode.contentType();
return contentType === WebInspector.resourceTypes.Script || contentType === WebInspector.resourceTypes.Document;
},
_toggleFormatScriptSource: function()
{
var uiSourceCode = this._sourcesView.currentUISourceCode();
if (!this._isFormatableScript(uiSourceCode))
return;
this._formatUISourceCodeScript(uiSourceCode);
WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
action: WebInspector.UserMetrics.UserActionNames.TogglePrettyPrint,
enabled: true,
url: uiSourceCode.originURL()
});
},
/**
* @param {!WebInspector.UISourceCode} uiSourceCode
* @param {!WebInspector.UISourceCode} formattedUISourceCode
* @param {!WebInspector.FormatterSourceMapping} mapping
* @private
*/
_showIfNeeded: function(uiSourceCode, formattedUISourceCode, mapping)
{
if (uiSourceCode !== this._sourcesView.currentUISourceCode())
return;
var sourceFrame = this._sourcesView.viewForFile(uiSourceCode);
var start = [0, 0];
if (sourceFrame) {
var selection = sourceFrame.selection();
start = mapping.originalToFormatted(selection.startLine, selection.startColumn);
}
this._sourcesView.showSourceLocation(formattedUISourceCode, start[0], start[1]);
this._updateButton(formattedUISourceCode);
},
/**
* @param {!WebInspector.UISourceCode} formattedUISourceCode
*/
_discardFormattedUISourceCodeScript: function(formattedUISourceCode)
{
var formatData = this._formatData.get(formattedUISourceCode);
if (!formatData)
return;
this._formatData.remove(formattedUISourceCode);
var path = formatData.projectId + ":" + formatData.path;
this._formattedPaths.remove(path);
this._pathsToFormatOnLoad.remove(path);
for (var i = 0; i < formatData.scripts.length; ++i) {
this._uiSourceCodes.remove(formatData.scripts[i]);
WebInspector.debuggerWorkspaceBinding.popSourceMapping(formatData.scripts[i]);
}
this._projectDelegate._removeFormatted(formattedUISourceCode.path());
},
/**
* @param {!WebInspector.Target} target
*/
_cleanForTarget: function(target)
{
var uiSourceCodes = this._formatData.keysArray();
for (var i = 0; i < uiSourceCodes.length; ++i) {
WebInspector.debuggerWorkspaceBinding.setSourceMapping(target, uiSourceCodes[i], null);
var formatData = this._formatData.get(uiSourceCodes[i]);
var scripts = [];
for (var j = 0; j < formatData.scripts.length; ++j) {
if (formatData.scripts[j].target() === target)
this._uiSourceCodes.remove(formatData.scripts[j]);
else
scripts.push(formatData.scripts[j]);
}
if (scripts.length)
formatData.scripts = scripts;
else {
this._formattedPaths.remove(formatData.projectId + ":" + formatData.path);
this._formatData.remove(uiSourceCodes[i]);
this._projectDelegate._removeFormatted(uiSourceCodes[i].path());
}
}
},
/**
* @param {!WebInspector.Event} event
*/
_debuggerReset: function(event)
{
var debuggerModel = /** @type {!WebInspector.DebuggerModel} */ (event.target);
this._cleanForTarget(debuggerModel.target());
},
/**
* @param {!WebInspector.UISourceCode} uiSourceCode
* @return {!Array.<!WebInspector.Script>}
*/
_scriptsForUISourceCode: function(uiSourceCode)
{
/**
* @param {!WebInspector.Script} script
* @return {boolean}
*/
function isInlineScript(script)
{
return script.isInlineScript() && !script.hasSourceURL;
}
if (uiSourceCode.contentType() === WebInspector.resourceTypes.Document) {
var scripts = [];
var targets = WebInspector.targetManager.targets();
for (var i = 0; i < targets.length; ++i) {
var networkURL = WebInspector.networkMapping.networkURL(uiSourceCode);
scripts.pushAll(targets[i].debuggerModel.scriptsForSourceURL(networkURL));
}
return scripts.filter(isInlineScript);
}
if (uiSourceCode.contentType() === WebInspector.resourceTypes.Script) {
var rawLocations = WebInspector.debuggerWorkspaceBinding.uiLocationToRawLocations(uiSourceCode, 0, 0);
return rawLocations.map(function(rawLocation) { return rawLocation.script(); });
}
return [];
},
/**
* @param {!WebInspector.UISourceCode} uiSourceCode
*/
_formatUISourceCodeScript: function(uiSourceCode)
{
var formattedPath = this._formattedPaths.get(uiSourceCode.project().id() + ":" + uiSourceCode.path());
if (formattedPath) {
var uiSourceCodePath = formattedPath;
var formattedUISourceCode = this._workspace.uiSourceCode(this._projectId, uiSourceCodePath);
var formatData = formattedUISourceCode ? this._formatData.get(formattedUISourceCode) : null;
if (formatData)
this._showIfNeeded(uiSourceCode, /** @type {!WebInspector.UISourceCode} */ (formattedUISourceCode), formatData.mapping);
return;
}
uiSourceCode.requestContent(contentLoaded.bind(this));
/**
* @this {WebInspector.ScriptFormatterEditorAction}
* @param {?string} content
*/
function contentLoaded(content)
{
var highlighterType = WebInspector.SourcesView.uiSourceCodeHighlighterType(uiSourceCode);
WebInspector.Formatter.format(uiSourceCode.contentType(), highlighterType, content || "", innerCallback.bind(this));
}
/**
* @this {WebInspector.ScriptFormatterEditorAction}
* @param {string} formattedContent
* @param {!WebInspector.FormatterSourceMapping} formatterMapping
*/
function innerCallback(formattedContent, formatterMapping)
{
var scripts = this._scriptsForUISourceCode(uiSourceCode);
var name;
if (uiSourceCode.contentType() === WebInspector.resourceTypes.Document)
name = uiSourceCode.displayName();
else
name = uiSourceCode.name() || (scripts.length ? scripts[0].scriptId : "");
var networkURL = WebInspector.networkMapping.networkURL(uiSourceCode);
formattedPath = this._projectDelegate._addFormatted(name, networkURL, uiSourceCode.contentType(), formattedContent);
var formattedUISourceCode = /** @type {!WebInspector.UISourceCode} */ (this._workspace.uiSourceCode(this._projectId, formattedPath));
var formatData = new WebInspector.FormatterScriptMapping.FormatData(uiSourceCode.project().id(), uiSourceCode.path(), formatterMapping, scripts);
this._formatData.set(formattedUISourceCode, formatData);
var path = uiSourceCode.project().id() + ":" + uiSourceCode.path();
this._formattedPaths.set(path, formattedPath);
this._pathsToFormatOnLoad.add(path);
for (var i = 0; i < scripts.length; ++i) {
this._uiSourceCodes.set(scripts[i], formattedUISourceCode);
var scriptMapping = /** @type {!WebInspector.FormatterScriptMapping} */(this._scriptMappingByTarget.get(scripts[i].target()));
WebInspector.debuggerWorkspaceBinding.pushSourceMapping(scripts[i], scriptMapping);
}
var targets = WebInspector.targetManager.targets();
for (var i = 0; i < targets.length; ++i) {
var scriptMapping = /** @type {!WebInspector.FormatterScriptMapping} */(this._scriptMappingByTarget.get(targets[i]));
WebInspector.debuggerWorkspaceBinding.setSourceMapping(targets[i], formattedUISourceCode, scriptMapping);
}
this._showIfNeeded(uiSourceCode, formattedUISourceCode, formatterMapping);
}
}
}