зеркало из https://github.com/mozilla/gecko-dev.git
Bug 827083 - Cannot attach remote web console to Firefox Android; r=past
This commit is contained in:
Родитель
0f057d1516
Коммит
aa99330a69
|
@ -468,6 +468,10 @@ Toolbox.prototype = {
|
|||
/**
|
||||
* Create a host object based on the given host type.
|
||||
*
|
||||
* Warning: some hosts require that the toolbox target provides a reference to
|
||||
* the attached tab. Not all Targets have a tab property - make sure you correctly
|
||||
* mix and match hosts and targets.
|
||||
*
|
||||
* @param {string} hostType
|
||||
* The host type of the new host object
|
||||
*
|
||||
|
|
|
@ -13,7 +13,9 @@ const Cu = Components.utils;
|
|||
const CONSOLEAPI_CLASS_ID = "{b49c18f8-3379-4fc0-8c90-d7772c1a9ff3}";
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/devtools/gDevTools.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
|
||||
"resource:///modules/devtools/gDevTools.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
|
||||
"resource:///modules/devtools/Target.jsm");
|
||||
|
@ -24,45 +26,30 @@ XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
|
||||
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/commonjs/promise/core.js");
|
||||
|
||||
const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
|
||||
let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["HUDService"];
|
||||
|
||||
function LogFactory(aMessagePrefix)
|
||||
{
|
||||
function log(aMessage) {
|
||||
var _msg = aMessagePrefix + " " + aMessage + "\n";
|
||||
dump(_msg);
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
let log = LogFactory("*** HUDService:");
|
||||
|
||||
// The HTML namespace.
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
// The XUL namespace.
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// The HUD service
|
||||
|
||||
function HUD_SERVICE()
|
||||
{
|
||||
// These methods access the "this" object, but they're registered as
|
||||
// event listeners. So we hammer in the "this" binding.
|
||||
this.onWindowUnload = this.onWindowUnload.bind(this);
|
||||
|
||||
/**
|
||||
* Keeps a reference for each HeadsUpDisplay that is created
|
||||
*/
|
||||
this.hudReferences = {};
|
||||
};
|
||||
}
|
||||
|
||||
HUD_SERVICE.prototype =
|
||||
{
|
||||
/**
|
||||
* Keeps a reference for each HeadsUpDisplay that is created
|
||||
* @type object
|
||||
*/
|
||||
hudReferences: null,
|
||||
|
||||
/**
|
||||
* getter for UI commands to be used by the frontend
|
||||
*
|
||||
|
@ -72,12 +59,6 @@ HUD_SERVICE.prototype =
|
|||
return HeadsUpDisplayUICommands;
|
||||
},
|
||||
|
||||
/**
|
||||
* The sequencer is a generator (after initialization) that returns unique
|
||||
* integers
|
||||
*/
|
||||
sequencer: null,
|
||||
|
||||
/**
|
||||
* Firefox-specific current tab getter
|
||||
*
|
||||
|
@ -88,134 +69,22 @@ HUD_SERVICE.prototype =
|
|||
},
|
||||
|
||||
/**
|
||||
* Activate a HeadsUpDisplay for the given tab context.
|
||||
* Open a Web Console for the given target.
|
||||
*
|
||||
* @param nsIDOMElement aTab
|
||||
* The xul:tab element.
|
||||
* @see devtools/framework/Target.jsm for details about targets.
|
||||
*
|
||||
* @param object aTarget
|
||||
* The target that the web console will connect to.
|
||||
* @param nsIDOMElement aIframe
|
||||
* The iframe element into which to place the web console.
|
||||
* @param RemoteTarget aTarget
|
||||
* The target that the web console will connect to.
|
||||
* @return object
|
||||
* The new HeadsUpDisplay instance.
|
||||
* A Promise object for the opening of the new WebConsole instance.
|
||||
*/
|
||||
activateHUDForContext: function HS_activateHUDForContext(aTab, aIframe,
|
||||
aTarget)
|
||||
openWebConsole: function HS_openWebConsole(aTarget, aIframe)
|
||||
{
|
||||
let hudId = "hud_" + aTab.linkedPanel;
|
||||
if (hudId in this.hudReferences) {
|
||||
return this.hudReferences[hudId];
|
||||
}
|
||||
|
||||
this.wakeup();
|
||||
|
||||
let window = aTab.ownerDocument.defaultView;
|
||||
let gBrowser = window.gBrowser;
|
||||
|
||||
window.addEventListener("unload", this.onWindowUnload, false);
|
||||
|
||||
let hud = new WebConsole(aTab, aIframe, aTarget);
|
||||
this.hudReferences[hudId] = hud;
|
||||
|
||||
return hud;
|
||||
},
|
||||
|
||||
/**
|
||||
* Deactivate a HeadsUpDisplay for the given tab context.
|
||||
*
|
||||
* @param nsIDOMElement aTab
|
||||
* The xul:tab element you want to enable the Web Console for.
|
||||
* @return void
|
||||
*/
|
||||
deactivateHUDForContext: function HS_deactivateHUDForContext(aTab)
|
||||
{
|
||||
let hudId = "hud_" + aTab.linkedPanel;
|
||||
if (!(hudId in this.hudReferences)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hud = this.getHudReferenceById(hudId);
|
||||
let document = hud.chromeDocument;
|
||||
|
||||
hud.destroy(function() {
|
||||
let id = WebConsoleUtils.supportsString(hudId);
|
||||
Services.obs.notifyObservers(id, "web-console-destroyed", null);
|
||||
});
|
||||
|
||||
delete this.hudReferences[hudId];
|
||||
|
||||
if (Object.keys(this.hudReferences).length == 0) {
|
||||
let autocompletePopup = document.
|
||||
getElementById("webConsole_autocompletePopup");
|
||||
if (autocompletePopup) {
|
||||
autocompletePopup.parentNode.removeChild(autocompletePopup);
|
||||
}
|
||||
|
||||
let window = document.defaultView;
|
||||
|
||||
window.removeEventListener("unload", this.onWindowUnload, false);
|
||||
|
||||
let gBrowser = window.gBrowser;
|
||||
let tabContainer = gBrowser.tabContainer;
|
||||
|
||||
this.suspend();
|
||||
}
|
||||
|
||||
let contentWindow = aTab.linkedBrowser.contentWindow;
|
||||
contentWindow.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* get a unique ID from the sequence generator
|
||||
*
|
||||
* @returns integer
|
||||
*/
|
||||
sequenceId: function HS_sequencerId()
|
||||
{
|
||||
if (!this.sequencer) {
|
||||
this.sequencer = this.createSequencer(-1);
|
||||
}
|
||||
return this.sequencer.next();
|
||||
},
|
||||
|
||||
/**
|
||||
* "Wake up" the Web Console activity. This is called when the first Web
|
||||
* Console is open. This method initializes the various observers we have.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
wakeup: function HS_wakeup()
|
||||
{
|
||||
if (Object.keys(this.hudReferences).length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
WebConsoleObserver.init();
|
||||
},
|
||||
|
||||
/**
|
||||
* Suspend Web Console activity. This is called when all Web Consoles are
|
||||
* closed.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
suspend: function HS_suspend()
|
||||
{
|
||||
delete this.lastFinishedRequestCallback;
|
||||
|
||||
WebConsoleObserver.uninit();
|
||||
},
|
||||
|
||||
/**
|
||||
* Shutdown all HeadsUpDisplays on quit-application-granted.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
shutdown: function HS_shutdown()
|
||||
{
|
||||
for (let hud of this.hudReferences) {
|
||||
this.deactivateHUDForContext(hud.tab);
|
||||
}
|
||||
let hud = new WebConsole(aTarget, aIframe);
|
||||
this.hudReferences[hud.hudId] = hud;
|
||||
return hud.init();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -226,8 +95,13 @@ HUD_SERVICE.prototype =
|
|||
*/
|
||||
getHudByWindow: function HS_getHudByWindow(aContentWindow)
|
||||
{
|
||||
let hudId = this.getHudIdByWindow(aContentWindow);
|
||||
return hudId ? this.hudReferences[hudId] : null;
|
||||
for each (let hud in this.hudReferences) {
|
||||
let target = hud.target;
|
||||
if (target && target.tab && target.window === aContentWindow) {
|
||||
return hud;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -239,16 +113,8 @@ HUD_SERVICE.prototype =
|
|||
*/
|
||||
getHudIdByWindow: function HS_getHudIdByWindow(aContentWindow)
|
||||
{
|
||||
let window = this.currentContext();
|
||||
let index =
|
||||
window.gBrowser.getBrowserIndexForDocument(aContentWindow.document);
|
||||
if (index == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let tab = window.gBrowser.tabs[index];
|
||||
let hudId = "hud_" + tab.linkedPanel;
|
||||
return hudId in this.hudReferences ? hudId : null;
|
||||
let hud = this.getHudByWindow(aContentWindow);
|
||||
return hud ? hud.hudId : null;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -270,101 +136,45 @@ HUD_SERVICE.prototype =
|
|||
* @type function
|
||||
*/
|
||||
lastFinishedRequestCallback: null,
|
||||
|
||||
/**
|
||||
* Creates a generator that always returns a unique number for use in the
|
||||
* indexes
|
||||
*
|
||||
* @returns Generator
|
||||
*/
|
||||
createSequencer: function HS_createSequencer(aInt)
|
||||
{
|
||||
function sequencer(aInt)
|
||||
{
|
||||
while(1) {
|
||||
aInt++;
|
||||
yield aInt;
|
||||
}
|
||||
}
|
||||
return sequencer(aInt);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called whenever a browser window closes. Cleans up any consoles still
|
||||
* around.
|
||||
*
|
||||
* @param nsIDOMEvent aEvent
|
||||
* The dispatched event.
|
||||
* @returns void
|
||||
*/
|
||||
onWindowUnload: function HS_onWindowUnload(aEvent)
|
||||
{
|
||||
let window = aEvent.target.defaultView;
|
||||
|
||||
window.removeEventListener("unload", this.onWindowUnload, false);
|
||||
|
||||
let gBrowser = window.gBrowser;
|
||||
let tabContainer = gBrowser.tabContainer;
|
||||
|
||||
let tab = tabContainer.firstChild;
|
||||
while (tab != null) {
|
||||
this.deactivateHUDForContext(tab);
|
||||
tab = tab.nextSibling;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A WebConsole instance is an interactive console initialized *per tab*
|
||||
* A WebConsole instance is an interactive console initialized *per target*
|
||||
* that displays console log data as well as provides an interactive terminal to
|
||||
* manipulate the current tab's document content.
|
||||
* manipulate the target's document content.
|
||||
*
|
||||
* This object only wraps the iframe that holds the Web Console UI.
|
||||
*
|
||||
* @param nsIDOMElement aTab
|
||||
* The xul:tab for which you want the WebConsole object.
|
||||
* @constructor
|
||||
* @param object aTarget
|
||||
* The target that the web console will connect to.
|
||||
* @param nsIDOMElement aIframe
|
||||
* iframe into which we should create the WebConsole UI.
|
||||
* @param RemoteTarget aTarget
|
||||
* The target that the web console will connect to.
|
||||
*/
|
||||
function WebConsole(aTab, aIframe, aTarget)
|
||||
function WebConsole(aTarget, aIframe)
|
||||
{
|
||||
this.tab = aTab;
|
||||
if (this.tab == null) {
|
||||
throw new Error('Missing tab');
|
||||
}
|
||||
|
||||
this.iframe = aIframe;
|
||||
if (this.iframe == null) {
|
||||
console.trace();
|
||||
throw new Error('Missing iframe');
|
||||
}
|
||||
|
||||
this.chromeDocument = this.tab.ownerDocument;
|
||||
this.chromeWindow = this.chromeDocument.defaultView;
|
||||
this.hudId = "hud_" + this.tab.linkedPanel;
|
||||
|
||||
this.target = aTarget;
|
||||
|
||||
this._onIframeLoad = this._onIframeLoad.bind(this);
|
||||
|
||||
this.iframe.className = "web-console-frame";
|
||||
this.iframe.addEventListener("load", this._onIframeLoad, true);
|
||||
|
||||
this.positionConsole();
|
||||
this.chromeDocument = this.iframe.ownerDocument;
|
||||
this.chromeWindow = this.chromeDocument.defaultView;
|
||||
this.hudId = "hud_" + Date.now();
|
||||
this.target = aTarget;
|
||||
}
|
||||
|
||||
WebConsole.prototype = {
|
||||
/**
|
||||
* The xul:tab for which the current Web Console instance was created.
|
||||
* @type nsIDOMElement
|
||||
*/
|
||||
tab: null,
|
||||
|
||||
chromeWindow: null,
|
||||
chromeDocument: null,
|
||||
hudId: null,
|
||||
target: null,
|
||||
iframe: null,
|
||||
_destroyer: null,
|
||||
|
||||
get browserWindow()
|
||||
{
|
||||
return this.target.isLocalTab ?
|
||||
this.chromeWindow.top : HUDService.currentContext();
|
||||
},
|
||||
|
||||
/**
|
||||
* Getter for HUDService.lastFinishedRequestCallback.
|
||||
|
@ -380,7 +190,7 @@ WebConsole.prototype = {
|
|||
*/
|
||||
get mainPopupSet()
|
||||
{
|
||||
return this.chromeDocument.getElementById("mainPopupSet");
|
||||
return this.browserWindow.document.getElementById("mainPopupSet");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -392,18 +202,48 @@ WebConsole.prototype = {
|
|||
return this.ui ? this.ui.outputNode : null;
|
||||
},
|
||||
|
||||
get gViewSourceUtils() this.chromeWindow.gViewSourceUtils,
|
||||
get gViewSourceUtils() this.browserWindow.gViewSourceUtils,
|
||||
|
||||
/**
|
||||
* The "load" event handler for the Web Console iframe.
|
||||
* @private
|
||||
* Initialize the Web Console instance.
|
||||
*
|
||||
* @return object
|
||||
* A Promise for the initialization.
|
||||
*/
|
||||
_onIframeLoad: function WC__onIframeLoad()
|
||||
init: function WC_init()
|
||||
{
|
||||
this.iframe.removeEventListener("load", this._onIframeLoad, true);
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let onIframeLoad = function() {
|
||||
this.iframe.removeEventListener("load", onIframeLoad, true);
|
||||
initUI();
|
||||
}.bind(this);
|
||||
|
||||
let initUI = function() {
|
||||
this.iframeWindow = this.iframe.contentWindow.wrappedJSObject;
|
||||
this.ui = new this.iframeWindow.WebConsoleFrame(this);
|
||||
this.ui.init().then(onSuccess, onFailure);
|
||||
}.bind(this);
|
||||
|
||||
let onSuccess = function() {
|
||||
deferred.resolve(this);
|
||||
}.bind(this);
|
||||
|
||||
let onFailure = function(aReason) {
|
||||
deferred.reject(aReason);
|
||||
};
|
||||
|
||||
let win, doc;
|
||||
if ((win = this.iframe.contentWindow) &&
|
||||
(doc = win.document) &&
|
||||
doc.readyState == "complete") {
|
||||
this.iframe.addEventListener("load", onIframeLoad, true);
|
||||
}
|
||||
else {
|
||||
initUI();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -418,50 +258,6 @@ WebConsole.prototype = {
|
|||
return l10n.getFormatStr("webConsoleWindowTitleAndURL", [url]);
|
||||
},
|
||||
|
||||
consoleWindowUnregisterOnHide: true,
|
||||
|
||||
/**
|
||||
* Position the Web Console UI.
|
||||
*/
|
||||
positionConsole: function WC_positionConsole()
|
||||
{
|
||||
let lastIndex = -1;
|
||||
|
||||
if (this.outputNode && this.outputNode.getIndexOfFirstVisibleRow) {
|
||||
lastIndex = this.outputNode.getIndexOfFirstVisibleRow() +
|
||||
this.outputNode.getNumberOfVisibleRows() - 1;
|
||||
}
|
||||
|
||||
this._beforePositionConsole(lastIndex);
|
||||
},
|
||||
|
||||
/**
|
||||
* Common code that needs to execute before the Web Console is repositioned.
|
||||
* @private
|
||||
* @param number aLastIndex
|
||||
* The last visible message in the console output before repositioning
|
||||
* occurred.
|
||||
*/
|
||||
_beforePositionConsole:
|
||||
function WC__beforePositionConsole(aLastIndex)
|
||||
{
|
||||
if (!this.ui) {
|
||||
return;
|
||||
}
|
||||
|
||||
let onLoad = function() {
|
||||
this.iframe.removeEventListener("load", onLoad, true);
|
||||
this.iframeWindow = this.iframe.contentWindow.wrappedJSObject;
|
||||
this.ui.positionConsole(this.iframeWindow);
|
||||
|
||||
if (aLastIndex > -1 && aLastIndex < this.outputNode.getRowCount()) {
|
||||
this.outputNode.ensureIndexIsVisible(aLastIndex);
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
this.iframe.addEventListener("load", onLoad, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* The JSTerm object that manages the console's input.
|
||||
* @see webconsole.js::JSTerm
|
||||
|
@ -478,7 +274,9 @@ WebConsole.prototype = {
|
|||
*/
|
||||
_onClearButton: function WC__onClearButton()
|
||||
{
|
||||
this.chromeWindow.DeveloperToolbar.resetErrorsCount(this.tab);
|
||||
if (this.target.isLocalTab) {
|
||||
this.browserWindow.DeveloperToolbar.resetErrorsCount(this.target.tab);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -498,7 +296,7 @@ WebConsole.prototype = {
|
|||
*/
|
||||
openLink: function WC_openLink(aLink)
|
||||
{
|
||||
this.chromeWindow.openUILinkIn(aLink, "tab");
|
||||
this.browserWindow.openUILinkIn(aLink, "tab");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -530,12 +328,13 @@ WebConsole.prototype = {
|
|||
viewSourceInStyleEditor:
|
||||
function WC_viewSourceInStyleEditor(aSourceURL, aSourceLine)
|
||||
{
|
||||
let styleSheets = this.tab.linkedBrowser.contentWindow.document.styleSheets;
|
||||
let styleSheets = {};
|
||||
if (this.target.isLocalTab) {
|
||||
styleSheets = this.target.window.document.styleSheets;
|
||||
}
|
||||
for each (let style in styleSheets) {
|
||||
if (style.href == aSourceURL) {
|
||||
let target = TargetFactory.forTab(this.tab);
|
||||
let gDevTools = this.chromeWindow.gDevTools;
|
||||
gDevTools.showToolbox(target, "styleeditor").then(function(toolbox) {
|
||||
gDevTools.showToolbox(this.target, "styleeditor").then(function(toolbox) {
|
||||
toolbox.getCurrentPanel().selectStyleSheet(style, aSourceLine);
|
||||
});
|
||||
return;
|
||||
|
@ -549,15 +348,20 @@ WebConsole.prototype = {
|
|||
* Destroy the object. Call this method to avoid memory leaks when the Web
|
||||
* Console is closed.
|
||||
*
|
||||
* @param function [aOnDestroy]
|
||||
* Optional function to invoke when the Web Console instance is
|
||||
* destroyed.
|
||||
* @return object
|
||||
* A Promise object that is resolved once the Web Console is closed.
|
||||
*/
|
||||
destroy: function WC_destroy(aOnDestroy)
|
||||
destroy: function WC_destroy()
|
||||
{
|
||||
// Make sure that the console panel does not try to call
|
||||
// deactivateHUDForContext() again.
|
||||
this.consoleWindowUnregisterOnHide = false;
|
||||
if (this._destroyer) {
|
||||
return this._destroyer.promise;
|
||||
}
|
||||
|
||||
delete HUDService.hudReferences[this.hudId];
|
||||
|
||||
let tabWindow = this.target.isLocalTab ? this.target.window : null;
|
||||
|
||||
this._destroyer = Promise.defer();
|
||||
|
||||
let popupset = this.mainPopupSet;
|
||||
let panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
|
||||
|
@ -566,27 +370,27 @@ WebConsole.prototype = {
|
|||
}
|
||||
|
||||
let onDestroy = function WC_onDestroyUI() {
|
||||
// Remove the iframe and the consolePanel if the Web Console is inside a
|
||||
// floating panel.
|
||||
if (this.consolePanel && this.consolePanel.parentNode) {
|
||||
this.consolePanel.hidePopup();
|
||||
this.consolePanel.parentNode.removeChild(this.consolePanel);
|
||||
this.consolePanel = null;
|
||||
try {
|
||||
tabWindow && tabWindow.focus();
|
||||
}
|
||||
catch (ex) {
|
||||
// Tab focus can fail if the tab is closed.
|
||||
}
|
||||
|
||||
if (this.iframe.parentNode) {
|
||||
this.iframe.parentNode.removeChild(this.iframe);
|
||||
}
|
||||
let id = WebConsoleUtils.supportsString(this.hudId);
|
||||
Services.obs.notifyObservers(id, "web-console-destroyed", null);
|
||||
|
||||
aOnDestroy && aOnDestroy();
|
||||
this._destroyer.resolve(null);
|
||||
}.bind(this);
|
||||
|
||||
if (this.ui) {
|
||||
this.ui.destroy(onDestroy);
|
||||
this.ui.destroy().then(onDestroy);
|
||||
}
|
||||
else {
|
||||
onDestroy();
|
||||
}
|
||||
|
||||
return this._destroyer.promise;
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -595,9 +399,16 @@ WebConsole.prototype = {
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var HeadsUpDisplayUICommands = {
|
||||
toggleHUD: function UIC_toggleHUD(aOptions)
|
||||
/**
|
||||
* Toggle the Web Console for the current tab.
|
||||
*
|
||||
* @return object
|
||||
* A Promise for either the opening of the toolbox that holds the Web
|
||||
* Console, or a Promise for the closing of the toolbox.
|
||||
*/
|
||||
toggleHUD: function UIC_toggleHUD()
|
||||
{
|
||||
var window = HUDService.currentContext();
|
||||
let window = HUDService.currentContext();
|
||||
let target = TargetFactory.forTab(window.gBrowser.selectedTab);
|
||||
let toolbox = gDevTools.getToolbox(target);
|
||||
|
||||
|
@ -606,84 +417,21 @@ var HeadsUpDisplayUICommands = {
|
|||
gDevTools.showToolbox(target, "webconsole");
|
||||
},
|
||||
|
||||
toggleRemoteHUD: function UIC_toggleRemoteHUD()
|
||||
{
|
||||
if (this.getOpenHUD()) {
|
||||
this.toggleHUD();
|
||||
return;
|
||||
}
|
||||
|
||||
let host = Services.prefs.getCharPref("devtools.debugger.remote-host");
|
||||
let port = Services.prefs.getIntPref("devtools.debugger.remote-port");
|
||||
|
||||
let check = { value: false };
|
||||
let input = { value: host + ":" + port };
|
||||
|
||||
let result = Services.prompt.prompt(null,
|
||||
l10n.getStr("remoteWebConsolePromptTitle"),
|
||||
l10n.getStr("remoteWebConsolePromptMessage"),
|
||||
input, null, check);
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
let parts = input.value.split(":");
|
||||
if (parts.length != 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
[host, port] = parts;
|
||||
if (!host.length || !port.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.prefs.setCharPref("devtools.debugger.remote-host", host);
|
||||
Services.prefs.setIntPref("devtools.debugger.remote-port", port);
|
||||
|
||||
this.toggleHUD({
|
||||
host: host,
|
||||
port: port,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the hudId for the active chrome window.
|
||||
* @return string|null
|
||||
* The hudId or null if the active chrome window has no open Web
|
||||
* Find if there is a Web Console open for the current tab and return the
|
||||
* instance.
|
||||
* @return object|null
|
||||
* The WebConsole object or null if the active tab has no open Web
|
||||
* Console.
|
||||
*/
|
||||
getOpenHUD: function UIC_getOpenHUD() {
|
||||
let chromeWindow = HUDService.currentContext();
|
||||
let hudId = "hud_" + chromeWindow.gBrowser.selectedTab.linkedPanel;
|
||||
return hudId in HUDService.hudReferences ? hudId : null;
|
||||
},
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// WebConsoleObserver
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var WebConsoleObserver = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
|
||||
init: function WCO_init()
|
||||
getOpenHUD: function UIC_getOpenHUD()
|
||||
{
|
||||
Services.obs.addObserver(this, "quit-application-granted", false);
|
||||
},
|
||||
|
||||
observe: function WCO_observe(aSubject, aTopic)
|
||||
{
|
||||
if (aTopic == "quit-application-granted") {
|
||||
HUDService.shutdown();
|
||||
}
|
||||
},
|
||||
|
||||
uninit: function WCO_uninit()
|
||||
{
|
||||
Services.obs.removeObserver(this, "quit-application-granted");
|
||||
let window = HUDService.currentContext();
|
||||
let target = TargetFactory.forTab(window.gBrowser.selectedTab);
|
||||
let toolbox = gDevTools.getToolbox(target);
|
||||
let panel = toolbox ? toolbox.getPanel("webconsole") : null;
|
||||
return panel ? panel.hud : null;
|
||||
},
|
||||
};
|
||||
|
||||
const HUDService = new HUD_SERVICE();
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@ this.EXPORTED_SYMBOLS = [ "WebConsolePanel" ];
|
|||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/commonjs/promise/core.js");
|
||||
Cu.import("resource:///modules/devtools/EventEmitter.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
|
||||
"resource:///modules/HUDService.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
|
||||
"resource:///modules/devtools/EventEmitter.jsm");
|
||||
|
||||
/**
|
||||
* A DevToolPanel that controls the Web Console.
|
||||
*/
|
||||
|
@ -26,32 +26,29 @@ function WebConsolePanel(iframeWindow, toolbox) {
|
|||
}
|
||||
|
||||
WebConsolePanel.prototype = {
|
||||
hud: null,
|
||||
|
||||
/**
|
||||
* open is effectively an asynchronous constructor
|
||||
* Open is effectively an asynchronous constructor.
|
||||
*
|
||||
* @return object
|
||||
* A Promise that is resolved when the Web Console completes opening.
|
||||
*/
|
||||
open: function StyleEditor_open() {
|
||||
let parentDoc = this._frameWindow.document.defaultView.parent.document;
|
||||
open: function WCP_open()
|
||||
{
|
||||
let parentDoc = this._toolbox.doc;
|
||||
let iframe = parentDoc.getElementById("toolbox-panel-iframe-webconsole");
|
||||
this.hud = HUDService.activateHUDForContext(this.target.tab, iframe,
|
||||
this._toolbox.target);
|
||||
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let hudId = this.hud.hudId;
|
||||
let onOpen = function _onWebConsoleOpen(aSubject) {
|
||||
aSubject.QueryInterface(Ci.nsISupportsString);
|
||||
if (hudId == aSubject.data) {
|
||||
Services.obs.removeObserver(onOpen, "web-console-created");
|
||||
let promise = HUDService.openWebConsole(this.target, iframe);
|
||||
|
||||
return promise.then(function onSuccess(aWebConsole) {
|
||||
this.hud = aWebConsole;
|
||||
this._isReady = true;
|
||||
this.emit("ready");
|
||||
deferred.resolve(this);
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
Services.obs.addObserver(onOpen, "web-console-created", false);
|
||||
|
||||
return deferred.promise;
|
||||
return this;
|
||||
}.bind(this), function onError(aReason) {
|
||||
Cu.reportError("WebConsolePanel open failed. " +
|
||||
aReason.error + ": " + aReason.message);
|
||||
});
|
||||
},
|
||||
|
||||
get target() this._toolbox.target,
|
||||
|
@ -61,28 +58,15 @@ WebConsolePanel.prototype = {
|
|||
|
||||
destroy: function WCP_destroy()
|
||||
{
|
||||
if (this.destroyer) {
|
||||
return this.destroyer.promise;
|
||||
if (this._destroyer) {
|
||||
return this._destroyer;
|
||||
}
|
||||
|
||||
this.destroyer = Promise.defer();
|
||||
|
||||
let hudId = this.hud.hudId;
|
||||
|
||||
let onClose = function _onWebConsoleClose(aSubject)
|
||||
{
|
||||
aSubject.QueryInterface(Ci.nsISupportsString);
|
||||
if (hudId == aSubject.data) {
|
||||
Services.obs.removeObserver(onClose, "web-console-destroyed");
|
||||
|
||||
this._destroyer = this.hud.destroy();
|
||||
this._destroyer.then(function() {
|
||||
this.emit("destroyed");
|
||||
this.destroyer.resolve(null);
|
||||
}
|
||||
}.bind(this);
|
||||
}.bind(this));
|
||||
|
||||
Services.obs.addObserver(onClose, "web-console-destroyed", false);
|
||||
HUDService.deactivateHUDForContext(this.hud.tab, false);
|
||||
|
||||
return this.destroyer.promise;
|
||||
return this._destroyer;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -28,14 +28,17 @@ function testClosingAfterCompletion(hud) {
|
|||
|
||||
// Focus the inputNode and perform the keycombo to close the WebConsole.
|
||||
inputNode.focus();
|
||||
EventUtils.synthesizeKey("k", { accelKey: true, shiftKey: true });
|
||||
|
||||
// We can't test for errors right away, because the error occurs after a
|
||||
// setTimeout(..., 0) in the WebConsole code.
|
||||
executeSoon(function() {
|
||||
gDevTools.once("toolbox-destroyed", function() {
|
||||
browser.removeEventListener("error", errorListener, false);
|
||||
is(errorWhileClosing, false, "no error while closing the WebConsole");
|
||||
finishTest();
|
||||
});
|
||||
|
||||
if (Services.appinfo.OS == "Darwin") {
|
||||
EventUtils.synthesizeKey("k", { accelKey: true, altKey: true });
|
||||
} else {
|
||||
EventUtils.synthesizeKey("k", { accelKey: true, shiftKey: true });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,13 +57,14 @@ function openConsoles() {
|
|||
let tab = openTabs[i];
|
||||
openConsole(tab, function(index, hud) {
|
||||
ok(hud, "HUD is open for tab " + index);
|
||||
let window = hud.tab.linkedBrowser.contentWindow;
|
||||
let window = hud.target.tab.linkedBrowser.contentWindow;
|
||||
window.console.log("message for tab " + index);
|
||||
consolesOpen++;
|
||||
}.bind(null, i));
|
||||
}
|
||||
|
||||
waitForSuccess({
|
||||
timeout: 10000,
|
||||
name: "4 web consoles opened",
|
||||
validatorFn: function()
|
||||
{
|
||||
|
|
|
@ -67,6 +67,7 @@ function onStyleEditorReady(aEvent, aPanel)
|
|||
return sheet;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
waitForFocus(function() {
|
||||
|
|
|
@ -238,9 +238,11 @@ function finishTest()
|
|||
finish();
|
||||
return;
|
||||
}
|
||||
if (hud.jsterm) {
|
||||
hud.jsterm.clearOutput(true);
|
||||
}
|
||||
|
||||
closeConsole(hud.tab, finish);
|
||||
closeConsole(hud.target.tab, finish);
|
||||
|
||||
hud = null;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "AutocompletePopup",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
|
||||
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/commonjs/promise/core.js");
|
||||
|
||||
const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
|
||||
let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
|
||||
|
||||
|
@ -168,9 +171,9 @@ const MIN_FONT_SIZE = 10;
|
|||
const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout";
|
||||
|
||||
/**
|
||||
* A WebConsoleFrame instance is an interactive console initialized *per tab*
|
||||
* A WebConsoleFrame instance is an interactive console initialized *per target*
|
||||
* that displays console log data as well as provides an interactive terminal to
|
||||
* manipulate the current tab's document content.
|
||||
* manipulate the target's document content.
|
||||
*
|
||||
* The WebConsoleFrame is responsible for the actual Web Console UI
|
||||
* implementation.
|
||||
|
@ -190,18 +193,9 @@ function WebConsoleFrame(aWebConsoleOwner)
|
|||
|
||||
this._toggleFilter = this._toggleFilter.bind(this);
|
||||
this._flushMessageQueue = this._flushMessageQueue.bind(this);
|
||||
this._connectionTimeout = this._connectionTimeout.bind(this);
|
||||
|
||||
this._outputTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this._outputTimerInitialized = false;
|
||||
|
||||
this._initDefaultFilterPrefs();
|
||||
this._commandController = new CommandController(this);
|
||||
this.positionConsole(window);
|
||||
|
||||
this.jsterm = new JSTerm(this);
|
||||
this.jsterm.inputNode.focus();
|
||||
this._initConnection();
|
||||
}
|
||||
|
||||
WebConsoleFrame.prototype = {
|
||||
|
@ -222,13 +216,6 @@ WebConsoleFrame.prototype = {
|
|||
*/
|
||||
proxy: null,
|
||||
|
||||
/**
|
||||
* Timer used for the connection.
|
||||
* @private
|
||||
* @type object
|
||||
*/
|
||||
_connectTimer: null,
|
||||
|
||||
/**
|
||||
* Getter for the xul:popupset that holds any popups we open.
|
||||
* @type nsIDOMElement
|
||||
|
@ -306,7 +293,7 @@ WebConsoleFrame.prototype = {
|
|||
groupDepth: 0,
|
||||
|
||||
/**
|
||||
* The current tab location.
|
||||
* The current target location.
|
||||
* @type string
|
||||
*/
|
||||
contentLocation: "",
|
||||
|
@ -336,6 +323,8 @@ WebConsoleFrame.prototype = {
|
|||
*/
|
||||
get webConsoleClient() this.proxy ? this.proxy.webConsoleClient : null,
|
||||
|
||||
_destroyer: null,
|
||||
|
||||
_saveRequestAndResponseBodies: false,
|
||||
|
||||
/**
|
||||
|
@ -364,60 +353,51 @@ WebConsoleFrame.prototype = {
|
|||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize the WebConsoleFrame instance.
|
||||
* @return object
|
||||
* A Promise object for the initialization.
|
||||
*/
|
||||
init: function WCF_init()
|
||||
{
|
||||
this._initUI();
|
||||
return this._initConnection();
|
||||
},
|
||||
|
||||
/**
|
||||
* Connect to the server using the remote debugging protocol.
|
||||
*
|
||||
* @private
|
||||
* @return object
|
||||
* A Promise object that is resolved/reject based on the connection
|
||||
* result.
|
||||
*/
|
||||
_initConnection: function WCF__initConnection()
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
|
||||
this.proxy = new WebConsoleConnectionProxy(this, this.owner.target);
|
||||
|
||||
let timeout = Services.prefs.getIntPref(PREF_CONNECTION_TIMEOUT);
|
||||
this._connectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this._connectTimer.initWithCallback(this._connectionTimeout,
|
||||
timeout, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
|
||||
this.proxy.connect(function() {
|
||||
// Don't complete connection if the connection timed-out.
|
||||
if (this._connectTimer) {
|
||||
this._connectTimer.cancel();
|
||||
this._connectTimer = null;
|
||||
let onSuccess = function() {
|
||||
this.saveRequestAndResponseBodies = this._saveRequestAndResponseBodies;
|
||||
this._onInitComplete();
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Connection timeout handler. This method simply prints a message informing
|
||||
* the user that the connection timed-out.
|
||||
* @private
|
||||
*/
|
||||
_connectionTimeout: function WCF__connectionTimeout()
|
||||
{
|
||||
this._connectTimer = null;
|
||||
deferred.resolve(this);
|
||||
}.bind(this);
|
||||
|
||||
let onFailure = function(aReason) {
|
||||
let node = this.createMessageNode(CATEGORY_JS, SEVERITY_ERROR,
|
||||
l10n.getStr("connectionTimeout"));
|
||||
aReason.error + ": " + aReason.message);
|
||||
this.outputMessage(CATEGORY_JS, node);
|
||||
deferred.reject(aReason);
|
||||
}.bind(this);
|
||||
|
||||
// Allow initialization to complete.
|
||||
this._onInitComplete();
|
||||
},
|
||||
let sendNotification = function() {
|
||||
let id = WebConsoleUtils.supportsString(this.hudId);
|
||||
Services.obs.notifyObservers(id, "web-console-created", null);
|
||||
}.bind(this);
|
||||
|
||||
/**
|
||||
* Reset the connection timeout timer.
|
||||
* @private
|
||||
*/
|
||||
_resetConnectionTimeout: function WCF__resetConnectionTimeout()
|
||||
{
|
||||
let timer = this._connectTimer;
|
||||
if (timer) {
|
||||
let timeout = timer.delay;
|
||||
timer.cancel();
|
||||
timer.initWithCallback(this._connectionTimeout, timeout,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
this.proxy.connect().then(onSuccess, onFailure).then(sendNotification);
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -426,6 +406,18 @@ WebConsoleFrame.prototype = {
|
|||
*/
|
||||
_initUI: function WCF__initUI()
|
||||
{
|
||||
// Remember that this script is loaded in the webconsole.xul context:
|
||||
// |window| is the iframe global.
|
||||
this.window = window;
|
||||
this.document = this.window.document;
|
||||
this.rootElement = this.document.documentElement;
|
||||
|
||||
this._initDefaultFilterPrefs();
|
||||
|
||||
// Register the controller to handle "select all" properly.
|
||||
this._commandController = new CommandController(this);
|
||||
this.window.controllers.insertControllerAt(0, this._commandController);
|
||||
|
||||
let doc = this.document;
|
||||
|
||||
this.filterBox = doc.querySelector(".hud-filter-box");
|
||||
|
@ -482,6 +474,10 @@ WebConsoleFrame.prototype = {
|
|||
this.owner._onClearButton();
|
||||
this.jsterm.clearOutput(true);
|
||||
}.bind(this));
|
||||
|
||||
this.jsterm = new JSTerm(this);
|
||||
this.jsterm.init();
|
||||
this.jsterm.inputNode.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -567,54 +563,6 @@ WebConsoleFrame.prototype = {
|
|||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback method for when the Web Console initialization is complete. For
|
||||
* now this method sends the web-console-created notification using the
|
||||
* nsIObserverService.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onInitComplete: function WC__onInitComplete()
|
||||
{
|
||||
let id = WebConsoleUtils.supportsString(this.hudId);
|
||||
Services.obs.notifyObservers(id, "web-console-created", null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Position the console in a different location.
|
||||
*
|
||||
* Note: you do not usually call this method. This is called by the WebConsole
|
||||
* instance that owns this iframe. You need to call this if you write
|
||||
* a different owner or you manually reposition the iframe.
|
||||
*
|
||||
* @param object aNewWindow
|
||||
* Repositioning causes the iframe to reload - bug 254144. You need to
|
||||
* provide the new window object so we can reinitialize the UI as
|
||||
* needed.
|
||||
*/
|
||||
positionConsole: function WCF_positionConsole(aNewWindow)
|
||||
{
|
||||
this.window = aNewWindow;
|
||||
this.document = this.window.document;
|
||||
this.rootElement = this.document.documentElement;
|
||||
|
||||
// register the controller to handle "select all" properly
|
||||
this.window.controllers.insertControllerAt(0, this._commandController);
|
||||
|
||||
let oldOutputNode = this.outputNode;
|
||||
|
||||
this._initUI();
|
||||
this.jsterm && this.jsterm._initUI();
|
||||
|
||||
if (oldOutputNode && oldOutputNode.childNodes.length) {
|
||||
let parentNode = this.outputNode.parentNode;
|
||||
parentNode.replaceChild(oldOutputNode, this.outputNode);
|
||||
this.outputNode = oldOutputNode;
|
||||
}
|
||||
|
||||
this.jsterm && this.jsterm.inputNode.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Increase, decrease or reset the font size.
|
||||
*
|
||||
|
@ -2706,15 +2654,21 @@ WebConsoleFrame.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Destroy the HUD object. Call this method to avoid memory leaks when the Web
|
||||
* Console is closed.
|
||||
* Destroy the WebConsoleFrame object. Call this method to avoid memory leaks
|
||||
* when the Web Console is closed.
|
||||
*
|
||||
* @param function [aOnDestroy]
|
||||
* Optional function to invoke when the Web Console instance is
|
||||
* @return object
|
||||
* A Promise that is resolved when the WebConsoleFrame instance is
|
||||
* destroyed.
|
||||
*/
|
||||
destroy: function WCF_destroy(aOnDestroy)
|
||||
destroy: function WCF_destroy()
|
||||
{
|
||||
if (this._destroyer) {
|
||||
return this._destroyer.promise;
|
||||
}
|
||||
|
||||
this._destroyer = Promise.defer();
|
||||
|
||||
this._cssNodes = {};
|
||||
this._outputQueue = [];
|
||||
this._pruneCategoriesQueue = {};
|
||||
|
@ -2726,22 +2680,26 @@ WebConsoleFrame.prototype = {
|
|||
}
|
||||
this._outputTimer = null;
|
||||
|
||||
if (this._connectTimer) {
|
||||
this._connectTimer.cancel();
|
||||
}
|
||||
this._connectTimer = null;
|
||||
|
||||
if (this.proxy) {
|
||||
this.proxy.disconnect(aOnDestroy);
|
||||
this.proxy = null;
|
||||
}
|
||||
|
||||
if (this.jsterm) {
|
||||
this.jsterm.destroy();
|
||||
this.jsterm = null;
|
||||
}
|
||||
|
||||
this._commandController = null;
|
||||
|
||||
let onDestroy = function() {
|
||||
this._destroyer.resolve(null);
|
||||
}.bind(this);
|
||||
|
||||
if (this.proxy) {
|
||||
this.proxy.disconnect().then(onDestroy);
|
||||
this.proxy = null;
|
||||
}
|
||||
else {
|
||||
onDestroy();
|
||||
}
|
||||
|
||||
return this._destroyer.promise;
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -2763,12 +2721,8 @@ function JSTerm(aWebConsoleFrame)
|
|||
this.history = [];
|
||||
this.historyIndex = 0;
|
||||
this.historyPlaceHolder = 0; // this.history.length;
|
||||
this.autocompletePopup = new AutocompletePopup(this.hud.owner.chromeDocument);
|
||||
this.autocompletePopup.onSelect = this.onAutocompleteSelect.bind(this);
|
||||
this.autocompletePopup.onClick = this.acceptProposedCompletion.bind(this);
|
||||
this._keyPress = this.keyPress.bind(this);
|
||||
this._inputEventHandler = this.inputEventHandler.bind(this);
|
||||
this._initUI();
|
||||
}
|
||||
|
||||
JSTerm.prototype = {
|
||||
|
@ -2790,6 +2744,10 @@ JSTerm.prototype = {
|
|||
*/
|
||||
history: null,
|
||||
|
||||
autocompletePopup: null,
|
||||
inputNode: null,
|
||||
completeNode: null,
|
||||
|
||||
/**
|
||||
* Getter for the element that holds the messages we display.
|
||||
* @type nsIDOMElement
|
||||
|
@ -2808,10 +2766,14 @@ JSTerm.prototype = {
|
|||
|
||||
/**
|
||||
* Initialize the JSTerminal UI.
|
||||
* @private
|
||||
*/
|
||||
_initUI: function JST__initUI()
|
||||
init: function JST_init()
|
||||
{
|
||||
let chromeDocument = this.hud.owner.chromeDocument;
|
||||
this.autocompletePopup = new AutocompletePopup(chromeDocument);
|
||||
this.autocompletePopup.onSelect = this.onAutocompleteSelect.bind(this);
|
||||
this.autocompletePopup.onClick = this.acceptProposedCompletion.bind(this);
|
||||
|
||||
let doc = this.hud.document;
|
||||
this.completeNode = doc.querySelector(".jsterm-complete-node");
|
||||
this.inputNode = doc.querySelector(".jsterm-input-node");
|
||||
|
@ -3819,6 +3781,12 @@ JSTerm.prototype = {
|
|||
this.autocompletePopup.destroy();
|
||||
this.autocompletePopup = null;
|
||||
|
||||
let popup = this.hud.owner.chromeDocument
|
||||
.getElementById("webConsole_autocompletePopup");
|
||||
if (popup) {
|
||||
popup.parentNode.removeChild(popup);
|
||||
}
|
||||
|
||||
this.inputNode.removeEventListener("keypress", this._keyPress, false);
|
||||
this.inputNode.removeEventListener("input", this._inputEventHandler, false);
|
||||
this.inputNode.removeEventListener("keyup", this._inputEventHandler, false);
|
||||
|
@ -4047,6 +4015,11 @@ function WebConsoleConnectionProxy(aWebConsole, aTarget)
|
|||
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
|
||||
this._onFileActivity = this._onFileActivity.bind(this);
|
||||
this._onTabNavigated = this._onTabNavigated.bind(this);
|
||||
this._onListTabs = this._onListTabs.bind(this);
|
||||
this._onAttachTab = this._onAttachTab.bind(this);
|
||||
this._onAttachConsole = this._onAttachConsole.bind(this);
|
||||
this._onCachedMessages = this._onCachedMessages.bind(this);
|
||||
this._connectionTimeout = this._connectionTimeout.bind(this);
|
||||
}
|
||||
|
||||
WebConsoleConnectionProxy.prototype = {
|
||||
|
@ -4092,6 +4065,16 @@ WebConsoleConnectionProxy.prototype = {
|
|||
*/
|
||||
connected: false,
|
||||
|
||||
/**
|
||||
* Timer used for the connection.
|
||||
* @private
|
||||
* @type object
|
||||
*/
|
||||
_connectTimer: null,
|
||||
|
||||
_connectDefer: null,
|
||||
_disconnecter: null,
|
||||
|
||||
/**
|
||||
* The WebConsoleActor ID.
|
||||
*
|
||||
|
@ -4130,11 +4113,31 @@ WebConsoleConnectionProxy.prototype = {
|
|||
/**
|
||||
* Initialize a debugger client and connect it to the debugger server.
|
||||
*
|
||||
* @param function [aCallback]
|
||||
* Optional function to invoke when connection is established.
|
||||
* @return object
|
||||
* A Promise object that is resolved/rejected based on the success of
|
||||
* the connection initialization.
|
||||
*/
|
||||
connect: function WCCP_connect(aCallback)
|
||||
connect: function WCCP_connect()
|
||||
{
|
||||
if (this._connectDefer) {
|
||||
return this._connectDefer.promise;
|
||||
}
|
||||
|
||||
this._connectDefer = Promise.defer();
|
||||
|
||||
let timeout = Services.prefs.getIntPref(PREF_CONNECTION_TIMEOUT);
|
||||
this._connectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this._connectTimer.initWithCallback(this._connectionTimeout,
|
||||
timeout, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
|
||||
let promise = this._connectDefer.promise;
|
||||
promise.then(function _onSucess() {
|
||||
this._connectTimer.cancel();
|
||||
this._connectTimer = null;
|
||||
}.bind(this), function _onFailure() {
|
||||
this._connectTimer = null;
|
||||
}.bind(this));
|
||||
|
||||
// TODO: convert the non-remote path to use the target API as well.
|
||||
let transport, client;
|
||||
if (this.target.isRemote) {
|
||||
|
@ -4143,7 +4146,6 @@ WebConsoleConnectionProxy.prototype = {
|
|||
else {
|
||||
this.initServer();
|
||||
transport = DebuggerServer.connectPipe();
|
||||
|
||||
client = this.client = new DebuggerClient(transport);
|
||||
}
|
||||
|
||||
|
@ -4157,39 +4159,54 @@ WebConsoleConnectionProxy.prototype = {
|
|||
if (this.target.isRemote) {
|
||||
if (!this.target.chrome) {
|
||||
// target.form is a TabActor grip
|
||||
this._attachTab(this.target.form, aCallback);
|
||||
this._attachTab(this.target.form);
|
||||
}
|
||||
else {
|
||||
// target.form is a RootActor grip
|
||||
this._consoleActor = this.target.form.consoleActor;
|
||||
this._attachConsole(aCallback);
|
||||
this._attachConsole();
|
||||
}
|
||||
}
|
||||
else {
|
||||
client.connect(function(aType, aTraits) {
|
||||
client.listTabs(this._onListTabs.bind(this, aCallback));
|
||||
client.listTabs(this._onListTabs);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
return promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Connection timeout handler.
|
||||
* @private
|
||||
*/
|
||||
_connectionTimeout: function WCCP__connectionTimeout()
|
||||
{
|
||||
let error = {
|
||||
error: "timeout",
|
||||
message: l10n.getStr("connectionTimeout"),
|
||||
};
|
||||
|
||||
this._connectDefer.reject(error);
|
||||
},
|
||||
|
||||
/**
|
||||
* The "listTabs" response handler.
|
||||
*
|
||||
* @private
|
||||
* @param function [aCallback]
|
||||
* Optional function to invoke once the connection is established.
|
||||
* @param object aResponse
|
||||
* The JSON response object received from the server.
|
||||
*/
|
||||
_onListTabs: function WCCP__onListTabs(aCallback, aResponse)
|
||||
_onListTabs: function WCCP__onListTabs(aResponse)
|
||||
{
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("listTabs failed: " + aResponse.error + " " +
|
||||
aResponse.message);
|
||||
this._connectDefer.reject(aResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
this._attachTab(aResponse.tabs[aResponse.selected], aCallback);
|
||||
this._attachTab(aResponse.tabs[aResponse.selected]);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -4198,74 +4215,65 @@ WebConsoleConnectionProxy.prototype = {
|
|||
* @private
|
||||
* @param object aTab
|
||||
* Grip for the tab to attach to.
|
||||
* @param function aCallback
|
||||
* Function to invoke when the connection is established.
|
||||
*/
|
||||
_attachTab: function WCCP__attachTab(aTab, aCallback)
|
||||
_attachTab: function WCCP__attachTab(aTab)
|
||||
{
|
||||
this._consoleActor = aTab.consoleActor;
|
||||
this._tabActor = aTab.actor;
|
||||
this.owner.onLocationChange(aTab.url, aTab.title);
|
||||
this.client.attachTab(this._tabActor,
|
||||
this._onAttachTab.bind(this, aCallback));
|
||||
this.client.attachTab(this._tabActor, this._onAttachTab);
|
||||
},
|
||||
|
||||
/**
|
||||
* The "attachTab" response handler.
|
||||
*
|
||||
* @private
|
||||
* @param function [aCallback]
|
||||
* Optional function to invoke once the connection is established.
|
||||
* @param object aResponse
|
||||
* The JSON response object received from the server.
|
||||
* @param object aTabClient
|
||||
* The TabClient instance for the attached tab.
|
||||
*/
|
||||
_onAttachTab: function WCCP__onAttachTab(aCallback, aResponse, aTabClient)
|
||||
_onAttachTab: function WCCP__onAttachTab(aResponse, aTabClient)
|
||||
{
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("attachTab failed: " + aResponse.error + " " +
|
||||
aResponse.message);
|
||||
this._connectDefer.reject(aResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
this.tabClient = aTabClient;
|
||||
this._attachConsole(aCallback);
|
||||
this._attachConsole();
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach to the Web Console actor.
|
||||
*
|
||||
* @private
|
||||
* @param function aCallback
|
||||
* Function to invoke when the connection is established.
|
||||
*/
|
||||
_attachConsole: function WCCP__attachConsole(aCallback)
|
||||
_attachConsole: function WCCP__attachConsole()
|
||||
{
|
||||
let listeners = ["PageError", "ConsoleAPI", "NetworkActivity",
|
||||
"FileActivity"];
|
||||
this.client.attachConsole(this._consoleActor, listeners,
|
||||
this._onAttachConsole.bind(this, aCallback));
|
||||
this._onAttachConsole);
|
||||
},
|
||||
|
||||
/**
|
||||
* The "attachConsole" response handler.
|
||||
*
|
||||
* @private
|
||||
* @param function [aCallback]
|
||||
* Optional function to invoke once the connection is established.
|
||||
* @param object aResponse
|
||||
* The JSON response object received from the server.
|
||||
* @param object aWebConsoleClient
|
||||
* The WebConsoleClient instance for the attached console, for the
|
||||
* specific tab we work with.
|
||||
*/
|
||||
_onAttachConsole:
|
||||
function WCCP__onAttachConsole(aCallback, aResponse, aWebConsoleClient)
|
||||
_onAttachConsole: function WCCP__onAttachConsole(aResponse, aWebConsoleClient)
|
||||
{
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("attachConsole failed: " + aResponse.error + " " +
|
||||
aResponse.message);
|
||||
this._connectDefer.reject(aResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4274,27 +4282,31 @@ WebConsoleConnectionProxy.prototype = {
|
|||
this._hasNativeConsoleAPI = aResponse.nativeConsoleAPI;
|
||||
|
||||
let msgs = ["PageError", "ConsoleAPI"];
|
||||
this.webConsoleClient.getCachedMessages(msgs,
|
||||
this._onCachedMessages.bind(this, aCallback));
|
||||
this.webConsoleClient.getCachedMessages(msgs, this._onCachedMessages);
|
||||
},
|
||||
|
||||
/**
|
||||
* The "cachedMessages" response handler.
|
||||
*
|
||||
* @private
|
||||
* @param function [aCallback]
|
||||
* Optional function to invoke once the connection is established.
|
||||
* @param object aResponse
|
||||
* The JSON response object received from the server.
|
||||
*/
|
||||
_onCachedMessages: function WCCP__onCachedMessages(aCallback, aResponse)
|
||||
_onCachedMessages: function WCCP__onCachedMessages(aResponse)
|
||||
{
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("Web Console getCachedMessages error: " + aResponse.error +
|
||||
" " + aResponse.message);
|
||||
this._connectDefer.reject(aResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._connectTimer) {
|
||||
// This happens if the Promise is rejected (eg. a timeout), but the
|
||||
// connection attempt is successful, nonetheless.
|
||||
Cu.reportError("Web Console getCachedMessages error: invalid state.");
|
||||
}
|
||||
|
||||
this.owner.displayCachedMessages(aResponse.messages);
|
||||
|
||||
if (!this._hasNativeConsoleAPI) {
|
||||
|
@ -4302,7 +4314,7 @@ WebConsoleConnectionProxy.prototype = {
|
|||
}
|
||||
|
||||
this.connected = true;
|
||||
aCallback && aCallback();
|
||||
this._connectDefer.resolve(this);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -4432,30 +4444,33 @@ WebConsoleConnectionProxy.prototype = {
|
|||
/**
|
||||
* Disconnect the Web Console from the remote server.
|
||||
*
|
||||
* @param function [aOnDisconnect]
|
||||
* Optional function to invoke when the connection is dropped.
|
||||
* @return object
|
||||
* A Promise object that is resolved when disconnect completes.
|
||||
*/
|
||||
disconnect: function WCCP_disconnect(aOnDisconnect)
|
||||
disconnect: function WCCP_disconnect()
|
||||
{
|
||||
if (this._disconnecter) {
|
||||
return this._disconnecter.promise;
|
||||
}
|
||||
|
||||
this._disconnecter = Promise.defer();
|
||||
|
||||
if (!this.client) {
|
||||
aOnDisconnect && aOnDisconnect();
|
||||
return;
|
||||
this._disconnecter.resolve(null);
|
||||
return this._disconnecter.promise;
|
||||
}
|
||||
|
||||
let onDisconnect = function() {
|
||||
if (timer) {
|
||||
timer.cancel();
|
||||
timer = null;
|
||||
this._disconnecter.resolve(null);
|
||||
}
|
||||
if (aOnDisconnect) {
|
||||
aOnDisconnect();
|
||||
aOnDisconnect = null;
|
||||
}
|
||||
};
|
||||
}.bind(this);
|
||||
|
||||
let timer = null;
|
||||
let remoteTarget = this.target.isRemote;
|
||||
if (aOnDisconnect && !remoteTarget) {
|
||||
if (!remoteTarget) {
|
||||
timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(onDisconnect, 1500, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
|
@ -4476,20 +4491,21 @@ WebConsoleConnectionProxy.prototype = {
|
|||
this.connected = false;
|
||||
this.owner = null;
|
||||
|
||||
try {
|
||||
if (!remoteTarget) {
|
||||
try {
|
||||
client.close(onDisconnect);
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
Cu.reportError("Web Console disconnect exception: " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
onDisconnect();
|
||||
}
|
||||
|
||||
if (remoteTarget) {
|
||||
}
|
||||
else {
|
||||
onDisconnect();
|
||||
}
|
||||
|
||||
return this._disconnecter.promise;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ WebConsoleActor.prototype =
|
|||
this.consoleProgressListener.destroy();
|
||||
this.consoleProgressListener = null;
|
||||
}
|
||||
this.conn.removeActorPool(this.actorPool);
|
||||
this.conn.removeActorPool(this._actorPool);
|
||||
this._actorPool = null;
|
||||
this.sandbox = null;
|
||||
this._sandboxWindowId = 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче