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.SDKObject} 34 * @param {!WebInspector.Target} target 35 * @param {!WebInspector.Workspace} workspace 36 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding 37 */ 38 WebInspector.LiveEditSupport = function(target, workspace, debuggerWorkspaceBinding) 39 { 40 WebInspector.SDKObject.call(this, target); 41 this._workspace = workspace; 42 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding; 43 this._projectId = "liveedit:" + target.id(); 44 this._projectDelegate = new WebInspector.DebuggerProjectDelegate(workspace, this._projectId, WebInspector.projectTypes.LiveEdit); 45 target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this); 46 this._debuggerReset(); 47 } 48 49 WebInspector.LiveEditSupport.prototype = { 50 /** 51 * @param {!WebInspector.UISourceCode} uiSourceCode 52 * @return {?WebInspector.UISourceCode} 53 */ 54 uiSourceCodeForLiveEdit: function(uiSourceCode) 55 { 56 var debuggerModelLocation = this._debuggerWorkspaceBinding.uiLocationToRawLocation(this.target(), uiSourceCode, 0, 0); 57 if (!debuggerModelLocation) 58 return null; 59 var uiLocation = this._debuggerWorkspaceBinding.rawLocationToUILocation(debuggerModelLocation); 60 61 // FIXME: Support live editing of scripts mapped to some file. 62 if (uiLocation.uiSourceCode !== uiSourceCode) 63 return uiLocation.uiSourceCode; 64 65 var script = debuggerModelLocation.script(); 66 if (this._uiSourceCodeForScriptId[script.scriptId]) 67 return this._uiSourceCodeForScriptId[script.scriptId]; 68 69 console.assert(!script.isInlineScript()); 70 var path = this._projectDelegate.addScript(script); 71 var liveEditUISourceCode = this._workspace.uiSourceCode(this._projectId, path); 72 73 liveEditUISourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this); 74 this._uiSourceCodeForScriptId[script.scriptId] = liveEditUISourceCode; 75 this._scriptIdForUISourceCode.set(liveEditUISourceCode, script.scriptId); 76 return liveEditUISourceCode; 77 }, 78 79 _debuggerReset: function() 80 { 81 /** @type {!Object.<string, !WebInspector.UISourceCode>} */ 82 this._uiSourceCodeForScriptId = {}; 83 /** @type {!Map.<!WebInspector.UISourceCode, string>} */ 84 this._scriptIdForUISourceCode = new Map(); 85 this._projectDelegate.reset(); 86 }, 87 88 /** 89 * @param {!WebInspector.Event} event 90 */ 91 _workingCopyCommitted: function(event) 92 { 93 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target); 94 var scriptId = /** @type {string} */ (this._scriptIdForUISourceCode.get(uiSourceCode)); 95 this.target().debuggerModel.setScriptSource(scriptId, uiSourceCode.workingCopy(), innerCallback.bind(this)); 96 97 /** 98 * @this {WebInspector.LiveEditSupport} 99 * @param {?string} error 100 * @param {!DebuggerAgent.SetScriptSourceError=} errorData 101 */ 102 function innerCallback(error, errorData) 103 { 104 if (error) { 105 var script = this.target().debuggerModel.scriptForId(scriptId); 106 WebInspector.LiveEditSupport.logDetailedError(error, errorData, script); 107 return; 108 } 109 WebInspector.LiveEditSupport.logSuccess(); 110 } 111 }, 112 113 __proto__: WebInspector.SDKObject.prototype 114 } 115 116 /** 117 * @param {!WebInspector.UISourceCode} uiSourceCode 118 * @return {?WebInspector.LiveEditSupport} 119 */ 120 WebInspector.LiveEditSupport.liveEditSupportForUISourceCode = function(uiSourceCode) 121 { 122 var projectId = uiSourceCode.project().id(); 123 var target = null; 124 var targets = WebInspector.targetManager.targets(); 125 for (var i = 0; i < targets.length; ++i) { 126 if (projectId === WebInspector.DefaultScriptMapping.projectIdForTarget(targets[i])) { 127 target = targets[i]; 128 break; 129 } 130 } 131 return target ? WebInspector.debuggerWorkspaceBinding.liveEditSupport(target) : null; 132 } 133 134 /** 135 * @param {?string} error 136 * @param {!DebuggerAgent.SetScriptSourceError=} errorData 137 * @param {!WebInspector.Script=} contextScript 138 */ 139 WebInspector.LiveEditSupport.logDetailedError = function(error, errorData, contextScript) 140 { 141 var warningLevel = WebInspector.Console.MessageLevel.Warning; 142 if (!errorData) { 143 if (error) 144 WebInspector.console.addMessage(WebInspector.UIString("LiveEdit failed: %s", error), warningLevel); 145 return; 146 } 147 var compileError = errorData.compileError; 148 if (compileError) { 149 var location = contextScript ? WebInspector.UIString(" at %s:%d:%d", contextScript.sourceURL, compileError.lineNumber, compileError.columnNumber) : ""; 150 var message = WebInspector.UIString("LiveEdit compile failed: %s%s", compileError.message, location); 151 WebInspector.console.error(message); 152 } else { 153 WebInspector.console.addMessage(WebInspector.UIString("Unknown LiveEdit error: %s; %s", JSON.stringify(errorData), error), warningLevel); 154 } 155 } 156 157 WebInspector.LiveEditSupport.logSuccess = function() 158 { 159 WebInspector.console.log(WebInspector.UIString("Recompilation and update succeeded.")); 160 } 161