1 /* See license.txt for terms of usage */ 2 3 define([ 4 "firebug/lib/object", 5 "firebug/firebug", 6 "firebug/chrome/reps", 7 "firebug/lib/locale", 8 "firebug/lib/events", 9 "firebug/lib/wrapper", 10 "firebug/lib/url", 11 "firebug/lib/css", 12 "firebug/lib/dom", 13 "firebug/chrome/firefox", 14 "firebug/chrome/window", 15 "firebug/lib/system", 16 "firebug/lib/xpath", 17 "firebug/lib/string", 18 "firebug/lib/xml", 19 "firebug/lib/array", 20 "firebug/lib/persist", 21 "firebug/lib/keywords", 22 "firebug/console/console", 23 "firebug/console/commandLineHelp", 24 "firebug/console/commandLineInclude", 25 "firebug/console/commandLineExposed", 26 "firebug/console/autoCompleter", 27 "firebug/console/commandHistory" 28 ], 29 function(Obj, Firebug, FirebugReps, Locale, Events, Wrapper, Url, Css, Dom, Firefox, Win, System, 30 Xpath, Str, Xml, Arr, Persist, Keywords, Console, CommandLineHelp, 31 CommandLineInclude, CommandLineExposed) { 32 33 // ********************************************************************************************* // 34 // Constants 35 36 const Cc = Components.classes; 37 const Ci = Components.interfaces; 38 39 const commandPrefix = ">>>"; 40 const reCmdSource = /^with\(_FirebugCommandLine\){(.*)};$/; 41 42 // ********************************************************************************************* // 43 // Command Line 44 45 Firebug.CommandLine = Obj.extend(Firebug.Module, 46 { 47 dispatchName: "commandLine", 48 49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 50 51 // targetWindow was needed by evaluateInSandbox, let's leave it for a while in case 52 // we rethink this yet again 53 initializeCommandLineIfNeeded: function (context, win) 54 { 55 if (!context || !win) 56 return; 57 58 // The command-line requires that the console has been initialized first, 59 // so make sure that's so. This call should have no effect if the console 60 // is already initialized. 61 var consoleIsReady = Firebug.Console.isReadyElsePreparing(context, win); 62 63 // Make sure the command-line is initialized. This call should have no 64 // effect if the command-line is already initialized. 65 var commandLineIsReady = Firebug.CommandLine.isReadyElsePreparing(context, win); 66 67 if (FBTrace.DBG_COMMANDLINE) 68 { 69 FBTrace.sysout("commandLine.initializeCommandLineIfNeeded console ready: " + 70 consoleIsReady + " commandLine ready: " + commandLineIsReady); 71 } 72 }, 73 74 // returns user-level wrapped object I guess. 75 evaluate: function(expr, context, thisValue, targetWindow, successConsoleFunction, 76 exceptionFunction, noStateChange) 77 { 78 if (!context) 79 return; 80 81 try 82 { 83 var result = null; 84 var debuggerState = Firebug.Debugger.beginInternalOperation(); 85 86 if (this.isSandbox(context)) 87 { 88 result = this.evaluateInSandbox(expr, context, thisValue, targetWindow, 89 successConsoleFunction, exceptionFunction); 90 } 91 else if (Firebug.Debugger.hasValidStack(context)) 92 { 93 result = this.evaluateInDebugFrame(expr, context, thisValue, targetWindow, 94 successConsoleFunction, exceptionFunction); 95 } 96 else 97 { 98 result = this.evaluateByEventPassing(expr, context, thisValue, targetWindow, 99 successConsoleFunction, exceptionFunction); 100 } 101 102 if (!noStateChange) 103 context.invalidatePanels("dom", "html"); 104 } 105 catch (exc) 106 { 107 // XXX jjb, I don't expect this to be taken, the try here is for the finally 108 if (FBTrace.DBG_ERRORS && FBTrace.DBG_COMMANDLINE) 109 { 110 FBTrace.sysout("commandLine.evaluate with context.stopped:" + context.stopped + 111 " EXCEPTION " + exc, exc); 112 } 113 } 114 finally 115 { 116 Firebug.Debugger.endInternalOperation(debuggerState); 117 } 118 119 return result; 120 }, 121 122 evaluateByEventPassing: function(expr, context, thisValue, targetWindow, 123 successConsoleFunction, exceptionFunction) 124 { 125 var win = targetWindow ? targetWindow : 126 (context.baseWindow ? context.baseWindow : context.window); 127 128 if (!win) 129 { 130 if (FBTrace.DBG_ERRORS && FBTrace.DBG_COMMANDLINE) 131 FBTrace.sysout("commandLine.evaluateByEventPassing: no targetWindow!"); 132 return; 133 } 134 135 //xxxHonza: do not detach the command line here. In case where Firebug is 136 // halted in the debugger and debugging a function executed in the command line 137 // the command line handler needs to be yet used to display the return value. 138 139 // Inject commandLine APIs again. 140 this.initializeCommandLineIfNeeded(context, win); 141 142 // Make sure the command line script is attached. 143 if (!Firebug.CommandLine.isAttached(context, win)) 144 { 145 FBTrace.sysout("commandLine: document does not have command line attached " + 146 "it's too early for command line "+Win.getWindowId(win)+" location:"+ 147 Win.safeGetWindowLocation(win), document); 148 149 if (Xml.isXMLPrettyPrint(context, win)) 150 { 151 var msg = Locale.$STR("commandline.disabledForXMLDocs"); 152 var row = Firebug.Console.logFormatted([msg], context, "warn", true); 153 var objectBox = row.querySelector(".objectBox"); 154 155 // Log a message with a clickable link that can be used to enable 156 // the command line - but the page will switch into HTML. The listener 157 // passed into the function is called when the user clicks the link. 158 FirebugReps.Description.render(msg, objectBox, Obj.bind(function() 159 { 160 // Reset the flag that protect script injection into the page. 161 context.isXMLPrettyPrint = false; 162 163 // Now inject the command line. 164 Firebug.CommandLine.initializeCommandLineIfNeeded(context, win); 165 }, this)); 166 } 167 else 168 { 169 Firebug.Console.logFormatted(["Firebug cannot find firebug-CommandLineAttached " + 170 "through Dom.getMappedData, it is too early for command line", 171 win], context, "error", true); 172 } 173 return; 174 } 175 176 var event = document.createEvent("Events"); 177 event.initEvent("firebugCommandLine", true, false); 178 Dom.setMappedData(win.document, "firebug-methodName", "evaluate"); 179 180 expr = expr.toString(); 181 expr = "with(_FirebugCommandLine){\n" + expr + "\n};"; 182 Dom.setMappedData(win.document, "firebug-expr", expr); 183 184 var consoleHandler = Firebug.Console.injector.getConsoleHandler(context, win); 185 186 if (!consoleHandler) 187 { 188 FBTrace.sysout("commandLine evaluateByEventPassing no consoleHandler "+ 189 Win.safeGetWindowLocation(win)); 190 return; 191 } 192 193 if (successConsoleFunction) 194 { 195 consoleHandler.setEvaluatedCallback( function useConsoleFunction(result) 196 { 197 var ignoreReturnValue = Console.getDefaultReturnValue(win); 198 if (result === ignoreReturnValue) 199 return; 200 201 successConsoleFunction(result, context); 202 }); 203 } 204 205 if (exceptionFunction) 206 { 207 consoleHandler.setEvaluateErrorCallback(function useExceptionFunction(result) 208 { 209 exceptionFunction(result, context, "errorMessage"); 210 }); 211 } 212 else 213 { 214 consoleHandler.setEvaluateErrorCallback(function useErrorFunction(result) 215 { 216 if (result) 217 { 218 var m = reCmdSource.exec(result.source); 219 if (m && m.length > 0) 220 result.source = m[1]; 221 } 222 223 Firebug.Console.logFormatted([result], context, "error", true); 224 }); 225 } 226 227 if (FBTrace.DBG_COMMANDLINE) 228 { 229 FBTrace.sysout("commandLine.evaluateByEventPassing '" + expr + 230 "' using consoleHandler:", consoleHandler); 231 } 232 233 try 234 { 235 win.document.dispatchEvent(event); 236 237 // Clean up the command line APIs. 238 Firebug.CommandLine.injector.detachCommandLine(context, win); 239 } 240 catch(exc) 241 { 242 if (FBTrace.DBG_COMMANDLINE || FBTrace.DBG_ERRORS) 243 FBTrace.sysout("commandLine.evaluateByEventPassing dispatchEvent FAILS " + exc, 244 {exc:exc, event:event}); 245 } 246 247 if (FBTrace.DBG_COMMANDLINE) 248 { 249 FBTrace.sysout("commandLine.evaluateByEventPassing return after firebugCommandLine " + 250 "event:", event); 251 } 252 }, 253 254 evaluateInDebugFrame: function(expr, context, thisValue, targetWindow, 255 successConsoleFunction, exceptionFunction) 256 { 257 var result = null; 258 259 // targetWindow may be frame in HTML 260 var win = targetWindow ? targetWindow : 261 (context.baseWindow ? context.baseWindow : context.window); 262 263 if (!context.commandLineAPI) 264 context.commandLineAPI = new FirebugCommandLineAPI(context); 265 266 var htmlPanel = context.getPanel("html", true); 267 var scope = { 268 api : context.commandLineAPI, 269 vars : htmlPanel?htmlPanel.getInspectorVars():null, 270 thisValue : thisValue 271 }; 272 273 try 274 { 275 result = Firebug.Debugger.evaluate(expr, context, scope); 276 277 successConsoleFunction(result, context); 278 } 279 catch (e) 280 { 281 exceptionFunction(e, context); 282 } 283 284 return result; 285 }, 286 287 evaluateByPostMessage: function(expr, context, thisValue, targetWindow, 288 successConsoleFunction, exceptionFunction) 289 { 290 // targetWindow may be frame in HTML 291 var win = targetWindow ? targetWindow : 292 (context.baseWindow ? context.baseWindow : context.window); 293 294 if (!win) 295 { 296 if (FBTrace.DBG_ERRORS && FBTrace.DBG_COMMANDLINE) 297 FBTrace.sysout("commandLine.evaluateByPostMessage: no targetWindow!"); 298 return; 299 } 300 301 // We're going to use some command-line facilities, but it may not have initialized yet. 302 this.initializeCommandLineIfNeeded(context, win); 303 304 expr = expr.toString(); 305 expr = "with(_FirebugCommandLine){\n" + expr + "\n};"; 306 307 var consoleHandler = Firebug.Console.injector.getConsoleHandler(context, win); 308 309 if (!consoleHandler) 310 { 311 FBTrace.sysout("commandLine evaluateByPostMessage no consoleHandler "+ 312 Win.safeGetWindowLocation(win)); 313 return; 314 } 315 316 if (successConsoleFunction) 317 { 318 consoleHandler.setEvaluatedCallback( function useConsoleFunction(result) 319 { 320 var ignoreReturnValue = Console.getDefaultReturnValue(win); 321 if (result === ignoreReturnValue) 322 return; 323 324 successConsoleFunction(result, context); 325 }); 326 } 327 328 if (exceptionFunction) 329 { 330 consoleHandler.evaluateError = function useExceptionFunction(result) 331 { 332 exceptionFunction(result, context, "errorMessage"); 333 } 334 } 335 else 336 { 337 consoleHandler.evaluateError = function useErrorFunction(result) 338 { 339 if (result) 340 { 341 var m = reCmdSource.exec(result.source); 342 if (m && m.length > 0) 343 result.source = m[1]; 344 } 345 346 Firebug.Console.logFormatted([result], context, "error", true); 347 } 348 } 349 350 return win.postMessage(expr, "*"); 351 }, 352 353 evaluateInWebPage: function(expr, context, targetWindow) 354 { 355 var win = targetWindow ? targetWindow : 356 (context.baseWindow ? context.baseWindow : context.window); 357 var element = Dom.addScript(win.document, "_firebugInWebPage", expr); 358 if (!element) 359 return; 360 361 setTimeout(function delayRemoveScriptTag() 362 { 363 // we don't need the script element, result is in DOM object 364 if (element.parentNode) 365 element.parentNode.removeChild(element); 366 }); 367 368 return "true"; 369 }, 370 371 // isSandbox(context) true, => context.global is a Sandbox 372 evaluateInSandbox: function(expr, context, thisValue, targetWindow, successConsoleFunction, 373 exceptionFunction) 374 { 375 var result, 376 scriptToEval = expr; 377 378 try 379 { 380 result = Components.utils.evalInSandbox(scriptToEval, context.global); 381 382 if (FBTrace.DBG_COMMANDLINE) 383 FBTrace.sysout("commandLine.evaluateInSandbox success for sandbox ", scriptToEval); 384 385 successConsoleFunction(result, context); 386 } 387 catch (e) 388 { 389 if (FBTrace.DBG_ERRORS && FBTrace.DBG_COMMANDLINE) 390 FBTrace.sysout("commandLine.evaluateInSandbox FAILED in "+context.getName()+ 391 " because "+e, e); 392 393 exceptionFunction(e, context); 394 395 result = new FirebugReps.ErrorMessageObj("commandLine.evaluateInSandbox FAILED: " + e, 396 Url.getDataURLForContent(scriptToEval, "FirebugCommandLineEvaluate"), 397 e.lineNumber, 0, "js", context, null); 398 } 399 400 return result; 401 }, 402 403 isSandbox: function (context) 404 { 405 return (context.global && context.global+"" === "[object Sandbox]"); 406 }, 407 408 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 409 410 enter: function(context, command) 411 { 412 var expr = command ? command : this.getExpression(context); 413 if (expr == "") 414 return; 415 416 var mozJSEnabled = Firebug.Options.getPref("javascript", "enabled"); 417 if (!mozJSEnabled) 418 { 419 Firebug.Console.log(Locale.$STR("console.JSDisabledInFirefoxPrefs"), context, "info"); 420 return; 421 } 422 423 if (!Firebug.commandEditor || context.panelName != "console") 424 { 425 this.clear(context); 426 Firebug.Console.log(commandPrefix + " " + expr, context, "command", FirebugReps.Text); 427 } 428 else 429 { 430 var shortExpr = Str.cropString(Str.stripNewLines(expr), 100); 431 Firebug.Console.log(commandPrefix + " " + shortExpr, context, "command", 432 FirebugReps.Text); 433 } 434 435 this.commandHistory.appendToHistory(expr); 436 437 var noscript = getNoScript(); 438 if (noscript) 439 { 440 var currentURI = Firefox.getCurrentURI(); 441 var noScriptURI = currentURI ? noscript.getSite(currentURI.spec) : null; 442 if (noScriptURI) 443 noScriptURI = (noscript.jsEnabled || noscript.isJSEnabled(noScriptURI)) ? 444 null : noScriptURI; 445 } 446 447 if (noscript && noScriptURI) 448 noscript.setJSEnabled(noScriptURI, true); 449 450 var goodOrBad = Obj.bind(Firebug.Console.log, Firebug.Console); 451 this.evaluate(expr, context, null, null, goodOrBad, goodOrBad); 452 453 if (noscript && noScriptURI) 454 noscript.setJSEnabled(noScriptURI, false); 455 456 var consolePanel = Firebug.currentContext.panelMap.console; 457 if (consolePanel) 458 Dom.scrollToBottom(consolePanel.panelNode); 459 }, 460 461 enterInspect: function(context) 462 { 463 var expr = this.getCommandLine(context).value; 464 if (expr == "") 465 return; 466 467 this.clear(context); 468 this.commandHistory.appendToHistory(expr); 469 470 this.evaluate(expr, context, null, null, function(result, context) 471 { 472 if (typeof(result) != undefined) 473 Firebug.chrome.select(result); 474 }); 475 }, 476 477 reenter: function(context) 478 { 479 var command = this.commandHistory.getLastCommand(); 480 this.enter(context, command); 481 }, 482 483 copyBookmarklet: function(context) 484 { 485 // XXXsilin: This needs escaping, and stripNewLines is exactly the 486 // wrong thing to do when it comes to JavaScript. 487 var commandLine = this.getCommandLine(context); 488 var expr = "javascript: " + Str.stripNewLines(commandLine.value); 489 System.copyToClipboard(expr); 490 }, 491 492 focus: function(context) 493 { 494 if (Firebug.isDetached()) 495 Firebug.chrome.focus(); 496 else 497 Firebug.toggleBar(true); 498 499 var commandLine = this.getCommandLine(context); 500 501 if (!context.panelName) 502 { 503 Firebug.chrome.selectPanel("console"); 504 } 505 else if (context.panelName != "console") 506 { 507 this.Popup.toggle(Firebug.currentContext); 508 setTimeout(function() { commandLine.select(); }); 509 } 510 else 511 { 512 // We are already on the console, if the command line has also 513 // the focus, toggle back. But only if the UI has been already 514 // opened. 515 if (commandLine.getAttribute("focused") != "true") 516 setTimeout(function() { commandLine.select(); }); 517 } 518 }, 519 520 clear: function(context) 521 { 522 var commandLine = this.getCommandLine(context); 523 524 if (commandLine.value) 525 { 526 commandLine.value = ""; 527 this.autoCompleter.hide(); 528 this.update(context); 529 return true; 530 } 531 532 return false; 533 }, 534 535 cancel: function(context) 536 { 537 return this.clear(context); 538 }, 539 540 update: function(context) 541 { 542 var commandLine = this.getCommandLine(context); 543 context.commandLineText = commandLine.value; 544 }, 545 546 // xxxsz: setMultiLine should just be called when switching between Command Line 547 // and Command Editor 548 // xxxHonza: it is called for me when switching between the Command Line and 549 // Command Editor 550 setMultiLine: function(multiLine, chrome, saveMultiLine) 551 { 552 var context = Firebug.currentContext; 553 554 if (FBTrace.DBG_COMMANDLINE) 555 { 556 FBTrace.sysout("commandLine.setMultiline; multiLine: " + multiLine + " for: " + 557 (context ? context.getName() : "no contet")); 558 } 559 560 if (context && context.panelName != "console") 561 return; 562 563 Dom.collapse(chrome.$("fbCommandBox"), multiLine); 564 Dom.collapse(chrome.$("fbPanelSplitter"), !multiLine); 565 Dom.collapse(chrome.$("fbSidePanelDeck"), !multiLine); 566 567 if (multiLine) 568 chrome.$("fbSidePanelDeck").selectedPanel = chrome.$("fbCommandEditorBox"); 569 570 var commandLine = this.getSingleRowCommandLine(); 571 var commandEditor = this.getCommandEditor(); 572 573 // we are just closing the view 574 if (saveMultiLine) 575 { 576 commandLine.value = commandEditor.value; 577 return; 578 } 579 580 if (context) 581 { 582 var text = context.commandLineText || ""; 583 context.commandLineText = text; 584 585 if (multiLine) 586 commandEditor.value = Str.cleanIndentation(text); 587 else 588 commandLine.value = Str.stripNewLines(text); 589 } 590 // else we may be hiding a panel while turning Firebug off 591 }, 592 593 toggleMultiLine: function(forceCommandEditor) 594 { 595 var showCommandEditor = forceCommandEditor || !Firebug.commandEditor; 596 if (showCommandEditor != Firebug.commandEditor) 597 Firebug.Options.set("commandEditor", showCommandEditor); 598 }, 599 600 checkOverflow: function(context) 601 { 602 if (!context) 603 return; 604 605 var commandLine = this.getCommandLine(context); 606 if (commandLine.value.indexOf("\n") >= 0) 607 { 608 setTimeout(Obj.bindFixed(function() 609 { 610 Firebug.Options.set("commandEditor", true); 611 612 // Switch to the Console panel, where the multiline command line 613 // is actually displayed. This should be improved see issue 5146 614 Firebug.chrome.selectPanel("console"); 615 }, this)); 616 } 617 }, 618 619 onCommandLineOverflow: function(event) 620 { 621 this.checkOverflow(Firebug.currentContext); 622 }, 623 624 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 625 // extends Module 626 627 initialize: function() 628 { 629 Firebug.Module.initialize.apply(this, arguments); 630 631 this.setAutoCompleter(); 632 this.commandHistory = new Firebug.CommandHistory(); 633 634 if (Firebug.commandEditor) 635 this.setMultiLine(true, Firebug.chrome); 636 }, 637 638 // (Re)create the auto-completer for the small command line. 639 setAutoCompleter: function() 640 { 641 if (this.autoCompleter) 642 this.autoCompleter.shutdown(); 643 644 var commandLine = this.getSingleRowCommandLine(); 645 var completionBox = this.getCompletionBox(); 646 647 var options = { 648 showCompletionPopup: Firebug.Options.get("commandLineShowCompleterPopup"), 649 completionPopup: Firebug.chrome.$("fbCommandLineCompletionList"), 650 popupMeasurer: Firebug.chrome.$("fbCommandLineMeasurer"), 651 tabWarnings: true, 652 includeCurrentScope: true 653 }; 654 655 this.autoCompleter = new Firebug.JSAutoCompleter(commandLine, completionBox, options); 656 }, 657 658 initializeUI: function() 659 { 660 this.onCommandLineInput = Obj.bind(this.onCommandLineInput, this); 661 this.onCommandLineOverflow = Obj.bind(this.onCommandLineOverflow, this); 662 this.onCommandLineKeyUp = Obj.bind(this.onCommandLineKeyUp, this); 663 this.onCommandLineKeyDown = Obj.bind(this.onCommandLineKeyDown, this); 664 this.onCommandLineKeyPress = Obj.bind(this.onCommandLineKeyPress, this); 665 this.attachListeners(); 666 }, 667 668 attachListeners: function() 669 { 670 var commandLine = this.getSingleRowCommandLine(); 671 672 Events.addEventListener(commandLine, "input", this.onCommandLineInput, true); 673 Events.addEventListener(commandLine, "overflow", this.onCommandLineOverflow, true); 674 Events.addEventListener(commandLine, "keyup", this.onCommandLineKeyUp, true); 675 Events.addEventListener(commandLine, "keydown", this.onCommandLineKeyDown, true); 676 Events.addEventListener(commandLine, "keypress", this.onCommandLineKeyPress, true); 677 }, 678 679 shutdown: function() 680 { 681 var commandLine = this.getSingleRowCommandLine(); 682 683 if (this.autoCompleter) 684 this.autoCompleter.shutdown(); 685 686 if (this.commandHistory) 687 this.commandHistory.detachListeners(); 688 689 Events.removeEventListener(commandLine, "input", this.onCommandLineInput, true); 690 Events.removeEventListener(commandLine, "overflow", this.onCommandLineOverflow, true); 691 Events.removeEventListener(commandLine, "keyup", this.onCommandLineKeyUp, true); 692 Events.removeEventListener(commandLine, "keydown", this.onCommandLineKeyDown, true); 693 Events.removeEventListener(commandLine, "keypress", this.onCommandLineKeyPress, true); 694 }, 695 696 destroyContext: function(context, persistedState) 697 { 698 var panelState = Persist.getPersistedState(this, "console"); 699 panelState.commandLineText = context.commandLineText; 700 701 var commandLine = this.getCommandLine(context); 702 commandLine.value = ""; 703 704 this.autoCompleter.hide(); 705 Persist.persistObjects(this, panelState); 706 // more of our work is done in the Console 707 708 // All command line handlers should be removed at this moment. 709 for (var handler in context.activeCommandLineHandlers) 710 { 711 FBTrace.sysout("commandLine.destroyContext; ERROR active commandlinehandler for: " + 712 context.getName()); 713 } 714 }, 715 716 showPanel: function(browser, panel) 717 { 718 if (!Firebug.currentContext) 719 return; 720 721 var chrome = Firebug.chrome; 722 var panelState = Persist.getPersistedState(this, "console"); 723 if (panelState.commandLineText) 724 { 725 var value = panelState.commandLineText; 726 var commandLine = this.getCommandLine(browser); 727 Firebug.currentContext.commandLineText = value; 728 729 commandLine.value = value; 730 731 // We don't need the persistent value in this session/context any more. The showPanel 732 // method is called every time the panel is selected and the text could have been 733 // changed in this session/context already. 734 delete panelState.commandLineText; 735 } 736 737 this.autoCompleter.hide(); 738 }, 739 740 updateOption: function(name, value) 741 { 742 if (name == "commandEditor") 743 this.setMultiLine(value, Firebug.chrome); 744 else if (name == "commandLineShowCompleterPopup") 745 this.setAutoCompleter(); 746 }, 747 748 // called by users of command line, currently: 749 // 1) Console on focus command line, 750 // 2) Watch onfocus, and 751 // 3) debugger loadedContext if watches exist 752 isReadyElsePreparing: function(context, win) 753 { 754 if (FBTrace.DBG_COMMANDLINE) 755 { 756 FBTrace.sysout("commandLine.isReadyElsePreparing " + context.getName() + " win: " + 757 (win ? win.location : "not given"), context); 758 } 759 760 if (this.isSandbox(context)) 761 return; 762 763 if (Xml.isXMLPrettyPrint(context, win)) 764 return false; 765 766 if (win) 767 { 768 Firebug.CommandLine.injector.attachCommandLine(context, win); 769 } 770 else 771 { 772 Firebug.CommandLine.injector.attachCommandLine(context, context.window); 773 for (var i=0; i<context.windows.length; i++) 774 Firebug.CommandLine.injector.attachCommandLine(context, context.windows[i]); 775 } 776 777 var contentView = Wrapper.getContentView(context.window); 778 if (!contentView) 779 { 780 if (FBTrace.DBG_ERRORS) 781 FBTrace.sysout("CommandLine ERROR context.window invalid", context.window); 782 return false; 783 } 784 785 // the attach is asynchronous, we can report when it is complete: 786 return contentView._FirebugCommandLine; 787 }, 788 789 onCommandLineKeyUp: function(event) 790 { 791 }, 792 793 onCommandLineKeyDown: function(event) 794 { 795 // XXX: Temporary hack to make FireClosure work (until that gets a new 796 // release out) 797 if (!this.autoCompleter.shouldIncludeHint && Firebug.JSAutoCompleter.transformScopeExpr) 798 this.setAutoCompleter(); 799 800 var context = Firebug.currentContext; 801 802 this.autoCompleter.handleKeyDown(event, context); 803 804 if (event.keyCode === KeyEvent.DOM_VK_H && Events.isControl(event)) 805 { 806 event.preventDefault(); 807 this.autoCompleter.hide(); 808 this.commandHistory.show(Firebug.chrome.$("fbCommandLineHistoryButton")); 809 return true; 810 } 811 812 // Parts of the code moved into key-press handler due to bug 613752 813 }, 814 815 onCommandLineKeyPress: function(event) 816 { 817 var context = Firebug.currentContext; 818 819 if (!this.autoCompleter.handleKeyPress(event, context)) 820 { 821 this.handleKeyPress(event); 822 } 823 }, 824 825 handleKeyPress: function(event) 826 { 827 switch (event.keyCode) 828 { 829 case KeyEvent.DOM_VK_RETURN: 830 case KeyEvent.DOM_VK_ENTER: 831 event.preventDefault(); 832 833 if (!event.metaKey && !event.shiftKey) 834 { 835 Firebug.CommandLine.enter(Firebug.currentContext); 836 this.commandHistory.hide(); 837 return true; 838 } 839 else if(!event.metaKey && event.shiftKey) 840 { 841 Firebug.CommandLine.enterInspect(Firebug.currentContext); 842 this.commandHistory.hide(); 843 return true; 844 } 845 break; 846 847 case KeyEvent.DOM_VK_UP: 848 event.preventDefault(); 849 this.commandHistory.cycleCommands(Firebug.currentContext, -1); 850 return true; 851 852 case KeyEvent.DOM_VK_DOWN: 853 event.preventDefault(); 854 this.commandHistory.cycleCommands(Firebug.currentContext, 1); 855 return true; 856 857 case KeyEvent.DOM_VK_ESCAPE: 858 event.preventDefault(); 859 if (Firebug.CommandLine.cancel(Firebug.currentContext)) 860 Events.cancelEvent(event); 861 this.commandHistory.hide(); 862 return true; 863 } 864 865 if (this.commandHistory.isOpen && !event.metaKey && !event.ctrlKey && !event.altKey) 866 this.commandHistory.hide(); 867 868 return false; 869 }, 870 871 onCommandLineInput: function(event) 872 { 873 var context = Firebug.currentContext; 874 875 this.autoCompleter.complete(context); 876 this.update(context); 877 }, 878 879 isAttached: function(context, win) 880 { 881 if (!context) 882 return false; 883 884 return Firebug.CommandLine.injector.isAttached(win ? win : context.window); 885 }, 886 887 onPanelEnable: function(panelName) 888 { 889 Dom.collapse(Firebug.chrome.$("fbCommandBox"), true); 890 Dom.collapse(Firebug.chrome.$("fbPanelSplitter"), true); 891 Dom.collapse(Firebug.chrome.$("fbSidePanelDeck"), true); 892 893 this.setMultiLine(Firebug.commandEditor, Firebug.chrome); 894 }, 895 896 onPanelDisable: function(panelName) 897 { 898 if (panelName != "console") // we don't care about other panels 899 return; 900 901 Dom.collapse(Firebug.chrome.$("fbCommandBox"), true); 902 Dom.collapse(Firebug.chrome.$("fbPanelSplitter"), true); 903 Dom.collapse(Firebug.chrome.$("fbSidePanelDeck"), true); 904 }, 905 906 getCommandLine: function(context) 907 { 908 return (!this.isInOtherPanel(context) && Firebug.commandEditor) ? 909 this.getCommandEditor(): 910 this.getSingleRowCommandLine(); 911 }, 912 913 isInOtherPanel: function(context) 914 { 915 // Command line on other panels is never multiline. 916 var visible = Firebug.CommandLine.Popup.isVisible(); 917 return visible && context.panelName != "console"; 918 }, 919 920 getExpression: function(context) 921 { 922 return (!this.isInOtherPanel(context) && Firebug.commandEditor) ? 923 this.getCommandEditor().getExpression() : 924 this.getSingleRowCommandLine().value; 925 }, 926 927 getCompletionBox: function() 928 { 929 return Firebug.chrome.$("fbCommandLineCompletion"); 930 }, 931 932 getSingleRowCommandLine: function() 933 { 934 return Firebug.chrome.$("fbCommandLine"); 935 }, 936 937 getCommandEditor: function() 938 { 939 return Firebug.CommandEditor; 940 } 941 942 }); 943 944 // ********************************************************************************************* // 945 // Shared Helpers 946 947 Firebug.CommandLine.CommandHandler = Obj.extend(Object, 948 { 949 handle: function(event, api, win) 950 { 951 var element = event.target; 952 var methodName = Dom.getMappedData(win.document, "firebug-methodName"); 953 954 // We create this array in the page using JS, so we need to look on the 955 // wrappedJSObject for it. 956 var contentView = Wrapper.getContentView(win); 957 if (contentView) 958 var hosed_userObjects = contentView._FirebugCommandLine.userObjects; 959 960 var userObjects = hosed_userObjects ? Arr.cloneArray(hosed_userObjects) : []; 961 962 if (FBTrace.DBG_COMMANDLINE) 963 FBTrace.sysout("commandLine.CommandHandler for " + Win.getWindowId(win) + 964 ": method " + methodName + " userObjects:", userObjects); 965 966 var subHandler = api[methodName]; 967 if (!subHandler) 968 return false; 969 970 Dom.deleteMappedData(win.document, "firebug-retValueType"); 971 var result = subHandler.apply(api, userObjects); 972 if (typeof result != "undefined") 973 { 974 if (result instanceof window.Array) 975 { 976 Dom.setMappedData(win.document, "firebug-retValueType", "array"); 977 for (var item in result) 978 hosed_userObjects.push(result[item]); 979 } 980 else 981 { 982 hosed_userObjects.push(result); 983 } 984 } 985 986 return true; 987 } 988 }); 989 990 // ********************************************************************************************* // 991 // Command Line API 992 993 /** 994 * These functions will be called in the extension like this: 995 * 996 * subHandler.apply(api, userObjects); 997 * 998 * Where subHandler is one of the entries below, api is this object and userObjects 999 * are entries in an array we created in the web page. 1000 */ 1001 function FirebugCommandLineAPI(context) 1002 { 1003 // returns unwrapped elements from the page 1004 this.$ = function(selector, start) 1005 { 1006 if (start && start.querySelector && ( 1007 start.nodeType == Node.ELEMENT_NODE || 1008 start.nodeType == Node.DOCUMENT_NODE || 1009 start.nodeType == Node.DOCUMENT_FRAGMENT_NODE)) 1010 { 1011 return start.querySelector(selector); 1012 } 1013 1014 var result = context.baseWindow.document.querySelector(selector); 1015 if (result == null && (selector || "")[0] !== "#") 1016 { 1017 if (context.baseWindow.document.getElementById(selector)) 1018 { 1019 // This should be removed in the next minor (non-bugfix) version 1020 var msg = Locale.$STRF("warning.dollar_change", [selector]); 1021 Firebug.Console.log(msg, context, "warn"); 1022 result = null; 1023 } 1024 } 1025 1026 return result; 1027 }; 1028 1029 // returns unwrapped elements from the page 1030 this.$$ = function(selector, start) 1031 { 1032 var result; 1033 1034 if (start && start.querySelectorAll && ( 1035 start.nodeType == Node.ELEMENT_NODE || 1036 start.nodeType == Node.DOCUMENT_NODE || 1037 start.nodeType == Node.DOCUMENT_FRAGMENT_NODE)) 1038 { 1039 result = start.querySelectorAll(selector); 1040 } 1041 else 1042 { 1043 result = context.baseWindow.document.querySelectorAll(selector); 1044 } 1045 1046 return Arr.cloneArray(result); 1047 }; 1048 1049 // returns unwrapped elements from the page 1050 this.$x = function(xpath, contextNode, resultType) 1051 { 1052 var XPathResultType = XPathResult.ANY_TYPE; 1053 1054 switch (resultType) 1055 { 1056 case "number": 1057 XPathResultType = XPathResult.NUMBER_TYPE; 1058 break; 1059 1060 case "string": 1061 XPathResultType = XPathResult.STRING_TYPE; 1062 break; 1063 1064 case "bool": 1065 XPathResultType = XPathResult.BOOLEAN_TYPE; 1066 break; 1067 1068 case "node": 1069 XPathResultType = XPathResult.FIRST_ORDERED_NODE_TYPE; 1070 break; 1071 1072 case "nodes": 1073 XPathResultType = XPathResult.UNORDERED_NODE_ITERATOR_TYPE; 1074 break; 1075 } 1076 1077 var doc = Wrapper.unwrapObject(context.baseWindow.document); 1078 return Xpath.evaluateXPath(doc, xpath, contextNode, XPathResultType); 1079 }; 1080 1081 // values from the extension space 1082 this.$n = function(index) 1083 { 1084 var htmlPanel = context.getPanel("html", true); 1085 if (!htmlPanel) 1086 return null; 1087 1088 if (index < 0 || index >= htmlPanel.inspectorHistory.length) 1089 return null; 1090 1091 var node = htmlPanel.inspectorHistory[index]; 1092 if (!node) 1093 return node; 1094 1095 return Wrapper.unwrapObject(node); 1096 }; 1097 1098 this.cd = function(object) 1099 { 1100 if (!(object instanceof window.Window)) 1101 throw "Object must be a window."; 1102 1103 // Make sure the command line is attached into the target iframe. 1104 var consoleReady = Firebug.Console.isReadyElsePreparing(context, object); 1105 if (FBTrace.DBG_COMMANDLINE) 1106 FBTrace.sysout("commandLine.cd; console ready: " + consoleReady); 1107 1108 // The window object parameter uses XPCSafeJSObjectWrapper, but we need XPCNativeWrapper 1109 // So, look within all registered consoleHandlers for 1110 // the same window (from tabWatcher) that uses uses XPCNativeWrapper (operator "==" works). 1111 var entry = Firebug.Console.injector.getConsoleHandler(context, object); 1112 if (entry) 1113 context.baseWindow = entry.win; 1114 1115 var format = Locale.$STR("commandline.CurrentWindow") + " %o"; 1116 Firebug.Console.logFormatted([format, context.baseWindow], context, "info"); 1117 return Firebug.Console.getDefaultReturnValue(context.window); 1118 }; 1119 1120 // no web page interaction 1121 this.clear = function() 1122 { 1123 Firebug.Console.clear(context); 1124 return Firebug.Console.getDefaultReturnValue(context.window); 1125 }; 1126 1127 // no web page interaction 1128 this.inspect = function(obj, panelName) 1129 { 1130 Firebug.chrome.select(obj, panelName); 1131 return Firebug.Console.getDefaultReturnValue(context.window); 1132 }; 1133 1134 this.keys = function(o) 1135 { 1136 // the object is from the page, unwrapped 1137 return Arr.keys(o); 1138 }; 1139 1140 this.values = function(o) 1141 { 1142 // the object is from the page, unwrapped 1143 return Arr.values(o); 1144 }; 1145 1146 this.debug = function(fn) 1147 { 1148 Firebug.Debugger.monitorFunction(fn, "debug"); 1149 return Firebug.Console.getDefaultReturnValue(context.window); 1150 }; 1151 1152 this.undebug = function(fn) 1153 { 1154 Firebug.Debugger.unmonitorFunction(fn, "debug"); 1155 return Firebug.Console.getDefaultReturnValue(context.window); 1156 }; 1157 1158 this.monitor = function(fn) 1159 { 1160 Firebug.Debugger.monitorFunction(fn, "monitor"); 1161 return Firebug.Console.getDefaultReturnValue(context.window); 1162 }; 1163 1164 this.unmonitor = function(fn) 1165 { 1166 Firebug.Debugger.unmonitorFunction(fn, "monitor"); 1167 return Firebug.Console.getDefaultReturnValue(context.window); 1168 }; 1169 1170 this.traceAll = function() 1171 { 1172 Firebug.Debugger.traceAll(Firebug.currentContext); 1173 return Firebug.Console.getDefaultReturnValue(context.window); 1174 }; 1175 1176 this.untraceAll = function() 1177 { 1178 Firebug.Debugger.untraceAll(Firebug.currentContext); 1179 return Firebug.Console.getDefaultReturnValue(context.window); 1180 }; 1181 1182 this.traceCalls = function(fn) 1183 { 1184 Firebug.Debugger.traceCalls(Firebug.currentContext, fn); 1185 return Firebug.Console.getDefaultReturnValue(context.window); 1186 }; 1187 1188 this.untraceCalls = function(fn) 1189 { 1190 Firebug.Debugger.untraceCalls(Firebug.currentContext, fn); 1191 return Firebug.Console.getDefaultReturnValue(context.window); 1192 }; 1193 1194 this.copy = function(x) 1195 { 1196 System.copyToClipboard(x); 1197 return Firebug.Console.getDefaultReturnValue(context.window); 1198 }; 1199 1200 // xxxHonza: removed from 1.10 (issue 5599) 1201 /*this.memoryProfile = function(title) 1202 { 1203 Firebug.MemoryProfiler.start(context, title); 1204 return Firebug.Console.getDefaultReturnValue(context.window); 1205 }; 1206 1207 this.memoryProfileEnd = function() 1208 { 1209 Firebug.MemoryProfiler.stop(context); 1210 return Firebug.Console.getDefaultReturnValue(context.window); 1211 };*/ 1212 1213 function createHandler(config, name) 1214 { 1215 return function() 1216 { 1217 try 1218 { 1219 return config.handler.call(null, context, arguments); 1220 } 1221 catch (err) 1222 { 1223 Firebug.Console.log(err, context, "errorMessage"); 1224 1225 if (FBTrace.DBG_ERRORS) 1226 { 1227 FBTrace.sysout("commandLine.api; EXCEPTION when executing " + 1228 "a command: " + name + ", " + err, err); 1229 } 1230 } 1231 } 1232 } 1233 1234 // Register user commands. 1235 var commands = CommandLineExposed.userCommands; 1236 for (var name in commands) 1237 { 1238 var config = commands[name]; 1239 this[name] = createHandler(config, name); 1240 } 1241 } 1242 1243 // ********************************************************************************************* // 1244 // CommandLine Injector 1245 1246 Firebug.CommandLine.injector = 1247 { 1248 isAttached: function(win) 1249 { 1250 var contentView = Wrapper.getContentView(win); 1251 return contentView._FirebugCommandLine ? true : false; 1252 }, 1253 1254 attachCommandLine: function(context, win) 1255 { 1256 win = win ? win : context.window; 1257 if (win instanceof win.Window) 1258 { 1259 // If the command line is already attached then end. 1260 if (this.isAttached(win)) 1261 return; 1262 1263 var contentView = Wrapper.getContentView(win); 1264 contentView._FirebugCommandLine = 1265 Firebug.CommandLineExposed.createFirebugCommandLine(context, win); 1266 1267 this.addCommandLineListener(context, win); 1268 } 1269 else if (Firebug.CommandLine.isSandbox(context)) 1270 { 1271 if (FBTrace.DBG_COMMANDLINE) 1272 { 1273 FBTrace.sysout("commandLine.injector context.global " + context.global, 1274 context.global); 1275 } 1276 } 1277 else 1278 { 1279 if (FBTrace.DBG_COMMANDLINE) 1280 { 1281 FBTrace.sysout("commandLine.injector, win: " + win + 1282 " not a Window or Sandbox", win); 1283 } 1284 } 1285 }, 1286 1287 detachCommandLine: function(context, win) 1288 { 1289 win = win ? win : context.window; 1290 if (this.isAttached(win)) 1291 { 1292 function failureCallback(result, context) 1293 { 1294 if (FBTrace.DBG_ERRORS) 1295 FBTrace.sysout("Firebug.CommandLine.evaluate FAILS " + result, result); 1296 } 1297 1298 //Firebug.CommandLine.evaluate("window._FirebugCommandLine.detachCommandLine()", 1299 // context, null, win, null, failureCallback ); 1300 var contentView = Wrapper.getContentView(win); 1301 contentView._FirebugCommandLine.detachCommandLine(); 1302 1303 this.removeCommandLineListener(context, win); 1304 } 1305 }, 1306 1307 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 1308 // Listener 1309 1310 addCommandLineListener: function(context, win) 1311 { 1312 // Register listener for command-line execution events. 1313 var handler = new CommandLineHandler(context, win); 1314 var boundHandler = Obj.bind(handler.handleEvent, handler); 1315 1316 if (!context.activeCommandLineHandlers) 1317 context.activeCommandLineHandlers = {}; 1318 1319 var consoleHandler = Firebug.Console.injector.getConsoleHandler(context, win); 1320 if (!consoleHandler) 1321 { 1322 if (FBTrace.DBG_ERRORS || FBTrace.DBG_COMMANDLINE) 1323 FBTrace.sysout("commandLine.addCommandLineListener; No console handler! " + 1324 " Command line listener can't be created." + context.getName()); 1325 return; 1326 } 1327 1328 context.activeCommandLineHandlers[consoleHandler.token] = boundHandler; 1329 1330 Events.addEventListener(win.document, "firebugExecuteCommand", boundHandler, true); 1331 1332 if (FBTrace.DBG_COMMANDLINE) 1333 { 1334 FBTrace.sysout("commandLine.addCommandLineListener to document in window" + 1335 win.location + " with console "); 1336 } 1337 }, 1338 1339 removeCommandLineListener: function(context, win) 1340 { 1341 var boundHandler = this.getCommandLineListener(context, win); 1342 if (boundHandler) 1343 { 1344 Events.removeEventListener(win.document, "firebugExecuteCommand", boundHandler, true); 1345 1346 var consoleHandler = Firebug.Console.injector.getConsoleHandler(context, win); 1347 delete context.activeCommandLineHandlers[consoleHandler.token]; 1348 1349 if (FBTrace.DBG_COMMANDLINE) 1350 { 1351 FBTrace.sysout("commandLine.detachCommandLineListener " + boundHandler + 1352 " in window with console " + win.location); 1353 } 1354 } 1355 else 1356 { 1357 if (FBTrace.DBG_ERRORS || FBTrace.DBG_COMMANDLINE) 1358 { 1359 FBTrace.sysout("commandLine.removeCommandLineListener; ERROR no handler! " + 1360 "This could cause memory leaks, please report an issue if you see this. " + 1361 context.getName()); 1362 } 1363 } 1364 }, 1365 1366 getCommandLineListener: function(context, win) 1367 { 1368 if (context.activeCommandLineHandlers) 1369 { 1370 var consoleHandler = Firebug.Console.injector.getConsoleHandler(context, win); 1371 if (consoleHandler) 1372 return context.activeCommandLineHandlers[consoleHandler.token]; 1373 1374 if (FBTrace.DBG_CONSOLE) 1375 { 1376 FBTrace.sysout("getCommandLineListener no consoleHandler for " + 1377 context.getName() + " win " + Win.safeGetWindowLocation(win)); 1378 } 1379 } 1380 }, 1381 }; 1382 1383 // ********************************************************************************************* // 1384 // CommandLine Handler 1385 1386 /** 1387 * This object is responsible for handling commands executing in the page context. 1388 * When a command (CMD API) is being executed, the page sends a DOM event that is 1389 * handled by 'handleEvent' method. 1390 * 1391 * @param {Object} context 1392 * @param {Object} win is the window the handler is bound into 1393 */ 1394 function CommandLineHandler(context, win) 1395 { 1396 this.handleEvent = function(event) 1397 { 1398 context.baseWindow = context.baseWindow || context.window; 1399 this.api = new FirebugCommandLineAPI(context); 1400 1401 if (FBTrace.DBG_COMMANDLINE) 1402 { 1403 FBTrace.sysout("commandLine.handleEvent('firebugExecuteCommand') " + 1404 "event in context.baseWindow " + context.baseWindow.location, event); 1405 } 1406 1407 // Appends variables into the api. 1408 var htmlPanel = context.getPanel("html", true); 1409 var vars = htmlPanel ? htmlPanel.getInspectorVars() : null; 1410 1411 for (var prop in vars) 1412 { 1413 function createHandler(p) 1414 { 1415 return function() 1416 { 1417 if (FBTrace.DBG_COMMANDLINE) 1418 FBTrace.sysout("commandLine.getInspectorHistory: " + p, vars); 1419 1420 return Wrapper.unwrapObject(vars[p]); 1421 } 1422 } 1423 1424 // XXXjjb should these be removed? 1425 this.api[prop] = createHandler(prop); 1426 } 1427 1428 if (!Firebug.CommandLine.CommandHandler.handle(event, this.api, win)) 1429 { 1430 var methodName = Dom.getMappedData(win.document, "firebug-methodName"); 1431 Firebug.Console.log(Locale.$STRF("commandline.MethodNotSupported", [methodName])); 1432 } 1433 1434 if (FBTrace.DBG_COMMANDLINE) 1435 { 1436 FBTrace.sysout("commandLine.handleEvent() " + 1437 Dom.getMappedData(win.document, "firebug-methodName") + 1438 " context.baseWindow: " + 1439 (context.baseWindow ? context.baseWindow.location : "no basewindow"), 1440 context.baseWindow); 1441 } 1442 }; 1443 } 1444 1445 function getNoScript() 1446 { 1447 // The wrappedJSObject here is not a security wrapper, it is a property set by the service. 1448 if (!this.noscript) 1449 this.noscript = Cc["@maone.net/noscript-service;1"] && 1450 Cc["@maone.net/noscript-service;1"].getService().wrappedJSObject; 1451 return this.noscript; 1452 } 1453 1454 1455 // ********************************************************************************************* // 1456 // Registration 1457 1458 Firebug.registerModule(Firebug.CommandLine); 1459 1460 return Firebug.CommandLine; 1461 1462 // ********************************************************************************************* // 1463 }); 1464