| 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 |