mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Merge m-c to fx-team
This commit is contained in:
commit
86b4184349
@ -103,64 +103,26 @@ function DeviceTabActor(connection, browser) {
|
||||
|
||||
DeviceTabActor.prototype = new BrowserTabActor();
|
||||
|
||||
DeviceTabActor.prototype.grip = function DTA_grip() {
|
||||
dbg_assert(!this.exited,
|
||||
'grip() should not be called on exited browser actor.');
|
||||
dbg_assert(this.actorID,
|
||||
'tab should have an actorID.');
|
||||
Object.defineProperty(DeviceTabActor.prototype, "title", {
|
||||
get: function() {
|
||||
return this.browser.title;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
let response = {
|
||||
'actor': this.actorID,
|
||||
'title': this.browser.title,
|
||||
'url': this.browser.document.documentURI
|
||||
};
|
||||
Object.defineProperty(DeviceTabActor.prototype, "url", {
|
||||
get: function() {
|
||||
return this.browser.document.documentURI;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
// Walk over tab actors added by extensions and add them to a new ActorPool.
|
||||
let actorPool = new ActorPool(this.conn);
|
||||
this._createExtraActors(DebuggerServer.tabActorFactories, actorPool);
|
||||
if (!actorPool.isEmpty()) {
|
||||
this._tabActorPool = actorPool;
|
||||
this.conn.addActorPool(this._tabActorPool);
|
||||
}
|
||||
|
||||
this._appendExtraActors(response);
|
||||
return response;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a thread actor and a pool for context-lifetime actors. It then sets
|
||||
* up the content window for debugging.
|
||||
*/
|
||||
DeviceTabActor.prototype._pushContext = function DTA_pushContext() {
|
||||
dbg_assert(!this._contextPool, "Can't push multiple contexts");
|
||||
|
||||
this._contextPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._contextPool);
|
||||
|
||||
this.threadActor = new ThreadActor(this, this.browser.wrappedJSObject);
|
||||
this._contextPool.addActor(this.threadActor);
|
||||
};
|
||||
|
||||
// Protocol Request Handlers
|
||||
|
||||
/**
|
||||
* Prepare to enter a nested event loop by disabling debuggee events.
|
||||
*/
|
||||
DeviceTabActor.prototype.preNest = function DTA_preNest() {
|
||||
let windowUtils = this.browser
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.suppressEventHandling(true);
|
||||
windowUtils.suspendTimeouts();
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepare to exit a nested event loop by enabling debuggee events.
|
||||
*/
|
||||
DeviceTabActor.prototype.postNest = function DTA_postNest(aNestData) {
|
||||
let windowUtils = this.browser
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.resumeTimeouts();
|
||||
windowUtils.suppressEventHandling(false);
|
||||
};
|
||||
Object.defineProperty(DeviceTabActor.prototype, "contentWindow", {
|
||||
get: function() {
|
||||
return this.browser;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
|
@ -25,7 +25,7 @@ function DebuggerPanel(iframeWindow, toolbox) {
|
||||
this._controller._target = this.target;
|
||||
this._bkp = this._controller.Breakpoints;
|
||||
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
DebuggerPanel.prototype = {
|
||||
|
@ -215,9 +215,18 @@ let DebuggerController = {
|
||||
|
||||
/**
|
||||
* Called for each location change in the debugged tab.
|
||||
*
|
||||
* @param string aType
|
||||
* Packet type.
|
||||
* @param object aPacket
|
||||
* Packet received from the server.
|
||||
*/
|
||||
_onTabNavigated: function DC__onTabNavigated() {
|
||||
DebuggerView._handleTabNavigation();
|
||||
_onTabNavigated: function DC__onTabNavigated(aType, aPacket) {
|
||||
if (aPacket.state == "start") {
|
||||
DebuggerView._handleTabNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
this.ThreadState._handleTabNavigation();
|
||||
this.StackFrames._handleTabNavigation();
|
||||
this.SourceScripts._handleTabNavigation();
|
||||
|
@ -40,7 +40,14 @@ function testInitialLoad() {
|
||||
function testLocationChange()
|
||||
{
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
|
||||
gDebugger.DebuggerController.client.addListener("tabNavigated", function onTabNavigated(aEvent, aPacket) {
|
||||
dump("tabNavigated state " + aPacket.state + "\n");
|
||||
if (aPacket.state == "start") {
|
||||
return;
|
||||
}
|
||||
|
||||
gDebugger.DebuggerController.client.removeListener("tabNavigated", onTabNavigated);
|
||||
|
||||
ok(true, "tabNavigated event was fired.");
|
||||
info("Still attached to the tab.");
|
||||
|
||||
@ -59,7 +66,14 @@ function testLocationChange()
|
||||
|
||||
function testBack()
|
||||
{
|
||||
gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
|
||||
gDebugger.DebuggerController.client.addListener("tabNavigated", function onTabNavigated(aEvent, aPacket) {
|
||||
dump("tabNavigated state " + aPacket.state + "\n");
|
||||
if (aPacket.state == "start") {
|
||||
return;
|
||||
}
|
||||
|
||||
gDebugger.DebuggerController.client.removeListener("tabNavigated", onTabNavigated);
|
||||
|
||||
ok(true, "tabNavigated event was fired after going back.");
|
||||
info("Still attached to the tab.");
|
||||
|
||||
@ -79,7 +93,14 @@ function testBack()
|
||||
|
||||
function testForward()
|
||||
{
|
||||
gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
|
||||
gDebugger.DebuggerController.client.addListener("tabNavigated", function onTabNavigated(aEvent, aPacket) {
|
||||
dump("tabNavigated state " + aPacket.state + "\n");
|
||||
if (aPacket.state == "start") {
|
||||
return;
|
||||
}
|
||||
|
||||
gDebugger.DebuggerController.client.removeListener("tabNavigated", onTabNavigated);
|
||||
|
||||
ok(true, "tabNavigated event was fired after going forward.");
|
||||
info("Still attached to the tab.");
|
||||
|
||||
|
@ -73,7 +73,13 @@ function testSimpleCall() {
|
||||
function testLocationChange()
|
||||
{
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
|
||||
gDebugger.DebuggerController.client.addListener("tabNavigated", function onTabNavigated(aEvent, aPacket) {
|
||||
dump("tabNavigated state " + aPacket.state + "\n");
|
||||
if (aPacket.state == "start") {
|
||||
return;
|
||||
}
|
||||
gDebugger.DebuggerController.client.removeListener("tabNavigated", onTabNavigated);
|
||||
|
||||
ok(true, "tabNavigated event was fired.");
|
||||
info("Still attached to the tab.");
|
||||
|
||||
|
@ -73,7 +73,13 @@ function testSimpleCall() {
|
||||
function testLocationChange()
|
||||
{
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
|
||||
gDebugger.DebuggerController.client.addListener("tabNavigated", function onTabNavigated(aEvent, aPacket) {
|
||||
dump("tabNavigated state " + aPacket.state + "\n");
|
||||
if (aPacket.state == "start") {
|
||||
return;
|
||||
}
|
||||
gDebugger.DebuggerController.client.removeListener("tabNavigated", onTabNavigated);
|
||||
|
||||
ok(true, "tabNavigated event was fired.");
|
||||
info("Still attached to the tab.");
|
||||
|
||||
|
@ -50,7 +50,13 @@ function testSimpleCall() {
|
||||
function testLocationChange()
|
||||
{
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
|
||||
gDebugger.DebuggerController.client.addListener("tabNavigated", function onTabNavigated(aEvent, aPacket) {
|
||||
dump("tabNavigated state " + aPacket.state + "\n");
|
||||
if (aPacket.state == "start") {
|
||||
return;
|
||||
}
|
||||
gDebugger.DebuggerController.client.removeListener("tabNavigated", onTabNavigated);
|
||||
|
||||
ok(true, "tabNavigated event was fired.");
|
||||
info("Still attached to the tab.");
|
||||
|
||||
|
@ -26,7 +26,13 @@ function get_tab()
|
||||
get_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
|
||||
gTab1Actor = aGrip.actor;
|
||||
gClient.request({ to: aGrip.actor, type: "attach" }, function(aResponse) {
|
||||
gClient.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
|
||||
gClient.addListener("tabNavigated", function onTabNavigated(aEvent, aPacket) {
|
||||
dump("onTabNavigated state " + aPacket.state + "\n");
|
||||
if (aPacket.state == "start") {
|
||||
return;
|
||||
}
|
||||
gClient.removeListener("tabNavigated", onTabNavigated);
|
||||
|
||||
is(aPacket.url, TAB2_URL, "Got a tab navigation notification.");
|
||||
gClient.addOneTimeListener("tabDetached", function (aEvent, aPacket) {
|
||||
ok(true, "Got a tab detach notification.");
|
||||
|
@ -26,7 +26,7 @@ const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
*/
|
||||
this.ToolSidebar = function ToolSidebar(tabbox, panel, showTabstripe=true)
|
||||
{
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this._tabbox = tabbox;
|
||||
this._panelDoc = this._tabbox.ownerDocument;
|
||||
|
@ -170,7 +170,7 @@ Object.defineProperty(Target.prototype, "version", {
|
||||
* be web pages served over http(s), but they don't have to be.
|
||||
*/
|
||||
function TabTarget(tab) {
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
this._tab = tab;
|
||||
this._setupListeners();
|
||||
}
|
||||
@ -201,6 +201,10 @@ TabTarget.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
get isLocalTab() {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Listen to the different tabs events.
|
||||
*/
|
||||
@ -305,7 +309,7 @@ TabWebProgressListener.prototype = {
|
||||
* these will have a chrome: URL
|
||||
*/
|
||||
function WindowTarget(window) {
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
this._window = window;
|
||||
}
|
||||
|
||||
@ -329,6 +333,10 @@ WindowTarget.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
get isLocalTab() {
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Target is not alive anymore.
|
||||
*/
|
||||
@ -354,7 +362,7 @@ WindowTarget.prototype = {
|
||||
* A RemoteTarget represents a page living in a remote Firefox instance.
|
||||
*/
|
||||
function RemoteTarget(form, client, chrome) {
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
this._client = client;
|
||||
this._form = form;
|
||||
this._chrome = chrome;
|
||||
@ -362,8 +370,12 @@ function RemoteTarget(form, client, chrome) {
|
||||
this.destroy = this.destroy.bind(this);
|
||||
this.client.addListener("tabDetached", this.destroy);
|
||||
|
||||
this._onTabNavigated = function onRemoteTabNavigated() {
|
||||
this.emit("navigate");
|
||||
this._onTabNavigated = function onRemoteTabNavigated(aType, aPacket) {
|
||||
if (aPacket.state == "start") {
|
||||
this.emit("will-navigate", aPacket);
|
||||
} else {
|
||||
this.emit("navigate", aPacket);
|
||||
}
|
||||
}.bind(this);
|
||||
this.client.addListener("tabNavigated", this._onTabNavigated);
|
||||
}
|
||||
@ -376,14 +388,16 @@ RemoteTarget.prototype = {
|
||||
|
||||
get chrome() this._chrome,
|
||||
|
||||
get name() this._form._title,
|
||||
get name() this._form.title,
|
||||
|
||||
get url() this._form._url,
|
||||
get url() this._form.url,
|
||||
|
||||
get client() this._client,
|
||||
|
||||
get form() this._form,
|
||||
|
||||
get isLocalTab() false,
|
||||
|
||||
/**
|
||||
* Target is not alive anymore.
|
||||
*/
|
||||
|
@ -127,7 +127,7 @@ this.Toolbox = function Toolbox(target, selectedTool, hostType) {
|
||||
|
||||
this._host = this._createHost(hostType);
|
||||
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
gDevTools.on("tool-registered", this._toolRegistered);
|
||||
gDevTools.on("tool-unregistered", this._toolUnregistered);
|
||||
@ -270,6 +270,10 @@ Toolbox.prototype = {
|
||||
dockBox.removeChild(dockBox.firstChild);
|
||||
}
|
||||
|
||||
if (!this._target.isLocalTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
let sideEnabled = Services.prefs.getBoolPref(this._prefs.SIDE_ENABLED);
|
||||
|
||||
for each (let position in this.HostType) {
|
||||
@ -476,6 +480,10 @@ Toolbox.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._target.isLocalTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newHost = this._createHost(hostType);
|
||||
return newHost.open().then(function(iframe) {
|
||||
// change toolbox document's parent to the new host
|
||||
|
@ -33,7 +33,7 @@ this.Hosts = {
|
||||
function BottomHost(hostTab) {
|
||||
this.hostTab = hostTab;
|
||||
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
BottomHost.prototype = {
|
||||
@ -101,7 +101,7 @@ BottomHost.prototype = {
|
||||
function SidebarHost(hostTab) {
|
||||
this.hostTab = hostTab;
|
||||
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
SidebarHost.prototype = {
|
||||
@ -166,7 +166,7 @@ SidebarHost.prototype = {
|
||||
function WindowHost() {
|
||||
this._boundUnload = this._boundUnload.bind(this);
|
||||
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
WindowHost.prototype = {
|
||||
|
@ -31,7 +31,7 @@ this.DevTools = function DevTools() {
|
||||
// destroy() is an observer's handler so we need to preserve context.
|
||||
this.destroy = this.destroy.bind(this);
|
||||
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
Services.obs.addObserver(this.destroy, "quit-application", false);
|
||||
|
||||
|
@ -85,7 +85,7 @@ function finishUp() {
|
||||
* else gives us a place to write documentation.
|
||||
*/
|
||||
function DevToolPanel(iframeWindow, toolbox) {
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this._toolbox = toolbox;
|
||||
|
||||
|
@ -13,13 +13,21 @@
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<notificationbox id="toolbox-notificationbox" flex="1">
|
||||
<toolbar class="devtools-tabbar">
|
||||
#ifdef XP_MACOSX
|
||||
<hbox id="toolbox-controls">
|
||||
<toolbarbutton id="toolbox-close" class="devtools-closebutton"></toolbarbutton>
|
||||
<hbox id="toolbox-dock-buttons"/>
|
||||
</hbox>
|
||||
#endif
|
||||
<radiogroup id="toolbox-tabs" orient="horizontal">
|
||||
</radiogroup>
|
||||
<hbox id="toolbox-buttons" flex="1" pack="end"/>
|
||||
#ifndef XP_MACOSX
|
||||
<hbox id="toolbox-controls">
|
||||
<hbox id="toolbox-dock-buttons"/>
|
||||
<toolbarbutton id="toolbox-close" class="devtools-closebutton"></toolbarbutton>
|
||||
</hbox>
|
||||
#endif
|
||||
</toolbar>
|
||||
<deck id="toolbox-deck" flex="1">
|
||||
</deck>
|
||||
|
@ -84,7 +84,7 @@ this.Highlighter = function Highlighter(aTarget, aInspector, aToolbox)
|
||||
this.chromeWin = this.chromeDoc.defaultView;
|
||||
this.inspector = aInspector
|
||||
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this._init();
|
||||
}
|
||||
@ -139,8 +139,13 @@ Highlighter.prototype = {
|
||||
|
||||
this.onToolSelected = function(event, id) {
|
||||
if (id != "inspector") {
|
||||
this.chromeWin.clearTimeout(this.pageEventsMuter);
|
||||
this.detachMouseListeners();
|
||||
this.hide();
|
||||
} else {
|
||||
if (!this.locked) {
|
||||
this.attachMouseListeners();
|
||||
}
|
||||
this.show();
|
||||
}
|
||||
}.bind(this);
|
||||
|
@ -42,7 +42,7 @@ this.InspectorPanel = function InspectorPanel(iframeWindow, toolbox) {
|
||||
this.tabTarget = (this.target.tab != null);
|
||||
this.winTarget = (this.target.window != null);
|
||||
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
InspectorPanel.prototype = {
|
||||
|
@ -58,7 +58,7 @@ this.EXPORTED_SYMBOLS = ["Selection"];
|
||||
*
|
||||
*/
|
||||
this.Selection = function Selection(node=null, track={attributes:true,detached:true}) {
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
this._onMutations = this._onMutations.bind(this);
|
||||
this.track = track;
|
||||
this.setNode(node);
|
||||
|
@ -49,7 +49,7 @@ browser.jar:
|
||||
content/browser/devtools/commandlineoutput.xhtml (commandline/commandlineoutput.xhtml)
|
||||
content/browser/devtools/commandlinetooltip.xhtml (commandline/commandlinetooltip.xhtml)
|
||||
content/browser/devtools/framework/toolbox-window.xul (framework/toolbox-window.xul)
|
||||
content/browser/devtools/framework/toolbox.xul (framework/toolbox.xul)
|
||||
* content/browser/devtools/framework/toolbox.xul (framework/toolbox.xul)
|
||||
content/browser/devtools/framework/toolbox.css (framework/toolbox.css)
|
||||
content/browser/devtools/inspector/inspector.xul (inspector/inspector.xul)
|
||||
content/browser/devtools/inspector/inspector.css (inspector/inspector.css)
|
||||
|
@ -58,7 +58,7 @@ this.MarkupView = function MarkupView(aInspector, aFrame, aControllerWindow)
|
||||
this._onNewSelection();
|
||||
|
||||
this._boundKeyDown = this._onKeyDown.bind(this);
|
||||
this._frame.addEventListener("keydown", this._boundKeyDown, false);
|
||||
this._frame.contentWindow.addEventListener("keydown", this._boundKeyDown, false);
|
||||
|
||||
this._boundFocus = this._onFocus.bind(this);
|
||||
this._frame.addEventListener("focus", this._boundFocus, false);
|
||||
@ -490,7 +490,7 @@ MarkupView.prototype = {
|
||||
this._frame.contentWindow.removeEventListener("underflow", this._boundResizePreview, true);
|
||||
delete this._boundUpdatePreview;
|
||||
|
||||
this._frame.removeEventListener("keydown", this._boundKeyDown, true);
|
||||
this._frame.contentWindow.removeEventListener("keydown", this._boundKeyDown, true);
|
||||
delete this._boundKeyDown;
|
||||
|
||||
this._inspector.selection.off("new-node", this._boundOnNewSelection);
|
||||
|
@ -40,7 +40,7 @@ function ProfileUI(uid, panel) {
|
||||
let doc = panel.document;
|
||||
let win = panel.window;
|
||||
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.isReady = false;
|
||||
this.panel = panel;
|
||||
@ -183,7 +183,7 @@ function ProfilerPanel(frame, toolbox) {
|
||||
this.profiles = new Map();
|
||||
this._uid = 0;
|
||||
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
ProfilerPanel.prototype = {
|
||||
|
@ -69,16 +69,11 @@ this.ResponsiveUIManager = {
|
||||
this.toggle(aWindow, aTab);
|
||||
default:
|
||||
}
|
||||
},
|
||||
|
||||
get events() {
|
||||
if (!this._eventEmitter) {
|
||||
this._eventEmitter = new EventEmitter();
|
||||
}
|
||||
return this._eventEmitter;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
EventEmitter.decorate(ResponsiveUIManager);
|
||||
|
||||
let presets = [
|
||||
// Phones
|
||||
{key: "320x480", width: 320, height: 480}, // iPhone, B2G, with <meta viewport>
|
||||
@ -175,7 +170,7 @@ function ResponsiveUI(aWindow, aTab)
|
||||
if (this._floatingScrollbars)
|
||||
switchToFloatingScrollbars(this.tab);
|
||||
|
||||
ResponsiveUIManager.events.emit("on", this.tab, this);
|
||||
ResponsiveUIManager.emit("on", this.tab, this);
|
||||
}
|
||||
|
||||
ResponsiveUI.prototype = {
|
||||
@ -232,7 +227,7 @@ ResponsiveUI.prototype = {
|
||||
this.stack.removeAttribute("responsivemode");
|
||||
|
||||
delete this.tab.__responsiveUI;
|
||||
ResponsiveUIManager.events.emit("off", this.tab, this);
|
||||
ResponsiveUIManager.emit("off", this.tab, this);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
function test() {
|
||||
let instance, widthBeforeClose, heightBeforeClose;
|
||||
let events = ResponsiveUI.ResponsiveUIManager.events;
|
||||
let mgr = ResponsiveUI.ResponsiveUIManager;
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
@ -17,7 +17,7 @@ function test() {
|
||||
|
||||
function startTest() {
|
||||
document.getElementById("Tools:ResponsiveUI").removeAttribute("disabled");
|
||||
events.once("on", function() {executeSoon(onUIOpen)});
|
||||
mgr.once("on", function() {executeSoon(onUIOpen)});
|
||||
synthesizeKeyFromKeyTag("key_responsiveUI");
|
||||
}
|
||||
|
||||
@ -121,12 +121,12 @@ function test() {
|
||||
widthBeforeClose = content.innerWidth;
|
||||
heightBeforeClose = content.innerHeight;
|
||||
|
||||
events.once("off", function() {executeSoon(restart)});
|
||||
mgr.once("off", function() {executeSoon(restart)});
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
}
|
||||
|
||||
function restart() {
|
||||
events.once("on", function() {executeSoon(onUIOpen2)});
|
||||
mgr.once("on", function() {executeSoon(onUIOpen2)});
|
||||
synthesizeKeyFromKeyTag("key_responsiveUI");
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ function test() {
|
||||
is(content.innerWidth, widthBeforeClose, "width restored.");
|
||||
is(content.innerHeight, heightBeforeClose, "height restored.");
|
||||
|
||||
events.once("off", function() {executeSoon(finishUp)});
|
||||
mgr.once("off", function() {executeSoon(finishUp)});
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
}
|
||||
|
||||
|
@ -6,19 +6,23 @@ this.EXPORTED_SYMBOLS = ["EventEmitter"];
|
||||
|
||||
/**
|
||||
* EventEmitter.
|
||||
*
|
||||
* @param Object aObjectToExtend
|
||||
* If aObjectToExtend is not null, the public methods of EventEmitter
|
||||
* are bound to the object.
|
||||
*/
|
||||
this.EventEmitter = function EventEmitter(aObjectToExtend) {
|
||||
if (aObjectToExtend) {
|
||||
aObjectToExtend.on = this.on.bind(this);
|
||||
aObjectToExtend.off = this.off.bind(this);
|
||||
aObjectToExtend.once = this.once.bind(this);
|
||||
aObjectToExtend.emit = this.emit.bind(this);
|
||||
}
|
||||
}
|
||||
this.EventEmitter = function EventEmitter() {};
|
||||
|
||||
/**
|
||||
* Decorate an object with event emitter functionality.
|
||||
*
|
||||
* @param Object aObjectToDecorate
|
||||
* Bind all public methods of EventEmitter to
|
||||
* the aObjectToDecorate object.
|
||||
*/
|
||||
EventEmitter.decorate = function EventEmitter_decorate (aObjectToDecorate) {
|
||||
let emitter = new EventEmitter();
|
||||
aObjectToDecorate.on = emitter.on.bind(emitter);
|
||||
aObjectToDecorate.off = emitter.off.bind(emitter);
|
||||
aObjectToDecorate.once = emitter.once.bind(emitter);
|
||||
aObjectToDecorate.emit = emitter.emit.bind(emitter);
|
||||
};
|
||||
|
||||
EventEmitter.prototype = {
|
||||
/**
|
||||
@ -103,5 +107,5 @@ EventEmitter.prototype = {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ function testEmitter(aObject) {
|
||||
|
||||
if (aObject) {
|
||||
emitter = aObject;
|
||||
new EventEmitter(emitter);
|
||||
EventEmitter.decorate(emitter);
|
||||
} else {
|
||||
emitter = new EventEmitter();
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "StyleEditorChrome",
|
||||
"resource:///modules/devtools/StyleEditorChrome.jsm");
|
||||
|
||||
this.StyleEditorPanel = function StyleEditorPanel(panelWin, toolbox) {
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this._toolbox = toolbox;
|
||||
this._target = toolbox.target;
|
||||
|
@ -177,10 +177,13 @@ TiltVisualizer.prototype = {
|
||||
let target = TargetFactory.forTab(aTab);
|
||||
let toolbox = gDevTools.getToolbox(target);
|
||||
if (toolbox) {
|
||||
this.inspector = toolbox.getPanel("inspector");
|
||||
this.inspector.selection.on("new-node", this.onNewNodeFromInspector);
|
||||
this.inspector.selection.on("detached", this.onNewNodeFromInspector);
|
||||
this.onNewNodeFromInspector();
|
||||
let panel = toolbox.getPanel("inspector");
|
||||
if (panel) {
|
||||
this.inspector = panel;
|
||||
this.inspector.selection.on("new-node", this.onNewNodeFromInspector);
|
||||
this.inspector.selection.on("detached", this.onNewNodeFromInspector);
|
||||
this.onNewNodeFromInspector();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -22,7 +22,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
|
||||
function WebConsolePanel(iframeWindow, toolbox) {
|
||||
this._frameWindow = iframeWindow;
|
||||
this._toolbox = toolbox;
|
||||
new EventEmitter(this);
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
WebConsolePanel.prototype = {
|
||||
|
@ -117,6 +117,12 @@ MOCHITEST_BROWSER_FILES = \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(OS_ARCH), Darwin)
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
browser_webconsole_bug_804845_ctrl_key_nav.js \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
browser_webconsole_bug_618311_private_browsing.js \
|
||||
|
@ -0,0 +1,214 @@
|
||||
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*
|
||||
* Contributor(s):
|
||||
* zmgmoz <zmgmoz@gmail.com>
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// Test navigation of webconsole contents via ctrl-a, ctrl-e, ctrl-p, ctrl-n
|
||||
// see https://bugzilla.mozilla.org/show_bug.cgi?id=804845
|
||||
|
||||
let jsterm, inputNode;
|
||||
function test() {
|
||||
addTab("data:text/html;charset=utf-8,Web Console test for bug 804845 and bug 619598");
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
openConsole(null, doTests);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function doTests(HUD) {
|
||||
jsterm = HUD.jsterm;
|
||||
inputNode = jsterm.inputNode;
|
||||
ok(!jsterm.inputNode.value, "inputNode.value is empty");
|
||||
is(jsterm.inputNode.selectionStart, 0);
|
||||
is(jsterm.inputNode.selectionEnd, 0);
|
||||
|
||||
testSingleLineInputNavNoHistory();
|
||||
testMultiLineInputNavNoHistory();
|
||||
testNavWithHistory();
|
||||
|
||||
jsterm = inputNode = null;
|
||||
executeSoon(finishTest);
|
||||
}
|
||||
|
||||
function testSingleLineInputNavNoHistory() {
|
||||
// Single char input
|
||||
EventUtils.synthesizeKey("1", {});
|
||||
is(inputNode.selectionStart, 1, "caret location after single char input");
|
||||
|
||||
// nav to start/end with ctrl-a and ctrl-e;
|
||||
EventUtils.synthesizeKey("a", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 0, "caret location after single char input and ctrl-a");
|
||||
|
||||
EventUtils.synthesizeKey("e", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 1, "caret location after single char input and ctrl-e");
|
||||
|
||||
// Second char input
|
||||
EventUtils.synthesizeKey("2", {});
|
||||
// nav to start/end with up/down keys; verify behaviour using ctrl-p/ctrl-n
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(inputNode.selectionStart, 0, "caret location after two char input and VK_UP");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(inputNode.selectionStart, 2, "caret location after two char input and VK_DOWN");
|
||||
|
||||
EventUtils.synthesizeKey("a", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 0, "move caret to beginning of 2 char input with ctrl-a");
|
||||
EventUtils.synthesizeKey("a", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 0, "no change of caret location on repeat ctrl-a");
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 0, "no change of caret location on ctrl-p from beginning of line");
|
||||
|
||||
EventUtils.synthesizeKey("e", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 2, "move caret to end of 2 char input with ctrl-e");
|
||||
EventUtils.synthesizeKey("e", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 2, "no change of caret location on repeat ctrl-e");
|
||||
EventUtils.synthesizeKey("n", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 2, "no change of caret location on ctrl-n from end of line");
|
||||
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 0, "ctrl-p moves to start of line");
|
||||
|
||||
EventUtils.synthesizeKey("n", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 2, "ctrl-n moves to end of line");
|
||||
}
|
||||
|
||||
function testMultiLineInputNavNoHistory() {
|
||||
let lineValues = ["one", "2", "something longer", "", "", "three!"];
|
||||
jsterm.setInputValue("");
|
||||
// simulate shift-return
|
||||
for (let i = 0; i < lineValues.length; i++) {
|
||||
jsterm.setInputValue(inputNode.value + lineValues[i]);
|
||||
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true });
|
||||
}
|
||||
let inputValue = inputNode.value;
|
||||
is(inputNode.selectionStart, inputNode.selectionEnd);
|
||||
is(inputNode.selectionStart, inputValue.length, "caret at end of multiline input");
|
||||
|
||||
// possibility newline is represented by one ('\r', '\n') or two ('\r\n') chars
|
||||
let newlineString = inputValue.match(/(\r\n?|\n\r?)$/)[0];
|
||||
|
||||
// Ok, test navigating within the multi-line string!
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
let expectedStringAfterCarat = lineValues[5]+newlineString;
|
||||
is(inputNode.value.slice(inputNode.selectionStart), expectedStringAfterCarat,
|
||||
"up arrow from end of multiline");
|
||||
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(inputNode.value.slice(inputNode.selectionStart), "",
|
||||
"down arrow from within multiline");
|
||||
|
||||
// navigate up through input lines
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.value.slice(inputNode.selectionStart), expectedStringAfterCarat,
|
||||
"ctrl-p from end of multiline");
|
||||
|
||||
for (let i = 4; i >= 0; i--) {
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
expectedStringAfterCarat = lineValues[i] + newlineString + expectedStringAfterCarat;
|
||||
is(inputNode.value.slice(inputNode.selectionStart), expectedStringAfterCarat,
|
||||
"ctrl-p from within line " + i + " of multiline input");
|
||||
}
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 0, "reached start of input");
|
||||
is(inputNode.value, inputValue,
|
||||
"no change to multiline input on ctrl-p from beginning of multiline");
|
||||
|
||||
// navigate to end of first line
|
||||
EventUtils.synthesizeKey("e", { ctrlKey: true });
|
||||
let caretPos = inputNode.selectionStart;
|
||||
let expectedStringBeforeCarat = lineValues[0];
|
||||
is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
|
||||
"ctrl-e into multiline input");
|
||||
EventUtils.synthesizeKey("e", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, caretPos,
|
||||
"repeat ctrl-e doesn't change caret position in multiline input");
|
||||
|
||||
// navigate down one line; ctrl-a to the beginning; ctrl-e to end
|
||||
for (let i = 1; i < lineValues.length; i++) {
|
||||
EventUtils.synthesizeKey("n", { ctrlKey: true });
|
||||
EventUtils.synthesizeKey("a", { ctrlKey: true });
|
||||
caretPos = inputNode.selectionStart;
|
||||
expectedStringBeforeCarat += newlineString;
|
||||
is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
|
||||
"ctrl-a to beginning of line " + (i+1) + " in multiline input");
|
||||
|
||||
EventUtils.synthesizeKey("e", { ctrlKey: true });
|
||||
caretPos = inputNode.selectionStart;
|
||||
expectedStringBeforeCarat += lineValues[i];
|
||||
is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
|
||||
"ctrl-e to end of line " + (i+1) + "in multiline input");
|
||||
}
|
||||
}
|
||||
|
||||
function testNavWithHistory() {
|
||||
// NOTE: Tests does NOT currently define behaviour for ctrl-p/ctrl-n with
|
||||
// caret placed _within_ single line input
|
||||
let values = ['"single line input"',
|
||||
'"a longer single-line input to check caret repositioning"',
|
||||
['"multi-line"', '"input"', '"here!"'].join("\n"),
|
||||
];
|
||||
// submit to history
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
jsterm.setInputValue(values[i]);
|
||||
jsterm.execute();
|
||||
}
|
||||
is(inputNode.selectionStart, 0, "caret location at start of empty line");
|
||||
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, values[values.length-1].length,
|
||||
"caret location correct at end of last history input");
|
||||
|
||||
// Navigate backwards history with ctrl-p
|
||||
for (let i = values.length-1; i > 0; i--) {
|
||||
let match = values[i].match(/(\n)/g);
|
||||
if (match) {
|
||||
// multi-line inputs won't update from history unless caret at beginning
|
||||
EventUtils.synthesizeKey("a", { ctrlKey: true });
|
||||
for (let i = 0; i < match.length; i++) {
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
}
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
} else {
|
||||
// single-line inputs will update from history from end of line
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
}
|
||||
is(inputNode.value, values[i-1],
|
||||
"ctrl-p updates inputNode from backwards history values[" + i-1 + "]");
|
||||
}
|
||||
let inputValue = inputNode.value;
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 0,
|
||||
"ctrl-p at beginning of history moves caret location to beginning of line");
|
||||
is(inputNode.value, inputValue,
|
||||
"no change to input value on ctrl-p from beginning of line");
|
||||
|
||||
// Navigate forwards history with ctrl-n
|
||||
for (let i = 1; i<values.length; i++) {
|
||||
EventUtils.synthesizeKey("n", { ctrlKey: true });
|
||||
is(inputNode.value, values[i],
|
||||
"ctrl-n updates inputNode from forwards history values[" + i + "]");
|
||||
is(inputNode.selectionStart, values[i].length,
|
||||
"caret location correct at end of history input for values[" + i + "]");
|
||||
}
|
||||
EventUtils.synthesizeKey("n", { ctrlKey: true });
|
||||
ok(!inputNode.value, "ctrl-n at end of history updates to empty input");
|
||||
|
||||
// Simulate editing multi-line
|
||||
inputValue = "one\nlinebreak";
|
||||
jsterm.setInputValue(inputValue);
|
||||
|
||||
// Attempt nav within input
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.value, inputValue,
|
||||
"ctrl-p from end of multi-line does not trigger history");
|
||||
|
||||
EventUtils.synthesizeKey("a", { ctrlKey: true });
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.value, values[values.length-1],
|
||||
"ctrl-p from start of multi-line triggers history");
|
||||
}
|
@ -378,6 +378,7 @@ WebConsoleFrame.prototype = {
|
||||
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;
|
||||
@ -3181,21 +3182,72 @@ JSTerm.prototype = {
|
||||
keyPress: function JSTF_keyPress(aEvent)
|
||||
{
|
||||
if (aEvent.ctrlKey) {
|
||||
let inputNode = this.inputNode;
|
||||
let closePopup = false;
|
||||
switch (aEvent.charCode) {
|
||||
case 97:
|
||||
// control-a
|
||||
this.inputNode.setSelectionRange(0, 0);
|
||||
let lineBeginPos = 0;
|
||||
if (this.hasMultilineInput()) {
|
||||
// find index of closest newline <= to cursor
|
||||
for (let i = inputNode.selectionStart-1; i >= 0; i--) {
|
||||
if (inputNode.value.charAt(i) == "\r" ||
|
||||
inputNode.value.charAt(i) == "\n") {
|
||||
lineBeginPos = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
inputNode.setSelectionRange(lineBeginPos, lineBeginPos);
|
||||
aEvent.preventDefault();
|
||||
closePopup = true;
|
||||
break;
|
||||
case 101:
|
||||
// control-e
|
||||
this.inputNode.setSelectionRange(this.inputNode.value.length,
|
||||
this.inputNode.value.length);
|
||||
let lineEndPos = inputNode.value.length;
|
||||
if (this.hasMultilineInput()) {
|
||||
// find index of closest newline >= cursor
|
||||
for (let i = inputNode.selectionEnd; i<lineEndPos; i++) {
|
||||
if (inputNode.value.charAt(i) == "\r" ||
|
||||
inputNode.value.charAt(i) == "\n") {
|
||||
lineEndPos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
inputNode.setSelectionRange(lineEndPos, lineEndPos);
|
||||
aEvent.preventDefault();
|
||||
break;
|
||||
case 110:
|
||||
// Control-N differs from down arrow: it ignores autocomplete state.
|
||||
// Note that we preserve the default 'down' navigation within
|
||||
// multiline text.
|
||||
if (Services.appinfo.OS == "Darwin" &&
|
||||
this.canCaretGoNext() &&
|
||||
this.historyPeruse(HISTORY_FORWARD)) {
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
closePopup = true;
|
||||
break;
|
||||
case 112:
|
||||
// Control-P differs from up arrow: it ignores autocomplete state.
|
||||
// Note that we preserve the default 'up' navigation within
|
||||
// multiline text.
|
||||
if (Services.appinfo.OS == "Darwin" &&
|
||||
this.canCaretGoPrevious() &&
|
||||
this.historyPeruse(HISTORY_BACK)) {
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
closePopup = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (closePopup) {
|
||||
if (this.autocompletePopup.isOpen) {
|
||||
this.clearCompletion();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (aEvent.shiftKey &&
|
||||
@ -3316,6 +3368,17 @@ JSTerm.prototype = {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Test for multiline input.
|
||||
*
|
||||
* @return boolean
|
||||
* True if CR or LF found in node value; else false.
|
||||
*/
|
||||
hasMultilineInput: function JST_hasMultilineInput()
|
||||
{
|
||||
return /[\r\n]/.test(this.inputNode.value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the caret is at a location that allows selecting the previous item
|
||||
* in history when the user presses the Up arrow key.
|
||||
@ -3983,7 +4046,7 @@ function WebConsoleConnectionProxy(aWebConsole, aTarget)
|
||||
this._onNetworkEvent = this._onNetworkEvent.bind(this);
|
||||
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
|
||||
this._onFileActivity = this._onFileActivity.bind(this);
|
||||
this._onLocationChange = this._onLocationChange.bind(this);
|
||||
this._onTabNavigated = this._onTabNavigated.bind(this);
|
||||
}
|
||||
|
||||
WebConsoleConnectionProxy.prototype = {
|
||||
@ -3995,6 +4058,12 @@ WebConsoleConnectionProxy.prototype = {
|
||||
*/
|
||||
owner: null,
|
||||
|
||||
/**
|
||||
* The target that the console connects to.
|
||||
* @type RemoteTarget
|
||||
*/
|
||||
target: null,
|
||||
|
||||
/**
|
||||
* The DebuggerClient object.
|
||||
*
|
||||
@ -4011,6 +4080,12 @@ WebConsoleConnectionProxy.prototype = {
|
||||
*/
|
||||
webConsoleClient: null,
|
||||
|
||||
/**
|
||||
* The TabClient instance we use.
|
||||
* @type object
|
||||
*/
|
||||
tabClient: null,
|
||||
|
||||
/**
|
||||
* Tells if the connection is established.
|
||||
* @type boolean
|
||||
@ -4025,6 +4100,14 @@ WebConsoleConnectionProxy.prototype = {
|
||||
*/
|
||||
_consoleActor: null,
|
||||
|
||||
/**
|
||||
* The TabActor ID.
|
||||
*
|
||||
* @private
|
||||
* @type string
|
||||
*/
|
||||
_tabActor: null,
|
||||
|
||||
/**
|
||||
* Tells if the window.console object of the remote web page is the native
|
||||
* object or not.
|
||||
@ -4069,23 +4152,24 @@ WebConsoleConnectionProxy.prototype = {
|
||||
client.addListener("networkEvent", this._onNetworkEvent);
|
||||
client.addListener("networkEventUpdate", this._onNetworkEventUpdate);
|
||||
client.addListener("fileActivity", this._onFileActivity);
|
||||
client.addListener("locationChange", this._onLocationChange);
|
||||
client.addListener("tabNavigated", this._onTabNavigated);
|
||||
|
||||
if (this.target.isRemote) {
|
||||
this._consoleActor = this.target.form.consoleActor;
|
||||
if (!this.target.chrome) {
|
||||
this.owner.onLocationChange(this.target.url, this.target.name);
|
||||
// target.form is a TabActor grip
|
||||
this._attachTab(this.target.form, aCallback);
|
||||
}
|
||||
else {
|
||||
// target.form is a RootActor grip
|
||||
this._consoleActor = this.target.form.consoleActor;
|
||||
this._attachConsole(aCallback);
|
||||
}
|
||||
|
||||
let listeners = ["PageError", "ConsoleAPI", "NetworkActivity",
|
||||
"FileActivity", "LocationChange"];
|
||||
this.client.attachConsole(this._consoleActor, listeners,
|
||||
this._onAttachConsole.bind(this, aCallback));
|
||||
return;
|
||||
}
|
||||
client.connect(function(aType, aTraits) {
|
||||
client.listTabs(this._onListTabs.bind(this, aCallback));
|
||||
}.bind(this));
|
||||
else {
|
||||
client.connect(function(aType, aTraits) {
|
||||
client.listTabs(this._onListTabs.bind(this, aCallback));
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -4099,19 +4183,67 @@ WebConsoleConnectionProxy.prototype = {
|
||||
*/
|
||||
_onListTabs: function WCCP__onListTabs(aCallback, aResponse)
|
||||
{
|
||||
let selectedTab = aResponse.tabs[aResponse.selected];
|
||||
if (selectedTab) {
|
||||
this._consoleActor = selectedTab.consoleActor;
|
||||
this.owner.onLocationChange(selectedTab.url, selectedTab.title);
|
||||
}
|
||||
else {
|
||||
this._consoleActor = aResponse.consoleActor;
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("listTabs failed: " + aResponse.error + " " +
|
||||
aResponse.message);
|
||||
return;
|
||||
}
|
||||
|
||||
this.owner._resetConnectionTimeout();
|
||||
this._attachTab(aResponse.tabs[aResponse.selected], aCallback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach to the tab actor.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
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));
|
||||
},
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("attachTab failed: " + aResponse.error + " " +
|
||||
aResponse.message);
|
||||
return;
|
||||
}
|
||||
|
||||
this.tabClient = aTabClient;
|
||||
this._attachConsole(aCallback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach to the Web Console actor.
|
||||
*
|
||||
* @private
|
||||
* @param function aCallback
|
||||
* Function to invoke when the connection is established.
|
||||
*/
|
||||
_attachConsole: function WCCP__attachConsole(aCallback)
|
||||
{
|
||||
let listeners = ["PageError", "ConsoleAPI", "NetworkActivity",
|
||||
"FileActivity", "LocationChange"];
|
||||
"FileActivity"];
|
||||
this.client.attachConsole(this._consoleActor, listeners,
|
||||
this._onAttachConsole.bind(this, aCallback));
|
||||
},
|
||||
@ -4260,7 +4392,7 @@ WebConsoleConnectionProxy.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* The "locationChange" message type handler. We redirect any message to
|
||||
* The "tabNavigated" message type handler. We redirect any message to
|
||||
* the UI for displaying.
|
||||
*
|
||||
* @private
|
||||
@ -4269,13 +4401,16 @@ WebConsoleConnectionProxy.prototype = {
|
||||
* @param object aPacket
|
||||
* The message received from the server.
|
||||
*/
|
||||
_onLocationChange: function WCCP__onLocationChange(aType, aPacket)
|
||||
_onTabNavigated: function WCCP__onTabNavigated(aType, aPacket)
|
||||
{
|
||||
if (!this.owner || aPacket.from != this._consoleActor) {
|
||||
if (!this.owner || aPacket.from != this._tabActor) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.owner.onLocationChange(aPacket.uri, aPacket.title);
|
||||
if (aPacket.url) {
|
||||
this.owner.onLocationChange(aPacket.url, aPacket.title);
|
||||
}
|
||||
|
||||
if (aPacket.state == "stop" && !aPacket.nativeConsoleAPI) {
|
||||
this.owner.logWarningAboutReplacedAPI();
|
||||
}
|
||||
@ -4319,7 +4454,8 @@ WebConsoleConnectionProxy.prototype = {
|
||||
};
|
||||
|
||||
let timer = null;
|
||||
if (aOnDisconnect) {
|
||||
let remoteTarget = this.target.isRemote;
|
||||
if (aOnDisconnect && !remoteTarget) {
|
||||
timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(onDisconnect, 1500, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
@ -4329,11 +4465,20 @@ WebConsoleConnectionProxy.prototype = {
|
||||
this.client.removeListener("networkEvent", this._onNetworkEvent);
|
||||
this.client.removeListener("networkEventUpdate", this._onNetworkEventUpdate);
|
||||
this.client.removeListener("fileActivity", this._onFileActivity);
|
||||
this.client.removeListener("locationChange", this._onLocationChange);
|
||||
this.client.removeListener("tabNavigated", this._onTabNavigated);
|
||||
|
||||
let client = this.client;
|
||||
|
||||
this.client = null;
|
||||
this.webConsoleClient = null;
|
||||
this.tabClient = null;
|
||||
this.target = null;
|
||||
this.connected = false;
|
||||
this.owner = null;
|
||||
|
||||
try {
|
||||
if (!this.target.isRemote) {
|
||||
this.client.close(onDisconnect);
|
||||
if (!remoteTarget) {
|
||||
client.close(onDisconnect);
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
@ -4342,10 +4487,9 @@ WebConsoleConnectionProxy.prototype = {
|
||||
onDisconnect();
|
||||
}
|
||||
|
||||
this.client = null;
|
||||
this.webConsoleClient = null;
|
||||
this.connected = false;
|
||||
this.owner = null;
|
||||
if (remoteTarget) {
|
||||
onDisconnect();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -480,9 +480,10 @@ DebuggerClient.prototype = {
|
||||
this._threadClients[aPacket.from]._onThreadState(aPacket);
|
||||
}
|
||||
// On navigation the server resumes, so the client must resume as well.
|
||||
// We achive that by generating a fake resumption packet that triggers
|
||||
// We achieve that by generating a fake resumption packet that triggers
|
||||
// the client's thread state change listeners.
|
||||
if (aPacket.type == UnsolicitedNotifications.tabNavigated &&
|
||||
if (this.activeThread &&
|
||||
aPacket.type == UnsolicitedNotifications.tabNavigated &&
|
||||
aPacket.from in this._tabClients) {
|
||||
let resumption = { from: this.activeThread._actor, type: "resumed" };
|
||||
this.activeThread._onThreadState(resumption);
|
||||
|
@ -354,24 +354,51 @@ BrowserTabActor.prototype = {
|
||||
// A constant prefix that will be used to form the actor ID by the server.
|
||||
actorPrefix: "tab",
|
||||
|
||||
grip: function BTA_grip() {
|
||||
dbg_assert(!this.exited,
|
||||
"grip() shouldn't be called on exited browser actor.");
|
||||
dbg_assert(this.actorID,
|
||||
"tab should have an actorID.");
|
||||
|
||||
/**
|
||||
* Getter for the tab title.
|
||||
* @return string
|
||||
* Tab title.
|
||||
*/
|
||||
get title() {
|
||||
let title = this.browser.contentTitle;
|
||||
// If contentTitle is empty (e.g. on a not-yet-restored tab), but there is a
|
||||
// tabbrowser (i.e. desktop Firefox, but not Fennec), we can use the label
|
||||
// as the title.
|
||||
if (!title && this._tabbrowser) {
|
||||
title = this._tabbrowser
|
||||
._getTabForContentWindow(this.browser.contentWindow).label;
|
||||
._getTabForContentWindow(this.contentWindow).label;
|
||||
}
|
||||
return title;
|
||||
},
|
||||
|
||||
/**
|
||||
* Getter for the tab URL.
|
||||
* @return string
|
||||
* Tab URL.
|
||||
*/
|
||||
get url() {
|
||||
return this.browser.currentURI.spec;
|
||||
},
|
||||
|
||||
/**
|
||||
* Getter for the tab content window.
|
||||
* @return nsIDOMWindow
|
||||
* Tab content window.
|
||||
*/
|
||||
get contentWindow() {
|
||||
return this.browser.contentWindow;
|
||||
},
|
||||
|
||||
grip: function BTA_grip() {
|
||||
dbg_assert(!this.exited,
|
||||
"grip() shouldn't be called on exited browser actor.");
|
||||
dbg_assert(this.actorID,
|
||||
"tab should have an actorID.");
|
||||
|
||||
let response = {
|
||||
actor: this.actorID,
|
||||
title: title,
|
||||
url: this.browser.currentURI.spec
|
||||
title: this.title,
|
||||
url: this.url,
|
||||
};
|
||||
|
||||
// Walk over tab actors added by extensions and add them to a new ActorPool.
|
||||
@ -391,10 +418,6 @@ BrowserTabActor.prototype = {
|
||||
*/
|
||||
disconnect: function BTA_disconnect() {
|
||||
this._detach();
|
||||
|
||||
if (this._progressListener) {
|
||||
this._progressListener.destroy();
|
||||
}
|
||||
this._extraActors = null;
|
||||
},
|
||||
|
||||
@ -412,9 +435,6 @@ BrowserTabActor.prototype = {
|
||||
type: "tabDetached" });
|
||||
}
|
||||
|
||||
if (this._progressListener) {
|
||||
this._progressListener.destroy();
|
||||
}
|
||||
this._browser = null;
|
||||
this._tabbrowser = null;
|
||||
},
|
||||
@ -455,7 +475,7 @@ BrowserTabActor.prototype = {
|
||||
this._contextPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._contextPool);
|
||||
|
||||
this.threadActor = new ThreadActor(this, this.browser.contentWindow.wrappedJSObject);
|
||||
this.threadActor = new ThreadActor(this, this.contentWindow.wrappedJSObject);
|
||||
this._contextPool.addActor(this.threadActor);
|
||||
},
|
||||
|
||||
@ -480,6 +500,10 @@ BrowserTabActor.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._progressListener) {
|
||||
this._progressListener.destroy();
|
||||
}
|
||||
|
||||
this.browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
|
||||
this.browser.removeEventListener("pageshow", this._onWindowCreated, true);
|
||||
|
||||
@ -489,7 +513,7 @@ BrowserTabActor.prototype = {
|
||||
this.conn.removeActorPool(this._tabPool);
|
||||
this._tabPool = null;
|
||||
if (this._tabActorPool) {
|
||||
this.conn.removeActorPool(this._tabActorPool);
|
||||
this.conn.removeActorPool(this._tabActorPool, true);
|
||||
this._tabActorPool = null;
|
||||
}
|
||||
|
||||
@ -515,10 +539,6 @@ BrowserTabActor.prototype = {
|
||||
|
||||
this._detach();
|
||||
|
||||
if (this._progressListener) {
|
||||
this._progressListener.destroy();
|
||||
}
|
||||
|
||||
return { type: "detached" };
|
||||
},
|
||||
|
||||
@ -530,7 +550,7 @@ BrowserTabActor.prototype = {
|
||||
// The tab is already closed.
|
||||
return;
|
||||
}
|
||||
let windowUtils = this.browser.contentWindow
|
||||
let windowUtils = this.contentWindow
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.suppressEventHandling(true);
|
||||
@ -545,7 +565,7 @@ BrowserTabActor.prototype = {
|
||||
// The tab is already closed.
|
||||
return;
|
||||
}
|
||||
let windowUtils = this.browser.contentWindow
|
||||
let windowUtils = this.contentWindow
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.resumeTimeouts();
|
||||
@ -572,11 +592,6 @@ BrowserTabActor.prototype = {
|
||||
if (this.threadActor.dbg) {
|
||||
this.threadActor.dbg.enabled = true;
|
||||
}
|
||||
if (this._progressListener) {
|
||||
delete this._progressListener._needsTabNavigated;
|
||||
}
|
||||
this.conn.send({ from: this.actorID, type: "tabNavigated",
|
||||
url: this.browser.contentDocument.URL });
|
||||
}
|
||||
}
|
||||
|
||||
@ -586,7 +601,26 @@ BrowserTabActor.prototype = {
|
||||
this.threadActor.findGlobals();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Tells if the window.console object is native or overwritten by script in
|
||||
* the page.
|
||||
*
|
||||
* @param nsIDOMWindow aWindow
|
||||
* The window object you want to check.
|
||||
* @return boolean
|
||||
* True if the window.console object is native, or false otherwise.
|
||||
*/
|
||||
hasNativeConsoleAPI: function BTA_hasNativeConsoleAPI(aWindow) {
|
||||
let isNative = false;
|
||||
try {
|
||||
let console = aWindow.wrappedJSObject.console;
|
||||
isNative = "__mozillaConsole__" in console;
|
||||
}
|
||||
catch (ex) { }
|
||||
return isNative;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -622,33 +656,45 @@ DebuggerProgressListener.prototype = {
|
||||
let isWindow = aFlag & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
|
||||
|
||||
// Skip non-interesting states.
|
||||
if (isStart && isDocument && isRequest && isNetwork) {
|
||||
if (!isWindow || !isNetwork ||
|
||||
aProgress.DOMWindow != this._tabActor.contentWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isStart && aRequest instanceof Ci.nsIChannel) {
|
||||
// If the request is about to happen in a new window, we are not concerned
|
||||
// about the request.
|
||||
if (aProgress.DOMWindow != this._tabActor.browser.contentWindow) {
|
||||
return;
|
||||
|
||||
// Proceed normally only if the debuggee is not paused.
|
||||
if (this._tabActor.threadActor.state == "paused") {
|
||||
aRequest.suspend();
|
||||
this._tabActor.threadActor.onResume();
|
||||
this._tabActor.threadActor.dbg.enabled = false;
|
||||
this._tabActor._pendingNavigation = aRequest;
|
||||
}
|
||||
|
||||
// If the debuggee is not paused, then proceed normally.
|
||||
if (this._tabActor.threadActor.state != "paused") {
|
||||
return;
|
||||
}
|
||||
|
||||
aRequest.suspend();
|
||||
this._tabActor.threadActor.onResume();
|
||||
this._tabActor.threadActor.dbg.enabled = false;
|
||||
this._tabActor._pendingNavigation = aRequest;
|
||||
this._needsTabNavigated = true;
|
||||
} else if (isStop && isWindow && isNetwork && this._needsTabNavigated) {
|
||||
delete this._needsTabNavigated;
|
||||
this._tabActor.threadActor.dbg.enabled = true;
|
||||
this._tabActor.conn.send({
|
||||
from: this._tabActor.actorID,
|
||||
type: "tabNavigated",
|
||||
url: this._tabActor.browser.contentDocument.URL
|
||||
url: aRequest.URI.spec,
|
||||
title: "",
|
||||
nativeConsoleAPI: true,
|
||||
state: "start",
|
||||
});
|
||||
} else if (isStop) {
|
||||
if (this._tabActor.threadActor.state == "running") {
|
||||
this._tabActor.threadActor.dbg.enabled = true;
|
||||
}
|
||||
|
||||
this.destroy();
|
||||
let window = this._tabActor.contentWindow;
|
||||
this._tabActor.conn.send({
|
||||
from: this._tabActor.actorID,
|
||||
type: "tabNavigated",
|
||||
url: this._tabActor.url,
|
||||
title: this._tabActor.title,
|
||||
nativeConsoleAPI: this._tabActor.hasNativeConsoleAPI(window),
|
||||
state: "stop",
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -657,7 +703,11 @@ DebuggerProgressListener.prototype = {
|
||||
*/
|
||||
destroy: function DPL_destroy() {
|
||||
if (this._tabActor._tabbrowser.removeProgressListener) {
|
||||
this._tabActor._tabbrowser.removeProgressListener(this);
|
||||
try {
|
||||
this._tabActor._tabbrowser.removeProgressListener(this);
|
||||
} catch (ex) {
|
||||
// This can throw during browser shutdown.
|
||||
}
|
||||
}
|
||||
this._tabActor._progressListener = null;
|
||||
this._tabActor = null;
|
||||
|
@ -541,11 +541,20 @@ DebuggerServerConnection.prototype = {
|
||||
|
||||
/**
|
||||
* Remove a previously-added pool of actors to the connection.
|
||||
*
|
||||
* @param ActorPool aActorPool
|
||||
* The ActorPool instance you want to remove.
|
||||
* @param boolean aCleanup
|
||||
* True if you want to disconnect each actor from the pool, false
|
||||
* otherwise.
|
||||
*/
|
||||
removeActorPool: function DSC_removeActorPool(aActorPool) {
|
||||
removeActorPool: function DSC_removeActorPool(aActorPool, aCleanup) {
|
||||
let index = this._extraPools.lastIndexOf(aActorPool);
|
||||
if (index > -1) {
|
||||
this._extraPools.splice(index, 1);
|
||||
let pool = this._extraPools.splice(index, 1);
|
||||
if (aCleanup) {
|
||||
pool.map(function(p) { p.cleanup(); });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -160,23 +160,7 @@ WebConsoleActor.prototype =
|
||||
return { actor: this.actorID };
|
||||
},
|
||||
|
||||
/**
|
||||
* Tells if the window.console object is native or overwritten by script in
|
||||
* the page.
|
||||
*
|
||||
* @return boolean
|
||||
* True if the window.console object is native, or false otherwise.
|
||||
*/
|
||||
hasNativeConsoleAPI: function WCA_hasNativeConsoleAPI()
|
||||
{
|
||||
let isNative = false;
|
||||
try {
|
||||
let consoleObject = WebConsoleUtils.unwrap(this.window).console;
|
||||
isNative = "__mozillaConsole__" in consoleObject;
|
||||
}
|
||||
catch (ex) { }
|
||||
return isNative;
|
||||
},
|
||||
hasNativeConsoleAPI: BrowserTabActor.prototype.hasNativeConsoleAPI,
|
||||
|
||||
/**
|
||||
* Destroy the current WebConsoleActor instance.
|
||||
@ -336,20 +320,11 @@ WebConsoleActor.prototype =
|
||||
MONITOR_FILE_ACTIVITY);
|
||||
startedListeners.push(listener);
|
||||
break;
|
||||
case "LocationChange":
|
||||
if (!this.consoleProgressListener) {
|
||||
this.consoleProgressListener =
|
||||
new ConsoleProgressListener(this.window, this);
|
||||
}
|
||||
this.consoleProgressListener.startMonitor(this.consoleProgressListener.
|
||||
MONITOR_LOCATION_CHANGE);
|
||||
startedListeners.push(listener);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
startedListeners: startedListeners,
|
||||
nativeConsoleAPI: this.hasNativeConsoleAPI(),
|
||||
nativeConsoleAPI: this.hasNativeConsoleAPI(this.window),
|
||||
};
|
||||
},
|
||||
|
||||
@ -370,7 +345,7 @@ WebConsoleActor.prototype =
|
||||
// listeners.
|
||||
let toDetach = aRequest.listeners ||
|
||||
["PageError", "ConsoleAPI", "NetworkActivity",
|
||||
"FileActivity", "LocationChange"];
|
||||
"FileActivity"];
|
||||
|
||||
while (toDetach.length > 0) {
|
||||
let listener = toDetach.shift();
|
||||
@ -403,13 +378,6 @@ WebConsoleActor.prototype =
|
||||
}
|
||||
stoppedListeners.push(listener);
|
||||
break;
|
||||
case "LocationChange":
|
||||
if (this.consoleProgressListener) {
|
||||
this.consoleProgressListener.stopMonitor(this.consoleProgressListener.
|
||||
MONITOR_LOCATION_CHANGE);
|
||||
}
|
||||
stoppedListeners.push(listener);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -737,34 +705,6 @@ WebConsoleActor.prototype =
|
||||
this.conn.send(packet);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for location changes. This method sends the new browser location
|
||||
* to the remote Web Console client.
|
||||
*
|
||||
* @see ConsoleProgressListener
|
||||
* @param string aState
|
||||
* Tells the location change state:
|
||||
* - "start" means a load has begun.
|
||||
* - "stop" means load completed.
|
||||
* @param string aURI
|
||||
* The new browser URI.
|
||||
* @param string aTitle
|
||||
* The new page title URI.
|
||||
*/
|
||||
onLocationChange: function WCA_onLocationChange(aState, aURI, aTitle)
|
||||
{
|
||||
// TODO: Bug 792062 - Make the tabNavigated notification reusable by the Web Console
|
||||
let packet = {
|
||||
from: this.actorID,
|
||||
type: "locationChange",
|
||||
uri: aURI,
|
||||
title: aTitle,
|
||||
state: aState,
|
||||
nativeConsoleAPI: this.hasNativeConsoleAPI(),
|
||||
};
|
||||
this.conn.send(packet);
|
||||
},
|
||||
|
||||
//////////////////
|
||||
// End of event handlers for various listeners.
|
||||
//////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user