1 /* See license.txt for terms of usage */ 2 3 FBL.ns(function() { with (FBL) { 4 5 // ************************************************************************************************ 6 // Constants 7 const Cc = Components.classes; 8 const Ci = Components.interfaces; 9 10 const commandHistoryMax = 1000; 11 const commandPrefix = ">>>"; 12 13 const reOpenBracket = /[\[\(\{]/; 14 const reCloseBracket = /[\]\)\}]/; 15 const reCmdSource = /^with\(_FirebugCommandLine\){(.*)};$/; 16 17 // ************************************************************************************************ 18 // GLobals 19 20 var commandHistory = [""]; 21 var commandPointer = 0; 22 var commandInsertPointer = -1; 23 24 // ************************************************************************************************ 25 26 Firebug.CommandLine = extend(Firebug.Module, 27 { 28 dispatchName: "commandLine", 29 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 30 31 // targetWindow was needed by evaluateInSandbox, let's leave it for a while in case we rethink this yet again 32 33 initializeCommandLineIfNeeded: function (context, win) 34 { 35 if (context == null) return; 36 if (win == null) return; 37 38 // The command-line requires that the console has been initialized first, 39 // so make sure that's so. This call should have no effect if the console 40 // is already initialized. 41 var consoleIsReady = Firebug.Console.isReadyElsePreparing(context, win); 42 43 // Make sure the command-line is initialized. This call should have no 44 // effect if the command-line is already initialized. 45 var commandLineIsReady = Firebug.CommandLine.isReadyElsePreparing(context, win); 46 47 if (FBTrace.DBG_CONSOLE) 48 FBTrace.sysout("initializeCommandLineIfNeeded console ready: "+consoleIsReady +" commandLine ready: "+commandLineIsReady); 49 }, 50 51 evaluate: function(expr, context, thisValue, targetWindow, successConsoleFunction, exceptionFunction) // returns user-level wrapped object I guess. 52 { 53 if (!context) 54 return; 55 56 var debuggerState = Firebug.Debugger.beginInternalOperation(); 57 try 58 { 59 var result = null; 60 61 if (context.stopped) 62 { 63 result = this.evaluateInDebugFrame(expr, context, thisValue, targetWindow, successConsoleFunction, exceptionFunction); 64 } 65 else 66 { 67 result = this.evaluateByEventPassing(expr, context, thisValue, targetWindow, successConsoleFunction, exceptionFunction); 68 } 69 70 context.invalidatePanels('dom', 'html'); 71 } 72 catch (exc) // XXX jjb, I don't expect this to be taken, the try here is for the finally 73 { 74 if (FBTrace.DBG_ERRORS) 75 FBTrace.sysout("CommandLine.evaluate with context.stopped:"+context.stopped+" FAILS:"+exc, exc); 76 } 77 finally 78 { 79 Firebug.Debugger.endInternalOperation(debuggerState); 80 } 81 82 return result; 83 }, 84 85 evaluateByEventPassing: function(expr, context, thisValue, targetWindow, successConsoleFunction, exceptionFunction) 86 { 87 var win = targetWindow ? targetWindow : ( context.baseWindow ? context.baseWindow : context.window ); 88 if (!win) 89 { 90 if (FBTrace.DBG_ERRORS) FBTrace.sysout("commandLine.evaluateByEventPassing: no targetWindow!\n"); 91 return; 92 } 93 94 // We're going to use some command-line facilities, but it may not have initialized yet. 95 this.initializeCommandLineIfNeeded(context, win); 96 97 // Make sure the command line script is attached. 98 var element = Firebug.Console.getFirebugConsoleElement(context, win); 99 if (element) 100 { 101 var attached = element.getAttribute("firebugCommandLineAttached"); 102 if (!attached) 103 { 104 FBTrace.sysout("Firebug console element does not have command line attached its too early for command line", element); 105 Firebug.Console.logFormatted(["Firebug cannot find firebugCommandLineAttached attribute on firebug console element, its too early for command line", element, win], context, "error", true); 106 return; 107 } 108 } 109 else 110 { 111 if (FBTrace.DBG_ERRORS) FBTrace.sysout("commandLine.evaluateByEventPassing: no firebug console element", win); 112 return; // we're in trouble here 113 } 114 115 var event = document.createEvent("Events"); 116 event.initEvent("firebugCommandLine", true, false); 117 element.setAttribute("methodName", "evaluate"); 118 119 expr = expr.toString(); 120 expr = "with(_FirebugCommandLine){" + expr + "\n};"; 121 element.setAttribute("expr", expr); 122 123 var consoleHandler; 124 for (var i=0; i<context.activeConsoleHandlers.length; i++) 125 { 126 if (context.activeConsoleHandlers[i].window == win) 127 { 128 consoleHandler = context.activeConsoleHandlers[i]; 129 break; 130 } 131 } 132 133 if (successConsoleFunction) 134 { 135 consoleHandler.evaluated = function useConsoleFunction(result) 136 { 137 successConsoleFunction(result, context); // result will be pass thru this function 138 } 139 } 140 141 if (exceptionFunction) 142 { 143 consoleHandler.evaluateError = function useExceptionFunction(result) 144 { 145 exceptionFunction(result, context); 146 } 147 } 148 else 149 { 150 consoleHandler.evaluateError = function useErrorFunction(result) 151 { 152 if (result) 153 { 154 var m = reCmdSource.exec(result.source); 155 if (m && m.length > 0) 156 result.source = m[1]; 157 } 158 159 Firebug.Console.logFormatted([result], context, "error", true); 160 } 161 } 162 163 if (FBTrace.DBG_CONSOLE) 164 FBTrace.sysout("evaluateByEventPassing \'"+expr+"\' using consoleHandler:", consoleHandler); 165 element.dispatchEvent(event); 166 if (FBTrace.DBG_CONSOLE) 167 FBTrace.sysout("evaluateByEventPassing return after firebugCommandLine event:", event); 168 }, 169 170 evaluateInDebugFrame: function(expr, context, thisValue, targetWindow, successConsoleFunction, exceptionFunction) 171 { 172 var result = null; 173 174 // targetWindow may be frame in HTML 175 var win = targetWindow ? targetWindow : ( context.baseWindow ? context.baseWindow : context.window ); 176 177 if (!context.commandLineAPI) 178 context.commandLineAPI = new FirebugCommandLineAPI(context, (win.wrappedJSObject?win.wrappedJSObject:win)); // TODO should be baseWindow 179 180 var htmlPanel = context.getPanel("html", true); 181 var scope = { 182 api : context.commandLineAPI, 183 vars : htmlPanel?htmlPanel.getInspectorVars():null, 184 thisValue : thisValue 185 }; 186 187 try 188 { 189 result = Firebug.Debugger.evaluate(expr, context, scope); 190 successConsoleFunction(result, context); // result will be pass thru this function 191 } 192 catch (e) 193 { 194 exceptionFunction(e, context); 195 } 196 return result; 197 }, 198 199 // 200 evaluateInWebPage: function(expr, context, targetWindow) 201 { 202 var win = targetWindow ? targetWindow : context.window; 203 var doc = (win.wrappedJSObject ? win.wrappedJSObject.document : win.document); 204 var element = addScript(doc, "_firebugInWebPage", expr); 205 element.parentNode.removeChild(element); // we don't need the script element, result is in DOM object 206 return "true"; 207 }, 208 209 // TODO: strip down to minimum, have one global sandbox that is reused. 210 evaluateInSandbox: function(expr, context, thisValue, targetWindow, skipNotDefinedMessages) // returns user-level wrapped object I guess. 211 { 212 // targetWindow may be frame in HTML 213 var win = targetWindow ? targetWindow : ( context.baseWindow ? context.baseWindow : context.window ); 214 215 if (!context.sandboxes) 216 context.sandboxes = []; 217 218 if (win.wrappedJSObject) // XPCNativeWrapper vs XPCSafeJSObjectWrapper 219 { 220 // in FF3.1, this path fails. 221 var sandbox = new Components.utils.Sandbox(win.location.toString()); 222 //sandbox.__proto__ = win.wrappedJSObject; 223 sandbox.__proto__ = win; 224 } 225 else 226 { 227 // in FF3.1, this path works 228 var sandbox = new Components.utils.Sandbox(win); // Use DOM Window 229 sandbox.__proto__ = win; 230 } 231 232 var scriptToEval = expr; 233 234 // If we want to use a specific |this|, wrap the expression with Function.apply() 235 // and inject the new |this| into the sandbox so it's easily accessible. 236 if (thisValue) { 237 // XXXdolske is this safe if we're recycling the sandbox? 238 sandbox.__thisValue__ = thisValue; 239 scriptToEval = "(function() { return " + scriptToEval + " \n}).apply(__thisValue__);"; 240 } 241 242 // Page scripts expect |window| to be the global object, not the 243 // sandbox object itself. Stick window into the scope chain so 244 // assignments like |foo = bar| are effectively |window.foo = 245 // bar|, else the page won't see the new value. 246 scriptToEval = "with (window?window:null) { " + scriptToEval + " \n};"; 247 248 try { 249 result = Components.utils.evalInSandbox(scriptToEval, sandbox); 250 if (FBTrace.DBG_CONSOLE) 251 FBTrace.sysout("commandLine.evaluateInSandbox success for "+win.location, scriptToEval); 252 } catch (e) { 253 if (FBTrace.DBG_ERRORS) 254 { 255 FBTrace.sysout("commandLine.evaluateInSandbox FAILED:"+e, e); 256 FBTrace.sysout("commandLine.evaluateInSandbox FAILED with [win, scriptToEval, sandbox]: "+win.location, [win, scriptToEval, sandbox]); 257 } 258 result = new FBL.ErrorMessage("commandLine.evaluateInSandbox FAILED: " + e, FBL.getDataURLForContent(scriptToEval, "FirebugCommandLineEvaluate"), e.lineNumber, 0, "js", context, null); 259 } 260 return result; 261 }, 262 263 getSandboxByWindow: function(context, win) 264 { 265 for (var i = 0; i < context.sandboxes.length; i++) { 266 // XXXdolske is accessing .window safe after untrusted script has run? 267 if (context.sandboxes[i].window === win.wrappedJSObject) 268 return context.sandboxes[i]; 269 } 270 return null; 271 }, 272 273 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 274 275 enter: function(context, command) 276 { 277 var commandLine = getCommandLine(context); 278 var expr = command ? command : commandLine.value; 279 if (expr == "") 280 return; 281 var MozJSEnabled = navigator.preference("javascript.enabled"); 282 283 if(MozJSEnabled) 284 { 285 if (!Firebug.largeCommandLine) 286 { 287 this.clear(context); 288 this.appendToHistory(expr); 289 Firebug.Console.log(commandPrefix + " " + expr, context, "command", FirebugReps.Text); 290 } 291 else 292 { 293 var shortExpr = cropString(stripNewLines(expr), 100); 294 Firebug.Console.log(commandPrefix + " " + shortExpr, context, "command", FirebugReps.Text); 295 } 296 297 var goodOrBad = FBL.bind(Firebug.Console.log, Firebug.Console); 298 299 var noscript = getNoScript(); 300 var uri = noscript && noscript.getSite(Firebug.chrome.getCurrentURI().spec); 301 302 if(noscript && !(noscript.jsEnabled || noscript.isJSEnabled(uri))) 303 { 304 305 noscript.setJSEnabled(uri, true); 306 this.evaluate(expr, context, null, null, goodOrBad); 307 noscript.setJSEnabled(uri, false); 308 } 309 else 310 this.evaluate(expr, context, null, null, goodOrBad); 311 } 312 else 313 Firebug.Console.log($STR("console.JSDisabledInFirefoxPrefs"), context, "info"); 314 }, 315 316 enterMenu: function(context) 317 { 318 var commandLine = getCommandLine(context); 319 var expr = commandLine.value; 320 if (expr == "") 321 return; 322 323 this.appendToHistory(expr, true); 324 325 this.evaluate(expr, context, null, null, function(result, context) 326 { 327 if (typeof(result) != "undefined") 328 { 329 Firebug.chrome.contextMenuObject = result; 330 331 var popup = Firebug.chrome.$("fbContextMenu"); 332 popup.showPopup(commandLine, -1, -1, "popup", "bottomleft", "topleft"); 333 } 334 }); 335 }, 336 337 enterInspect: function(context) 338 { 339 var commandLine = getCommandLine(context); 340 var expr = commandLine.value; 341 if (expr == "") 342 return; 343 344 this.clear(context); 345 this.appendToHistory(expr); 346 347 this.evaluate(expr, context, null, null, function(result, context) 348 { 349 if (typeof(result) != undefined) 350 Firebug.chrome.select(result); 351 }); 352 }, 353 354 reenter: function(context) 355 { 356 var command = commandHistory[commandInsertPointer]; 357 if (command) 358 this.enter(context, command); 359 }, 360 361 copyBookmarklet: function(context) 362 { 363 var commandLine = getCommandLine(context); 364 var expr = "javascript: " + stripNewLines(commandLine.value); 365 copyToClipboard(expr); 366 }, 367 368 focus: function(context) 369 { 370 if (Firebug.isDetached()) 371 Firebug.chrome.focus(); 372 else 373 Firebug.toggleBar(true); 374 375 if (!context.panelName) 376 Firebug.chrome.selectPanel("console"); 377 else if (context.panelName != "console") 378 { 379 Firebug.chrome.switchToPanel(context, "console"); 380 381 var commandLine = getCommandLine(context); 382 setTimeout(function() { commandLine.select(); }); 383 } 384 else // then we are already on the console, toggle back 385 { 386 Firebug.chrome.unswitchToPanel(context, "console", true); 387 } 388 }, 389 390 clear: function(context) 391 { 392 var commandLine = getCommandLine(context); 393 commandLine.value = context.commandLineText = ""; 394 this.autoCompleter.reset(); 395 }, 396 397 cancel: function(context) 398 { 399 var commandLine = getCommandLine(context); 400 if (!this.autoCompleter.revert(commandLine)) 401 this.clear(context); 402 }, 403 404 update: function(context) 405 { 406 var commandLine = getCommandLine(context); 407 context.commandLineText = commandLine.value; 408 this.autoCompleter.reset(); 409 }, 410 411 complete: function(context, reverse) 412 { 413 var commandLine = getCommandLine(context); 414 this.autoCompleter.complete(context, commandLine, true, reverse); 415 context.commandLineText = commandLine.value; 416 }, 417 418 setMultiLine: function(multiLine, chrome, saveMultiLine) 419 { 420 if (FirebugContext && FirebugContext.panelName != "console") 421 return; 422 423 collapse(chrome.$("fbCommandBox"), multiLine); 424 collapse(chrome.$("fbPanelSplitter"), !multiLine); 425 collapse(chrome.$("fbSidePanelDeck"), !multiLine); 426 427 if (multiLine) 428 chrome.$("fbSidePanelDeck").selectedPanel = chrome.$("fbLargeCommandBox"); 429 430 var commandLineSmall = chrome.$("fbCommandLine"); 431 var commandLineLarge = chrome.$("fbLargeCommandLine"); 432 433 if (saveMultiLine) // we are just closing the view 434 { 435 commandLineSmall.value = commandLineLarge.value; 436 return; 437 } 438 439 if (multiLine) 440 commandLineLarge.value = cleanIndentation(commandLineSmall.value); 441 else 442 commandLineSmall.value = stripNewLines(commandLineLarge.value); 443 }, 444 445 toggleMultiLine: function(forceLarge) 446 { 447 var large = forceLarge || !Firebug.largeCommandLine; 448 if (large != Firebug.largeCommandLine) 449 Firebug.setPref(Firebug.prefDomain, "largeCommandLine", large); 450 }, 451 452 checkOverflow: function(context) 453 { 454 if (!context) 455 return; 456 457 var commandLine = getCommandLine(context); 458 if (commandLine.value.indexOf("\n") >= 0) 459 { 460 setTimeout(bindFixed(function() 461 { 462 Firebug.setPref(Firebug.prefDomain, "largeCommandLine", true); 463 }, this)); 464 } 465 }, 466 467 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 468 469 appendToHistory: function(command, unique) 470 { 471 if (unique && commandHistory[commandInsertPointer] == command) 472 return; 473 474 ++commandInsertPointer; 475 if (commandInsertPointer >= commandHistoryMax) 476 commandInsertPointer = 0; 477 478 commandPointer = commandInsertPointer+1; 479 commandHistory[commandInsertPointer] = command; 480 }, 481 482 cycleCommandHistory: function(context, dir) 483 { 484 var commandLine = getCommandLine(context); 485 486 commandHistory[commandPointer] = commandLine.value; 487 488 if (dir < 0) 489 { 490 --commandPointer; 491 if (commandPointer < 0) 492 commandPointer = 0; 493 } 494 else 495 { 496 ++commandPointer; 497 if (commandPointer > commandInsertPointer+1) 498 commandPointer = commandInsertPointer+1; 499 } 500 501 var command = commandHistory[commandPointer]; 502 503 this.autoCompleter.reset(); 504 505 commandLine.value = context.commandLineText = command; 506 commandLine.inputField.setSelectionRange(command.length, command.length); 507 }, 508 509 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 510 // extends Module 511 512 initialize: function() 513 { 514 Firebug.Module.initialize.apply(this, arguments); 515 516 this.autoCompleter = new Firebug.AutoCompleter(getExpressionOffset, getDot, 517 autoCompleteEval, false, true); 518 519 if (Firebug.largeCommandLine) 520 this.setMultiLine(true, Firebug.chrome); 521 }, 522 523 initializeUI: function() 524 { 525 this.attachListeners(); 526 }, 527 528 reattachContext: function(browser, context) 529 { 530 this.attachListeners(); 531 }, 532 533 attachListeners: function() 534 { 535 Firebug.chrome.$("fbLargeCommandLine").addEventListener('focus', this.onCommandLineFocus, true); 536 Firebug.chrome.$("fbCommandLine").addEventListener('focus', this.onCommandLineFocus, true); 537 538 Firebug.Console.addListener(this); // to get onConsoleInjection 539 }, 540 541 showContext: function(browser, context) 542 { 543 var command = Firebug.chrome.$("cmd_focusCommandLine"); 544 command.setAttribute("disabled", !context); 545 }, 546 547 showPanel: function(browser, panel) 548 { 549 var chrome = Firebug.chrome; 550 551 var isConsole = panel && panel.name == "console"; 552 if (Firebug.largeCommandLine) 553 { 554 if (isConsole) 555 { 556 collapse(chrome.$("fbPanelSplitter"), false); 557 collapse(chrome.$("fbSidePanelDeck"), false); 558 chrome.$("fbSidePanelDeck").selectedPanel = chrome.$("fbLargeCommandBox"); 559 collapse(chrome.$("fbCommandBox"), true); 560 } 561 } 562 else 563 collapse(chrome.$("fbCommandBox"), !isConsole); 564 565 var value = panel ? panel.context.commandLineText : null; 566 var commandLine = getCommandLine(browser); 567 commandLine.value = value ? value : ""; 568 }, 569 570 updateOption: function(name, value) 571 { 572 if (name == "largeCommandLine") 573 this.setMultiLine(value, Firebug.chrome); 574 }, 575 576 // called by users of command line, currently: 577 // 1) Console on focus command line, 2) Watch onfocus, and 3) debugger loadedContext if watches exist 578 isReadyElsePreparing: function(context, win) 579 { 580 if (FBTrace.DBG_CONSOLE) 581 FBTrace.sysout("command line isReadyElsePreparing ", context); 582 583 if (win) 584 Firebug.CommandLine.injector.attachCommandLine(context, win); 585 else 586 { 587 Firebug.CommandLine.injector.attachCommandLine(context, context.window); 588 for (var i = 0; i < context.windows.length; i++) 589 Firebug.CommandLine.injector.attachCommandLine(context, context.windows[i]); 590 } 591 592 if (!context.window.wrappedJSObject) 593 { 594 FBTrace.sysout("context.window with no wrappedJSObject!", context.window); 595 return false; 596 } 597 598 // the attach is asynchronous, we can report when it is complete: 599 if (context.window.wrappedJSObject._FirebugCommandLine) 600 return true; 601 else 602 return false; 603 }, 604 605 onCommandLineFocus: function(event) 606 { 607 Firebug.CommandLine.attachConsoleOnFocus(); 608 609 if (!Firebug.CommandLine.isAttached(FirebugContext)) 610 { 611 return Firebug.CommandLine.isReadyElsePreparing(FirebugContext); 612 } 613 else 614 { 615 if (FBTrace.DBG_CONSOLE) 616 { 617 try 618 { 619 var cmdLine = FirebugContext.window.wrappedJSObject._FirebugCommandLine 620 FBTrace.sysout("onCommandLineFocus, attachCommandLine ", cmdLine); 621 } 622 catch (e) 623 { 624 FBTrace.sysout("onCommandLineFocus, did NOT attachCommandLine ", e); 625 } 626 } 627 return true; // is attached. 628 } 629 }, 630 631 isAttached: function(context) 632 { 633 return context && context.window && context.window.wrappedJSObject && context.window.wrappedJSObject._FirebugCommandLine; 634 }, 635 636 attachConsoleOnFocus: function() 637 { 638 if (!FirebugContext) 639 { 640 if (FBTrace.DBG_ERRORS) 641 FBTrace.sysout("commandLine.attachConsoleOnFocus no FirebugContext"); 642 return; 643 } 644 645 if (FBTrace.DBG_CONSOLE) 646 FBTrace.sysout("attachConsoleOnFocus: FirebugContext is "+FirebugContext.getName() +" in window "+window.location); 647 648 649 // User has decided to use the command line, but the web page may not have the console if the page has no javascript 650 if (Firebug.Console.isReadyElsePreparing(FirebugContext)) 651 { 652 // the page had _firebug so we know that consoleInjected.js compiled and ran. 653 if (FBTrace.DBG_CONSOLE) 654 { 655 if (FirebugContext) 656 FBTrace.sysout("attachConsoleOnFocus: ", (FirebugContext.window?FirebugContext.window.wrappedJSObject._firebug:"No FirebugContext.window")); 657 else 658 FBTrace.sysout("attachConsoleOnFocus: No FirebugContext\n"); 659 } 660 } 661 else 662 { 663 Firebug.Console.injector.forceConsoleCompilationInPage(FirebugContext, FirebugContext.window); 664 665 if (FBTrace.DBG_CONSOLE) 666 FBTrace.sysout("attachConsoleOnFocus, attachConsole "+FirebugContext.window.location+"\n"); 667 } 668 }, 669 670 onPanelEnable: function(panelName) 671 { 672 collapse(Firebug.chrome.$("fbCommandBox"), true); 673 collapse(Firebug.chrome.$("fbPanelSplitter"), true); 674 collapse(Firebug.chrome.$("fbSidePanelDeck"), true); 675 676 this.setMultiLine(Firebug.largeCommandLine, Firebug.chrome); 677 }, 678 679 onPanelDisable: function(panelName) 680 { 681 if (panelName != 'console') // we don't care about other panels 682 return; 683 684 collapse(Firebug.chrome.$("fbCommandBox"), true); 685 collapse(Firebug.chrome.$("fbPanelSplitter"), true); 686 collapse(Firebug.chrome.$("fbSidePanelDeck"), true); 687 }, 688 689 // ********************************************************************************************* 690 // Firebug.Console listener 691 onConsoleInjected: function(context, win) 692 { 693 // for some reason the console has been injected. If the user had focus in the command line they want it added in the page also. 694 // If the user has the cursor in the command line and reloads, the focus will already be there. issue 1339 695 var isFocused = ($("fbLargeCommandLine").getAttribute("focused") == "true"); 696 isFocused = isFocused || ($("fbCommandLine").getAttribute("focused") == "true"); 697 if (isFocused) 698 setTimeout(this.onCommandLineFocus); 699 }, 700 }); 701 702 // ************************************************************************************************ 703 // Shared Helpers 704 705 Firebug.CommandLine.CommandHandler = extend(Object, 706 { 707 handle: function(event, api, win) 708 { 709 var element = event.target; 710 var methodName = element.getAttribute("methodName"); 711 712 var hosed_userObjects = (win.wrappedJSObject?win.wrappedJSObject:win)._firebug.userObjects; 713 714 var userObjects = hosed_userObjects ? cloneArray(hosed_userObjects) : []; 715 716 if (FBTrace.DBG_CONSOLE) 717 { 718 var uid = element.getAttribute('uid'); // set if // DBG removed from Injected 719 FBTrace.sysout("Firebug.CommandLine.CommandHandler: ("+uid+") "+methodName+" userObjects:", userObjects); 720 FBTrace.sysout("Firebug.CommandLine.CommandHandler: "+(win.wrappedJSObject?"win.wrappedJSObject._firebug":"win._firebug"), (win.wrappedJSObject?win.wrappedJSObject._firebug:win._firebug)); 721 if (!userObjects) 722 debugger; 723 } 724 725 var subHandler = api[methodName]; 726 if (!subHandler) 727 return false; 728 729 element.removeAttribute("retValueType"); 730 var result = subHandler.apply(api, userObjects); 731 if (typeof result != "undefined") 732 { 733 if (result instanceof Array) 734 { 735 element.setAttribute("retValueType", "array"); 736 for (var item in result) 737 hosed_userObjects.push(result[item]); 738 } 739 else 740 { 741 hosed_userObjects.push(result); 742 } 743 } 744 745 return true; 746 } 747 }); 748 749 // ************************************************************************************************ 750 // Local Helpers 751 752 function getExpressionOffset(command, offset) 753 { 754 // XXXjoe This is kind of a poor-man's JavaScript parser - trying 755 // to find the start of the expression that the cursor is inside. 756 // Not 100% fool proof, but hey... 757 758 var bracketCount = 0; 759 760 var start = command.length-1; 761 for (; start >= 0; --start) 762 { 763 var c = command[start]; 764 if ((c == "," || c == ";" || c == " ") && !bracketCount) 765 break; 766 if (reOpenBracket.test(c)) 767 { 768 if (bracketCount) 769 --bracketCount; 770 else 771 break; 772 } 773 else if (reCloseBracket.test(c)) 774 ++bracketCount; 775 } 776 777 return start + 1; 778 } 779 780 function getDot(expr, offset) 781 { 782 var lastDot = expr.lastIndexOf("."); 783 if (lastDot == -1) 784 return null; 785 else 786 return {start: lastDot+1, end: expr.length-1}; 787 } 788 789 function autoCompleteEval(preExpr, expr, postExpr, context) 790 { 791 try 792 { 793 if (preExpr) 794 { 795 // Remove the trailing dot (if there is one) 796 var lastDot = preExpr.lastIndexOf("."); 797 if (lastDot != -1) 798 preExpr = preExpr.substr(0, lastDot); 799 800 var self = this; 801 Firebug.CommandLine.evaluate(preExpr, context, context.thisValue, null, 802 function found(result, context) 803 { 804 if (FBTrace.DBG_CONSOLE) 805 FBTrace.sysout("commandLine autoCompleteEval \'"+preExpr+"\' found result", result); 806 807 self.complete = keys(result).sort(); 808 }, 809 function failed(result, context) 810 { 811 if (FBTrace.DBG_CONSOLE) 812 FBTrace.sysout("commandLine autoCompleteEval \'"+preExpr+"\' failed result", result); 813 814 self.complete = []; 815 } 816 ); 817 return self.complete; 818 } 819 else 820 { 821 if (context.stopped) 822 return Firebug.Debugger.getCurrentFrameKeys(context); 823 else 824 return keys(context.window.wrappedJSObject).sort(); // return is safe 825 } 826 } 827 catch (exc) 828 { 829 if (FBTrace.DBG_ERRORS) 830 FBTrace.sysout("commandLine.autoCompleteEval FAILED", exc); 831 return []; 832 } 833 } 834 835 function injectScript(script, win) 836 { 837 win.location = "javascript: " + script; 838 } 839 840 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 841 842 function getCommandLine(context) 843 { 844 return Firebug.largeCommandLine 845 ? Firebug.chrome.$("fbLargeCommandLine") 846 : Firebug.chrome.$("fbCommandLine"); 847 } 848 849 const reIndent = /^(\s+)/; 850 851 function getIndent(line) 852 { 853 var m = reIndent.exec(line); 854 return m ? m[0].length : 0; 855 } 856 857 function cleanIndentation(text) 858 { 859 var lines = splitLines(text); 860 861 var minIndent = -1; 862 for (var i = 0; i < lines.length; ++i) 863 { 864 var line = lines[i]; 865 var indent = getIndent(line); 866 if (minIndent == -1 && line && !isWhitespace(line)) 867 minIndent = indent; 868 if (indent >= minIndent) 869 lines[i] = line.substr(minIndent); 870 } 871 return lines.join(""); 872 } 873 874 // ************************************************************************************************ 875 // Command line APIs definition 876 877 function FirebugCommandLineAPI(context, baseWindow) 878 { 879 this.$ = function(id) 880 { 881 var doc = baseWindow.document; 882 return baseWindow.document.getElementById(id); 883 }; 884 885 this.$$ = function(selector) 886 { 887 return FBL.getElementsBySelector(baseWindow.document, selector); 888 }; 889 890 this.$x = function(xpath) 891 { 892 return FBL.getElementsByXPath(baseWindow.document, xpath); 893 }; 894 895 this.$n = function(index) 896 { 897 var htmlPanel = context.getPanel("html", true); 898 if (!htmlPanel) 899 return null; 900 901 if (index < 0 || index >= htmlPanel.inspectorHistory.length) 902 return null; 903 904 var node = htmlPanel.inspectorHistory[index]; 905 if (!node) 906 return node; 907 908 return node.wrappedJSObject; 909 }; 910 911 this.cd = function(object) 912 { 913 if (!(object instanceof Window)) 914 throw "Object must be a window."; 915 916 // The window object parameter uses XPCSafeJSObjectWrapper, but we need XPCNativeWrapper 917 // (and its wrappedJSObject member). So, look within all registered consoleHandlers for 918 // the same window (from tabWatcher) that uses uses XPCNativeWrapper (operator "==" works). 919 for (var i=0; i<context.activeConsoleHandlers.length; i++) { 920 if (context.activeConsoleHandlers[i].window == object) { 921 baseWindow = context.baseWindow = context.activeConsoleHandlers[i].window; 922 break; 923 } 924 } 925 926 Firebug.Console.log(["Current window:", context.baseWindow], context, "info"); 927 }; 928 929 this.clear = function() 930 { 931 Firebug.Console.clear(context); 932 }; 933 934 this.inspect = function(obj, panelName) 935 { 936 Firebug.chrome.select(obj, panelName); 937 }; 938 939 this.keys = function(o) 940 { 941 return FBL.keys(o); 942 }; 943 944 this.values = function(o) 945 { 946 return FBL.values(o); 947 }; 948 949 this.debug = function(fn) 950 { 951 Firebug.Debugger.monitorFunction(fn, "debug"); 952 }; 953 954 this.undebug = function(fn) 955 { 956 Firebug.Debugger.unmonitorFunction(fn, "debug"); 957 }; 958 959 this.monitor = function(fn) 960 { 961 Firebug.Debugger.monitorFunction(fn, "monitor"); 962 }; 963 964 this.unmonitor = function(fn) 965 { 966 Firebug.Debugger.unmonitorFunction(fn, "monitor"); 967 }; 968 969 this.traceAll = function() 970 { 971 Firebug.Debugger.traceAll(FirebugContext); 972 }; 973 974 this.untraceAll = function() 975 { 976 Firebug.Debugger.untraceAll(FirebugContext); 977 }; 978 979 this.traceCalls = function(fn) 980 { 981 Firebug.Debugger.traceCalls(FirebugContext, fn); 982 }; 983 984 this.untraceCalls = function(fn) 985 { 986 Firebug.Debugger.untraceCalls(FirebugContext, fn); 987 }; 988 989 this.monitorEvents = function(object, types) 990 { 991 monitorEvents(object, types, context); 992 }; 993 994 this.unmonitorEvents = function(object, types) 995 { 996 unmonitorEvents(object, types, context); 997 }; 998 999 this.profile = function(title) 1000 { 1001 Firebug.Profiler.startProfiling(context, title); 1002 }; 1003 1004 this.profileEnd = function() 1005 { 1006 Firebug.Profiler.stopProfiling(context); 1007 }; 1008 1009 this.copy = function(x) 1010 { 1011 FBL.copyToClipboard(x); 1012 }; 1013 } 1014 1015 // ************************************************************************************************ 1016 1017 Firebug.CommandLine.injector = { 1018 1019 attachCommandLine: function(context, win) 1020 { 1021 if (!win) 1022 return; 1023 1024 // If the command line is already attached then end. 1025 var doc = win.document; 1026 if ($("_firebugCommandLineInjector", doc)) 1027 return; 1028 1029 if (context.stopped) 1030 Firebug.CommandLine.injector.evalCommandLineScript(context); 1031 else 1032 Firebug.CommandLine.injector.injectCommandLineScript(doc); 1033 1034 Firebug.CommandLine.injector.addCommandLineListener(context, win, doc); 1035 }, 1036 1037 evalCommandLineScript: function(context) 1038 { 1039 var scriptSource = getResource("chrome://firebug/content/commandLineInjected.js"); 1040 Firebug.Debugger.evaluate(scriptSource, context); 1041 if (FBTrace.DBG_CONSOLE) 1042 FBTrace.sysout("evalCommandLineScript ", scriptSource); 1043 }, 1044 1045 injectCommandLineScript: function(doc) 1046 { 1047 // Inject command line script into the page. 1048 var scriptSource = getResource("chrome://firebug/content/commandLineInjected.js"); 1049 var addedElement = addScript(doc, "_firebugCommandLineInjector", scriptSource); 1050 if (FBTrace.DBG_CONSOLE) 1051 FBTrace.sysout("injectCommandLineScript ", addedElement); 1052 }, 1053 1054 addCommandLineListener: function(context, win, doc) 1055 { 1056 // Register listener for command-line execution events. 1057 var handler = new CommandLineHandler(context, win); 1058 var element = Firebug.Console.getFirebugConsoleElement(context, win); 1059 element.addEventListener("firebugExecuteCommand", bind(handler.handleEvent, handler) , true); 1060 if (FBTrace.DBG_CONSOLE) 1061 FBTrace.sysout("addCommandLineListener to element in window with console "+win.location, win.console); 1062 } 1063 }; 1064 1065 function CommandLineHandler(context, win) 1066 { 1067 this.handleEvent = function(event) // win is the window the handler is bound into 1068 { 1069 var baseWindow = context.baseWindow? context.baseWindow : context.window; 1070 this.api = new FirebugCommandLineAPI(context, baseWindow.wrappedJSObject); 1071 1072 if (FBTrace.DBG_CONSOLE) 1073 FBTrace.sysout("commandline.handleEvent('firebugExecuteCommand') event in baseWindow "+baseWindow.location, event); 1074 1075 // Appends variables into the api. 1076 var htmlPanel = context.getPanel("html", true); 1077 var vars = htmlPanel?htmlPanel.getInspectorVars():null; 1078 for (var prop in vars) 1079 { 1080 function createHandler(p) { 1081 return function() { 1082 if (FBTrace.DBG_CONSOLE) 1083 FBTrace.sysout("commandline.getInspectorHistory: " + p, vars); 1084 return vars[p] ? vars[p].wrappedJSObject : null; 1085 } 1086 } 1087 this.api[prop] = createHandler(prop); // XXXjjb should these be removed? 1088 } 1089 1090 if (!Firebug.CommandLine.CommandHandler.handle(event, this.api, win)) 1091 { 1092 var methodName = event.target.getAttribute("methodName"); 1093 Firebug.Console.log($STRF("commandline.MethodNotSupported", [methodName])); 1094 } 1095 if (FBTrace.DBG_CONSOLE) 1096 FBTrace.sysout("commandline.handleEvent() "+event.target.getAttribute("methodName")+" context.baseWindow: "+(context.baseWindow?context.baseWindow.location:"no basewindow"), context.baseWindow); 1097 }; 1098 } 1099 1100 function getNoScript() 1101 { 1102 if (!this.noscript) 1103 this.noscript = Cc["@maone.net/noscript-service;1"] && 1104 Cc["@maone.net/noscript-service;1"].getService().wrappedJSObject; 1105 return this.noscript; 1106 } 1107 1108 // ************************************************************************************************ 1109 1110 Firebug.registerModule(Firebug.CommandLine); 1111 1112 // ************************************************************************************************ 1113 1114 }}); 1115