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 * @extends {WebInspector.Object} 34 * @implements {WebInspector.TargetManager.Observer} 35 * @param {!WebInspector.Workspace} workspace 36 */ 37 WebInspector.ScriptSnippetModel = function(workspace) 38 { 39 this._workspace = workspace; 40 /** @type {!Object.<string, !WebInspector.UISourceCode>} */ 41 this._uiSourceCodeForSnippetId = {}; 42 /** @type {!Map.<!WebInspector.UISourceCode, string>} */ 43 this._snippetIdForUISourceCode = new Map(); 44 45 /** @type {!Map.<!WebInspector.Target, !WebInspector.SnippetScriptMapping>} */ 46 this._mappingForTarget = new Map(); 47 this._snippetStorage = new WebInspector.SnippetStorage("script", "Script snippet #"); 48 this._lastSnippetEvaluationIndexSetting = WebInspector.settings.createSetting("lastSnippetEvaluationIndex", 0); 49 this._projectId = WebInspector.projectTypes.Snippets + ":"; 50 this._projectDelegate = new WebInspector.SnippetsProjectDelegate(workspace, this, this._projectId); 51 this._project = this._workspace.project(this._projectId); 52 this._loadSnippets(); 53 WebInspector.targetManager.observeTargets(this); 54 } 55 56 WebInspector.ScriptSnippetModel.prototype = { 57 58 /** 59 * @param {!WebInspector.Target} target 60 */ 61 targetAdded: function(target) 62 { 63 this._mappingForTarget.set(target, new WebInspector.SnippetScriptMapping(target, this)); 64 }, 65 66 /** 67 * @param {!WebInspector.Target} target 68 */ 69 targetRemoved: function(target) 70 { 71 this._mappingForTarget.remove(target); 72 }, 73 74 /** 75 * @param {!WebInspector.Target} target 76 * @return {!WebInspector.SnippetScriptMapping|undefined} 77 */ 78 snippetScriptMapping: function(target) { 79 return this._mappingForTarget.get(target); 80 }, 81 82 /** 83 * @param {!WebInspector.Script} script 84 */ 85 addScript: function(script) 86 { 87 this._mappingForTarget.get(script.target()).addScript(script); 88 }, 89 90 /** 91 * @param {!WebInspector.Target} target 92 * @return {!WebInspector.SnippetScriptMapping} 93 */ 94 createSnippetScriptMapping: function(target) 95 { 96 return new WebInspector.SnippetScriptMapping(target, this); 97 }, 98 99 /** 100 * @return {!WebInspector.Project} 101 */ 102 project: function() 103 { 104 return this._project; 105 }, 106 107 _loadSnippets: function() 108 { 109 var snippets = this._snippetStorage.snippets(); 110 for (var i = 0; i < snippets.length; ++i) 111 this._addScriptSnippet(snippets[i]); 112 }, 113 114 /** 115 * @param {string} content 116 * @return {string} 117 */ 118 createScriptSnippet: function(content) 119 { 120 var snippet = this._snippetStorage.createSnippet(); 121 snippet.content = content; 122 return this._addScriptSnippet(snippet); 123 }, 124 125 /** 126 * @param {!WebInspector.Snippet} snippet 127 * @return {string} 128 */ 129 _addScriptSnippet: function(snippet) 130 { 131 var path = this._projectDelegate.addSnippet(snippet.name, new WebInspector.SnippetContentProvider(snippet)); 132 var uiSourceCode = this._workspace.uiSourceCode(this._projectId, path); 133 if (!uiSourceCode) { 134 console.assert(uiSourceCode); 135 return ""; 136 } 137 uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this); 138 this._snippetIdForUISourceCode.set(uiSourceCode, snippet.id); 139 var breakpointLocations = this._removeBreakpoints(uiSourceCode); 140 this._restoreBreakpoints(uiSourceCode, breakpointLocations); 141 this._uiSourceCodeForSnippetId[snippet.id] = uiSourceCode; 142 return path; 143 }, 144 145 /** 146 * @param {!WebInspector.Event} event 147 */ 148 _workingCopyChanged: function(event) 149 { 150 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target); 151 this._scriptSnippetEdited(uiSourceCode); 152 }, 153 154 /** 155 * @param {string} path 156 */ 157 deleteScriptSnippet: function(path) 158 { 159 var uiSourceCode = this._workspace.uiSourceCode(this._projectId, path); 160 if (!uiSourceCode) 161 return; 162 var snippetId = this._snippetIdForUISourceCode.get(uiSourceCode) || ""; 163 var snippet = this._snippetStorage.snippetForId(snippetId); 164 this._snippetStorage.deleteSnippet(snippet); 165 this._removeBreakpoints(uiSourceCode); 166 this._releaseSnippetScript(uiSourceCode); 167 delete this._uiSourceCodeForSnippetId[snippet.id]; 168 this._snippetIdForUISourceCode.remove(uiSourceCode); 169 this._projectDelegate.removeFile(snippet.name); 170 }, 171 172 /** 173 * @param {string} name 174 * @param {string} newName 175 * @param {function(boolean, string=)} callback 176 */ 177 renameScriptSnippet: function(name, newName, callback) 178 { 179 newName = newName.trim(); 180 if (!newName || newName.indexOf("/") !== -1 || name === newName || this._snippetStorage.snippetForName(newName)) { 181 callback(false); 182 return; 183 } 184 var snippet = this._snippetStorage.snippetForName(name); 185 console.assert(snippet, "Snippet '" + name + "' was not found."); 186 var uiSourceCode = this._uiSourceCodeForSnippetId[snippet.id]; 187 console.assert(uiSourceCode, "No uiSourceCode was found for snippet '" + name + "'."); 188 189 var breakpointLocations = this._removeBreakpoints(uiSourceCode); 190 snippet.name = newName; 191 this._restoreBreakpoints(uiSourceCode, breakpointLocations); 192 callback(true, newName); 193 }, 194 195 /** 196 * @param {string} name 197 * @param {string} newContent 198 */ 199 _setScriptSnippetContent: function(name, newContent) 200 { 201 var snippet = this._snippetStorage.snippetForName(name); 202 snippet.content = newContent; 203 }, 204 205 /** 206 * @param {!WebInspector.UISourceCode} uiSourceCode 207 */ 208 _scriptSnippetEdited: function(uiSourceCode) 209 { 210 var breakpointLocations = this._removeBreakpoints(uiSourceCode); 211 this._releaseSnippetScript(uiSourceCode); 212 this._restoreBreakpoints(uiSourceCode, breakpointLocations); 213 this._mappingForTarget.values().forEach(function(mapping) {mapping._restoreBreakpoints(uiSourceCode, breakpointLocations)}); 214 }, 215 216 /** 217 * @return {number} 218 */ 219 _nextEvaluationIndex: function() 220 { 221 var evaluationIndex = this._lastSnippetEvaluationIndexSetting.get() + 1; 222 this._lastSnippetEvaluationIndexSetting.set(evaluationIndex); 223 return evaluationIndex; 224 }, 225 226 /** 227 * @param {!WebInspector.ExecutionContext} executionContext 228 * @param {!WebInspector.UISourceCode} uiSourceCode 229 */ 230 evaluateScriptSnippet: function(executionContext, uiSourceCode) 231 { 232 var breakpointLocations = this._removeBreakpoints(uiSourceCode); 233 this._releaseSnippetScript(uiSourceCode); 234 this._restoreBreakpoints(uiSourceCode, breakpointLocations); 235 236 var target = executionContext.target(); 237 var evaluationIndex = this._nextEvaluationIndex(); 238 var mapping = this._mappingForTarget.get(target); 239 mapping._setEvaluationIndex(evaluationIndex, uiSourceCode); 240 var evaluationUrl = mapping._evaluationSourceURL(uiSourceCode); 241 var expression = uiSourceCode.workingCopy(); 242 WebInspector.console.show(); 243 target.debuggerAgent().compileScript(expression, evaluationUrl, executionContext.id, compileCallback.bind(this, target)); 244 245 /** 246 * @param {!WebInspector.Target} target 247 * @param {?string} error 248 * @param {!DebuggerAgent.ScriptId=} scriptId 249 * @param {?DebuggerAgent.ExceptionDetails=} exceptionDetails 250 * @this {WebInspector.ScriptSnippetModel} 251 */ 252 function compileCallback(target, error, scriptId, exceptionDetails) 253 { 254 if (!uiSourceCode || this._mappingForTarget.get(target).evaluationIndex(uiSourceCode) !== evaluationIndex) 255 return; 256 257 if (error) { 258 console.error(error); 259 return; 260 } 261 262 if (!scriptId) { 263 this._printRunOrCompileScriptResultFailure(target, exceptionDetails, evaluationUrl); 264 return; 265 } 266 267 var breakpointLocations = this._removeBreakpoints(uiSourceCode); 268 this._restoreBreakpoints(uiSourceCode, breakpointLocations); 269 270 this._runScript(scriptId, executionContext, evaluationUrl); 271 } 272 }, 273 274 /** 275 * @param {!DebuggerAgent.ScriptId} scriptId 276 * @param {!WebInspector.ExecutionContext} executionContext 277 * @param {?string=} sourceURL 278 */ 279 _runScript: function(scriptId, executionContext, sourceURL) 280 { 281 var target = executionContext.target(); 282 target.debuggerAgent().runScript(scriptId, executionContext.id, "console", false, runCallback.bind(this, target)); 283 284 /** 285 * @param {!WebInspector.Target} target 286 * @param {?string} error 287 * @param {?RuntimeAgent.RemoteObject} result 288 * @param {?DebuggerAgent.ExceptionDetails=} exceptionDetails 289 * @this {WebInspector.ScriptSnippetModel} 290 */ 291 function runCallback(target, error, result, exceptionDetails) 292 { 293 if (error) { 294 console.error(error); 295 return; 296 } 297 298 if (!exceptionDetails) 299 this._printRunScriptResult(target, result, sourceURL); 300 else 301 this._printRunOrCompileScriptResultFailure(target, exceptionDetails, sourceURL); 302 } 303 }, 304 305 /** 306 * @param {!WebInspector.Target} target 307 * @param {?RuntimeAgent.RemoteObject} result 308 * @param {?string=} sourceURL 309 */ 310 _printRunScriptResult: function(target, result, sourceURL) 311 { 312 var consoleMessage = new WebInspector.ConsoleMessage( 313 target, 314 WebInspector.ConsoleMessage.MessageSource.JS, 315 WebInspector.ConsoleMessage.MessageLevel.Log, 316 "", 317 undefined, 318 sourceURL, 319 undefined, 320 undefined, 321 undefined, 322 [result], 323 undefined); 324 target.consoleModel.addMessage(consoleMessage); 325 }, 326 327 /** 328 * @param {!WebInspector.Target} target 329 * @param {?DebuggerAgent.ExceptionDetails=} exceptionDetails 330 * @param {?string=} sourceURL 331 */ 332 _printRunOrCompileScriptResultFailure: function(target, exceptionDetails, sourceURL) 333 { 334 var consoleMessage = new WebInspector.ConsoleMessage( 335 target, 336 exceptionDetails.source, 337 WebInspector.ConsoleMessage.MessageLevel.Error, 338 exceptionDetails.text, 339 undefined, 340 sourceURL, 341 exceptionDetails.line, 342 exceptionDetails.column, 343 undefined, 344 undefined, 345 exceptionDetails.stackTrace); 346 target.consoleModel.addMessage(consoleMessage); 347 }, 348 349 /** 350 * @param {!WebInspector.UISourceCode} uiSourceCode 351 * @return {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>} 352 */ 353 _removeBreakpoints: function(uiSourceCode) 354 { 355 var breakpointLocations = WebInspector.breakpointManager.breakpointLocationsForUISourceCode(uiSourceCode); 356 for (var i = 0; i < breakpointLocations.length; ++i) 357 breakpointLocations[i].breakpoint.remove(); 358 return breakpointLocations; 359 }, 360 361 /** 362 * @param {!WebInspector.UISourceCode} uiSourceCode 363 * @param {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>} breakpointLocations 364 */ 365 _restoreBreakpoints: function(uiSourceCode, breakpointLocations) 366 { 367 for (var i = 0; i < breakpointLocations.length; ++i) { 368 var uiLocation = breakpointLocations[i].uiLocation; 369 var breakpoint = breakpointLocations[i].breakpoint; 370 WebInspector.breakpointManager.setBreakpoint(uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber, breakpoint.condition(), breakpoint.enabled()); 371 } 372 }, 373 374 /** 375 * @param {!WebInspector.UISourceCode} uiSourceCode 376 */ 377 _releaseSnippetScript: function(uiSourceCode) 378 { 379 this._mappingForTarget.values().forEach(function(mapping) {mapping._releaseSnippetScript(uiSourceCode)}); 380 }, 381 382 /** 383 * @param {string} sourceURL 384 * @return {?string} 385 */ 386 _snippetIdForSourceURL: function(sourceURL) 387 { 388 var snippetPrefix = WebInspector.Script.snippetSourceURLPrefix; 389 if (!sourceURL.startsWith(snippetPrefix)) 390 return null; 391 var splitURL = sourceURL.substring(snippetPrefix.length).split("_"); 392 var snippetId = splitURL[0]; 393 return snippetId; 394 }, 395 396 __proto__: WebInspector.Object.prototype 397 } 398 399 /** 400 * @constructor 401 * @implements {WebInspector.DebuggerSourceMapping} 402 * @param {!WebInspector.Target} target 403 * @param {!WebInspector.ScriptSnippetModel} scriptSnippetModel 404 */ 405 WebInspector.SnippetScriptMapping = function(target, scriptSnippetModel) 406 { 407 this._target = target; 408 this._scriptSnippetModel = scriptSnippetModel; 409 /** @type {!Object.<string, !WebInspector.UISourceCode>} */ 410 this._uiSourceCodeForScriptId = {}; 411 /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.Script>} */ 412 this._scriptForUISourceCode = new Map(); 413 /** @type {!Map.<!WebInspector.UISourceCode, number>} */ 414 this._evaluationIndexForUISourceCode = new Map(); 415 target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._reset, this); 416 } 417 418 WebInspector.SnippetScriptMapping.prototype = { 419 /** 420 * @param {!WebInspector.UISourceCode} uiSourceCode 421 */ 422 _releaseSnippetScript: function(uiSourceCode) 423 { 424 var script = this._scriptForUISourceCode.get(uiSourceCode); 425 if (!script) 426 return; 427 428 delete this._uiSourceCodeForScriptId[script.scriptId]; 429 this._scriptForUISourceCode.remove(uiSourceCode); 430 this._evaluationIndexForUISourceCode.remove(uiSourceCode); 431 }, 432 433 /** 434 +* @param {number} evaluationIndex 435 * @param {!WebInspector.UISourceCode} uiSourceCode 436 */ 437 _setEvaluationIndex: function(evaluationIndex, uiSourceCode) 438 { 439 this._evaluationIndexForUISourceCode.set(uiSourceCode, evaluationIndex); 440 }, 441 442 /** 443 * @param {!WebInspector.UISourceCode} uiSourceCode 444 * @return {number|undefined} 445 */ 446 evaluationIndex: function(uiSourceCode) 447 { 448 return this._evaluationIndexForUISourceCode.get(uiSourceCode); 449 }, 450 451 /** 452 * @param {!WebInspector.UISourceCode} uiSourceCode 453 * @return {string} 454 */ 455 _evaluationSourceURL: function(uiSourceCode) 456 { 457 var evaluationSuffix = "_" + this._evaluationIndexForUISourceCode.get(uiSourceCode); 458 var snippetId = this._scriptSnippetModel._snippetIdForUISourceCode.get(uiSourceCode); 459 return WebInspector.Script.snippetSourceURLPrefix + snippetId + evaluationSuffix; 460 }, 461 462 _reset: function() 463 { 464 this._uiSourceCodeForScriptId = {}; 465 this._scriptForUISourceCode.clear(); 466 this._evaluationIndexForUISourceCode.clear(); 467 }, 468 469 /** 470 * @param {!WebInspector.DebuggerModel.Location} rawLocation 471 * @return {?WebInspector.UILocation} 472 */ 473 rawLocationToUILocation: function(rawLocation) 474 { 475 var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Location} */(rawLocation); 476 var uiSourceCode = this._uiSourceCodeForScriptId[debuggerModelLocation.scriptId]; 477 if (!uiSourceCode) 478 return null; 479 480 return uiSourceCode.uiLocation(debuggerModelLocation.lineNumber, debuggerModelLocation.columnNumber || 0); 481 }, 482 483 /** 484 * @param {!WebInspector.UISourceCode} uiSourceCode 485 * @param {number} lineNumber 486 * @param {number} columnNumber 487 * @return {?WebInspector.DebuggerModel.Location} 488 */ 489 uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber) 490 { 491 var script = this._scriptForUISourceCode.get(uiSourceCode); 492 if (!script) 493 return null; 494 495 return this._target.debuggerModel.createRawLocation(script, lineNumber, columnNumber); 496 }, 497 498 /** 499 * @param {string} sourceURL 500 * @return {?string} 501 */ 502 snippetIdForSourceURL: function(sourceURL) 503 { 504 return this._scriptSnippetModel._snippetIdForSourceURL(sourceURL); 505 }, 506 507 /** 508 * @param {!WebInspector.Script} script 509 */ 510 addScript: function(script) 511 { 512 var snippetId = this.snippetIdForSourceURL(script.sourceURL); 513 if (!snippetId) 514 return; 515 var uiSourceCode = this._scriptSnippetModel._uiSourceCodeForSnippetId[snippetId]; 516 517 if (!uiSourceCode || this._evaluationSourceURL(uiSourceCode) !== script.sourceURL) 518 return; 519 520 console.assert(!this._scriptForUISourceCode.get(uiSourceCode)); 521 WebInspector.debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCode, this); 522 this._uiSourceCodeForScriptId[script.scriptId] = uiSourceCode; 523 this._scriptForUISourceCode.set(uiSourceCode, script); 524 WebInspector.debuggerWorkspaceBinding.pushSourceMapping(script, this); 525 }, 526 527 /** 528 * @param {!WebInspector.UISourceCode} uiSourceCode 529 * @param {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>} breakpointLocations 530 */ 531 _restoreBreakpoints: function(uiSourceCode, breakpointLocations) 532 { 533 var script = this._scriptForUISourceCode.get(uiSourceCode); 534 if (!script) 535 return; 536 537 var rawLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (script.target().debuggerModel.createRawLocation(script, 0, 0)); 538 var scriptUISourceCode = WebInspector.debuggerWorkspaceBinding.rawLocationToUILocation(rawLocation).uiSourceCode; 539 if (scriptUISourceCode) 540 this._scriptSnippetModel._restoreBreakpoints(scriptUISourceCode, breakpointLocations); 541 }, 542 543 /** 544 * @return {boolean} 545 */ 546 isIdentity: function() 547 { 548 return false; 549 }, 550 551 /** 552 * @param {!WebInspector.UISourceCode} uiSourceCode 553 * @param {number} lineNumber 554 * @return {boolean} 555 */ 556 uiLineHasMapping: function(uiSourceCode, lineNumber) 557 { 558 return true; 559 } 560 } 561 562 /** 563 * @constructor 564 * @implements {WebInspector.ContentProvider} 565 * @param {!WebInspector.Snippet} snippet 566 */ 567 WebInspector.SnippetContentProvider = function(snippet) 568 { 569 this._snippet = snippet; 570 } 571 572 WebInspector.SnippetContentProvider.prototype = { 573 /** 574 * @return {string} 575 */ 576 contentURL: function() 577 { 578 return ""; 579 }, 580 581 /** 582 * @return {!WebInspector.ResourceType} 583 */ 584 contentType: function() 585 { 586 return WebInspector.resourceTypes.Script; 587 }, 588 589 /** 590 * @param {function(?string)} callback 591 */ 592 requestContent: function(callback) 593 { 594 callback(this._snippet.content); 595 }, 596 597 /** 598 * @param {string} query 599 * @param {boolean} caseSensitive 600 * @param {boolean} isRegex 601 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback 602 */ 603 searchInContent: function(query, caseSensitive, isRegex, callback) 604 { 605 /** 606 * @this {WebInspector.SnippetContentProvider} 607 */ 608 function performSearch() 609 { 610 callback(WebInspector.ContentProvider.performSearchInContent(this._snippet.content, query, caseSensitive, isRegex)); 611 } 612 613 // searchInContent should call back later. 614 window.setTimeout(performSearch.bind(this), 0); 615 } 616 } 617 618 /** 619 * @constructor 620 * @extends {WebInspector.ContentProviderBasedProjectDelegate} 621 * @param {!WebInspector.Workspace} workspace 622 * @param {!WebInspector.ScriptSnippetModel} model 623 * @param {string} id 624 */ 625 WebInspector.SnippetsProjectDelegate = function(workspace, model, id) 626 { 627 WebInspector.ContentProviderBasedProjectDelegate.call(this, workspace, id, WebInspector.projectTypes.Snippets); 628 this._model = model; 629 } 630 631 WebInspector.SnippetsProjectDelegate.prototype = { 632 /** 633 * @param {string} name 634 * @param {!WebInspector.ContentProvider} contentProvider 635 * @return {string} 636 */ 637 addSnippet: function(name, contentProvider) 638 { 639 return this.addContentProvider("", name, name, contentProvider); 640 }, 641 642 /** 643 * @return {boolean} 644 */ 645 canSetFileContent: function() 646 { 647 return true; 648 }, 649 650 /** 651 * @param {string} path 652 * @param {string} newContent 653 * @param {function(?string)} callback 654 */ 655 setFileContent: function(path, newContent, callback) 656 { 657 this._model._setScriptSnippetContent(path, newContent); 658 callback(""); 659 }, 660 661 /** 662 * @return {boolean} 663 */ 664 canRename: function() 665 { 666 return true; 667 }, 668 669 /** 670 * @param {string} path 671 * @param {string} newName 672 * @param {function(boolean, string=)} callback 673 */ 674 performRename: function(path, newName, callback) 675 { 676 this._model.renameScriptSnippet(path, newName, callback); 677 }, 678 679 /** 680 * @param {string} path 681 * @param {?string} name 682 * @param {string} content 683 * @param {function(?string)} callback 684 */ 685 createFile: function(path, name, content, callback) 686 { 687 var filePath = this._model.createScriptSnippet(content); 688 callback(filePath); 689 }, 690 691 /** 692 * @param {string} path 693 */ 694 deleteFile: function(path) 695 { 696 this._model.deleteScriptSnippet(path); 697 }, 698 699 __proto__: WebInspector.ContentProviderBasedProjectDelegate.prototype 700 } 701 702 /** 703 * @type {!WebInspector.ScriptSnippetModel} 704 */ 705 WebInspector.scriptSnippetModel; 706