strong-arc
Version:
A visual suite for the StrongLoop API Platform
438 lines (388 loc) • 14.3 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.TargetManager.Observer}
*/
WebInspector.CSSWorkspaceBinding = function()
{
/** @type {!Map.<!WebInspector.Target, !WebInspector.CSSWorkspaceBinding.TargetInfo>} */
this._targetToTargetInfo = new Map();
WebInspector.targetManager.observeTargets(this);
WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameCreatedOrNavigated, this);
}
WebInspector.CSSWorkspaceBinding.prototype = {
/**
* @param {!WebInspector.Target} target
*/
targetAdded: function(target)
{
this._targetToTargetInfo.set(target, new WebInspector.CSSWorkspaceBinding.TargetInfo(target, WebInspector.workspace, WebInspector.networkWorkspaceBinding));
},
/**
* @param {!WebInspector.Target} target
*/
targetRemoved: function(target)
{
this._targetToTargetInfo.remove(target)._dispose();
},
/**
* @param {!WebInspector.CSSStyleSheetHeader} header
* @param {!WebInspector.CSSSourceMapping} mapping
*/
pushSourceMapping: function(header, mapping)
{
this._ensureInfoForHeader(header)._pushSourceMapping(mapping);
},
/**
* @param {!WebInspector.CSSStyleSheetHeader} header
* @return {?WebInspector.CSSWorkspaceBinding.HeaderInfo}
*/
_headerInfo: function(header)
{
var map = this._targetToTargetInfo.get(header.target());
return map._headerInfo(header.id) || null;
},
/**
* @param {!WebInspector.CSSStyleSheetHeader} header
* @return {!WebInspector.CSSWorkspaceBinding.HeaderInfo}
*/
_ensureInfoForHeader: function(header)
{
var targetInfo = this._targetToTargetInfo.get(header.target());
if (!targetInfo) {
targetInfo = new WebInspector.CSSWorkspaceBinding.TargetInfo(header.target(), WebInspector.workspace, WebInspector.networkWorkspaceBinding);
this._targetToTargetInfo.set(header.target(), targetInfo);
}
return targetInfo._ensureInfoForHeader(header);
},
/**
* @param {!WebInspector.Event} event
*/
_mainFrameCreatedOrNavigated: function(event)
{
var target = /** @type {!WebInspector.ResourceTreeModel} */ (event.target).target();
this._targetToTargetInfo.get(target)._reset();
},
/**
* @param {!WebInspector.CSSStyleSheetHeader} header
*/
updateLocations: function(header)
{
var info = this._headerInfo(header);
if (info)
info._updateLocations();
},
/**
* @param {!WebInspector.CSSLocation} rawLocation
* @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegate
* @return {!WebInspector.CSSWorkspaceBinding.LiveLocation}
*/
createLiveLocation: function(rawLocation, updateDelegate)
{
var header = rawLocation.styleSheetId ? rawLocation.target().cssModel.styleSheetHeaderForId(rawLocation.styleSheetId) : null;
return new WebInspector.CSSWorkspaceBinding.LiveLocation(rawLocation.target().cssModel, header, rawLocation, updateDelegate);
},
/**
* @param {!WebInspector.CSSWorkspaceBinding.LiveLocation} location
*/
_addLiveLocation: function(location)
{
this._ensureInfoForHeader(location._header)._addLocation(location);
},
/**
* @param {!WebInspector.CSSWorkspaceBinding.LiveLocation} location
*/
_removeLiveLocation: function(location)
{
var info = this._headerInfo(location._header);
if (info)
info._removeLocation(location);
},
/**
* @param {!WebInspector.CSSProperty} cssProperty
* @param {boolean} forName
* @return {?WebInspector.UILocation}
*/
propertyUILocation: function(cssProperty, forName)
{
var style = cssProperty.ownerStyle;
if (!style || !style.parentRule || !style.styleSheetId)
return null;
var range = cssProperty.range;
if (!range)
return null;
var url = style.parentRule.resourceURL();
if (!url)
return null;
var line = forName ? range.startLine : range.endLine;
// End of range is exclusive, so subtract 1 from the end offset.
var column = forName ? range.startColumn : range.endColumn - (cssProperty.text && cssProperty.text.endsWith(";") ? 2 : 1);
var rawLocation = new WebInspector.CSSLocation(style.target(), style.styleSheetId, url, line, column);
return this.rawLocationToUILocation(rawLocation);
},
/**
* @param {?WebInspector.CSSLocation} rawLocation
* @return {?WebInspector.UILocation}
*/
rawLocationToUILocation: function(rawLocation)
{
if (!rawLocation)
return null;
var cssModel = rawLocation.target().cssModel;
var frameIdToSheetIds = cssModel.styleSheetIdsByFrameIdForURL(rawLocation.url);
if (!Object.values(frameIdToSheetIds).length)
return null;
var styleSheetIds = [];
for (var frameId in frameIdToSheetIds)
styleSheetIds = styleSheetIds.concat(frameIdToSheetIds[frameId]);
var uiLocation;
for (var i = 0; !uiLocation && i < styleSheetIds.length; ++i) {
var header = cssModel.styleSheetHeaderForId(styleSheetIds[i]);
if (!header)
continue;
var info = this._headerInfo(header);
if (info)
uiLocation = info._rawLocationToUILocation(rawLocation.lineNumber, rawLocation.columnNumber);
}
return uiLocation || null;
}
}
/**
* @constructor
* @param {!WebInspector.Target} target
* @param {!WebInspector.Workspace} workspace
* @param {!WebInspector.NetworkWorkspaceBinding} networkWorkspaceBinding
*/
WebInspector.CSSWorkspaceBinding.TargetInfo = function(target, workspace, networkWorkspaceBinding)
{
this._target = target;
this._workspace = workspace;
var cssModel = target.cssModel;
this._stylesSourceMapping = new WebInspector.StylesSourceMapping(cssModel, workspace);
this._sassSourceMapping = new WebInspector.SASSSourceMapping(cssModel, workspace, networkWorkspaceBinding);
/** @type {!StringMap.<!WebInspector.CSSWorkspaceBinding.HeaderInfo>} */
this._headerInfoById = new StringMap();
cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
}
WebInspector.CSSWorkspaceBinding.TargetInfo.prototype = {
/**
* @param {!WebInspector.Event} event
*/
_styleSheetAdded: function(event)
{
var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
this._stylesSourceMapping.addHeader(header);
this._sassSourceMapping.addHeader(header);
},
/**
* @param {!WebInspector.Event} event
*/
_styleSheetRemoved: function(event)
{
var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
this._stylesSourceMapping.removeHeader(header);
this._sassSourceMapping.removeHeader(header);
this._headerInfoById.remove(header.id);
},
/**
* @param {!CSSAgent.StyleSheetId} id
*/
_headerInfo: function(id)
{
return this._headerInfoById.get(id);
},
_ensureInfoForHeader: function(header)
{
var info = this._headerInfoById.get(header.id);
if (!info) {
info = new WebInspector.CSSWorkspaceBinding.HeaderInfo(header);
this._headerInfoById.set(header.id, info);
}
return info;
},
_dispose: function()
{
this._reset();
this._target.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
this._target.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
},
_reset: function()
{
this._headerInfoById.clear();
}
}
/**
* @constructor
* @param {!WebInspector.CSSStyleSheetHeader} header
*/
WebInspector.CSSWorkspaceBinding.HeaderInfo = function(header)
{
this._header = header;
/** @type {!Array.<!WebInspector.CSSSourceMapping>} */
this._sourceMappings = [];
/** @type {!Set.<!WebInspector.LiveLocation>} */
this._locations = new Set();
}
WebInspector.CSSWorkspaceBinding.HeaderInfo.prototype = {
/**
* @param {!WebInspector.LiveLocation} location
*/
_addLocation: function(location)
{
this._locations.add(location);
location.update();
},
/**
* @param {!WebInspector.LiveLocation} location
*/
_removeLocation: function(location)
{
this._locations.remove(location);
},
_updateLocations: function()
{
var items = this._locations.values();
for (var i = 0; i < items.length; ++i)
items[i].update();
},
/**
* @param {number} lineNumber
* @param {number=} columnNumber
* @return {?WebInspector.UILocation}
*/
_rawLocationToUILocation: function(lineNumber, columnNumber)
{
var uiLocation = null;
var rawLocation = new WebInspector.CSSLocation(this._header.target(), this._header.id, this._header.resourceURL(), lineNumber, columnNumber);
for (var i = this._sourceMappings.length - 1; !uiLocation && i >= 0; --i)
uiLocation = this._sourceMappings[i].rawLocationToUILocation(rawLocation);
return uiLocation;
},
/**
* @param {!WebInspector.CSSSourceMapping} sourceMapping
*/
_pushSourceMapping: function(sourceMapping)
{
this._sourceMappings.push(sourceMapping);
this._updateLocations();
}
}
/**
* @constructor
* @extends {WebInspector.LiveLocation}
* @param {!WebInspector.CSSStyleModel} cssModel
* @param {?WebInspector.CSSStyleSheetHeader} header
* @param {!WebInspector.CSSLocation} rawLocation
* @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegate
*/
WebInspector.CSSWorkspaceBinding.LiveLocation = function(cssModel, header, rawLocation, updateDelegate)
{
WebInspector.LiveLocation.call(this, updateDelegate);
this._cssModel = cssModel;
this._rawLocation = rawLocation;
if (!header)
this._clearStyleSheet();
else
this._setStyleSheet(header);
}
WebInspector.CSSWorkspaceBinding.LiveLocation.prototype = {
/**
* @param {!WebInspector.Event} event
*/
_styleSheetAdded: function(event)
{
console.assert(!this._header);
var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
if (header.sourceURL && header.sourceURL === this._rawLocation.url)
this._setStyleSheet(header);
},
/**
* @param {!WebInspector.Event} event
*/
_styleSheetRemoved: function(event)
{
console.assert(this._header);
var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
if (this._header !== header)
return;
WebInspector.cssWorkspaceBinding._removeLiveLocation(this);
this._clearStyleSheet();
},
/**
* @param {!WebInspector.CSSStyleSheetHeader} header
*/
_setStyleSheet: function(header)
{
this._header = header;
WebInspector.cssWorkspaceBinding._addLiveLocation(this);
this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
},
_clearStyleSheet: function()
{
delete this._header;
this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
},
/**
* @return {?WebInspector.UILocation}
*/
uiLocation: function()
{
var cssLocation = this._rawLocation;
if (this._header) {
var headerInfo = WebInspector.cssWorkspaceBinding._headerInfo(this._header);
return headerInfo._rawLocationToUILocation(cssLocation.lineNumber, cssLocation.columnNumber);
}
var uiSourceCode = WebInspector.workspace.uiSourceCodeForURL(cssLocation.url);
if (!uiSourceCode)
return null;
return uiSourceCode.uiLocation(cssLocation.lineNumber, cssLocation.columnNumber);
},
dispose: function()
{
WebInspector.LiveLocation.prototype.dispose.call(this);
if (this._header)
WebInspector.cssWorkspaceBinding._removeLiveLocation(this);
this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
},
__proto__: WebInspector.LiveLocation.prototype
}
/**
* @interface
*/
WebInspector.CSSSourceMapping = function()
{
}
WebInspector.CSSSourceMapping.prototype = {
/**
* @param {!WebInspector.CSSLocation} rawLocation
* @return {?WebInspector.UILocation}
*/
rawLocationToUILocation: function(rawLocation) { },
/**
* @param {!WebInspector.UISourceCode} uiSourceCode
* @param {number} lineNumber
* @param {number} columnNumber
* @return {?WebInspector.CSSLocation}
*/
uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber) { },
/**
* @return {boolean}
*/
isIdentity: function() { },
/**
* @param {!WebInspector.UISourceCode} uiSourceCode
* @param {number} lineNumber
* @return {boolean}
*/
uiLineHasMapping: function(uiSourceCode, lineNumber) { }
}
/**
* @type {!WebInspector.CSSWorkspaceBinding}
*/
WebInspector.cssWorkspaceBinding;