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 * @interface 33 */ 34 WebInspector.ProjectSearchConfig = function() {} 35 36 WebInspector.ProjectSearchConfig.prototype = { 37 /** 38 * @return {string} 39 */ 40 query: function() { }, 41 42 /** 43 * @return {boolean} 44 */ 45 ignoreCase: function() { }, 46 47 /** 48 * @return {boolean} 49 */ 50 isRegex: function() { }, 51 52 /** 53 * @return {!Array.<string>} 54 */ 55 queries: function() { }, 56 57 /** 58 * @param {string} filePath 59 * @return {boolean} 60 */ 61 filePathMatchesFileQuery: function(filePath) { } 62 } 63 64 /** 65 * @constructor 66 * @param {string} parentPath 67 * @param {string} name 68 * @param {string} originURL 69 * @param {string} url 70 * @param {!WebInspector.ResourceType} contentType 71 */ 72 WebInspector.FileDescriptor = function(parentPath, name, originURL, url, contentType) 73 { 74 this.parentPath = parentPath; 75 this.name = name; 76 this.originURL = originURL; 77 this.url = url; 78 this.contentType = contentType; 79 } 80 81 /** 82 * @interface 83 */ 84 WebInspector.ProjectDelegate = function() { } 85 86 WebInspector.ProjectDelegate.prototype = { 87 /** 88 * @return {string} 89 */ 90 type: function() { }, 91 92 /** 93 * @return {string} 94 */ 95 displayName: function() { }, 96 97 /** 98 * @return {string} 99 */ 100 url: function() { }, 101 102 /** 103 * @param {string} path 104 * @param {function(?Date, ?number)} callback 105 */ 106 requestMetadata: function(path, callback) { }, 107 108 /** 109 * @param {string} path 110 * @param {function(?string)} callback 111 */ 112 requestFileContent: function(path, callback) { }, 113 114 /** 115 * @return {boolean} 116 */ 117 canSetFileContent: function() { }, 118 119 /** 120 * @param {string} path 121 * @param {string} newContent 122 * @param {function(?string)} callback 123 */ 124 setFileContent: function(path, newContent, callback) { }, 125 126 /** 127 * @return {boolean} 128 */ 129 canRename: function() { }, 130 131 /** 132 * @param {string} path 133 * @param {string} newName 134 * @param {function(boolean, string=, string=, string=, !WebInspector.ResourceType=)} callback 135 */ 136 rename: function(path, newName, callback) { }, 137 138 /** 139 * @param {string} path 140 * @param {function()=} callback 141 */ 142 refresh: function(path, callback) { }, 143 144 /** 145 * @param {string} path 146 */ 147 excludeFolder: function(path) { }, 148 149 /** 150 * @param {string} path 151 * @param {?string} name 152 * @param {string} content 153 * @param {function(?string)} callback 154 */ 155 createFile: function(path, name, content, callback) { }, 156 157 /** 158 * @param {string} path 159 */ 160 deleteFile: function(path) { }, 161 162 remove: function() { }, 163 164 /** 165 * @param {string} path 166 * @param {string} query 167 * @param {boolean} caseSensitive 168 * @param {boolean} isRegex 169 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback 170 */ 171 searchInFileContent: function(path, query, caseSensitive, isRegex, callback) { }, 172 173 /** 174 * @param {!WebInspector.ProjectSearchConfig} searchConfig 175 * @param {!Array.<string>} filesMathingFileQuery 176 * @param {!WebInspector.Progress} progress 177 * @param {function(!Array.<string>)} callback 178 */ 179 findFilesMatchingSearchRequest: function(searchConfig, filesMathingFileQuery, progress, callback) { }, 180 181 /** 182 * @param {!WebInspector.Progress} progress 183 */ 184 indexContent: function(progress) { } 185 } 186 187 /** 188 * @constructor 189 * @param {!WebInspector.Project} project 190 */ 191 WebInspector.ProjectStore = function(project) 192 { 193 this._project = project; 194 } 195 196 WebInspector.ProjectStore.prototype = { 197 /** 198 * @param {!WebInspector.FileDescriptor} fileDescriptor 199 */ 200 addFile: function(fileDescriptor) 201 { 202 this._project._addFile(fileDescriptor); 203 }, 204 205 /** 206 * @param {string} path 207 */ 208 removeFile: function(path) 209 { 210 this._project._removeFile(path); 211 }, 212 213 /** 214 * @return {!WebInspector.Project} 215 */ 216 project: function() 217 { 218 return this._project; 219 } 220 } 221 222 /** 223 * @constructor 224 * @extends {WebInspector.Object} 225 * @param {!WebInspector.Workspace} workspace 226 * @param {string} projectId 227 * @param {!WebInspector.ProjectDelegate} projectDelegate 228 */ 229 WebInspector.Project = function(workspace, projectId, projectDelegate) 230 { 231 /** @type {!Object.<string, !{uiSourceCode: !WebInspector.UISourceCode, index: number}>} */ 232 this._uiSourceCodesMap = {}; 233 /** @type {!Array.<!WebInspector.UISourceCode>} */ 234 this._uiSourceCodesList = []; 235 this._workspace = workspace; 236 this._projectId = projectId; 237 this._projectDelegate = projectDelegate; 238 this._url = this._projectDelegate.url(); 239 this._displayName = this._projectDelegate.displayName(); 240 } 241 242 /** 243 * @enum {string} 244 */ 245 WebInspector.Project.Events = { 246 DisplayNameUpdated: "DisplayNameUpdated" 247 }; 248 249 WebInspector.Project.prototype = { 250 /** 251 * @return {string} 252 */ 253 id: function() 254 { 255 return this._projectId; 256 }, 257 258 /** 259 * @return {string} 260 */ 261 type: function() 262 { 263 return this._projectDelegate.type(); 264 }, 265 266 /** 267 * @return {string} 268 */ 269 displayName: function() 270 { 271 return this._displayName; 272 }, 273 274 /** 275 * @param {string} displayName 276 */ 277 setDisplayName: function(displayName) 278 { 279 if (this._displayName === displayName) 280 return; 281 this._displayName = displayName; 282 this.dispatchEventToListeners(WebInspector.Project.Events.DisplayNameUpdated); 283 }, 284 285 /** 286 * @return {string} 287 */ 288 url: function() 289 { 290 return this._url; 291 }, 292 293 /** 294 * @return {boolean} 295 */ 296 isServiceProject: function() 297 { 298 return this._projectDelegate.type() === WebInspector.projectTypes.Debugger || this._projectDelegate.type() === WebInspector.projectTypes.Formatter || this._projectDelegate.type() === WebInspector.projectTypes.LiveEdit; 299 }, 300 301 /** 302 * @param {!WebInspector.FileDescriptor} fileDescriptor 303 */ 304 _addFile: function(fileDescriptor) 305 { 306 var path = fileDescriptor.parentPath ? fileDescriptor.parentPath + "/" + fileDescriptor.name : fileDescriptor.name; 307 var uiSourceCode = this.uiSourceCode(path); 308 if (uiSourceCode) 309 return; 310 311 uiSourceCode = new WebInspector.UISourceCode(this, fileDescriptor.parentPath, fileDescriptor.name, fileDescriptor.originURL, fileDescriptor.url, fileDescriptor.contentType); 312 313 this._uiSourceCodesMap[path] = {uiSourceCode: uiSourceCode, index: this._uiSourceCodesList.length}; 314 this._uiSourceCodesList.push(uiSourceCode); 315 this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.UISourceCodeAdded, uiSourceCode); 316 }, 317 318 /** 319 * @param {string} path 320 */ 321 _removeFile: function(path) 322 { 323 var uiSourceCode = this.uiSourceCode(path); 324 if (!uiSourceCode) 325 return; 326 327 var entry = this._uiSourceCodesMap[path]; 328 var movedUISourceCode = this._uiSourceCodesList[this._uiSourceCodesList.length - 1]; 329 this._uiSourceCodesList[entry.index] = movedUISourceCode; 330 var movedEntry = this._uiSourceCodesMap[movedUISourceCode.path()]; 331 movedEntry.index = entry.index; 332 this._uiSourceCodesList.splice(this._uiSourceCodesList.length - 1, 1); 333 delete this._uiSourceCodesMap[path]; 334 this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.UISourceCodeRemoved, entry.uiSourceCode); 335 }, 336 337 _remove: function() 338 { 339 this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.ProjectRemoved, this); 340 this._uiSourceCodesMap = {}; 341 this._uiSourceCodesList = []; 342 }, 343 344 /** 345 * @return {!WebInspector.Workspace} 346 */ 347 workspace: function() 348 { 349 return this._workspace; 350 }, 351 352 /** 353 * @param {string} path 354 * @return {?WebInspector.UISourceCode} 355 */ 356 uiSourceCode: function(path) 357 { 358 var entry = this._uiSourceCodesMap[path]; 359 return entry ? entry.uiSourceCode : null; 360 }, 361 362 /** 363 * @param {string} originURL 364 * @return {?WebInspector.UISourceCode} 365 */ 366 uiSourceCodeForOriginURL: function(originURL) 367 { 368 for (var i = 0; i < this._uiSourceCodesList.length; ++i) { 369 var uiSourceCode = this._uiSourceCodesList[i]; 370 if (uiSourceCode.originURL() === originURL) 371 return uiSourceCode; 372 } 373 return null; 374 }, 375 376 /** 377 * @return {!Array.<!WebInspector.UISourceCode>} 378 */ 379 uiSourceCodes: function() 380 { 381 return this._uiSourceCodesList; 382 }, 383 384 /** 385 * @param {!WebInspector.UISourceCode} uiSourceCode 386 * @param {function(?Date, ?number)} callback 387 */ 388 requestMetadata: function(uiSourceCode, callback) 389 { 390 this._projectDelegate.requestMetadata(uiSourceCode.path(), callback); 391 }, 392 393 /** 394 * @param {!WebInspector.UISourceCode} uiSourceCode 395 * @param {function(?string)} callback 396 */ 397 requestFileContent: function(uiSourceCode, callback) 398 { 399 this._projectDelegate.requestFileContent(uiSourceCode.path(), callback); 400 }, 401 402 /** 403 * @return {boolean} 404 */ 405 canSetFileContent: function() 406 { 407 return this._projectDelegate.canSetFileContent(); 408 }, 409 410 /** 411 * @param {!WebInspector.UISourceCode} uiSourceCode 412 * @param {string} newContent 413 * @param {function(?string)} callback 414 */ 415 setFileContent: function(uiSourceCode, newContent, callback) 416 { 417 this._projectDelegate.setFileContent(uiSourceCode.path(), newContent, onSetContent.bind(this)); 418 419 /** 420 * @param {?string} content 421 * @this {WebInspector.Project} 422 */ 423 function onSetContent(content) 424 { 425 this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.UISourceCodeContentCommitted, { uiSourceCode: uiSourceCode, content: newContent }); 426 callback(content); 427 } 428 }, 429 430 /** 431 * @return {boolean} 432 */ 433 canRename: function() 434 { 435 return this._projectDelegate.canRename(); 436 }, 437 438 /** 439 * @param {!WebInspector.UISourceCode} uiSourceCode 440 * @param {string} newName 441 * @param {function(boolean, string=, string=, string=, !WebInspector.ResourceType=)} callback 442 */ 443 rename: function(uiSourceCode, newName, callback) 444 { 445 if (newName === uiSourceCode.name()) { 446 callback(true, uiSourceCode.name(), uiSourceCode.url, uiSourceCode.originURL(), uiSourceCode.contentType()); 447 return; 448 } 449 450 this._projectDelegate.rename(uiSourceCode.path(), newName, innerCallback.bind(this)); 451 452 /** 453 * @param {boolean} success 454 * @param {string=} newName 455 * @param {string=} newURL 456 * @param {string=} newOriginURL 457 * @param {!WebInspector.ResourceType=} newContentType 458 * @this {WebInspector.Project} 459 */ 460 function innerCallback(success, newName, newURL, newOriginURL, newContentType) 461 { 462 if (!success || !newName) { 463 callback(false); 464 return; 465 } 466 var oldPath = uiSourceCode.path(); 467 var newPath = uiSourceCode.parentPath() ? uiSourceCode.parentPath() + "/" + newName : newName; 468 this._uiSourceCodesMap[newPath] = this._uiSourceCodesMap[oldPath]; 469 delete this._uiSourceCodesMap[oldPath]; 470 callback(true, newName, newURL, newOriginURL, newContentType); 471 } 472 }, 473 474 /** 475 * @param {string} path 476 * @param {function()=} callback 477 */ 478 refresh: function(path, callback) 479 { 480 this._projectDelegate.refresh(path, callback); 481 }, 482 483 /** 484 * @param {string} path 485 */ 486 excludeFolder: function(path) 487 { 488 this._projectDelegate.excludeFolder(path); 489 var uiSourceCodes = this._uiSourceCodesList.slice(); 490 for (var i = 0; i < uiSourceCodes.length; ++i) { 491 var uiSourceCode = uiSourceCodes[i]; 492 if (uiSourceCode.path().startsWith(path.substr(1))) 493 this._removeFile(uiSourceCode.path()); 494 } 495 }, 496 497 /** 498 * @param {string} path 499 * @param {?string} name 500 * @param {string} content 501 * @param {function(?string)} callback 502 */ 503 createFile: function(path, name, content, callback) 504 { 505 this._projectDelegate.createFile(path, name, content, innerCallback); 506 507 function innerCallback(filePath) 508 { 509 callback(filePath); 510 } 511 }, 512 513 /** 514 * @param {string} path 515 */ 516 deleteFile: function(path) 517 { 518 this._projectDelegate.deleteFile(path); 519 }, 520 521 remove: function() 522 { 523 this._projectDelegate.remove(); 524 }, 525 526 /** 527 * @param {!WebInspector.UISourceCode} uiSourceCode 528 * @param {string} query 529 * @param {boolean} caseSensitive 530 * @param {boolean} isRegex 531 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback 532 */ 533 searchInFileContent: function(uiSourceCode, query, caseSensitive, isRegex, callback) 534 { 535 this._projectDelegate.searchInFileContent(uiSourceCode.path(), query, caseSensitive, isRegex, callback); 536 }, 537 538 /** 539 * @param {!WebInspector.ProjectSearchConfig} searchConfig 540 * @param {!Array.<string>} filesMathingFileQuery 541 * @param {!WebInspector.Progress} progress 542 * @param {function(!Array.<string>)} callback 543 */ 544 findFilesMatchingSearchRequest: function(searchConfig, filesMathingFileQuery, progress, callback) 545 { 546 this._projectDelegate.findFilesMatchingSearchRequest(searchConfig, filesMathingFileQuery, progress, callback); 547 }, 548 549 /** 550 * @param {!WebInspector.Progress} progress 551 */ 552 indexContent: function(progress) 553 { 554 this._projectDelegate.indexContent(progress); 555 }, 556 557 __proto__: WebInspector.Object.prototype 558 } 559 560 /** 561 * @enum {string} 562 */ 563 WebInspector.projectTypes = { 564 Debugger: "debugger", 565 Formatter: "formatter", 566 LiveEdit: "liveedit", 567 Network: "network", 568 Snippets: "snippets", 569 FileSystem: "filesystem", 570 ContentScripts: "contentscripts" 571 } 572 573 /** 574 * @constructor 575 * @extends {WebInspector.Object} 576 * @param {!WebInspector.FileSystemMapping} fileSystemMapping 577 */ 578 WebInspector.Workspace = function(fileSystemMapping) 579 { 580 this._fileSystemMapping = fileSystemMapping; 581 /** @type {!Object.<string, !WebInspector.Project>} */ 582 this._projects = {}; 583 this._hasResourceContentTrackingExtensions = false; 584 InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.RevealSourceLine, this._revealSourceLine, this); 585 } 586 587 WebInspector.Workspace.Events = { 588 UISourceCodeAdded: "UISourceCodeAdded", 589 UISourceCodeRemoved: "UISourceCodeRemoved", 590 UISourceCodeContentCommitted: "UISourceCodeContentCommitted", 591 ProjectAdded: "ProjectAdded", 592 ProjectRemoved: "ProjectRemoved" 593 } 594 595 WebInspector.Workspace.prototype = { 596 /** 597 * @return {!Array.<!WebInspector.UISourceCode>} 598 */ 599 unsavedSourceCodes: function() 600 { 601 function filterUnsaved(sourceCode) 602 { 603 return sourceCode.isDirty(); 604 } 605 return this.uiSourceCodes().filter(filterUnsaved); 606 }, 607 608 /** 609 * @param {string} projectId 610 * @param {string} path 611 * @return {?WebInspector.UISourceCode} 612 */ 613 uiSourceCode: function(projectId, path) 614 { 615 var project = this._projects[projectId]; 616 return project ? project.uiSourceCode(path) : null; 617 }, 618 619 /** 620 * @param {string} originURL 621 * @return {?WebInspector.UISourceCode} 622 */ 623 uiSourceCodeForOriginURL: function(originURL) 624 { 625 var projects = this.projectsForType(WebInspector.projectTypes.Network); 626 projects = projects.concat(this.projectsForType(WebInspector.projectTypes.ContentScripts)); 627 for (var i = 0; i < projects.length; ++i) { 628 var project = projects[i]; 629 var uiSourceCode = project.uiSourceCodeForOriginURL(originURL); 630 if (uiSourceCode) 631 return uiSourceCode; 632 } 633 return null; 634 }, 635 636 /** 637 * @param {string} type 638 * @return {!Array.<!WebInspector.UISourceCode>} 639 */ 640 uiSourceCodesForProjectType: function(type) 641 { 642 var result = []; 643 for (var projectName in this._projects) { 644 var project = this._projects[projectName]; 645 if (project.type() === type) 646 result = result.concat(project.uiSourceCodes()); 647 } 648 return result; 649 }, 650 651 /** 652 * @param {string} projectId 653 * @param {!WebInspector.ProjectDelegate} projectDelegate 654 * @return {!WebInspector.ProjectStore} 655 */ 656 addProject: function(projectId, projectDelegate) 657 { 658 var project = new WebInspector.Project(this, projectId, projectDelegate); 659 this._projects[projectId] = project; 660 var projectStore = new WebInspector.ProjectStore(project); 661 this.dispatchEventToListeners(WebInspector.Workspace.Events.ProjectAdded, project); 662 return projectStore; 663 }, 664 665 /** 666 * @param {string} projectId 667 */ 668 removeProject: function(projectId) 669 { 670 var project = this._projects[projectId]; 671 if (!project) 672 return; 673 delete this._projects[projectId]; 674 project._remove(); 675 }, 676 677 /** 678 * @param {string} projectId 679 * @return {!WebInspector.Project} 680 */ 681 project: function(projectId) 682 { 683 return this._projects[projectId]; 684 }, 685 686 /** 687 * @return {!Array.<!WebInspector.Project>} 688 */ 689 projects: function() 690 { 691 return Object.values(this._projects); 692 }, 693 694 /** 695 * @param {string} type 696 * @return {!Array.<!WebInspector.Project>} 697 */ 698 projectsForType: function(type) 699 { 700 function filterByType(project) 701 { 702 return project.type() === type; 703 } 704 return this.projects().filter(filterByType); 705 }, 706 707 /** 708 * @return {!Array.<!WebInspector.UISourceCode>} 709 */ 710 uiSourceCodes: function() 711 { 712 var result = []; 713 for (var projectId in this._projects) { 714 var project = this._projects[projectId]; 715 result = result.concat(project.uiSourceCodes()); 716 } 717 return result; 718 }, 719 720 /** 721 * @param {string} url 722 * @return {boolean} 723 */ 724 hasMappingForURL: function(url) 725 { 726 return this._fileSystemMapping.hasMappingForURL(url); 727 }, 728 729 /** 730 * @param {string} url 731 * @return {?WebInspector.UISourceCode} 732 */ 733 _networkUISourceCodeForURL: function(url) 734 { 735 var splitURL = WebInspector.ParsedURL.splitURLIntoPathComponents(url); 736 var projectId = splitURL[0]; 737 var project = this.project(projectId); 738 return project ? project.uiSourceCode(splitURL.slice(1).join("/")) : null; 739 }, 740 741 /** 742 * @param {string} url 743 * @return {?WebInspector.UISourceCode} 744 */ 745 _contentScriptUISourceCodeForURL: function(url) 746 { 747 var splitURL = WebInspector.ParsedURL.splitURLIntoPathComponents(url); 748 var projectId = "contentscripts:" + splitURL[0]; 749 var project = this.project(projectId); 750 return project ? project.uiSourceCode(splitURL.slice(1).join("/")) : null; 751 }, 752 753 /** 754 * @param {string} url 755 * @return {?WebInspector.UISourceCode} 756 */ 757 uiSourceCodeForURL: function(url) 758 { 759 var file = this._fileSystemMapping.fileForURL(url); 760 if (!file) 761 return this._networkUISourceCodeForURL(url) || this._contentScriptUISourceCodeForURL(url); 762 763 var projectId = WebInspector.FileSystemWorkspaceBinding.projectId(file.fileSystemPath); 764 var project = this.project(projectId); 765 return project ? project.uiSourceCode(file.filePath) : null; 766 }, 767 768 /** 769 * @param {string} fileSystemPath 770 * @param {string} filePath 771 * @return {string} 772 */ 773 urlForPath: function(fileSystemPath, filePath) 774 { 775 return this._fileSystemMapping.urlForPath(fileSystemPath, filePath); 776 }, 777 778 /** 779 * @param {!WebInspector.UISourceCode} networkUISourceCode 780 * @param {!WebInspector.UISourceCode} uiSourceCode 781 * @param {!WebInspector.FileSystemWorkspaceBinding} fileSystemWorkspaceBinding 782 */ 783 addMapping: function(networkUISourceCode, uiSourceCode, fileSystemWorkspaceBinding) 784 { 785 var url = networkUISourceCode.url; 786 var path = uiSourceCode.path(); 787 var fileSystemPath = fileSystemWorkspaceBinding.fileSystemPath(uiSourceCode.project().id()); 788 this._fileSystemMapping.addMappingForResource(url, fileSystemPath, path); 789 }, 790 791 /** 792 * @param {!WebInspector.UISourceCode} uiSourceCode 793 */ 794 removeMapping: function(uiSourceCode) 795 { 796 this._fileSystemMapping.removeMappingForURL(uiSourceCode.url); 797 }, 798 799 /** 800 * @param {boolean} hasExtensions 801 */ 802 setHasResourceContentTrackingExtensions: function(hasExtensions) 803 { 804 this._hasResourceContentTrackingExtensions = hasExtensions; 805 }, 806 807 /** 808 * @return {boolean} 809 */ 810 hasResourceContentTrackingExtensions: function() 811 { 812 return this._hasResourceContentTrackingExtensions; 813 }, 814 815 /** 816 * @param {!WebInspector.Event} event 817 */ 818 _revealSourceLine: function(event) 819 { 820 var url = /** @type {string} */ (event.data["url"]); 821 var lineNumber = /** @type {number} */ (event.data["lineNumber"]); 822 var columnNumber = /** @type {number} */ (event.data["columnNumber"]); 823 824 var uiSourceCode = this.uiSourceCodeForURL(url); 825 if (uiSourceCode) { 826 WebInspector.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber)); 827 return; 828 } 829 830 /** 831 * @param {!WebInspector.Event} event 832 * @this {WebInspector.Workspace} 833 */ 834 function listener(event) 835 { 836 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); 837 if (uiSourceCode.url === url) { 838 WebInspector.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber)); 839 this.removeEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, listener, this); 840 } 841 } 842 843 this.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, listener, this); 844 }, 845 846 __proto__: WebInspector.Object.prototype 847 } 848 849 /** 850 * @type {!WebInspector.Workspace} 851 */ 852 WebInspector.workspace; 853