OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2012 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 /** | |
32 * @constructor | |
33 * @implements {WebInspector.SourceMapping} | |
34 * @param {!WebInspector.CSSStyleModel} cssModel | |
35 * @param {!WebInspector.Workspace} workspace | |
36 * @param {!WebInspector.NetworkWorkspaceBinding} networkWorkspaceBinding | |
37 */ | |
38 WebInspector.SASSSourceMapping = function(cssModel, workspace, networkWorkspaceB
inding) | |
39 { | |
40 this.pollPeriodMs = 5000; | |
41 this.pollIntervalMs = 200; | |
42 | |
43 this._cssModel = cssModel; | |
44 this._workspace = workspace; | |
45 this._networkWorkspaceBinding = networkWorkspaceBinding; | |
46 this._addingRevisionCounter = 0; | |
47 this._reset(); | |
48 WebInspector.fileManager.addEventListener(WebInspector.FileManager.EventType
s.SavedURL, this._fileSaveFinished, this); | |
49 WebInspector.settings.cssSourceMapsEnabled.addChangeListener(this._toggleSou
rceMapSupport, this) | |
50 this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheet
Changed, this._styleSheetChanged, this); | |
51 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeA
dded, this._uiSourceCodeAdded, this); | |
52 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeC
ontentCommitted, this._uiSourceCodeContentCommitted, this); | |
53 this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemove
d, this._reset, this); | |
54 } | |
55 | |
56 WebInspector.SASSSourceMapping.prototype = { | |
57 /** | |
58 * @param {!WebInspector.Event} event | |
59 */ | |
60 _styleSheetChanged: function(event) | |
61 { | |
62 var id = /** @type {!CSSAgent.StyleSheetId} */ (event.data.styleSheetId)
; | |
63 if (this._addingRevisionCounter) { | |
64 --this._addingRevisionCounter; | |
65 return; | |
66 } | |
67 var header = this._cssModel.styleSheetHeaderForId(id); | |
68 if (!header) | |
69 return; | |
70 | |
71 this.removeHeader(header); | |
72 }, | |
73 | |
74 /** | |
75 * @param {!WebInspector.Event} event | |
76 */ | |
77 _toggleSourceMapSupport: function(event) | |
78 { | |
79 var enabled = /** @type {boolean} */ (event.data); | |
80 var headers = this._cssModel.styleSheetHeaders(); | |
81 for (var i = 0; i < headers.length; ++i) { | |
82 if (enabled) | |
83 this.addHeader(headers[i]); | |
84 else | |
85 this.removeHeader(headers[i]); | |
86 } | |
87 }, | |
88 | |
89 /** | |
90 * @param {!WebInspector.Event} event | |
91 */ | |
92 _fileSaveFinished: function(event) | |
93 { | |
94 var sassURL = /** @type {string} */ (event.data); | |
95 this._sassFileSaved(sassURL, false); | |
96 }, | |
97 | |
98 /** | |
99 * @param {string} headerName | |
100 * @param {!NetworkAgent.Headers} headers | |
101 * @return {?string} | |
102 */ | |
103 _headerValue: function(headerName, headers) | |
104 { | |
105 headerName = headerName.toLowerCase(); | |
106 var value = null; | |
107 for (var name in headers) { | |
108 if (name.toLowerCase() === headerName) { | |
109 value = headers[name]; | |
110 break; | |
111 } | |
112 } | |
113 return value; | |
114 }, | |
115 | |
116 /** | |
117 * @param {!NetworkAgent.Headers} headers | |
118 * @return {?Date} | |
119 */ | |
120 _lastModified: function(headers) | |
121 { | |
122 var lastModifiedHeader = this._headerValue("last-modified", headers); | |
123 if (!lastModifiedHeader) | |
124 return null; | |
125 var lastModified = new Date(lastModifiedHeader); | |
126 if (isNaN(lastModified.getTime())) | |
127 return null; | |
128 return lastModified; | |
129 }, | |
130 | |
131 /** | |
132 * @param {!NetworkAgent.Headers} headers | |
133 * @param {string} url | |
134 * @return {?Date} | |
135 */ | |
136 _checkLastModified: function(headers, url) | |
137 { | |
138 var lastModified = this._lastModified(headers); | |
139 if (lastModified) | |
140 return lastModified; | |
141 | |
142 var etagMessage = this._headerValue("etag", headers) ? ", \"ETag\" respo
nse header found instead" : ""; | |
143 var message = String.sprintf("The \"Last-Modified\" response header is m
issing or invalid for %s%s. The CSS auto-reload functionality will not work corr
ectly.", url, etagMessage); | |
144 WebInspector.console.log(message); | |
145 return null; | |
146 }, | |
147 | |
148 /** | |
149 * @param {string} sassURL | |
150 * @param {boolean} wasLoadedFromFileSystem | |
151 */ | |
152 _sassFileSaved: function(sassURL, wasLoadedFromFileSystem) | |
153 { | |
154 var cssURLs = this._cssURLsForSASSURL[sassURL]; | |
155 if (!cssURLs) | |
156 return; | |
157 if (!WebInspector.settings.cssReloadEnabled.get()) | |
158 return; | |
159 | |
160 var sassFile = this._workspace.uiSourceCodeForURL(sassURL); | |
161 console.assert(sassFile); | |
162 if (wasLoadedFromFileSystem) | |
163 sassFile.requestMetadata(metadataReceived.bind(this)); | |
164 else | |
165 NetworkAgent.loadResourceForFrontend(WebInspector.resourceTreeModel.
mainFrame.id, sassURL, undefined, sassLoadedViaNetwork.bind(this)); | |
166 | |
167 /** | |
168 * @param {?Protocol.Error} error | |
169 * @param {number} statusCode | |
170 * @param {!NetworkAgent.Headers} headers | |
171 * @param {string} content | |
172 * @this {WebInspector.SASSSourceMapping} | |
173 */ | |
174 function sassLoadedViaNetwork(error, statusCode, headers, content) | |
175 { | |
176 if (error || statusCode >= 400) { | |
177 console.error("Could not load content for " + sassURL + " : " +
(error || ("HTTP status code: " + statusCode))); | |
178 return; | |
179 } | |
180 var lastModified = this._checkLastModified(headers, sassURL); | |
181 if (!lastModified) | |
182 return; | |
183 metadataReceived.call(this, lastModified); | |
184 } | |
185 | |
186 /** | |
187 * @param {?Date} timestamp | |
188 * @this {WebInspector.SASSSourceMapping} | |
189 */ | |
190 function metadataReceived(timestamp) | |
191 { | |
192 if (!timestamp) | |
193 return; | |
194 | |
195 var now = Date.now(); | |
196 var deadlineMs = now + this.pollPeriodMs; | |
197 var pollData = this._pollDataForSASSURL[sassURL]; | |
198 if (pollData) { | |
199 var dataByURL = pollData.dataByURL; | |
200 for (var url in dataByURL) | |
201 clearTimeout(dataByURL[url].timer); | |
202 } | |
203 pollData = { dataByURL: {}, deadlineMs: deadlineMs, sassTimestamp: t
imestamp }; | |
204 this._pollDataForSASSURL[sassURL] = pollData; | |
205 for (var i = 0; i < cssURLs.length; ++i) { | |
206 pollData.dataByURL[cssURLs[i]] = { previousPoll: now }; | |
207 this._pollCallback(cssURLs[i], sassURL, false); | |
208 } | |
209 } | |
210 }, | |
211 | |
212 /** | |
213 * @param {string} cssURL | |
214 * @param {string} sassURL | |
215 * @param {boolean} stopPolling | |
216 */ | |
217 _pollCallback: function(cssURL, sassURL, stopPolling) | |
218 { | |
219 var now; | |
220 var pollData = this._pollDataForSASSURL[sassURL]; | |
221 if (!pollData) | |
222 return; | |
223 | |
224 if (stopPolling || (now = new Date().getTime()) > pollData.deadlineMs) { | |
225 delete pollData.dataByURL[cssURL]; | |
226 if (!Object.keys(pollData.dataByURL).length) | |
227 delete this._pollDataForSASSURL[sassURL]; | |
228 return; | |
229 } | |
230 var nextPoll = this.pollIntervalMs + pollData.dataByURL[cssURL].previous
Poll; | |
231 var remainingTimeoutMs = Math.max(0, nextPoll - now); | |
232 pollData.dataByURL[cssURL].previousPoll = now + remainingTimeoutMs; | |
233 pollData.dataByURL[cssURL].timer = setTimeout(this._reloadCSS.bind(this,
cssURL, sassURL, this._pollCallback.bind(this)), remainingTimeoutMs); | |
234 }, | |
235 | |
236 /** | |
237 * @param {string} cssURL | |
238 * @param {string} sassURL | |
239 * @param {function(string, string, boolean)} callback | |
240 */ | |
241 _reloadCSS: function(cssURL, sassURL, callback) | |
242 { | |
243 var cssUISourceCode = this._workspace.uiSourceCodeForURL(cssURL); | |
244 if (!cssUISourceCode) { | |
245 WebInspector.console.warn(WebInspector.UIString("%s resource missing
. Please reload the page.", cssURL)); | |
246 callback(cssURL, sassURL, true); | |
247 return; | |
248 } | |
249 | |
250 if (this._workspace.hasMappingForURL(sassURL)) | |
251 this._reloadCSSFromFileSystem(cssUISourceCode, sassURL, callback); | |
252 else | |
253 this._reloadCSSFromNetwork(cssUISourceCode, sassURL, callback); | |
254 }, | |
255 | |
256 /** | |
257 * @param {!WebInspector.UISourceCode} cssUISourceCode | |
258 * @param {string} sassURL | |
259 * @param {function(string, string, boolean)} callback | |
260 */ | |
261 _reloadCSSFromNetwork: function(cssUISourceCode, sassURL, callback) | |
262 { | |
263 var cssURL = cssUISourceCode.url; | |
264 var data = this._pollDataForSASSURL[sassURL]; | |
265 if (!data) { | |
266 callback(cssURL, sassURL, true); | |
267 return; | |
268 } | |
269 var headers = { "if-modified-since": new Date(data.sassTimestamp.getTime
() - 1000).toUTCString() }; | |
270 NetworkAgent.loadResourceForFrontend(WebInspector.resourceTreeModel.main
Frame.id, cssURL, headers, contentLoaded.bind(this)); | |
271 | |
272 /** | |
273 * @param {?Protocol.Error} error | |
274 * @param {number} statusCode | |
275 * @param {!NetworkAgent.Headers} headers | |
276 * @param {string} content | |
277 * @this {WebInspector.SASSSourceMapping} | |
278 */ | |
279 function contentLoaded(error, statusCode, headers, content) | |
280 { | |
281 if (error || statusCode >= 400) { | |
282 console.error("Could not load content for " + cssURL + " : " + (
error || ("HTTP status code: " + statusCode))); | |
283 callback(cssURL, sassURL, true); | |
284 return; | |
285 } | |
286 if (!this._pollDataForSASSURL[sassURL]) { | |
287 callback(cssURL, sassURL, true); | |
288 return; | |
289 } | |
290 if (statusCode === 304) { | |
291 callback(cssURL, sassURL, false); | |
292 return; | |
293 } | |
294 var lastModified = this._checkLastModified(headers, cssURL); | |
295 if (!lastModified) { | |
296 callback(cssURL, sassURL, true); | |
297 return; | |
298 } | |
299 if (lastModified.getTime() < data.sassTimestamp.getTime()) { | |
300 callback(cssURL, sassURL, false); | |
301 return; | |
302 } | |
303 this._updateCSSRevision(cssUISourceCode, content, sassURL, callback)
; | |
304 } | |
305 }, | |
306 | |
307 /** | |
308 * @param {!WebInspector.UISourceCode} cssUISourceCode | |
309 * @param {string} content | |
310 * @param {string} sassURL | |
311 * @param {function(string, string, boolean)} callback | |
312 */ | |
313 _updateCSSRevision: function(cssUISourceCode, content, sassURL, callback) | |
314 { | |
315 ++this._addingRevisionCounter; | |
316 cssUISourceCode.addRevision(content); | |
317 this._cssUISourceCodeUpdated(cssUISourceCode.url, sassURL, callback); | |
318 }, | |
319 | |
320 /** | |
321 * @param {!WebInspector.UISourceCode} cssUISourceCode | |
322 * @param {string} sassURL | |
323 * @param {function(string, string, boolean)} callback | |
324 */ | |
325 _reloadCSSFromFileSystem: function(cssUISourceCode, sassURL, callback) | |
326 { | |
327 cssUISourceCode.requestMetadata(metadataCallback.bind(this)); | |
328 | |
329 /** | |
330 * @param {?Date} timestamp | |
331 * @this {WebInspector.SASSSourceMapping} | |
332 */ | |
333 function metadataCallback(timestamp) | |
334 { | |
335 var cssURL = cssUISourceCode.url; | |
336 if (!timestamp) { | |
337 callback(cssURL, sassURL, false); | |
338 return; | |
339 } | |
340 var cssTimestamp = timestamp.getTime(); | |
341 var pollData = this._pollDataForSASSURL[sassURL]; | |
342 if (!pollData) { | |
343 callback(cssURL, sassURL, true); | |
344 return; | |
345 } | |
346 | |
347 if (cssTimestamp < pollData.sassTimestamp.getTime()) { | |
348 callback(cssURL, sassURL, false); | |
349 return; | |
350 } | |
351 | |
352 cssUISourceCode.requestOriginalContent(contentCallback.bind(this)); | |
353 | |
354 /** | |
355 * @param {?string} content | |
356 * @this {WebInspector.SASSSourceMapping} | |
357 */ | |
358 function contentCallback(content) | |
359 { | |
360 // Empty string is a valid value, null means error. | |
361 if (content === null) | |
362 return; | |
363 this._updateCSSRevision(cssUISourceCode, content, sassURL, callb
ack); | |
364 } | |
365 } | |
366 }, | |
367 | |
368 /** | |
369 * @param {string} cssURL | |
370 * @param {string} sassURL | |
371 * @param {function(string, string, boolean)} callback | |
372 */ | |
373 _cssUISourceCodeUpdated: function(cssURL, sassURL, callback) | |
374 { | |
375 var completeSourceMapURL = this._completeSourceMapURLForCSSURL[cssURL]; | |
376 if (!completeSourceMapURL) | |
377 return; | |
378 var ids = this._cssModel.styleSheetIdsForURL(cssURL); | |
379 if (!ids) | |
380 return; | |
381 var headers = []; | |
382 for (var i = 0; i < ids.length; ++i) | |
383 headers.push(this._cssModel.styleSheetHeaderForId(ids[i])); | |
384 for (var i = 0; i < ids.length; ++i) | |
385 this._loadSourceMapAndBindUISourceCode(headers, true, completeSource
MapURL); | |
386 callback(cssURL, sassURL, true); | |
387 }, | |
388 | |
389 /** | |
390 * @param {!WebInspector.CSSStyleSheetHeader} header | |
391 */ | |
392 addHeader: function(header) | |
393 { | |
394 if (!header.sourceMapURL || !header.sourceURL || header.isInline || !Web
Inspector.settings.cssSourceMapsEnabled.get()) | |
395 return; | |
396 var completeSourceMapURL = WebInspector.ParsedURL.completeURL(header.sou
rceURL, header.sourceMapURL); | |
397 if (!completeSourceMapURL) | |
398 return; | |
399 this._completeSourceMapURLForCSSURL[header.sourceURL] = completeSourceMa
pURL; | |
400 this._loadSourceMapAndBindUISourceCode([header], false, completeSourceMa
pURL); | |
401 }, | |
402 | |
403 /** | |
404 * @param {!WebInspector.CSSStyleSheetHeader} header | |
405 */ | |
406 removeHeader: function(header) | |
407 { | |
408 var sourceURL = header.sourceURL; | |
409 if (!sourceURL || !header.sourceMapURL || header.isInline || !this._comp
leteSourceMapURLForCSSURL[sourceURL]) | |
410 return; | |
411 delete this._sourceMapByStyleSheetURL[sourceURL]; | |
412 delete this._completeSourceMapURLForCSSURL[sourceURL]; | |
413 for (var sassURL in this._cssURLsForSASSURL) { | |
414 var urls = this._cssURLsForSASSURL[sassURL]; | |
415 urls.remove(sourceURL); | |
416 if (!urls.length) | |
417 delete this._cssURLsForSASSURL[sassURL]; | |
418 } | |
419 var completeSourceMapURL = WebInspector.ParsedURL.completeURL(sourceURL,
header.sourceMapURL); | |
420 if (completeSourceMapURL) | |
421 delete this._sourceMapByURL[completeSourceMapURL]; | |
422 WebInspector.cssWorkspaceBinding.updateLocations(header); | |
423 }, | |
424 | |
425 /** | |
426 * @param {!Array.<!WebInspector.CSSStyleSheetHeader>} headersWithSameSource
URL | |
427 * @param {boolean} forceRebind | |
428 * @param {string} completeSourceMapURL | |
429 */ | |
430 _loadSourceMapAndBindUISourceCode: function(headersWithSameSourceURL, forceR
ebind, completeSourceMapURL) | |
431 { | |
432 console.assert(headersWithSameSourceURL.length); | |
433 var sourceURL = headersWithSameSourceURL[0].sourceURL; | |
434 this._loadSourceMapForStyleSheet(completeSourceMapURL, sourceURL, forceR
ebind, sourceMapLoaded.bind(this)); | |
435 | |
436 /** | |
437 * @param {?WebInspector.SourceMap} sourceMap | |
438 * @this {WebInspector.SASSSourceMapping} | |
439 */ | |
440 function sourceMapLoaded(sourceMap) | |
441 { | |
442 if (!sourceMap) | |
443 return; | |
444 | |
445 this._sourceMapByStyleSheetURL[sourceURL] = sourceMap; | |
446 for (var i = 0; i < headersWithSameSourceURL.length; ++i) { | |
447 if (forceRebind) | |
448 WebInspector.cssWorkspaceBinding.updateLocations(headersWith
SameSourceURL[i]); | |
449 else | |
450 this._bindUISourceCode(headersWithSameSourceURL[i], sourceMa
p); | |
451 } | |
452 } | |
453 }, | |
454 | |
455 /** | |
456 * @param {string} cssURL | |
457 * @param {string} sassURL | |
458 */ | |
459 _addCSSURLforSASSURL: function(cssURL, sassURL) | |
460 { | |
461 var cssURLs; | |
462 if (this._cssURLsForSASSURL.hasOwnProperty(sassURL)) | |
463 cssURLs = this._cssURLsForSASSURL[sassURL]; | |
464 else { | |
465 cssURLs = []; | |
466 this._cssURLsForSASSURL[sassURL] = cssURLs; | |
467 } | |
468 if (cssURLs.indexOf(cssURL) === -1) | |
469 cssURLs.push(cssURL); | |
470 }, | |
471 | |
472 /** | |
473 * @param {string} completeSourceMapURL | |
474 * @param {string} completeStyleSheetURL | |
475 * @param {boolean} forceReload | |
476 * @param {function(?WebInspector.SourceMap)} callback | |
477 */ | |
478 _loadSourceMapForStyleSheet: function(completeSourceMapURL, completeStyleShe
etURL, forceReload, callback) | |
479 { | |
480 var sourceMap = this._sourceMapByURL[completeSourceMapURL]; | |
481 if (sourceMap && !forceReload) { | |
482 callback(sourceMap); | |
483 return; | |
484 } | |
485 | |
486 var pendingCallbacks = this._pendingSourceMapLoadingCallbacks[completeSo
urceMapURL]; | |
487 if (pendingCallbacks) { | |
488 pendingCallbacks.push(callback); | |
489 return; | |
490 } | |
491 | |
492 pendingCallbacks = [callback]; | |
493 this._pendingSourceMapLoadingCallbacks[completeSourceMapURL] = pendingCa
llbacks; | |
494 | |
495 WebInspector.SourceMap.load(completeSourceMapURL, completeStyleSheetURL,
sourceMapLoaded.bind(this)); | |
496 | |
497 /** | |
498 * @param {?WebInspector.SourceMap} sourceMap | |
499 * @this {WebInspector.SASSSourceMapping} | |
500 */ | |
501 function sourceMapLoaded(sourceMap) | |
502 { | |
503 var callbacks = this._pendingSourceMapLoadingCallbacks[completeSourc
eMapURL]; | |
504 delete this._pendingSourceMapLoadingCallbacks[completeSourceMapURL]; | |
505 if (!callbacks) | |
506 return; | |
507 if (sourceMap) | |
508 this._sourceMapByURL[completeSourceMapURL] = sourceMap; | |
509 else | |
510 delete this._sourceMapByURL[completeSourceMapURL]; | |
511 for (var i = 0; i < callbacks.length; ++i) | |
512 callbacks[i](sourceMap); | |
513 } | |
514 }, | |
515 | |
516 /** | |
517 * @param {!WebInspector.CSSStyleSheetHeader} header | |
518 * @param {!WebInspector.SourceMap} sourceMap | |
519 */ | |
520 _bindUISourceCode: function(header, sourceMap) | |
521 { | |
522 WebInspector.cssWorkspaceBinding.pushSourceMapping(header, this); | |
523 var rawURL = header.sourceURL; | |
524 var sources = sourceMap.sources(); | |
525 for (var i = 0; i < sources.length; ++i) { | |
526 var url = sources[i]; | |
527 this._addCSSURLforSASSURL(rawURL, url); | |
528 if (!this._workspace.hasMappingForURL(url) && !this._workspace.uiSou
rceCodeForURL(url)) { | |
529 var contentProvider = sourceMap.sourceContentProvider(url, WebIn
spector.resourceTypes.Stylesheet); | |
530 this._networkWorkspaceBinding.addFileForURL(url, contentProvider
); | |
531 } | |
532 } | |
533 }, | |
534 | |
535 /** | |
536 * @param {!WebInspector.RawLocation} rawLocation | |
537 * @return {?WebInspector.UILocation} | |
538 */ | |
539 rawLocationToUILocation: function(rawLocation) | |
540 { | |
541 var location = /** @type WebInspector.CSSLocation */ (rawLocation); | |
542 var entry; | |
543 var sourceMap = this._sourceMapByStyleSheetURL[location.url]; | |
544 if (!sourceMap) | |
545 return null; | |
546 entry = sourceMap.findEntry(location.lineNumber, location.columnNumber); | |
547 if (!entry || entry.length === 2) | |
548 return null; | |
549 var uiSourceCode = this._workspace.uiSourceCodeForURL(entry[2]); | |
550 if (!uiSourceCode) | |
551 return null; | |
552 return uiSourceCode.uiLocation(entry[3], entry[4]); | |
553 }, | |
554 | |
555 /** | |
556 * @param {!WebInspector.UISourceCode} uiSourceCode | |
557 * @param {number} lineNumber | |
558 * @param {number} columnNumber | |
559 * @return {!WebInspector.RawLocation} | |
560 */ | |
561 uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber) | |
562 { | |
563 // FIXME: Implement this when ui -> raw mapping has clients. | |
564 return new WebInspector.CSSLocation(this._cssModel.target(), null, uiSou
rceCode.url || "", lineNumber, columnNumber); | |
565 }, | |
566 | |
567 /** | |
568 * @return {boolean} | |
569 */ | |
570 isIdentity: function() | |
571 { | |
572 return false; | |
573 }, | |
574 | |
575 /** | |
576 * @param {!WebInspector.UISourceCode} uiSourceCode | |
577 * @param {number} lineNumber | |
578 * @return {boolean} | |
579 */ | |
580 uiLineHasMapping: function(uiSourceCode, lineNumber) | |
581 { | |
582 return true; | |
583 }, | |
584 | |
585 /** | |
586 * @return {!WebInspector.Target} | |
587 */ | |
588 target: function() | |
589 { | |
590 return this._cssModel.target(); | |
591 }, | |
592 | |
593 /** | |
594 * @param {!WebInspector.Event} event | |
595 */ | |
596 _uiSourceCodeAdded: function(event) | |
597 { | |
598 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
); | |
599 var cssURLs = this._cssURLsForSASSURL[uiSourceCode.url]; | |
600 if (!cssURLs) | |
601 return; | |
602 for (var i = 0; i < cssURLs.length; ++i) { | |
603 var ids = this._cssModel.styleSheetIdsForURL(cssURLs[i]); | |
604 for (var j = 0; j < ids.length; ++j) { | |
605 var header = this._cssModel.styleSheetHeaderForId(ids[j]); | |
606 console.assert(header); | |
607 WebInspector.cssWorkspaceBinding.updateLocations(/** @type {!Web
Inspector.CSSStyleSheetHeader} */ (header)); | |
608 } | |
609 } | |
610 }, | |
611 | |
612 /** | |
613 * @param {!WebInspector.Event} event | |
614 */ | |
615 _uiSourceCodeContentCommitted: function(event) | |
616 { | |
617 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
.uiSourceCode); | |
618 if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSyst
em) | |
619 this._sassFileSaved(uiSourceCode.url, true); | |
620 }, | |
621 | |
622 _reset: function() | |
623 { | |
624 this._addingRevisionCounter = 0; | |
625 this._completeSourceMapURLForCSSURL = {}; | |
626 this._cssURLsForSASSURL = {}; | |
627 /** @type {!Object.<string, !Array.<function(?WebInspector.SourceMap)>>}
*/ | |
628 this._pendingSourceMapLoadingCallbacks = {}; | |
629 /** @type {!Object.<string, !{deadlineMs: number, dataByURL: !Object.<st
ring, !{timer: number, previousPoll: number}>}>} */ | |
630 this._pollDataForSASSURL = {}; | |
631 /** @type {!Object.<string, !WebInspector.SourceMap>} */ | |
632 this._sourceMapByURL = {}; | |
633 this._sourceMapByStyleSheetURL = {}; | |
634 } | |
635 } | |
OLD | NEW |