OLD | NEW |
| (Empty) |
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. | |
4 | |
5 /** | |
6 * @constructor | |
7 * @implements {WebInspector.TargetManager.Observer} | |
8 */ | |
9 WebInspector.CSSWorkspaceBinding = function() | |
10 { | |
11 /** @type {!Map.<!WebInspector.Target, !WebInspector.CSSWorkspaceBinding.Tar
getInfo>} */ | |
12 this._targetToTargetInfo = new Map(); | |
13 WebInspector.targetManager.observeTargets(this); | |
14 | |
15 WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel,
WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameCre
atedOrNavigated, this); | |
16 } | |
17 | |
18 WebInspector.CSSWorkspaceBinding.prototype = { | |
19 /** | |
20 * @param {!WebInspector.Target} target | |
21 */ | |
22 targetAdded: function(target) | |
23 { | |
24 this._targetToTargetInfo.put(target, new WebInspector.CSSWorkspaceBindin
g.TargetInfo(target, WebInspector.workspace, WebInspector.networkWorkspaceBindin
g)); | |
25 }, | |
26 | |
27 /** | |
28 * @param {!WebInspector.Target} target | |
29 */ | |
30 targetRemoved: function(target) | |
31 { | |
32 this._targetToTargetInfo.remove(target)._dispose(); | |
33 }, | |
34 | |
35 /** | |
36 * @param {!WebInspector.CSSStyleSheetHeader} header | |
37 * @param {!WebInspector.SourceMapping} mapping | |
38 */ | |
39 pushSourceMapping: function(header, mapping) | |
40 { | |
41 this._ensureInfoForHeader(header)._pushSourceMapping(mapping); | |
42 }, | |
43 | |
44 /** | |
45 * @param {!WebInspector.CSSStyleSheetHeader} header | |
46 * @return {?WebInspector.CSSWorkspaceBinding.HeaderInfo} | |
47 */ | |
48 _headerInfo: function(header) | |
49 { | |
50 var map = this._targetToTargetInfo.get(header.target()); | |
51 return map._headerInfo(header.id) || null; | |
52 }, | |
53 | |
54 /** | |
55 * @param {!WebInspector.CSSStyleSheetHeader} header | |
56 * @return {!WebInspector.CSSWorkspaceBinding.HeaderInfo} | |
57 */ | |
58 _ensureInfoForHeader: function(header) | |
59 { | |
60 var targetInfo = this._targetToTargetInfo.get(header.target()); | |
61 if (!targetInfo) { | |
62 targetInfo = new WebInspector.CSSWorkspaceBinding.TargetInfo(header.
target(), WebInspector.workspace, WebInspector.networkWorkspaceBinding); | |
63 this._targetToTargetInfo.put(header.target(), targetInfo); | |
64 } | |
65 return targetInfo._ensureInfoForHeader(header); | |
66 }, | |
67 | |
68 /** | |
69 * @param {!WebInspector.Event} event | |
70 */ | |
71 _mainFrameCreatedOrNavigated: function(event) | |
72 { | |
73 var target = /** @type {!WebInspector.ResourceTreeModel} */ (event.targe
t).target(); | |
74 this._targetToTargetInfo.get(target)._reset(); | |
75 }, | |
76 | |
77 /** | |
78 * @param {!WebInspector.CSSStyleSheetHeader} header | |
79 */ | |
80 updateLocations: function(header) | |
81 { | |
82 var info = this._headerInfo(header); | |
83 if (info) | |
84 info._updateLocations(); | |
85 }, | |
86 | |
87 /** | |
88 * @param {!WebInspector.CSSLocation} rawLocation | |
89 * @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDel
egate | |
90 * @return {!WebInspector.CSSWorkspaceBinding.LiveLocation} | |
91 */ | |
92 createLiveLocation: function(rawLocation, updateDelegate) | |
93 { | |
94 var header = rawLocation.styleSheetId ? rawLocation.target().cssModel.st
yleSheetHeaderForId(rawLocation.styleSheetId) : null; | |
95 return new WebInspector.CSSWorkspaceBinding.LiveLocation(rawLocation.tar
get().cssModel, header, rawLocation, updateDelegate); | |
96 }, | |
97 | |
98 /** | |
99 * @param {!WebInspector.CSSWorkspaceBinding.LiveLocation} location | |
100 */ | |
101 _addLiveLocation: function(location) | |
102 { | |
103 this._ensureInfoForHeader(location._header)._addLocation(location); | |
104 }, | |
105 | |
106 /** | |
107 * @param {!WebInspector.CSSWorkspaceBinding.LiveLocation} location | |
108 */ | |
109 _removeLiveLocation: function(location) | |
110 { | |
111 var info = this._headerInfo(location._header); | |
112 if (info) | |
113 info._removeLocation(location); | |
114 }, | |
115 | |
116 /** | |
117 * @param {!WebInspector.CSSProperty} cssProperty | |
118 * @param {boolean} forName | |
119 * @return {?WebInspector.UILocation} | |
120 */ | |
121 propertyUILocation: function(cssProperty, forName) | |
122 { | |
123 var style = cssProperty.ownerStyle; | |
124 if (!style || !style.parentRule || !style.styleSheetId) | |
125 return null; | |
126 | |
127 var range = cssProperty.range; | |
128 if (!range) | |
129 return null; | |
130 | |
131 var url = style.parentRule.resourceURL(); | |
132 if (!url) | |
133 return null; | |
134 | |
135 var line = forName ? range.startLine : range.endLine; | |
136 // End of range is exclusive, so subtract 1 from the end offset. | |
137 var column = forName ? range.startColumn : range.endColumn - (cssPropert
y.text && cssProperty.text.endsWith(";") ? 2 : 1); | |
138 var rawLocation = new WebInspector.CSSLocation(style.target(), style.sty
leSheetId, url, line, column); | |
139 return this.rawLocationToUILocation(rawLocation); | |
140 }, | |
141 | |
142 /** | |
143 * @param {?WebInspector.CSSLocation} rawLocation | |
144 * @return {?WebInspector.UILocation} | |
145 */ | |
146 rawLocationToUILocation: function(rawLocation) | |
147 { | |
148 if (!rawLocation) | |
149 return null; | |
150 var cssModel = rawLocation.target().cssModel; | |
151 var frameIdToSheetIds = cssModel.styleSheetIdsByFrameIdForURL(rawLocatio
n.url); | |
152 if (!Object.values(frameIdToSheetIds).length) | |
153 return null; | |
154 var styleSheetIds = []; | |
155 for (var frameId in frameIdToSheetIds) | |
156 styleSheetIds = styleSheetIds.concat(frameIdToSheetIds[frameId]); | |
157 var uiLocation; | |
158 for (var i = 0; !uiLocation && i < styleSheetIds.length; ++i) { | |
159 var header = cssModel.styleSheetHeaderForId(styleSheetIds[i]); | |
160 if (!header) | |
161 continue; | |
162 var info = this._headerInfo(header); | |
163 if (info) | |
164 uiLocation = info._rawLocationToUILocation(rawLocation.lineNumbe
r, rawLocation.columnNumber); | |
165 } | |
166 return uiLocation || null; | |
167 } | |
168 } | |
169 | |
170 /** | |
171 * @constructor | |
172 * @param {!WebInspector.Target} target | |
173 * @param {!WebInspector.Workspace} workspace | |
174 * @param {!WebInspector.NetworkWorkspaceBinding} networkWorkspaceBinding | |
175 */ | |
176 WebInspector.CSSWorkspaceBinding.TargetInfo = function(target, workspace, networ
kWorkspaceBinding) | |
177 { | |
178 this._target = target; | |
179 this._workspace = workspace; | |
180 | |
181 var cssModel = target.cssModel; | |
182 this._stylesSourceMapping = new WebInspector.StylesSourceMapping(cssModel, w
orkspace); | |
183 this._sassSourceMapping = new WebInspector.SASSSourceMapping(cssModel, works
pace, networkWorkspaceBinding); | |
184 | |
185 /** @type {!StringMap.<!WebInspector.CSSWorkspaceBinding.HeaderInfo>} */ | |
186 this._headerInfoById = new StringMap(); | |
187 | |
188 cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded,
this._styleSheetAdded, this); | |
189 cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemove
d, this._styleSheetRemoved, this); | |
190 } | |
191 | |
192 WebInspector.CSSWorkspaceBinding.TargetInfo.prototype = { | |
193 /** | |
194 * @param {!WebInspector.Event} event | |
195 */ | |
196 _styleSheetAdded: function(event) | |
197 { | |
198 var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.dat
a); | |
199 this._stylesSourceMapping.addHeader(header); | |
200 this._sassSourceMapping.addHeader(header); | |
201 }, | |
202 | |
203 /** | |
204 * @param {!WebInspector.Event} event | |
205 */ | |
206 _styleSheetRemoved: function(event) | |
207 { | |
208 var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.dat
a); | |
209 this._stylesSourceMapping.removeHeader(header); | |
210 this._sassSourceMapping.removeHeader(header); | |
211 this._headerInfoById.remove(header.id); | |
212 }, | |
213 | |
214 /** | |
215 * @param {!CSSAgent.StyleSheetId} id | |
216 */ | |
217 _headerInfo: function(id) | |
218 { | |
219 return this._headerInfoById.get(id); | |
220 }, | |
221 | |
222 _ensureInfoForHeader: function(header) | |
223 { | |
224 var info = this._headerInfoById.get(header.id); | |
225 if (!info) { | |
226 info = new WebInspector.CSSWorkspaceBinding.HeaderInfo(header); | |
227 this._headerInfoById.put(header.id, info); | |
228 } | |
229 return info; | |
230 }, | |
231 | |
232 _dispose: function() | |
233 { | |
234 this._reset(); | |
235 this._target.cssModel.removeEventListener(WebInspector.CSSStyleModel.Eve
nts.StyleSheetAdded, this._styleSheetAdded, this); | |
236 this._target.cssModel.removeEventListener(WebInspector.CSSStyleModel.Eve
nts.StyleSheetRemoved, this._styleSheetRemoved, this); | |
237 }, | |
238 | |
239 _reset: function() | |
240 { | |
241 this._headerInfoById.clear(); | |
242 } | |
243 } | |
244 | |
245 /** | |
246 * @constructor | |
247 * @param {!WebInspector.CSSStyleSheetHeader} header | |
248 */ | |
249 WebInspector.CSSWorkspaceBinding.HeaderInfo = function(header) | |
250 { | |
251 this._header = header; | |
252 | |
253 /** @type {!Array.<!WebInspector.SourceMapping>} */ | |
254 this._sourceMappings = []; | |
255 | |
256 /** @type {!Set.<!WebInspector.LiveLocation>} */ | |
257 this._locations = new Set(); | |
258 } | |
259 | |
260 WebInspector.CSSWorkspaceBinding.HeaderInfo.prototype = { | |
261 /** | |
262 * @param {!WebInspector.LiveLocation} location | |
263 */ | |
264 _addLocation: function(location) | |
265 { | |
266 this._locations.add(location); | |
267 location.update(); | |
268 }, | |
269 | |
270 /** | |
271 * @param {!WebInspector.LiveLocation} location | |
272 */ | |
273 _removeLocation: function(location) | |
274 { | |
275 this._locations.remove(location); | |
276 }, | |
277 | |
278 _updateLocations: function() | |
279 { | |
280 var items = this._locations.values(); | |
281 for (var i = 0; i < items.length; ++i) | |
282 items[i].update(); | |
283 }, | |
284 | |
285 /** | |
286 * @param {number} lineNumber | |
287 * @param {number=} columnNumber | |
288 * @return {?WebInspector.UILocation} | |
289 */ | |
290 _rawLocationToUILocation: function(lineNumber, columnNumber) | |
291 { | |
292 var uiLocation = null; | |
293 var rawLocation = new WebInspector.CSSLocation(this._header.target(), th
is._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(rawLoca
tion); | |
296 return uiLocation; | |
297 }, | |
298 | |
299 /** | |
300 * @param {!WebInspector.SourceMapping} sourceMapping | |
301 */ | |
302 _pushSourceMapping: function(sourceMapping) | |
303 { | |
304 this._sourceMappings.push(sourceMapping); | |
305 this._updateLocations(); | |
306 } | |
307 } | |
308 | |
309 /** | |
310 * @constructor | |
311 * @extends {WebInspector.LiveLocation} | |
312 * @param {!WebInspector.CSSStyleModel} cssModel | |
313 * @param {?WebInspector.CSSStyleSheetHeader} header | |
314 * @param {!WebInspector.CSSLocation} rawLocation | |
315 * @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegat
e | |
316 */ | |
317 WebInspector.CSSWorkspaceBinding.LiveLocation = function(cssModel, header, rawLo
cation, updateDelegate) | |
318 { | |
319 WebInspector.LiveLocation.call(this, rawLocation, updateDelegate); | |
320 this._cssModel = cssModel; | |
321 if (!header) | |
322 this._clearStyleSheet(); | |
323 else | |
324 this._setStyleSheet(header); | |
325 } | |
326 | |
327 WebInspector.CSSWorkspaceBinding.LiveLocation.prototype = { | |
328 /** | |
329 * @param {!WebInspector.Event} event | |
330 */ | |
331 _styleSheetAdded: function(event) | |
332 { | |
333 console.assert(!this._header); | |
334 var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.dat
a); | |
335 if (header.sourceURL && header.sourceURL === this.rawLocation().url) | |
336 this._setStyleSheet(header); | |
337 }, | |
338 | |
339 /** | |
340 * @param {!WebInspector.Event} event | |
341 */ | |
342 _styleSheetRemoved: function(event) | |
343 { | |
344 console.assert(this._header); | |
345 var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.dat
a); | |
346 if (this._header !== header) | |
347 return; | |
348 WebInspector.cssWorkspaceBinding._removeLiveLocation(this); | |
349 this._clearStyleSheet(); | |
350 }, | |
351 | |
352 /** | |
353 * @param {!WebInspector.CSSStyleSheetHeader} header | |
354 */ | |
355 _setStyleSheet: function(header) | |
356 { | |
357 this._header = header; | |
358 WebInspector.cssWorkspaceBinding._addLiveLocation(this); | |
359 this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.Sty
leSheetAdded, this._styleSheetAdded, this); | |
360 this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleS
heetRemoved, this._styleSheetRemoved, this); | |
361 }, | |
362 | |
363 _clearStyleSheet: function() | |
364 { | |
365 delete this._header; | |
366 this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.Sty
leSheetRemoved, this._styleSheetRemoved, this); | |
367 this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleS
heetAdded, this._styleSheetAdded, this); | |
368 }, | |
369 | |
370 /** | |
371 * @return {?WebInspector.UILocation} | |
372 */ | |
373 uiLocation: function() | |
374 { | |
375 var cssLocation = /** @type WebInspector.CSSLocation */ (this.rawLocatio
n()); | |
376 if (this._header) { | |
377 var headerInfo = WebInspector.cssWorkspaceBinding._headerInfo(this._
header); | |
378 return headerInfo._rawLocationToUILocation(cssLocation.lineNumber, c
ssLocation.columnNumber); | |
379 } | |
380 var uiSourceCode = WebInspector.workspace.uiSourceCodeForURL(cssLocation
.url); | |
381 if (!uiSourceCode) | |
382 return null; | |
383 return uiSourceCode.uiLocation(cssLocation.lineNumber, cssLocation.colum
nNumber); | |
384 }, | |
385 | |
386 dispose: function() | |
387 { | |
388 WebInspector.LiveLocation.prototype.dispose.call(this); | |
389 if (this._header) | |
390 WebInspector.cssWorkspaceBinding._removeLiveLocation(this); | |
391 this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.Sty
leSheetAdded, this._styleSheetAdded, this); | |
392 this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.Sty
leSheetRemoved, this._styleSheetRemoved, this); | |
393 }, | |
394 | |
395 __proto__: WebInspector.LiveLocation.prototype | |
396 } | |
397 | |
398 /** | |
399 * @type {!WebInspector.CSSWorkspaceBinding} | |
400 */ | |
401 WebInspector.cssWorkspaceBinding; | |
OLD | NEW |