Chromium Code Reviews| Index: Source/devtools/front_end/sdk/CSSWorkspaceBinding.js |
| diff --git a/Source/devtools/front_end/sdk/CSSWorkspaceBinding.js b/Source/devtools/front_end/sdk/CSSWorkspaceBinding.js |
| index 75574889c97779049f35892d951c8d2dbe8d15b1..f0977917e7c6c0cc9a3936a4b901943763d5f060 100644 |
| --- a/Source/devtools/front_end/sdk/CSSWorkspaceBinding.js |
| +++ b/Source/devtools/front_end/sdk/CSSWorkspaceBinding.js |
| @@ -4,20 +4,127 @@ |
| /** |
| * @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.targetManager.addModelListener(WebInspector.CSSStyleModel, WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); |
| } |
| WebInspector.CSSWorkspaceBinding.prototype = { |
| /** |
| + * @param {!WebInspector.Target} target |
| + */ |
| + targetAdded: function(target) |
| + { |
| + this._targetToTargetInfo.put(target, new WebInspector.CSSWorkspaceBinding.TargetInfo(target)); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.Target} target |
| + */ |
| + targetRemoved: function(target) |
| + { |
| + this._targetToTargetInfo.remove(target)._dispose(); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.CSSStyleSheetHeader} header |
| + * @param {!WebInspector.SourceMapping} 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()); |
| + this._targetToTargetInfo.put(header.target(), targetInfo); |
| + } |
| + return targetInfo._ensureInfoForHeader(header); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.Event} event |
| + */ |
| + _mainFrameCreatedOrNavigated: function(event) |
| + { |
| + var target = /** @type {!WebInspector.ResourceTreeModel} */ (event.target).target(); |
| + var info = this._targetToTargetInfo.remove(target); |
| + if (info) |
| + info._dispose(); |
| + this._targetToTargetInfo.put(target, new WebInspector.CSSWorkspaceBinding.TargetInfo(target)); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.Event} event |
| + */ |
| + _styleSheetRemoved: function(event) |
| + { |
| + var target = /** @type {!WebInspector.CSSStyleModel} */ (event.target).target(); |
| + var info = this._targetToTargetInfo.get(target); |
| + info._styleSheetRemoved(/** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data).id); |
| + }, |
| + |
| + /** |
| + * @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.CSSStyleModel.LiveLocation} |
| + * @return {!WebInspector.CSSWorkspaceBinding.LiveLocation} |
| */ |
| createLiveLocation: function(rawLocation, updateDelegate) |
| { |
| - return /** @type {!WebInspector.CSSStyleModel.LiveLocation} */ (rawLocation.createLiveLocation(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); |
| }, |
| /** |
| @@ -52,7 +159,270 @@ WebInspector.CSSWorkspaceBinding.prototype = { |
| */ |
| rawLocationToUILocation: function(rawLocation) |
| { |
| - return rawLocation ? rawLocation.target().cssModel.rawLocationToUILocation(rawLocation) : null; |
| + 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 |
| + */ |
| +WebInspector.CSSWorkspaceBinding.TargetInfo = function(target) |
| +{ |
| + this._target = target; |
| + |
| + /** @type {!StringMap.<!WebInspector.CSSWorkspaceBinding.HeaderInfo>} */ |
| + this._headerInfoById = new StringMap(); |
| + |
| + this._mapping = new WebInspector.CSSStyleSheetMapping(target.cssModel, WebInspector.workspace, WebInspector.networkWorkspaceBinding); |
| +} |
| + |
| +WebInspector.CSSWorkspaceBinding.TargetInfo.prototype = { |
| + /** |
| + * @param {!CSSAgent.StyleSheetId} id |
| + */ |
| + _styleSheetRemoved: function(id) |
| + { |
| + this._headerInfoById.remove(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.put(header.id, info); |
| + } |
| + return info; |
| + }, |
| + |
| + _dispose: function() |
| + { |
| + this._mapping._dispose(); |
| + } |
| +} |
| + |
| +/** |
| + * @constructor |
| + * @param {!WebInspector.CSSStyleSheetHeader} header |
| + */ |
| +WebInspector.CSSWorkspaceBinding.HeaderInfo = function(header) |
| +{ |
| + this._header = header; |
| + |
| + /** @type {!Array.<!WebInspector.SourceMapping>} */ |
| + 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.SourceMapping} 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, rawLocation, updateDelegate); |
| + this._cssModel = cssModel; |
| + 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 = /** @type WebInspector.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 |
| +} |
| + |
| +/** |
| + * @constructor |
| + * @param {!WebInspector.CSSStyleModel} cssModel |
| + * @param {!WebInspector.Workspace} workspace |
| + * @param {!WebInspector.NetworkWorkspaceBinding} networkWorkspaceBinding |
| + */ |
| +WebInspector.CSSStyleSheetMapping = function(cssModel, workspace, networkWorkspaceBinding) |
|
vsevik
2014/07/22 16:37:59
This is essentially the same object as WebInspecto
|
| +{ |
| + this._cssModel = cssModel; |
| + this._workspace = workspace; |
| + this._stylesSourceMapping = new WebInspector.StylesSourceMapping(cssModel, workspace); |
| + this._sassSourceMapping = new WebInspector.SASSSourceMapping(cssModel, workspace, networkWorkspaceBinding); |
| + |
| + cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this); |
| + cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); |
| +} |
| + |
| +WebInspector.CSSStyleSheetMapping.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); |
| + }, |
| + |
| + _dispose: function() |
| + { |
| + this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this); |
| + this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); |
| } |
| } |