1 /* See license.txt for terms of usage */ 2 3 define([ 4 "firebug/lib/wrapper", 5 "firebug/lib/events", 6 "firebug/lib/dom", 7 ], 8 function(Wrapper, Events, Dom) { 9 10 // ********************************************************************************************* // 11 // Command Line APIs 12 13 // List of command line APIs 14 var commands = ["$", "$$", "$x", "$n", "cd", "clear", "inspect", "keys", 15 "values", "debug", "undebug", "monitor", "unmonitor", "traceCalls", "untraceCalls", 16 "traceAll", "untraceAll", "copy" /*, "memoryProfile", "memoryProfileEnd"*/]; 17 18 // List of shortcuts for some console methods 19 var consoleShortcuts = ["dir", "dirxml", "table"]; 20 21 // List of console variables. 22 var props = ["$0", "$1"]; 23 24 // Registered commands, name -> config object. 25 var userCommands = {}; 26 27 // ********************************************************************************************* // 28 // Command Line Implementation 29 30 /** 31 * Returns a command line object (bundled with passed window through closure). The object 32 * provides all necessary APIs as described here: 33 * http://getfirebug.com/wiki/index.php/Command_Line_API 34 * 35 * @param {Object} context 36 * @param {Object} win 37 */ 38 function createFirebugCommandLine(context, win) 39 { 40 var contentView = Wrapper.getContentView(win); 41 if (!contentView) 42 { 43 if (FBTrace.DBG_COMMANDLINE || FBTrace.DBG_ERRORS) 44 FBTrace.sysout("createFirebugCommandLine ERROR no contentView " + context.getName()); 45 46 return null; 47 } 48 49 // The commandLine object 50 var commandLine = { 51 __exposedProps__: {} 52 }; 53 54 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 55 // Exposed Properties 56 57 function createCommandHandler(cmd) { 58 return function() { 59 return notifyFirebug(arguments, cmd, "firebugExecuteCommand"); 60 } 61 } 62 63 function createShortcutHandler(cmd) { 64 return function() { 65 return console[cmd].apply(console, arguments); 66 } 67 } 68 69 function createVariableHandler(prop) { 70 return function() { 71 return notifyFirebug(arguments, prop, "firebugExecuteCommand"); 72 } 73 } 74 75 // Define command line methods 76 for (var i=0; i<commands.length; i++) 77 { 78 var command = commands[i]; 79 80 // If the method is already defined, don't override it. 81 if (command in contentView) 82 continue; 83 84 commandLine[command] = createCommandHandler(command); 85 commandLine.__exposedProps__[command] = "rw"; 86 } 87 88 var console = Firebug.ConsoleExposed.createFirebugConsole(context, win); 89 90 // Define shortcuts for some console methods 91 for (var i=0; i<consoleShortcuts.length; i++) 92 { 93 var command = consoleShortcuts[i]; 94 95 // If the method is already defined, don't override it. 96 if (command in contentView) 97 continue; 98 99 commandLine[command] = createShortcutHandler(command); 100 commandLine.__exposedProps__[command] = "r"; 101 } 102 103 // Define console variables. 104 for (var i=0; i<props.length; i++) 105 { 106 var prop = props[i]; 107 if (prop in contentView) 108 continue; 109 110 commandLine.__defineGetter__(prop, createVariableHandler(prop)); 111 commandLine.__exposedProps__[prop] = "r"; 112 } 113 114 // Define user registered commands. 115 for (var name in userCommands) 116 { 117 // If the method is already defined, don't override it. 118 if (name in contentView) 119 continue; 120 121 var config = userCommands[name]; 122 123 if (config.getter) 124 { 125 commandLine.__defineGetter__(name, createVariableHandler(name)); 126 commandLine.__exposedProps__[name] = "r"; 127 } 128 else 129 { 130 commandLine[name] = createCommandHandler(name); 131 commandLine.__exposedProps__[name] = "r"; 132 } 133 } 134 135 attachCommandLine(); 136 137 // xxxHonza: TODO make this private. 138 commandLine["detachCommandLine"] = detachCommandLine; 139 commandLine.__exposedProps__["detachCommandLine"] = "r"; 140 141 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 142 // Helpers (not accessible from web content) 143 144 function attachCommandLine() 145 { 146 if (FBTrace.DBG_COMMANDLINE) 147 FBTrace.sysout("commandLine.Exposed.attachCommandLine; " + window.location); 148 149 if (!contentView.console) 150 { 151 var console = createFirebugConsole(context, win); 152 contentView.console = console; 153 } 154 155 Events.addEventListener(contentView.document, "firebugCommandLine", 156 firebugEvalEvent, true); 157 } 158 159 function detachCommandLine() 160 { 161 Events.removeEventListener(contentView.document, "firebugCommandLine", 162 firebugEvalEvent, true); 163 164 // suicide! 165 delete contentView._FirebugCommandLine; 166 167 if (FBTrace.DBG_COMMANDLINE) 168 FBTrace.sysout("commandLine.Exposed.detachCommandLine; " + window.location); 169 } 170 171 function firebugEvalEvent(event) 172 { 173 if (FBTrace.DBG_COMMANDLINE) 174 FBTrace.sysout("commandLine.Exposed.firebugEvalEvent " + window.location); 175 176 // see commandLine.js 177 var expr = Dom.getMappedData(contentView.document, "firebug-expr"); 178 evaluate(expr); 179 180 if (FBTrace.DBG_COMMANDLINE) 181 FBTrace.sysout("commandLine.Exposed; did evaluate on " + expr); 182 } 183 184 function evaluate(expr) 185 { 186 try 187 { 188 var line = Components.stack.lineNumber; 189 var result = contentView.eval(expr); 190 191 // See Issue 5221 192 //var result = FirebugEvaluate(expr, contentView); 193 notifyFirebug([result], "evaluated", "firebugAppendConsole"); 194 } 195 catch (exc) 196 { 197 // change source and line number of exeptions from commandline code 198 // create new error since properties of nsIXPCException are not modifiable 199 var shouldModify, isXPCException; 200 if (exc.filename == Components.stack.filename) 201 shouldModify = isXPCException = true; 202 else if (exc.fileName == Components.stack.filename) 203 shouldModify = true; 204 205 if (shouldModify) 206 { 207 var result = new Error; 208 result.stack = null; 209 result.source = expr; 210 result.message = exc.message; 211 result.lineNumber = exc.lineNumber - line; 212 result.fileName = "data:," + encodeURIComponent(expr); 213 214 if (!isXPCException) 215 result.name = exc.name; 216 } 217 else 218 { 219 result = exc; 220 } 221 222 notifyFirebug([result], "evaluateError", "firebugAppendConsole"); 223 } 224 } 225 226 function notifyFirebug(objs, methodName, eventID) 227 { 228 var event = contentView.document.createEvent("Events"); 229 event.initEvent(eventID, true, false); 230 231 commandLine.userObjects = []; 232 for (var i=0; i<objs.length; i++) 233 commandLine.userObjects.push(objs[i]); 234 235 var length = commandLine.userObjects.length; 236 Dom.setMappedData(contentView.document, "firebug-methodName", methodName); 237 238 contentView.document.dispatchEvent(event); 239 240 if (FBTrace.DBG_COMMANDLINE) 241 { 242 FBTrace.sysout("commandLine.Exposed; dispatched event " + methodName + " via " + 243 eventID + " with " + objs.length + " user objects, [0]:" + 244 commandLine.userObjects[0]); 245 } 246 247 var result; 248 if (Dom.getMappedData(contentView.document, "firebug-retValueType") == "array") 249 result = []; 250 251 if (!result && commandLine.userObjects.length == length + 1) 252 return commandLine.userObjects[length]; 253 254 for (var i=length; i<commandLine.userObjects.length && result; i++) 255 result.push(commandLine.userObjects[i]); 256 257 return result; 258 } 259 260 return commandLine; 261 }; 262 263 /* see Issue 5221 264 // chrome: urls are filtered out by debugger, so we create script with a data url 265 // to get eval sequences in location list and 0 error ofsets 266 const evalFileSrc = "data:text/javascript,FirebugEvaluate=function(t,w)w.eval(t)"; 267 var script = document.createElementNS("http://www.w3.org/1999/xhtml", "script") 268 script.src = evalFileSrc; 269 document.documentElement.appendChild(script); 270 */ 271 272 // ********************************************************************************************* // 273 // User Commands 274 275 function registerCommand(name, config) 276 { 277 if (commands[name] || consoleShortcuts[name] || props[name] || userCommands[name]) 278 { 279 if (FBTrace.DBG_ERRORS) 280 { 281 FBTrace.sysout("firebug.registerCommand; ERROR This command is already " + 282 "registered: " + name); 283 } 284 285 return false; 286 } 287 288 userCommands[name] = config; 289 return true; 290 } 291 292 function unregisterCommand(name) 293 { 294 if (!userCommands[name]) 295 { 296 if (FBTrace.DBG_ERRORS) 297 { 298 FBTrace.sysout("firebug.unregisterCommand; ERROR This command is not " + 299 "registered: " + name); 300 } 301 302 return false; 303 } 304 305 delete userCommands[name]; 306 return true; 307 } 308 309 // ********************************************************************************************* // 310 // Registration 311 312 Firebug.CommandLineExposed = 313 { 314 createFirebugCommandLine: createFirebugCommandLine, 315 commands: commands, 316 consoleShortcuts: consoleShortcuts, 317 properties: props, 318 userCommands: userCommands, 319 registerCommand: registerCommand, 320 unregisterCommand: unregisterCommand, 321 }; 322 323 return Firebug.CommandLineExposed; 324 325 // ********************************************************************************************* // 326 }); 327