Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / devtools / front_end / bindings / CSSWorkspaceBinding.js
blob383ac172ee3761c45ad820ed64a86f1c2b13b925
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6 * @constructor
7 * @implements {WebInspector.TargetManager.Observer}
8 * @param {!WebInspector.TargetManager} targetManager
9 * @param {!WebInspector.Workspace} workspace
10 * @param {!WebInspector.NetworkMapping} networkMapping
12 WebInspector.CSSWorkspaceBinding = function(targetManager, workspace, networkMapping)
14 this._workspace = workspace;
15 this._networkMapping = networkMapping;
17 /** @type {!Map.<!WebInspector.CSSStyleModel, !WebInspector.CSSWorkspaceBinding.TargetInfo>} */
18 this._modelToTargetInfo = new Map();
19 targetManager.observeTargets(this);
21 targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameCreatedOrNavigated, this);
24 WebInspector.CSSWorkspaceBinding.prototype = {
25 /**
26 * @override
27 * @param {!WebInspector.Target} target
29 targetAdded: function(target)
31 var cssModel = WebInspector.CSSStyleModel.fromTarget(target);
32 if (cssModel)
33 this._modelToTargetInfo.set(cssModel, new WebInspector.CSSWorkspaceBinding.TargetInfo(cssModel, this._workspace, this._networkMapping));
36 /**
37 * @override
38 * @param {!WebInspector.Target} target
40 targetRemoved: function(target)
42 var cssModel = WebInspector.CSSStyleModel.fromTarget(target);
43 if (cssModel)
44 this._modelToTargetInfo.remove(cssModel)._dispose();
47 /**
48 * @param {!WebInspector.CSSStyleSheetHeader} header
49 * @param {!WebInspector.CSSSourceMapping} mapping
51 pushSourceMapping: function(header, mapping)
53 this._ensureInfoForHeader(header)._pushSourceMapping(mapping);
56 /**
57 * @param {!WebInspector.CSSStyleSheetHeader} header
58 * @return {?WebInspector.CSSWorkspaceBinding.HeaderInfo}
60 _headerInfo: function(header)
62 var map = this._modelToTargetInfo.get(header.cssModel());
63 return map._headerInfo(header.id) || null;
66 /**
67 * @param {!WebInspector.CSSStyleSheetHeader} header
68 * @return {!WebInspector.CSSWorkspaceBinding.HeaderInfo}
70 _ensureInfoForHeader: function(header)
72 var targetInfo = this._modelToTargetInfo.get(header.cssModel());
73 if (!targetInfo) {
74 targetInfo = new WebInspector.CSSWorkspaceBinding.TargetInfo(header.cssModel(), this._workspace, this._networkMapping);
75 this._modelToTargetInfo.set(header.cssModel(), targetInfo);
77 return targetInfo._ensureInfoForHeader(header);
80 /**
81 * @param {!WebInspector.Event} event
83 _mainFrameCreatedOrNavigated: function(event)
85 var target = /** @type {!WebInspector.ResourceTreeModel} */ (event.target).target();
86 var cssModel = WebInspector.CSSStyleModel.fromTarget(target);
87 if (cssModel)
88 this._modelToTargetInfo.get(cssModel)._reset();
91 /**
92 * @param {!WebInspector.CSSStyleSheetHeader} header
94 updateLocations: function(header)
96 var info = this._headerInfo(header);
97 if (info)
98 info._updateLocations();
102 * @param {!WebInspector.CSSLocation} rawLocation
103 * @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegate
104 * @return {!WebInspector.CSSWorkspaceBinding.LiveLocation}
106 createLiveLocation: function(rawLocation, updateDelegate)
108 var header = rawLocation.styleSheetId ? rawLocation.cssModel().styleSheetHeaderForId(rawLocation.styleSheetId) : null;
109 return new WebInspector.CSSWorkspaceBinding.LiveLocation(rawLocation.cssModel(), header, rawLocation, this, updateDelegate);
113 * @param {!WebInspector.CSSWorkspaceBinding.LiveLocation} location
115 _addLiveLocation: function(location)
117 this._ensureInfoForHeader(location._header)._addLocation(location);
121 * @param {!WebInspector.CSSWorkspaceBinding.LiveLocation} location
123 _removeLiveLocation: function(location)
125 var info = this._headerInfo(location._header);
126 if (info)
127 info._removeLocation(location);
131 * @param {!WebInspector.CSSProperty} cssProperty
132 * @param {boolean} forName
133 * @return {?WebInspector.UILocation}
135 propertyUILocation: function(cssProperty, forName)
137 var style = cssProperty.ownerStyle;
138 if (!style || !style.parentRule || !style.styleSheetId)
139 return null;
141 var range = cssProperty.range;
142 if (!range)
143 return null;
145 var url = style.parentRule.resourceURL();
146 if (!url)
147 return null;
149 var line = forName ? range.startLine : range.endLine;
150 // End of range is exclusive, so subtract 1 from the end offset.
151 var column = forName ? range.startColumn : range.endColumn - (cssProperty.text && cssProperty.text.endsWith(";") ? 2 : 1);
152 var header = style.cssModel().styleSheetHeaderForId(style.styleSheetId);
153 var rawLocation = new WebInspector.CSSLocation(style.cssModel(), style.styleSheetId, url, header.lineNumberInSource(line), header.columnNumberInSource(line, column));
154 return this.rawLocationToUILocation(rawLocation);
158 * @param {?WebInspector.CSSLocation} rawLocation
159 * @return {?WebInspector.UILocation}
161 rawLocationToUILocation: function(rawLocation)
163 if (!rawLocation)
164 return null;
165 var header = rawLocation.cssModel().styleSheetHeaderForId(rawLocation.styleSheetId);
166 if (!header)
167 return null;
168 var info = this._headerInfo(header);
169 return info ? info._rawLocationToUILocation(rawLocation.lineNumber, rawLocation.columnNumber) : null;
174 * @constructor
175 * @param {!WebInspector.CSSStyleModel} cssModel
176 * @param {!WebInspector.Workspace} workspace
177 * @param {!WebInspector.NetworkMapping} networkMapping
179 WebInspector.CSSWorkspaceBinding.TargetInfo = function(cssModel, workspace, networkMapping)
181 this._cssModel = cssModel;
182 this._stylesSourceMapping = new WebInspector.StylesSourceMapping(cssModel, workspace, networkMapping);
183 this._sassSourceMapping = new WebInspector.SASSSourceMapping(cssModel, workspace, networkMapping, WebInspector.NetworkProject.forTarget(cssModel.target()));
185 /** @type {!Map.<string, !WebInspector.CSSWorkspaceBinding.HeaderInfo>} */
186 this._headerInfoById = new Map();
188 cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
189 cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
192 WebInspector.CSSWorkspaceBinding.TargetInfo.prototype = {
194 * @param {!WebInspector.Event} event
196 _styleSheetAdded: function(event)
198 var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
199 this._stylesSourceMapping.addHeader(header);
200 this._sassSourceMapping.addHeader(header);
204 * @param {!WebInspector.Event} event
206 _styleSheetRemoved: function(event)
208 var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
209 this._stylesSourceMapping.removeHeader(header);
210 this._sassSourceMapping.removeHeader(header);
211 this._headerInfoById.remove(header.id);
215 * @param {!CSSAgent.StyleSheetId} id
217 _headerInfo: function(id)
219 return this._headerInfoById.get(id);
222 _ensureInfoForHeader: function(header)
224 var info = this._headerInfoById.get(header.id);
225 if (!info) {
226 info = new WebInspector.CSSWorkspaceBinding.HeaderInfo(header);
227 this._headerInfoById.set(header.id, info);
229 return info;
232 _dispose: function()
234 this._reset();
235 this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
236 this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
239 _reset: function()
241 this._headerInfoById.clear();
246 * @constructor
247 * @param {!WebInspector.CSSStyleSheetHeader} header
249 WebInspector.CSSWorkspaceBinding.HeaderInfo = function(header)
251 this._header = header;
253 /** @type {!Array.<!WebInspector.CSSSourceMapping>} */
254 this._sourceMappings = [];
256 /** @type {!Set.<!WebInspector.LiveLocation>} */
257 this._locations = new Set();
260 WebInspector.CSSWorkspaceBinding.HeaderInfo.prototype = {
262 * @param {!WebInspector.LiveLocation} location
264 _addLocation: function(location)
266 this._locations.add(location);
267 location.update();
271 * @param {!WebInspector.LiveLocation} location
273 _removeLocation: function(location)
275 this._locations.delete(location);
278 _updateLocations: function()
280 var items = this._locations.valuesArray();
281 for (var i = 0; i < items.length; ++i)
282 items[i].update();
286 * @param {number} lineNumber
287 * @param {number=} columnNumber
288 * @return {?WebInspector.UILocation}
290 _rawLocationToUILocation: function(lineNumber, columnNumber)
292 var uiLocation = null;
293 var rawLocation = new WebInspector.CSSLocation(this._header.cssModel(), this._header.id, this._header.resourceURL(), lineNumber, columnNumber);
294 for (var i = this._sourceMappings.length - 1; !uiLocation && i >= 0; --i)
295 uiLocation = this._sourceMappings[i].rawLocationToUILocation(rawLocation);
296 return uiLocation;
300 * @param {!WebInspector.CSSSourceMapping} sourceMapping
302 _pushSourceMapping: function(sourceMapping)
304 this._sourceMappings.push(sourceMapping);
305 this._updateLocations();
310 * @constructor
311 * @extends {WebInspector.LiveLocation}
312 * @param {!WebInspector.CSSStyleModel} cssModel
313 * @param {?WebInspector.CSSStyleSheetHeader} header
314 * @param {!WebInspector.CSSLocation} rawLocation
315 * @param {!WebInspector.CSSWorkspaceBinding} binding
316 * @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegate
318 WebInspector.CSSWorkspaceBinding.LiveLocation = function(cssModel, header, rawLocation, binding, updateDelegate)
320 WebInspector.LiveLocation.call(this, updateDelegate);
321 this._cssModel = cssModel;
322 this._rawLocation = rawLocation;
323 this._binding = binding;
324 if (!header)
325 this._clearStyleSheet();
326 else
327 this._setStyleSheet(header);
330 WebInspector.CSSWorkspaceBinding.LiveLocation.prototype = {
332 * @param {!WebInspector.Event} event
334 _styleSheetAdded: function(event)
336 console.assert(!this._header);
337 var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
338 if (header.sourceURL && header.sourceURL === this._rawLocation.url)
339 this._setStyleSheet(header);
343 * @param {!WebInspector.Event} event
345 _styleSheetRemoved: function(event)
347 console.assert(this._header);
348 var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
349 if (this._header !== header)
350 return;
351 this._binding._removeLiveLocation(this);
352 this._clearStyleSheet();
356 * @param {!WebInspector.CSSStyleSheetHeader} header
358 _setStyleSheet: function(header)
360 this._header = header;
361 this._binding._addLiveLocation(this);
362 this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
363 this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
366 _clearStyleSheet: function()
368 delete this._header;
369 this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
370 this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
374 * @override
375 * @return {?WebInspector.UILocation}
377 uiLocation: function()
379 var cssLocation = this._rawLocation;
380 if (this._header) {
381 var headerInfo = this._binding._headerInfo(this._header);
382 return headerInfo._rawLocationToUILocation(cssLocation.lineNumber, cssLocation.columnNumber);
384 var uiSourceCode = this._binding._networkMapping.uiSourceCodeForURL(cssLocation.url, cssLocation.target());
385 if (!uiSourceCode)
386 return null;
387 return uiSourceCode.uiLocation(cssLocation.lineNumber, cssLocation.columnNumber);
390 dispose: function()
392 WebInspector.LiveLocation.prototype.dispose.call(this);
393 if (this._header)
394 this._binding._removeLiveLocation(this);
395 this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
396 this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
399 __proto__: WebInspector.LiveLocation.prototype
403 * @interface
405 WebInspector.CSSSourceMapping = function()
409 WebInspector.CSSSourceMapping.prototype = {
411 * @param {!WebInspector.CSSLocation} rawLocation
412 * @return {?WebInspector.UILocation}
414 rawLocationToUILocation: function(rawLocation) { },
417 * @param {!WebInspector.UISourceCode} uiSourceCode
418 * @param {number} lineNumber
419 * @param {number} columnNumber
420 * @return {?WebInspector.CSSLocation}
422 uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber) { },
425 * @return {boolean}
427 isIdentity: function() { },
430 * @param {!WebInspector.UISourceCode} uiSourceCode
431 * @param {number} lineNumber
432 * @return {boolean}
434 uiLineHasMapping: function(uiSourceCode, lineNumber) { }
438 * @type {!WebInspector.CSSWorkspaceBinding}
440 WebInspector.cssWorkspaceBinding;