Merge m-c to inbound.

This commit is contained in:
Ryan VanderMeulen 2013-04-01 14:32:42 -04:00
commit 49b4423e2d
49 changed files with 1706 additions and 376 deletions

View File

@ -91,3 +91,4 @@ fd72dbbd692012224145be1bf13df1d7675fd277 FIREFOX_AURORA_17_BASE
cf8750abee06cde395c659f8ecd8ae019d7512e3 FIREFOX_AURORA_19_BASE
5bb309998e7050c9ee80b0147de1e473f008e221 FIREFOX_AURORA_20_BASE
cc37417e2c284aed960f98ffa479de4ccdd5c7c3 FIREFOX_AURORA_21_BASE
1c070ab0f9db59f13423b9c1db60419f7a9098f9 FIREFOX_AURORA_22_BASE

2
b2g/confvars.sh Executable file → Normal file
View File

@ -5,7 +5,7 @@
MOZ_APP_BASENAME=B2G
MOZ_APP_VENDOR=Mozilla
MOZ_APP_VERSION=22.0a1
MOZ_APP_VERSION=23.0a1
MOZ_APP_UA_NAME=Firefox
MOZ_UA_OS_AGNOSTIC=1

View File

@ -1 +1 @@
22.0a1
23.0a1

View File

@ -14,3 +14,4 @@ Cu.import("resource:///modules/devtools/CmdInspect.jsm");
Cu.import("resource:///modules/devtools/CmdResize.jsm");
Cu.import("resource:///modules/devtools/CmdTilt.jsm");
Cu.import("resource:///modules/devtools/CmdScratchpad.jsm");
Cu.import("resource:///modules/devtools/cmd-profiler.jsm");

View File

@ -22,8 +22,8 @@ function DebuggerPanel(iframeWindow, toolbox) {
this.panelWin = iframeWindow;
this._toolbox = toolbox;
this._controller = this.panelWin.DebuggerController;
this._view = this.panelWin.DebuggerView;
this._controller = this.panelWin.DebuggerController;
this._controller._target = this.target;
this._bkp = this._controller.Breakpoints;
@ -32,48 +32,38 @@ function DebuggerPanel(iframeWindow, toolbox) {
DebuggerPanel.prototype = {
/**
* open is effectively an asynchronous constructor
* Open is effectively an asynchronous constructor.
*
* @return object
* A Promise that is resolved when the Debugger completes opening.
*/
open: function DebuggerPanel_open() {
let deferred = Promise.defer();
let promise;
this._ensureOnlyOneRunningDebugger();
let onDebuggerLoaded = function () {
this.panelWin.removeEventListener("Debugger:Loaded",
onDebuggerLoaded, true);
this._isReady = true;
this.emit("ready");
deferred.resolve(this);
}.bind(this);
let onDebuggerConnected = function () {
this.panelWin.removeEventListener("Debugger:Connected",
onDebuggerConnected, true);
this.emit("connected");
}.bind(this);
this.panelWin.addEventListener("Debugger:Loaded", onDebuggerLoaded, true);
this.panelWin.addEventListener("Debugger:Connected",
onDebuggerConnected, true);
// Remote debugging gets the debuggee from a RemoteTarget object.
if (this.target.isRemote) {
this.panelWin._remoteFlag = true;
return deferred.promise;
// Local debugging needs to make the target remote.
if (!this.target.isRemote) {
promise = this.target.makeRemote();
} else {
promise = Promise.resolve(this.target);
}
// Local debugging needs to convert the TabTarget to a RemoteTarget.
return this.target.makeRemote().then(function success() {
return deferred.promise;
});
return promise
.then(() => this._controller.startupDebugger())
.then(() => this._controller.connect())
.then(() => {
this.isReady = true;
this.emit("ready");
return this;
})
.then(null, function onError(aReason) {
Cu.reportError("DebuggerPanel open failed. " +
reason.error + ": " + reason.message);
});
},
// DevToolPanel API
get target() this._toolbox.target,
get isReady() this._isReady,
destroy: function() {
this.emit("destroyed");
return Promise.resolve(null);

View File

@ -38,6 +38,9 @@ Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
Cu.import("resource:///modules/devtools/VariablesView.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
XPCOMUtils.defineLazyModuleGetter(this, "Parser",
"resource:///modules/devtools/Parser.jsm");
@ -51,158 +54,126 @@ let DebuggerController = {
initialize: function DC_initialize() {
dumpn("Initializing the DebuggerController");
this._startupDebugger = this._startupDebugger.bind(this);
this._shutdownDebugger = this._shutdownDebugger.bind(this);
this.startupDebugger = this.startupDebugger.bind(this);
this.shutdownDebugger = this.shutdownDebugger.bind(this);
this._onTabNavigated = this._onTabNavigated.bind(this);
this._onTabDetached = this._onTabDetached.bind(this);
window.addEventListener("DOMContentLoaded", this._startupDebugger, true);
window.addEventListener("unload", this._shutdownDebugger, true);
// Chrome debugging lives in a different process and needs to handle
// debugger startup and shutdown by itself.
if (window._isChromeDebugger) {
window.addEventListener("DOMContentLoaded", this.startupDebugger, true);
window.addEventListener("unload", this.shutdownDebugger, true);
}
},
/**
* Initializes the view and connects a debugger client to the server.
* Initializes the view.
*
* @return object
* A promise that is resolved when the debugger finishes startup.
*/
_startupDebugger: function DC__startupDebugger() {
startupDebugger: function DC_startupDebugger() {
if (this._isInitialized) {
return;
}
this._isInitialized = true;
window.removeEventListener("DOMContentLoaded", this._startupDebugger, true);
window.removeEventListener("DOMContentLoaded", this.startupDebugger, true);
DebuggerView.initialize(function() {
let deferred = Promise.defer();
DebuggerView.initialize(() => {
DebuggerView._isInitialized = true;
window.dispatchEvent(document, "Debugger:Loaded");
this._connect();
}.bind(this));
// Chrome debugging needs to initiate the connection by itself.
if (window._isChromeDebugger) {
this.connect().then(deferred.resolve);
} else {
deferred.resolve();
}
});
return deferred.promise;
},
/**
* Destroys the view and disconnects the debugger client from the server.
*
* @return object
* A promise that is resolved when the debugger finishes shutdown.
*/
_shutdownDebugger: function DC__shutdownDebugger() {
shutdownDebugger: function DC__shutdownDebugger() {
if (this._isDestroyed || !DebuggerView._isInitialized) {
return;
}
this._isDestroyed = true;
window.removeEventListener("unload", this._shutdownDebugger, true);
window.removeEventListener("unload", this.shutdownDebugger, true);
DebuggerView.destroy(function() {
let deferred = Promise.defer();
DebuggerView.destroy(() => {
DebuggerView._isDestroyed = true;
this.SourceScripts.disconnect();
this.StackFrames.disconnect();
this.ThreadState.disconnect();
this._disconnect();
window.dispatchEvent(document, "Debugger:Unloaded");
this.disconnect();
deferred.resolve();
// Chrome debugging needs to close its parent process on shutdown.
window._isChromeDebugger && this._quitApp();
}.bind(this));
},
});
/**
* Prepares the hostname and port number for a remote debugger connection
* and handles connection retries and timeouts.
* XXX: remove all this (bug 823577)
* @return boolean
* True if connection should proceed normally, false otherwise.
*/
_prepareConnection: function DC__prepareConnection() {
// If we exceeded the total number of connection retries, bail.
if (this._remoteConnectionTry === Prefs.remoteConnectionRetries) {
Services.prompt.alert(null,
L10N.getStr("remoteDebuggerPromptTitle"),
L10N.getStr("remoteDebuggerConnectionFailedMessage"));
// If the connection was not established before a certain number of
// retries, close the remote debugger.
this._shutdownDebugger();
return false;
}
// TODO: This is ugly, need to rethink the design for the UI in #751677.
if (!Prefs.remoteAutoConnect) {
let prompt = new RemoteDebuggerPrompt();
let result = prompt.show(!!this._remoteConnectionTimeout);
// If the connection was not established before the user canceled the
// prompt, close the remote debugger.
if (!result) {
this._shutdownDebugger();
return false;
}
Prefs.remoteHost = prompt.remote.host;
Prefs.remotePort = prompt.remote.port;
Prefs.remoteAutoConnect = prompt.remote.auto;
}
// If this debugger is connecting remotely to a server, we need to check
// after a while if the connection actually succeeded.
this._remoteConnectionTry = ++this._remoteConnectionTry || 1;
this._remoteConnectionTimeout = window.setTimeout(function() {
// If we couldn't connect to any server yet, try again...
if (!this.activeThread) {
this._onRemoteConnectionTimeout();
this._connect();
}
}.bind(this), Prefs.remoteTimeout);
// Proceed with the connection normally.
return true;
},
/**
* Called when a remote connection timeout occurs.
*/
_onRemoteConnectionTimeout: function DC__onRemoteConnectionTimeout() {
Cu.reportError("Couldn't connect to " +
Prefs.remoteHost + ":" + Prefs.remotePort);
return deferred.promise;
},
/**
* Initializes a debugger client and connects it to the debugger server,
* wiring event handlers as necessary.
*
* @return object
* A promise that is resolved when the debugger finishes connecting.
*/
_connect: function DC__connect() {
function callback() {
window.dispatchEvent(document, "Debugger:Connected");
}
connect: function DC_connect() {
let deferred = Promise.defer();
if (!window._isChromeDebugger) {
let client = this.client = this._target.client;
this._target.on("close", this._onTabDetached);
this._target.on("navigate", this._onTabNavigated);
this._target.on("will-navigate", this._onTabNavigated);
let target = this._target;
let { client, form } = target;
target.on("close", this._onTabDetached);
target.on("navigate", this._onTabNavigated);
target.on("will-navigate", this._onTabNavigated);
if (this._target.chrome) {
let dbg = this._target.form.chromeDebugger;
this._startChromeDebugging(client, dbg, callback);
if (target.chrome) {
this._startChromeDebugging(client, form.chromeDebugger, deferred.resolve);
} else {
this._startDebuggingTab(client, this._target.form, callback);
this._startDebuggingTab(client, form, deferred.resolve);
}
return;
return deferred.promise;
}
// Chrome debugging needs to make the connection to the debuggee.
let transport = debuggerSocketConnect(Prefs.chromeDebuggingHost,
Prefs.chromeDebuggingPort);
let client = this.client = new DebuggerClient(transport);
let client = new DebuggerClient(transport);
client.addListener("tabNavigated", this._onTabNavigated);
client.addListener("tabDetached", this._onTabDetached);
client.connect(function(aType, aTraits) {
client.listTabs(function(aResponse) {
this._startChromeDebugging(client, aResponse.chromeDebugger, callback);
}.bind(this));
}.bind(this));
client.connect((aType, aTraits) => {
client.listTabs((aResponse) => {
this._startChromeDebugging(client, aResponse.chromeDebugger, deferred.resolve);
});
});
return deferred.promise;
},
/**
* Disconnects the debugger client and removes event handlers as necessary.
*/
_disconnect: function DC__disconnect() {
disconnect: function DC_disconnect() {
// Return early if the client didn't even have a chance to instantiate.
if (!this.client) {
return;
@ -249,7 +220,7 @@ let DebuggerController = {
* Called when the debugged tab is closed.
*/
_onTabDetached: function DC__onTabDetached() {
this._shutdownDebugger();
this.shutdownDebugger();
},
/**
@ -259,6 +230,8 @@ let DebuggerController = {
* The debugger client.
* @param object aTabGrip
* The remote protocol grip of the tab.
* @param function aCallback
* A function to invoke once the client attached to the active thread.
*/
_startDebuggingTab: function DC__startDebuggingTab(aClient, aTabGrip, aCallback) {
if (!aClient) {
@ -267,14 +240,14 @@ let DebuggerController = {
}
this.client = aClient;
aClient.attachTab(aTabGrip.actor, function(aResponse, aTabClient) {
aClient.attachTab(aTabGrip.actor, (aResponse, aTabClient) => {
if (!aTabClient) {
Cu.reportError("No tab client found!");
return;
}
this.tabClient = aTabClient;
aClient.attachThread(aResponse.threadActor, function(aResponse, aThreadClient) {
aClient.attachThread(aResponse.threadActor, (aResponse, aThreadClient) => {
if (!aThreadClient) {
Cu.reportError("Couldn't attach to thread: " + aResponse.error);
return;
@ -289,8 +262,8 @@ let DebuggerController = {
if (aCallback) {
aCallback();
}
}.bind(this));
}.bind(this));
});
});
},
/**
@ -300,6 +273,8 @@ let DebuggerController = {
* The debugger client.
* @param object aChromeDebugger
* The remote protocol grip of the chrome debugger.
* @param function aCallback
* A function to invoke once the client attached to the active thread.
*/
_startChromeDebugging: function DC__startChromeDebugging(aClient, aChromeDebugger, aCallback) {
if (!aClient) {
@ -308,7 +283,7 @@ let DebuggerController = {
}
this.client = aClient;
aClient.attachThread(aChromeDebugger, function(aResponse, aThreadClient) {
aClient.attachThread(aChromeDebugger, (aResponse, aThreadClient) => {
if (!aThreadClient) {
Cu.reportError("Couldn't attach to thread: " + aResponse.error);
return;
@ -323,7 +298,7 @@ let DebuggerController = {
if (aCallback) {
aCallback();
}
}.bind(this));
});
},
/**

View File

@ -20,44 +20,31 @@ function test()
{
let scriptShown = false;
let framesAdded = false;
let resumed = false;
let testStarted = false;
gTab = addTab(TAB_URL, function onAddTab() {
info("tab added");
gDebuggee = gTab.linkedBrowser.contentWindow.wrappedJSObject;
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.panelWin;
resumed = true;
let target = TargetFactory.forTab(gTab);
gDevTools.showToolbox(target, "jsdebugger").then(function(toolbox) {
info("jsdebugger panel opened");
gPane = toolbox.getCurrentPanel();
gDebugger = gPane.panelWin;
gDebugger.addEventListener("Debugger:AfterSourcesAdded", onAfterSourcesAdded);
});
});
function onAfterSourcesAdded()
{
info("scripts added");
gDebugger.removeEventListener("Debugger:AfterSourcesAdded",onAfterSourcesAdded);
gDebugger.addEventListener("Debugger:SourceShown", onSourceShown);
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded",
function onFramesAdded() {
info("frames added");
framesAdded = true;
executeSoon(startTest);
});
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
framesAdded = true;
executeSoon(startTest);
});
executeSoon(function() {
gDebuggee.firstCall();
});
}
});
function onSourceShown(aEvent)
{
scriptShown = aEvent.detail.url.indexOf("-02.js") != -1;
info("script shown " + aEvent.detail.url);
executeSoon(startTest);
}
@ -66,7 +53,6 @@ function test()
if (scriptShown && framesAdded && !testStarted) {
gDebugger.removeEventListener("Debugger:SourceShown", onSourceShown);
testStarted = true;
info("test started");
Services.tm.currentThread.dispatch({ run: performTest }, 0);
}
}
@ -171,7 +157,8 @@ function test()
{
info("add a breakpoint to the second script which is not selected");
is(Object.keys(gBreakpoints).length, 0, "no breakpoints in the debugger");
is(Object.keys(gBreakpoints).length, 0,
"no breakpoints in the debugger");
ok(!gPane.getBreakpoint(gSources.selectedValue, 6),
"getBreakpoint(selectedScript, 6) returns no breakpoint");
isnot(gSources.values[0], gSources.selectedValue,
@ -204,7 +191,9 @@ function test()
executeSoon(function() {
ok(aBreakpointClient.actor in gBreakpoints,
"breakpoint2 client found in the list of debugger breakpoints");
is(Object.keys(gBreakpoints).length, 1, "one breakpoint in the debugger");
is(Object.keys(gBreakpoints).length, 1,
"one breakpoint in the debugger");
is(gPane.getBreakpoint(gSources.values[0], 5), aBreakpointClient,
"getBreakpoint(locations[0], 5) returns the correct breakpoint");
@ -229,7 +218,7 @@ function test()
is(aEvent.added[0].line, 4, "editor breakpoint line is correct");
is(gEditor.getBreakpoints().length, 1,
"editor.getBreakpoints().length is correct");
"editor.getBreakpoints().length is correct");
}
function onEditorTextChanged()

View File

@ -27,54 +27,52 @@ function test() {
}]);
}
let testCommands = function(dbg, cmd) {
// Wait for the initial resume...
dbg._controller.activeThread.addOneTimeListener("resumed", function() {
info("Starting tests");
// Wait for the initial resume...
dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
info("Starting tests");
let contentDoc = content.window.document;
let output = contentDoc.querySelector("input[type=text]");
let btnDoit = contentDoc.querySelector("input[type=button]");
let contentDoc = content.window.document;
let output = contentDoc.querySelector("input[type=text]");
let btnDoit = contentDoc.querySelector("input[type=button]");
helpers.audit(options, [{
setup: "dbg list",
exec: { output: /browser_dbg_cmd.html/ }
}]);
helpers.audit(options, [{
setup: "dbg list",
exec: { output: /browser_dbg_cmd.html/ }
}]);
cmd("dbg interrupt", function() {
ok(true, "debugger is paused");
dbg._controller.activeThread.addOneTimeListener("resumed", function() {
ok(true, "debugger continued");
dbg._controller.activeThread.addOneTimeListener("paused", function() {
cmd("dbg interrupt", function() {
ok(true, "debugger is paused");
dbg._controller.activeThread.addOneTimeListener("resumed", function() {
ok(true, "debugger continued");
dbg._controller.activeThread.addOneTimeListener("paused", function() {
cmd("dbg step in", function() {
cmd("dbg step in", function() {
cmd("dbg step in", function() {
cmd("dbg step in", function() {
is(output.value, "step in", "debugger stepped in");
cmd("dbg step over", function() {
is(output.value, "step over", "debugger stepped over");
cmd("dbg step out", function() {
is(output.value, "step out", "debugger stepped out");
is(output.value, "step in", "debugger stepped in");
cmd("dbg step over", function() {
is(output.value, "step over", "debugger stepped over");
cmd("dbg step out", function() {
is(output.value, "step out", "debugger stepped out");
cmd("dbg continue", function() {
cmd("dbg continue", function() {
cmd("dbg continue", function() {
is(output.value, "dbg continue", "debugger continued");
is(output.value, "dbg continue", "debugger continued");
helpers.audit(options, [{
setup: "dbg close",
completed: false,
exec: { output: "" }
}]);
helpers.audit(options, [{
setup: "dbg close",
completed: false,
exec: { output: "" }
}]);
let toolbox = gDevTools.getToolbox(options.target);
if (!toolbox) {
let toolbox = gDevTools.getToolbox(options.target);
if (!toolbox) {
ok(true, "Debugger was closed.");
deferred.resolve();
} else {
toolbox.on("destroyed", function () {
ok(true, "Debugger was closed.");
deferred.resolve();
} else {
toolbox.on("destroyed", function () {
ok(true, "Debugger was closed.");
deferred.resolve();
});
}
});
});
}
});
});
});
@ -82,22 +80,16 @@ function test() {
});
});
});
EventUtils.sendMouseEvent({type:"click"}, btnDoit);
});
helpers.audit(options, [{
setup: "dbg continue",
exec: { output: "" }
}]);
EventUtils.sendMouseEvent({type:"click"}, btnDoit);
});
});
};
if (dbg._controller.activeThread) {
testCommands(dbg, cmd);
} else {
dbg.once("connected", testCommands.bind(null, dbg, cmd));
}
helpers.audit(options, [{
setup: "dbg continue",
exec: { output: "" }
}]);
});
});
});
});

View File

@ -48,20 +48,19 @@ function test() {
openDone.then(function(toolbox) {
let dbg = toolbox.getCurrentPanel();
ok(dbg, "DebuggerPanel exists");
dbg.once("connected", function() {
// Wait for the initial resume...
dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
dbg._view.Variables.lazyEmpty = false;
client = dbg.panelWin.gClient;
client.activeThread.addOneTimeListener("framesadded", function() {
line0 = '' + options.window.wrappedJSObject.line0;
deferred.resolve();
});
// Wait for the initial resume...
dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
info("Starting tests");
// Trigger newScript notifications using eval.
content.wrappedJSObject.firstCall();
client = dbg.panelWin.gClient;
client.activeThread.addOneTimeListener("framesadded", function() {
line0 = '' + options.window.wrappedJSObject.line0;
deferred.resolve();
});
// Trigger newScript notifications using eval.
content.wrappedJSObject.firstCall();
});
});

View File

@ -13,9 +13,15 @@
<body>
<p>Peanut butter jelly time!</p>
<script type="text/javascript">
function inline() {
}
<script type="text/javascript;version=1.8">
function inline() {}
let arrow = () => {}
let foo = bar => {}
let foo2 = bar2 = baz2 => 42;
setTimeout((foo, bar, baz) => {});
setTimeout((foo, bar, baz) => 42);
</script>
</body>

View File

@ -83,7 +83,11 @@ function htmlSearch(callback) {
executeSoon(function() {
let expectedResults = [
["inline", "-02.html", "", 16, 15],
]
["arrow", "-02.html", "", 17, 10],
["foo", "-02.html", "", 19, 10],
["foo2", "-02.html", "", 20, 10],
["bar2", "-02.html", "", 20, 17]
];
for (let [label, value, description, line, col] of expectedResults) {
is(gFilteredFunctions.selectedItem.label,
@ -118,7 +122,7 @@ function htmlSearch(callback) {
}
});
write("@inline");
write("@");
}
function firstSearch(callback) {
@ -148,7 +152,7 @@ function firstSearch(callback) {
["a_test", "-01.js", "foo.sub.sub", 31, 6],
["n_test" + s + "z", "-01.js", "foo.sub.sub", 33, 6],
["test_SAME_NAME", "-01.js", "foo.sub.sub.sub", 36, 8]
]
];
for (let [label, value, description, line, col] of expectedResults) {
is(gFilteredFunctions.selectedItem.label,
@ -213,7 +217,7 @@ function secondSearch(callback) {
["x", "-02.js", "", 19, 31],
["y", "-02.js", "", 19, 40],
["z", "-02.js", "", 19, 49]
]
];
for (let [label, value, description, line, col] of expectedResults) {
is(gFilteredFunctions.selectedItem.label,

View File

@ -156,12 +156,10 @@ function wait_for_connect_and_resume(aOnDebugging, aTab) {
gDevTools.showToolbox(target, "jsdebugger").then(function(toolbox) {
let dbg = toolbox.getCurrentPanel();
dbg.once("connected", function dbgConnected() {
// Wait for the initial resume...
dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
aOnDebugging();
});
// Wait for the initial resume...
dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
aOnDebugging();
});
});
}
@ -176,16 +174,16 @@ function debug_tab_pane(aURL, aOnDebugging, aBeforeTabAdded) {
let debuggee = gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject;
let target = TargetFactory.forTab(gBrowser.selectedTab);
info("Opening Debugger");
gDevTools.showToolbox(target, "jsdebugger").then(function(toolbox) {
let dbg = toolbox.getCurrentPanel();
dbg.once("connected", function() {
// Wait for the initial resume...
dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
dbg._view.Variables.lazyEmpty = false;
dbg._view.Variables.lazyAppend = false;
aOnDebugging(tab, debuggee, dbg);
});
// Wait for the initial resume...
dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
info("Debugger has started");
dbg._view.Variables.lazyEmpty = false;
dbg._view.Variables.lazyAppend = false;
aOnDebugging(tab, debuggee, dbg);
});
});
});
@ -200,17 +198,16 @@ function debug_remote(aURL, aOnDebugging, aBeforeTabAdded) {
let tab = addTab(aURL, function() {
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
info("Opening Remote Debugger");
let win = DebuggerUI.toggleRemoteDebugger();
win._dbgwin.addEventListener("Debugger:Connected", function dbgConnected() {
win._dbgwin.removeEventListener("Debugger:Connected", dbgConnected, true);
// Wait for the initial resume...
win.panelWin.gClient.addOneTimeListener("resumed", function() {
win._dbgwin.DebuggerView.Variables.lazyEmpty = false;
win._dbgwin.DebuggerView.Variables.lazyAppend = false;
aOnDebugging(tab, debuggee, win);
});
}, true);
// Wait for the initial resume...
win.panelWin.gClient.addOneTimeListener("resumed", function() {
info("Remote Debugger has started");
win._dbgwin.DebuggerView.Variables.lazyEmpty = false;
win._dbgwin.DebuggerView.Variables.lazyAppend = false;
aOnDebugging(tab, debuggee, win);
});
});
}
@ -219,10 +216,10 @@ function debug_chrome(aURL, aOnClosing, aOnDebugging) {
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
info("Opening Browser Debugger");
DebuggerUI.toggleChromeDebugger(aOnClosing, function dbgRan(process) {
info("Browser Debugger has started");
let win = DebuggerUI.toggleChromeDebugger(aOnClosing, function(process) {
// Wait for the remote debugging process to start...
// The remote debugging process has started...
info("Browser Debugger has started");
aOnDebugging(tab, debuggee, process);
});
});

View File

@ -142,7 +142,7 @@ ProfilerConnection.prototype = {
*/
function ProfilerController(target) {
this.profiler = new ProfilerConnection(target.client);
this.pool = {};
this.profiles = new Map();
// Chrome debugging targets have already obtained a reference to the
// profiler actor.
@ -210,12 +210,14 @@ ProfilerController.prototype = {
* argument: an error object (may be null).
*/
start: function PC_start(name, cb) {
if (this.pool[name]) {
if (this.profiles.has(name)) {
return;
}
let profile = this.pool[name] = makeProfile(name);
let profiler = this.profiler;
let profile = makeProfile(name);
this.profiles.set(name, profile);
// If profile is already running, no need to do anything.
if (this.isProfileRecording(profile)) {
@ -251,15 +253,15 @@ ProfilerController.prototype = {
*/
stop: function PC_stop(name, cb) {
let profiler = this.profiler;
let profile = this.pool[name];
let profile = this.profiles.get(name);
if (!profile || !this.isProfileRecording(profile)) {
return;
}
let isRecording = function () {
for (let name in this.pool) {
if (this.isProfileRecording(this.pool[name])) {
for (let [ name, profile ] of this.profiles) {
if (this.isProfileRecording(profile)) {
return true;
}
}

View File

@ -44,15 +44,19 @@ XPCOMUtils.defineLazyModuleGetter(this, "Services",
* @param ProfilerPanel panel
* A reference to the container panel.
*/
function ProfileUI(uid, panel) {
function ProfileUI(uid, name, panel) {
let doc = panel.document;
let win = panel.window;
EventEmitter.decorate(this);
this.isReady = false;
this.isStarted = false;
this.isFinished = false;
this.panel = panel;
this.uid = uid;
this.name = name;
this.iframe = doc.createElement("iframe");
this.iframe.setAttribute("flex", "1");
@ -70,9 +74,6 @@ function ProfileUI(uid, panel) {
return;
}
let label = doc.querySelector("li#profile-" + this.uid + " > h1");
let name = label.textContent.replace(/\s\*$/, "");
switch (event.data.status) {
case "loaded":
if (this.panel._runningUid !== null) {
@ -87,26 +88,10 @@ function ProfileUI(uid, panel) {
this.emit("ready");
break;
case "start":
// Start profiling and, once started, notify the underlying page
// so that it could update the UI. Also, once started, we add a
// star to the profile name to indicate which profile is currently
// running.
this.panel.startProfiling(name, function onStart() {
label.textContent = name + " *";
this.panel.broadcast(this.uid, {task: "onStarted"});
this.emit("started");
}.bind(this));
this.start();
break;
case "stop":
// Stop profiling and, once stopped, notify the underlying page so
// that it could update the UI and remove a star from the profile
// name.
this.panel.stopProfiling(name, function onStop() {
label.textContent = name;
this.panel.broadcast(this.uid, {task: "onStopped"});
this.emit("stopped");
}.bind(this));
this.stop();
break;
case "disabled":
this.emit("disabled");
@ -169,6 +154,56 @@ ProfileUI.prototype = {
poll();
},
/**
* Update profile's label in the sidebar.
*
* @param string text
* New text for the label.
*/
updateLabel: function PUI_udpateLabel(text) {
let doc = this.panel.document;
let label = doc.querySelector("li#profile-" + this.uid + "> h1");
label.textContent = text;
},
/**
* Start profiling and, once started, notify the underlying page
* so that it could update the UI. Also, once started, we add a
* star to the profile name to indicate which profile is currently
* running.
*/
start: function PUI_start() {
if (this.isStarted || this.isFinished) {
return;
}
this.panel.startProfiling(this.name, function onStart() {
this.isStarted = true;
this.updateLabel(this.name + " *");
this.panel.broadcast(this.uid, {task: "onStarted"});
this.emit("started");
}.bind(this));
},
/**
* Stop profiling and, once stopped, notify the underlying page so
* that it could update the UI and remove a star from the profile
* name.
*/
stop: function PUI_stop() {
if (!this.isStarted || this.isFinished) {
return;
}
this.panel.stopProfiling(this.name, function onStop() {
this.isStarted = false;
this.isFinished = true;
this.updateLabel(this.name);
this.panel.broadcast(this.uid, {task: "onStopped"});
this.emit("stopped");
}.bind(this));
},
/**
* Destroys the ProfileUI instance.
*/
@ -276,7 +311,9 @@ ProfilerPanel.prototype = {
this.controller.connect(function onConnect() {
let create = this.document.getElementById("profiler-create");
create.addEventListener("click", this.createProfile.bind(this), false);
create.addEventListener("click", function (ev) {
this.createProfile()
}.bind(this), false);
create.removeAttribute("disabled");
let profile = this.createProfile();
@ -303,13 +340,21 @@ ProfilerPanel.prototype = {
* the newly created profile, they have do to switch
* explicitly.
*
* @param string name
* (optional) name of the new profile
*
* @return ProfilerPanel
*/
createProfile: function PP_addProfile() {
createProfile: function PP_createProfile(name) {
if (name && this.getProfileByName(name)) {
return this.getProfileByName(name);
}
let uid = ++this._uid;
let list = this.document.getElementById("profiles-list");
let item = this.document.createElement("li");
let wrap = this.document.createElement("h1");
name = name || L10N.getFormatStr("profiler.profileName", [uid]);
item.setAttribute("id", "profile-" + uid);
item.setAttribute("data-uid", uid);
@ -318,12 +363,12 @@ ProfilerPanel.prototype = {
}.bind(this), false);
wrap.className = "profile-name";
wrap.textContent = L10N.getFormatStr("profiler.profileName", [uid]);
wrap.textContent = name;
item.appendChild(wrap);
list.appendChild(item);
let profile = new ProfileUI(uid, this);
let profile = new ProfileUI(uid, name, this);
this.profiles.set(uid, profile);
this.emit("profileCreated", uid);
@ -424,6 +469,40 @@ ProfilerPanel.prototype = {
}.bind(this));
},
/**
* Lookup an individual profile by its name.
*
* @param string name name of the profile
* @return profile object or null
*/
getProfileByName: function PP_getProfileByName(name) {
if (!this.profiles) {
return null;
}
for (let [ uid, profile ] of this.profiles) {
if (profile.name === name) {
return profile;
}
}
return null;
},
/**
* Lookup an individual profile by its UID.
*
* @param number uid UID of the profile
* @return profile object or null
*/
getProfileByUID: function PP_getProfileByUID(uid) {
if (!this.profiles) {
return null;
}
return this.profiles.get(uid) || null;
},
/**
* Broadcast messages to all Cleopatra instances.
*

View File

@ -0,0 +1,211 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
this.EXPORTED_SYMBOLS = [];
Cu.import("resource:///modules/devtools/gcli.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/devtools/Require.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
"resource:///modules/devtools/gDevTools.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "console",
"resource://gre/modules/devtools/Console.jsm");
var Promise = require('util/promise');
/*
* 'profiler' command. Doesn't do anything.
*/
gcli.addCommand({
name: "profiler",
description: gcli.lookup("profilerDesc"),
manual: gcli.lookup("profilerManual")
});
/*
* 'profiler open' command
*/
gcli.addCommand({
name: "profiler open",
description: gcli.lookup("profilerOpenDesc"),
params: [],
exec: function (args, context) {
return gDevTools.showToolbox(context.environment.target, "jsprofiler")
.then(function () null);
}
});
/*
* 'profiler close' command
*/
gcli.addCommand({
name: "profiler close",
description: gcli.lookup("profilerCloseDesc"),
params: [],
exec: function (args, context) {
return gDevTools.closeToolbox(context.environment.target)
.then(function () null);
}
});
/*
* 'profiler start' command
*/
gcli.addCommand({
name: "profiler start",
description: gcli.lookup("profilerStartDesc"),
returnType: "string",
params: [
{
name: "name",
type: "string"
}
],
exec: function (args, context) {
function start() {
let name = args.name;
let panel = getPanel(context, "jsprofiler");
let profile = panel.getProfileByName(name) || panel.createProfile(name);
if (profile.isStarted) {
throw gcli.lookup("profilerAlreadyStarted");
}
if (profile.isFinished) {
throw gcli.lookup("profilerAlradyFinished");
}
panel.switchToProfile(profile, function () profile.start());
return gcli.lookup("profilerStarting");
}
return gDevTools.showToolbox(context.environment.target, "jsprofiler")
.then(start);
}
});
/*
* 'profiler stop' command
*/
gcli.addCommand({
name: "profiler stop",
description: gcli.lookup("profilerStopDesc"),
returnType: "string",
params: [
{
name: "name",
type: "string"
}
],
exec: function (args, context) {
function stop() {
let panel = getPanel(context, "jsprofiler");
let profile = panel.getProfileByName(args.name);
if (!profile) {
throw gcli.lookup("profilerNotFound");
}
if (profile.isFinished) {
throw gcli.lookup("profilerAlreadyFinished");
}
if (!profile.isStarted) {
throw gcli.lookup("profilerNotStarted");
}
panel.switchToProfile(profile, function () profile.stop());
return gcli.lookup("profilerStopping");
}
return gDevTools.showToolbox(context.environment.target, "jsprofiler")
.then(stop);
}
});
/*
* 'profiler list' command
*/
gcli.addCommand({
name: "profiler list",
description: gcli.lookup("profilerListDesc"),
returnType: "dom",
params: [],
exec: function (args, context) {
let panel = getPanel(context, "jsprofiler");
if (!panel) {
throw gcli.lookup("profilerNotReady");
}
let doc = panel.document;
let div = createXHTMLElement(doc, "div");
let ol = createXHTMLElement(doc, "ol");
for ([ uid, profile] of panel.profiles) {
let li = createXHTMLElement(doc, "li");
li.textContent = profile.name;
if (profile.isStarted) {
li.textContent += " *";
}
ol.appendChild(li);
}
div.appendChild(ol);
return div;
}
});
/*
* 'profiler show' command
*/
gcli.addCommand({
name: "profiler show",
description: gcli.lookup("profilerShowDesc"),
params: [
{
name: "name",
type: "string"
}
],
exec: function (args, context) {
let panel = getPanel(context, "jsprofiler");
if (!panel) {
throw gcli.lookup("profilerNotReady");
}
let profile = panel.getProfileByName(args.name);
if (!profile) {
throw gcli.lookup("profilerNotFound");
}
panel.switchToProfile(profile);
}
});
function getPanel(context, id) {
if (context == null) {
return undefined;
}
let toolbox = gDevTools.getToolbox(context.environment.target);
return toolbox == null ? undefined : toolbox.getPanel(id);
}
function createXHTMLElement(document, tagname) {
return document.createElementNS("http://www.w3.org/1999/xhtml", tagname);
}

View File

@ -14,6 +14,7 @@ MOCHITEST_BROWSER_TESTS = \
browser_profiler_profiles.js \
browser_profiler_remote.js \
browser_profiler_bug_834878_source_buttons.js \
browser_profiler_cmd.js \
head.js \
$(NULL)

View File

@ -0,0 +1,125 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const URL = "data:text/html;charset=utf8,<p>JavaScript Profiler test</p>";
let gTarget, gPanel, gOptions;
function cmd(typed, expected="") {
helpers.audit(gOptions, [{
setup: typed,
exec: { output: expected }
}]);
}
function test() {
waitForExplicitFinish();
helpers.addTabWithToolbar(URL, function (options) {
gOptions = options;
gTarget = options.target;
return gDevTools.showToolbox(options.target, "jsprofiler")
.then(setupGlobals)
.then(testProfilerStart)
.then(testProfilerList)
.then(testProfilerStop)
.then(testProfilerClose)
}).then(finishUp);
}
function setupGlobals() {
let deferred = Promise.defer();
gPanel = gDevTools.getToolbox(gTarget).getPanel("jsprofiler");
deferred.resolve();
return deferred.promise;
}
function testProfilerStart() {
let deferred = Promise.defer();
gPanel.once("started", function () {
is(gPanel.profiles.size, 2, "There are two profiles");
ok(!gPanel.getProfileByName("Profile 1").isStarted, "Profile 1 wasn't started");
ok(gPanel.getProfileByName("Profile 2").isStarted, "Profile 2 was started");
cmd('profiler start "Profile 2"', "This profile has already been started");
deferred.resolve();
});
cmd("profiler start", "Starting...");
return deferred.promise;
}
function testProfilerList() {
let deferred = Promise.defer();
cmd("profiler list", /^.*Profile\s1.*Profile\s2\s\*.*$/);
deferred.resolve();
return deferred.promise;
}
function testProfilerStop() {
let deferred = Promise.defer();
gPanel.once("stopped", function () {
ok(!gPanel.getProfileByName("Profile 2").isStarted, "Profile 2 was stopped");
ok(gPanel.getProfileByName("Profile 2").isFinished, "Profile 2 was stopped");
cmd('profiler stop "Profile 2"', "This profile has already been completed. " +
"Use 'profile show' command to see its results");
cmd('profiler stop "Profile 1"', "This profile has not been started yet. " +
"Use 'profile start' to start profliling");
cmd('profiler stop "invalid"', "Profile not found")
deferred.resolve();
});
cmd('profiler stop "Profile 2"', "Stopping...");
return deferred.promise;
}
function testProfilerShow() {
let deferred = Promise.defer();
is(gPanel.getProfileByName("Profile 2").uid, gPanel.activeProfile.uid,
"Profile 2 is active");
gPanel.once("profileSwitched", function () {
is(gPanel.getProfileByName("Profile 1").uid, gPanel.activeProfile.uid,
"Profile 1 is active");
cmd('profile show "invalid"', "Profile not found");
deferred.resolve();
});
cmd('profile show "Profile 1"');
return deferred.promise;
}
function testProfilerClose() {
let deferred = Promise.defer();
helpers.audit(gOptions, [{
setup: "profiler close",
completed: false,
exec: { output: "" }
}]);
let toolbox = gDevTools.getToolbox(gOptions.target);
if (!toolbox) {
ok(true, "Profiler was closed.");
deferred.resolve();
} else {
toolbox.on("destroyed", function () {
ok(true, "Profiler was closed.");
deferred.resolve();
});
}
return deferred.promise;
}
function finishUp() {
gTarget = null;
gPanel = null;
gOptions = null;
finish();
}

View File

@ -37,6 +37,26 @@ function onProfileCreated(name, uid) {
}
function onProfileSwitched(name, uid) {
gPanel.once("profileCreated", onNamedProfileCreated);
gPanel.once("profileSwitched", onNamedProfileSwitched);
ok(gPanel.activeProfile.uid === uid, "Switched to a new profile");
gPanel.createProfile("Custom Profile");
}
function onNamedProfileCreated(name, uid) {
is(gPanel.profiles.size, 3, "There are three profiles now");
is(gPanel.getProfileByUID(uid).name, "Custom Profile", "Name is correct");
let label = gPanel.document.querySelector("li#profile-" + uid + "> h1");
is(label.textContent, "Custom Profile", "Name is correct on the label");
let btn = gPanel.document.getElementById("profile-" + uid);
ok(btn, "Profile item has been added to the sidebar");
btn.click();
}
function onNamedProfileSwitched(name, uid) {
ok(gPanel.activeProfile.uid === uid, "Switched to a new profile");
tearDown(gTab, function onTearDown() {

View File

@ -14,7 +14,12 @@ let gDevTools = temp.gDevTools;
Cu.import("resource://gre/modules/devtools/dbg-server.jsm", temp);
let DebuggerServer = temp.DebuggerServer;
// Import the GCLI test helper
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
registerCleanupFunction(function () {
helpers = null;
Services.prefs.clearUserPref(PROFILER_ENABLED);
Services.prefs.clearUserPref(REMOTE_ENABLED);
DebuggerServer.destroy();

View File

@ -264,6 +264,34 @@ SyntaxTree.prototype = {
inferredLocation: inferredLocation
});
}
},
/**
* Callback invoked for each arrow expression node.
* @param Node aNode
*/
onArrowExpression: function STW_onArrowExpression(aNode) {
let parent = aNode._parent;
let inferredName, inferredChain, inferredLocation;
// Infer the function's name from an enclosing syntax tree node.
let inferredInfo = ParserHelpers.inferFunctionExpressionInfo(aNode);
inferredName = inferredInfo.name;
inferredChain = inferredInfo.chain;
inferredLocation = inferredInfo.loc;
// Current node may be part of a larger assignment expression stack.
if (parent.type == "AssignmentExpression") {
this.onFunctionExpression(parent);
}
if (inferredName && inferredName.toLowerCase().contains(lowerCaseToken)) {
store.push({
inferredName: inferredName,
inferredChain: inferredChain,
inferredLocation: inferredLocation
});
}
}
});
@ -1528,6 +1556,45 @@ let SyntaxTreeVisitor = {
this[aNode.body.type](aNode.body, aNode, aCallbacks);
},
/**
* An arrow expression.
*
* interface ArrowExpression <: Function, Expression {
* type: "ArrowExpression";
* params: [ Pattern ];
* defaults: [ Expression ];
* rest: Identifier | null;
* body: BlockStatement | Expression;
* generator: boolean;
* expression: boolean;
* }
*/
ArrowExpression: function STV_ArrowExpression(aNode, aParent, aCallbacks) {
aNode._parent = aParent;
if (this.break) {
return;
}
if (aCallbacks.onNode) {
if (aCallbacks.onNode(aNode, aParent) === false) {
return;
}
}
if (aCallbacks.onArrowExpression) {
aCallbacks.onArrowExpression(aNode);
}
for (let param of aNode.params) {
this[param.type](param, aNode, aCallbacks);
}
for (let _default of aNode.defaults) {
this[_default.type](_default, aNode, aCallbacks);
}
if (aNode.rest) {
this[aNode.rest.type](aNode.rest, aNode, aCallbacks);
}
this[aNode.body.type](aNode.body, aNode, aCallbacks);
},
/**
* A sequence expression, i.e., a comma-separated sequence of expressions.
*

View File

@ -555,6 +555,16 @@ StyleEditorChrome.prototype = {
editor.enableStyleSheet(editor.styleSheet.disabled);
});
wire(aSummary, ".stylesheet-name", {
events: {
"keypress": function onStylesheetNameActivate(aEvent) {
if (aEvent.keyCode == aEvent.DOM_VK_RETURN) {
this._view.activeSummary = aSummary;
}
}.bind(this)
}
});
wire(aSummary, ".stylesheet-saveButton", function onSaveButton(aEvent) {
aEvent.stopPropagation();
aEvent.target.blur();

View File

@ -80,13 +80,13 @@
title="&visibilityToggle.tooltip;"
accesskey="&saveButton.accesskey;"></a>
<hgroup class="stylesheet-info">
<h1><a class="stylesheet-name" href="#"><xul:label crop="start"/></a></h1>
<h1><a class="stylesheet-name" tabindex="0"><xul:label crop="start"/></a></h1>
<div class="stylesheet-more">
<h3 class="stylesheet-title"></h3>
<h3 class="stylesheet-rule-count"></h3>
<h3 class="stylesheet-error-message"></h3>
<xul:spacer/>
<h3><a class="stylesheet-saveButton" href="#"
<h3><a class="stylesheet-saveButton"
title="&saveButton.tooltip;"
accesskey="&saveButton.accesskey;">&saveButton.label;</a></h3>
</div>

View File

@ -29,6 +29,7 @@ _BROWSER_TEST_FILES = \
browser_styleeditor_sv_keynav.js \
browser_styleeditor_sv_resize.js \
browser_styleeditor_bug_826982_location_changed.js \
browser_styleeditor_bug_851132_middle_click.js \
head.js \
helpers.js \
four.html \

View File

@ -0,0 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TESTCASE_URI = TEST_BASE + "four.html";
function test() {
waitForExplicitFinish();
addTabAndLaunchStyleEditorChromeWhenLoaded(function (aChrome) {
run(aChrome);
});
content.location = TESTCASE_URI;
}
let gSEChrome, timeoutID;
function run(aChrome) {
gSEChrome = aChrome;
gBrowser.tabContainer.addEventListener("TabOpen", onTabAdded, false);
aChrome.editors[0].addActionListener({onAttach: onEditor0Attach});
aChrome.editors[1].addActionListener({onAttach: onEditor1Attach});
}
function getStylesheetNameLinkFor(aEditor) {
return gSEChrome.getSummaryElementForEditor(aEditor).querySelector(".stylesheet-name");
}
function onEditor0Attach(aEditor) {
waitForFocus(function () {
// left mouse click should focus editor 1
EventUtils.synthesizeMouseAtCenter(
getStylesheetNameLinkFor(gSEChrome.editors[1]),
{button: 0},
gChromeWindow);
}, gChromeWindow);
}
function onEditor1Attach(aEditor) {
ok(aEditor.sourceEditor.hasFocus(),
"left mouse click has given editor 1 focus");
// right mouse click should not open a new tab
EventUtils.synthesizeMouseAtCenter(
getStylesheetNameLinkFor(gSEChrome.editors[2]),
{button: 1},
gChromeWindow);
setTimeout(finish, 0);
}
function onTabAdded() {
ok(false, "middle mouse click has opened a new tab");
finish();
}
registerCleanupFunction(function () {
gBrowser.tabContainer.removeEventListener("TabOpen", onTabAdded, false);
gSEChrome = null;
});

View File

@ -525,6 +525,9 @@
@BINPATH@/components/TCPSocketParentIntermediary.js
@BINPATH@/components/TCPSocket.manifest
@BINPATH@/components/AppProtocolHandler.js
@BINPATH@/components/AppProtocolHandler.manifest
#ifdef MOZ_WEBRTC
@BINPATH@/components/PeerConnection.js
@BINPATH@/components/PeerConnection.manifest

View File

@ -1060,3 +1060,69 @@ paintflashingManual=Draw repainted areas in different colors
# LOCALIZATION NOTE (paintflashingTooltip) A string displayed as the
# tooltip of button in devtools toolbox which toggles paint flashing.
paintflashingTooltip=Highlight painted area
# LOCALIZATION NOTE (profilerDesc) A very short string used to describe the
# function of the profiler command.
profilerDesc=Manage profiler
# LOCALIZATION NOTE (profilerManual) A longer description describing the
# set of commands that control the profiler.
profilerManual=Commands to start or stop a JavaScript profiler
# LOCALIZATION NOTE (profilerOpen) A very short string used to describe the function
# of the profiler open command.
profilerOpenDesc=Open the profiler
# LOCALIZATION NOTE (profilerClose) A very short string used to describe the function
# of the profiler close command.
profilerCloseDesc=Close the profiler
# LOCALIZATION NOTE (profilerStart) A very short string used to describe the function
# of the profiler start command.
profilerStartDesc=Start profiling
# LOCALIZATION NOTE (profilerStop) A very short string used to describe the function
# of the profiler stop command.
profilerStopDesc=Stop profiling
# LOCALIZATION NOTE (profilerList) A very short string used to describe the function
# of the profiler list command.
profilerListDesc=List all profiles
# LOCALIZATION NOTE (profilerShow) A very short string used to describe the function
# of the profiler show command.
profilerShowDesc=Show individual profile
# LOCALIZATION NOTE (profilerAlreadyStarted) A message that is displayed whenever
# an operation cannot be completed because the profile in question has already
# been started.
profilerAlreadyStarted=This profile has already been started
# LOCALIZATION NOTE (profilerAlreadyFinished) A message that is displayed whenever
# an operation cannot be completed because the profile in question has already
# been finished. It also contains a hint to use the 'profile show' command to see
# the profiling results.
profilerAlreadyFinished=This profile has already been completed. Use 'profile show' command to see its results
# LOCALIZATION NOTE (profilerNotFound) A message that is displayed whenever
# an operation cannot be completed because the profile in question could not be
# found.
profilerNotFound=Profile not found
# LOCALIZATION NOTE (profilerNotStarted) A message that is displayed whenever
# an operation cannot be completed because the profile in question has not been
# started yet. It also contains a hint to use the 'profile start' command to
# start the profiler.
profilerNotStarted=This profile has not been started yet. Use 'profile start' to start profliling
# LOCALIZATION NOTE (profilerStarting) A very short string that indicates that
# we're starting the profiler.
profilerStarting=Starting...
# LOCALIZATION NOTE (profilerStopping) A very short string that indicates that
# we're stopping the profiler.
profilerStopping=Stopping...
# LOCALIZATION NOTE (profilerNotReady) A message that is displayed whenever
# an operation cannot be completed because the profiler has not been opened yet.
profilerNotReady=For this command to work you need to open the profiler first

View File

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
22.0a1
23.0a1

View File

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
22.0a1
23.0a1

2
mobile/android/confvars.sh Executable file → Normal file
View File

@ -5,7 +5,7 @@
MOZ_APP_BASENAME=Fennec
MOZ_APP_VENDOR=Mozilla
MOZ_APP_VERSION=22.0a1
MOZ_APP_VERSION=23.0a1
MOZ_APP_UA_NAME=Firefox
MOZ_BRANDING_DIRECTORY=mobile/android/branding/unofficial

View File

@ -10,7 +10,7 @@ VPATH := @srcdir@
include $(DEPTH)/config/autoconf.mk
# Definitions used by constants.js.
weave_version := 1.24.0
weave_version := 1.25.0
weave_id := {340c2bbc-ce74-4362-90b5-7c26312808ef}
# Preprocess files.

View File

@ -298,6 +298,7 @@ LoginManager.prototype = {
switch (event.type) {
case "DOMContentLoaded":
event.target.removeEventListener(event.type, this, false);
this._pwmgr._fillDocument(event.target);
return;

View File

@ -2234,6 +2234,9 @@ this.AddonManager = {
OPTIONS_TYPE_INLINE: 2,
// Options will be displayed in a new tab, if possible
OPTIONS_TYPE_TAB: 3,
// Same as OPTIONS_TYPE_INLINE, but no Preferences button will be shown.
// Used to indicate that only non-interactive information will be shown.
OPTIONS_TYPE_INLINE_INFO: 4,
// Constants for displayed or hidden options notifications
// Options notification will be displayed

View File

@ -392,6 +392,7 @@ function UpdateParser(aId, aUpdateKey, aUrl, aObserver) {
this.id = aId;
this.updateKey = aUpdateKey;
this.observer = aObserver;
this.url = aUrl;
this.timer = Cc["@mozilla.org/timer;1"].
createInstance(Ci.nsITimer);
@ -408,7 +409,7 @@ function UpdateParser(aId, aUpdateKey, aUrl, aObserver) {
try {
this.request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
createInstance(Ci.nsIXMLHttpRequest);
this.request.open("GET", aUrl, true);
this.request.open("GET", this.url, true);
this.request.channel.notificationCallbacks = new CertUtils.BadCertHandler(!requireBuiltIn);
this.request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
this.request.overrideMimeType("text/xml");
@ -428,6 +429,7 @@ UpdateParser.prototype = {
observer: null,
request: null,
timer: null,
url: null,
/**
* Called when the manifest has been successfully loaded.
@ -454,14 +456,15 @@ UpdateParser.prototype = {
}
if (!Components.isSuccessCode(request.status)) {
WARN("Request failed: " + request.status);
WARN("Request failed: " + this.url + " - " + request.status);
this.notifyError(AddonUpdateChecker.ERROR_DOWNLOAD_ERROR);
return;
}
let channel = request.channel;
if (channel instanceof Ci.nsIHttpChannel && !channel.requestSucceeded) {
WARN("Request failed: " + channel.responseStatus + ": " + channel.responseStatusText);
WARN("Request failed: " + this.url + " - " + channel.responseStatus +
": " + channel.responseStatusText);
this.notifyError(AddonUpdateChecker.ERROR_DOWNLOAD_ERROR);
return;
}
@ -502,12 +505,13 @@ UpdateParser.prototype = {
this.timer = null;
if (!Components.isSuccessCode(this.request.status)) {
WARN("Request failed: " + this.request.status);
WARN("Request failed: " + this.url + " - " + this.request.status);
}
else if (this.request.channel instanceof Ci.nsIHttpChannel) {
try {
if (this.request.channel.requestSucceeded) {
WARN("Request failed: " + this.request.channel.responseStatus + ": " +
WARN("Request failed: " + this.url + " - " +
this.request.channel.responseStatus + ": " +
this.request.channel.responseStatusText);
}
}

View File

@ -420,7 +420,7 @@ function PluginWrapper(aId, aName, aDescription, aTags) {
}
PluginWrapper.prototype = {
optionsType: AddonManager.OPTIONS_TYPE_INLINE,
optionsType: AddonManager.OPTIONS_TYPE_INLINE_INFO,
optionsURL: "chrome://mozapps/content/extensions/pluginPrefs.xul",
get updateDate() {

View File

@ -760,7 +760,8 @@ function loadManifestFromRDF(aUri, aStream) {
if (addon.optionsType &&
addon.optionsType != AddonManager.OPTIONS_TYPE_DIALOG &&
addon.optionsType != AddonManager.OPTIONS_TYPE_INLINE &&
addon.optionsType != AddonManager.OPTIONS_TYPE_TAB) {
addon.optionsType != AddonManager.OPTIONS_TYPE_TAB &&
addon.optionsType != AddonManager.OPTIONS_TYPE_INLINE_INFO) {
throw new Error("Install manifest specifies unknown type: " + addon.optionsType);
}
}
@ -1681,8 +1682,6 @@ var XPIProvider = {
// of XPCOM
Services.obs.addObserver({
observe: function shutdownObserver(aSubject, aTopic, aData) {
Services.prefs.setCharPref(PREF_BOOTSTRAP_ADDONS,
JSON.stringify(XPIProvider.bootstrappedAddons));
for (let id in XPIProvider.bootstrappedAddons) {
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = XPIProvider.bootstrappedAddons[id].descriptor;
@ -1789,6 +1788,14 @@ var XPIProvider = {
Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, false);
},
/**
* Persists changes to XPIProvider.bootstrappedAddons to it's store (a pref).
*/
persistBootstrappedAddons: function XPI_persistBootstrappedAddons() {
Services.prefs.setCharPref(PREF_BOOTSTRAP_ADDONS,
JSON.stringify(this.bootstrappedAddons));
},
/**
* Adds a list of currently active add-ons to the next crash report.
*/
@ -2939,6 +2946,7 @@ var XPIProvider = {
// Cache the new install location states
let cache = JSON.stringify(this.getInstallLocationStates());
Services.prefs.setCharPref(PREF_INSTALL_CACHE, cache);
this.persistBootstrappedAddons();
// Clear out any cached migration data.
XPIDatabase.migrateData = null;
@ -3680,6 +3688,7 @@ var XPIProvider = {
type: aType,
descriptor: aFile.persistentDescriptor
};
this.persistBootstrappedAddons();
this.addAddonsToCrashReporter();
// Locales only contain chrome and can't have bootstrap scripts
@ -3747,6 +3756,7 @@ var XPIProvider = {
unloadBootstrapScope: function XPI_unloadBootstrapScope(aId) {
delete this.bootstrapScopes[aId];
delete this.bootstrappedAddons[aId];
this.persistBootstrappedAddons();
this.addAddonsToCrashReporter();
},
@ -5952,6 +5962,7 @@ function AddonWrapper(aAddon) {
case AddonManager.OPTIONS_TYPE_TAB:
return hasOptionsURL ? aAddon.optionsType : null;
case AddonManager.OPTIONS_TYPE_INLINE:
case AddonManager.OPTIONS_TYPE_INLINE_INFO:
return (hasOptionsXUL || hasOptionsURL) ? aAddon.optionsType : null;
}
return null;

View File

@ -891,6 +891,8 @@ var gViewController = {
aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE) {
return false;
}
if (aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO)
return false;
return true;
},
doCommand: function cmd_showItemPreferences_doCommand(aAddon) {
@ -1162,6 +1164,11 @@ var gViewController = {
onEvent: function gVC_onEvent() {}
};
function hasInlineOptions(aAddon) {
return (aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE ||
aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO);
}
function openOptionsInTab(optionsURL) {
var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
@ -2727,7 +2734,7 @@ var gDetailView = {
AddonManager.removeManagerListener(this);
this.clearLoading();
if (this._addon) {
if (this._addon.optionsType == AddonManager.OPTIONS_TYPE_INLINE) {
if (hasInlineOptions(this._addon)) {
Services.obs.notifyObservers(document,
AddonManager.OPTIONS_NOTIFICATION_HIDDEN,
this._addon.id);
@ -2849,7 +2856,7 @@ var gDetailView = {
fillSettingsRows: function gDetailView_fillSettingsRows(aScrollToPreferences, aCallback) {
this.emptySettingsRows();
if (this._addon.optionsType != AddonManager.OPTIONS_TYPE_INLINE) {
if (!hasInlineOptions(this._addon)) {
if (aCallback)
aCallback();
return;
@ -2970,8 +2977,7 @@ var gDetailView = {
onDisabling: function gDetailView_onDisabling(aNeedsRestart) {
this.updateState();
if (!aNeedsRestart &&
this._addon.optionsType == AddonManager.OPTIONS_TYPE_INLINE) {
if (!aNeedsRestart && hasInlineOptions(this._addon)) {
Services.obs.notifyObservers(document,
AddonManager.OPTIONS_NOTIFICATION_HIDDEN,
this._addon.id);

View File

@ -1237,7 +1237,8 @@
}
}
this._preferencesBtn.hidden = !this.mAddon.optionsURL;
this._preferencesBtn.hidden = (!this.mAddon.optionsURL) ||
this.mAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO;
if (this.hasPermission("enable")) {
this._enableBtn.hidden = false;

View File

@ -58,6 +58,7 @@ MOCHITEST_BROWSER_MAIN = \
browser_openDialog.js \
browser_types.js \
browser_inlinesettings.js \
browser_inlinesettings_info.js \
browser_tabsettings.js \
browser_pluginprefs.js \
$(NULL)

View File

@ -0,0 +1,8 @@
function install (params, aReason) {
}
function uninstall (params, aReason) {
}
function startup (params, aReason) {
}
function shutdown (params, aReason) {
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" ?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>inlinesettings1@tests.mozilla.org</em:id>
<em:name>Inline Settings (Bootstrap)</em:name>
<em:version>1</em:version>
<em:bootstrap>true</em:bootstrap>
<em:optionsType>4</em:optionsType>
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" ?>
<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<setting pref="extensions.inlinesettings1.bool" type="bool" title="Bool" checkboxlabel="Check box label"/>
<setting pref="extensions.inlinesettings1.boolint" type="boolint" on="1" off="2" title="BoolInt"/>
<setting pref="extensions.inlinesettings1.integer" type="integer" title="Integer"/>
<setting pref="extensions.inlinesettings1.string" type="string" title="String"/>
<setting type="control" title="Menulist">
<menulist sizetopopup="always" oncommand="window._testValue = this.value;">
<menupopup>
<menuitem label="Alpha" value="1" />
<menuitem label="Bravo" value="2" />
<menuitem label="Charlie" value="3" />
</menupopup>
</menulist>
</setting>
<setting pref="extensions.inlinesettings1.color" type="color" title="Color"/>
<setting pref="extensions.inlinesettings1.file" type="file" title="File"/>
<setting pref="extensions.inlinesettings1.directory" type="directory" title="Directory"/>
</vbox>

View File

@ -0,0 +1,570 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests various aspects of the details view
var gManagerWindow;
var gCategoryUtilities;
var gProvider;
const SETTINGS_ROWS = 8;
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(window);
var observer = {
lastDisplayed: null,
callback: null,
checkDisplayed: function(aExpected) {
is(this.lastDisplayed, aExpected, "'addon-options-displayed' notification should have fired");
this.lastDisplayed = null;
},
checkNotDisplayed: function() {
is(this.lastDisplayed, null, "'addon-options-displayed' notification should not have fired");
},
lastHidden: null,
checkHidden: function(aExpected) {
is(this.lastHidden, aExpected, "'addon-options-hidden' notification should have fired");
this.lastHidden = null;
},
checkNotHidden: function() {
is(this.lastHidden, null, "'addon-options-hidden' notification should not have fired");
},
observe: function(aSubject, aTopic, aData) {
if (aTopic == AddonManager.OPTIONS_NOTIFICATION_DISPLAYED) {
this.lastDisplayed = aData;
// Test if the binding has applied before the observers are notified. We test the second setting here,
// because the code operates on the first setting and we want to check it applies to all.
var setting = aSubject.querySelector("rows > setting[first-row] ~ setting");
var input = gManagerWindow.document.getAnonymousElementByAttribute(setting, "class", "preferences-title");
isnot(input, null, "XBL binding should be applied");
// Add some extra height to the scrolling pane to ensure that it needs to scroll when appropriate.
gManagerWindow.document.getElementById("detail-controls").style.marginBottom = "1000px";
if (this.callback) {
var tempCallback = this.callback;
this.callback = null;
tempCallback();
}
} else if (aTopic == AddonManager.OPTIONS_NOTIFICATION_HIDDEN) {
this.lastHidden = aData;
}
}
};
function installAddon(aCallback) {
AddonManager.getInstallForURL(TESTROOT + "addons/browser_inlinesettings1_info.xpi",
function(aInstall) {
aInstall.addListener({
onInstallEnded: function() {
executeSoon(aCallback);
}
});
aInstall.install();
}, "application/x-xpinstall");
}
function checkScrolling(aShouldHaveScrolled) {
var detailView = gManagerWindow.document.getElementById("detail-view");
var boxObject = detailView.boxObject;
boxObject.QueryInterface(Ci.nsIScrollBoxObject);
ok(detailView.scrollHeight > boxObject.height, "Page should require scrolling");
if (aShouldHaveScrolled)
isnot(detailView.scrollTop, 0, "Page should have scrolled");
else
is(detailView.scrollTop, 0, "Page should not have scrolled");
}
function test() {
waitForExplicitFinish();
gProvider = new MockProvider();
gProvider.createAddons([{
id: "inlinesettings2@tests.mozilla.org",
name: "Inline Settings (Regular)",
version: "1",
optionsURL: CHROMEROOT + "options.xul",
optionsType: AddonManager.OPTIONS_TYPE_INLINE_INFO,
operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_DISABLE,
},{
id: "inlinesettings3@tests.mozilla.org",
name: "Inline Settings (More Options)",
description: "Tests for option types introduced after Mozilla 7.0",
version: "1",
optionsURL: CHROMEROOT + "more_options.xul",
optionsType: AddonManager.OPTIONS_TYPE_INLINE_INFO
},{
id: "noninlinesettings@tests.mozilla.org",
name: "Non-Inline Settings",
version: "1",
optionsURL: CHROMEROOT + "addon_prefs.xul"
}]);
installAddon(function () {
open_manager("addons://list/extension", function(aWindow) {
gManagerWindow = aWindow;
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
Services.obs.addObserver(observer,
AddonManager.OPTIONS_NOTIFICATION_DISPLAYED,
false);
Services.obs.addObserver(observer,
AddonManager.OPTIONS_NOTIFICATION_HIDDEN,
false);
run_next_test();
});
});
}
function end_test() {
Services.obs.removeObserver(observer,
AddonManager.OPTIONS_NOTIFICATION_DISPLAYED);
Services.prefs.clearUserPref("extensions.inlinesettings1.bool");
Services.prefs.clearUserPref("extensions.inlinesettings1.boolint");
Services.prefs.clearUserPref("extensions.inlinesettings1.integer");
Services.prefs.clearUserPref("extensions.inlinesettings1.string");
Services.prefs.clearUserPref("extensions.inlinesettings1.color");
Services.prefs.clearUserPref("extensions.inlinesettings1.file");
Services.prefs.clearUserPref("extensions.inlinesettings1.directory");
Services.prefs.clearUserPref("extensions.inlinesettings3.radioBool");
Services.prefs.clearUserPref("extensions.inlinesettings3.radioInt");
Services.prefs.clearUserPref("extensions.inlinesettings3.radioString");
Services.prefs.clearUserPref("extensions.inlinesettings3.menulist");
MockFilePicker.cleanup();
close_manager(gManagerWindow, function() {
observer.checkHidden("inlinesettings2@tests.mozilla.org");
Services.obs.removeObserver(observer,
AddonManager.OPTIONS_NOTIFICATION_HIDDEN);
AddonManager.getAddonByID("inlinesettings1@tests.mozilla.org", function(aAddon) {
aAddon.uninstall();
finish();
});
});
}
// Addon with options.xul
add_test(function() {
var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE_INFO, "Options should be inline info type");
addon.parentNode.ensureElementIsVisible(addon);
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
is_element_hidden(button, "Preferences button should be hidden");
run_next_test();
});
// Addon with inline preferences as optionsURL
add_test(function() {
var addon = get_addon_element(gManagerWindow, "inlinesettings2@tests.mozilla.org");
is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE_INFO, "Options should be inline info type");
addon.parentNode.ensureElementIsVisible(addon);
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
is_element_hidden(button, "Preferences button should be hidden");
run_next_test();
});
// Addon with non-inline preferences as optionsURL
add_test(function() {
var addon = get_addon_element(gManagerWindow, "noninlinesettings@tests.mozilla.org");
is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_DIALOG, "Options should be dialog type");
addon.parentNode.ensureElementIsVisible(addon);
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
is_element_visible(button, "Preferences button should be visible");
run_next_test();
});
// Addon with options.xul, also a test for the setting.xml bindings
add_test(function() {
var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
addon.parentNode.ensureElementIsVisible(addon);
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
wait_for_view_load(gManagerWindow, function() {
observer.checkDisplayed("inlinesettings1@tests.mozilla.org");
var grid = gManagerWindow.document.getElementById("detail-grid");
var settings = grid.querySelectorAll("rows > setting");
is(settings.length, SETTINGS_ROWS, "Grid should have settings children");
ok(settings[0].hasAttribute("first-row"), "First visible row should have first-row attribute");
Services.prefs.setBoolPref("extensions.inlinesettings1.bool", false);
var input = gManagerWindow.document.getAnonymousElementByAttribute(settings[0], "anonid", "input");
isnot(input.checked, true, "Checkbox should have initial value");
is(input.label, "Check box label", "Checkbox should be labelled");
EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
is(input.checked, true, "Checkbox should have updated value");
is(Services.prefs.getBoolPref("extensions.inlinesettings1.bool"), true, "Bool pref should have been updated");
EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
isnot(input.checked, true, "Checkbox should have updated value");
is(Services.prefs.getBoolPref("extensions.inlinesettings1.bool"), false, "Bool pref should have been updated");
ok(!settings[1].hasAttribute("first-row"), "Not the first row");
Services.prefs.setIntPref("extensions.inlinesettings1.boolint", 0);
var input = gManagerWindow.document.getAnonymousElementByAttribute(settings[1], "anonid", "input");
isnot(input.checked, true, "Checkbox should have initial value");
EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
is(input.checked, true, "Checkbox should have updated value");
is(Services.prefs.getIntPref("extensions.inlinesettings1.boolint"), 1, "BoolInt pref should have been updated");
EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
isnot(input.checked, true, "Checkbox should have updated value");
is(Services.prefs.getIntPref("extensions.inlinesettings1.boolint"), 2, "BoolInt pref should have been updated");
ok(!settings[2].hasAttribute("first-row"), "Not the first row");
Services.prefs.setIntPref("extensions.inlinesettings1.integer", 0);
var input = gManagerWindow.document.getAnonymousElementByAttribute(settings[2], "anonid", "input");
is(input.value, "0", "Number box should have initial value");
input.select();
EventUtils.synthesizeKey("1", {}, gManagerWindow);
EventUtils.synthesizeKey("3", {}, gManagerWindow);
is(input.value, "13", "Number box should have updated value");
is(Services.prefs.getIntPref("extensions.inlinesettings1.integer"), 13, "Integer pref should have been updated");
EventUtils.synthesizeKey("VK_DOWN", {}, gManagerWindow);
is(input.value, "12", "Number box should have updated value");
is(Services.prefs.getIntPref("extensions.inlinesettings1.integer"), 12, "Integer pref should have been updated");
ok(!settings[3].hasAttribute("first-row"), "Not the first row");
Services.prefs.setCharPref("extensions.inlinesettings1.string", "foo");
var input = gManagerWindow.document.getAnonymousElementByAttribute(settings[3], "anonid", "input");
is(input.value, "foo", "Text box should have initial value");
input.select();
EventUtils.synthesizeKey("b", {}, gManagerWindow);
EventUtils.synthesizeKey("a", {}, gManagerWindow);
EventUtils.synthesizeKey("r", {}, gManagerWindow);
is(input.value, "bar", "Text box should have updated value");
is(Services.prefs.getCharPref("extensions.inlinesettings1.string"), "bar", "String pref should have been updated");
ok(!settings[4].hasAttribute("first-row"), "Not the first row");
var input = settings[4].firstElementChild;
is(input.value, "1", "Menulist should have initial value");
input.focus();
EventUtils.synthesizeKey("b", {}, gManagerWindow);
is(input.value, "2", "Menulist should have updated value");
is(gManagerWindow._testValue, "2", "Menulist oncommand handler should've updated the test value");
delete gManagerWindow._testValue;
ok(!settings[5].hasAttribute("first-row"), "Not the first row");
Services.prefs.setCharPref("extensions.inlinesettings1.color", "#FF0000");
input = gManagerWindow.document.getAnonymousElementByAttribute(settings[5], "anonid", "input");
is(input.color, "#FF0000", "Color picker should have initial value");
input.focus();
EventUtils.synthesizeKey("VK_RIGHT", {}, gManagerWindow);
EventUtils.synthesizeKey("VK_RIGHT", {}, gManagerWindow);
EventUtils.synthesizeKey("VK_RETURN", {}, gManagerWindow);
input.hidePopup();
is(input.color, "#FF9900", "Color picker should have updated value");
is(Services.prefs.getCharPref("extensions.inlinesettings1.color"), "#FF9900", "Color pref should have been updated");
try {
ok(!settings[6].hasAttribute("first-row"), "Not the first row");
var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button");
input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input");
is(input.value, "", "Label value should be empty");
is(input.tooltipText, "", "Label tooltip should be empty");
var profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile);
MockFilePicker.returnFiles = [profD];
MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
is(input.value, profD.path, "Label value should match file chosen");
is(input.tooltipText, profD.path, "Label tooltip should match file chosen");
is(Services.prefs.getCharPref("extensions.inlinesettings1.file"), profD.path, "File pref should match file chosen");
MockFilePicker.returnFiles = [curProcD];
MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
is(input.value, profD.path, "Label value should not have changed");
is(input.tooltipText, profD.path, "Label tooltip should not have changed");
is(Services.prefs.getCharPref("extensions.inlinesettings1.file"), profD.path, "File pref should not have changed");
ok(!settings[7].hasAttribute("first-row"), "Not the first row");
button = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "button");
input = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "input");
is(input.value, "", "Label value should be empty");
is(input.tooltipText, "", "Label tooltip should be empty");
MockFilePicker.returnFiles = [profD];
MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
is(input.value, profD.path, "Label value should match file chosen");
is(input.tooltipText, profD.path, "Label tooltip should match file chosen");
is(Services.prefs.getCharPref("extensions.inlinesettings1.directory"), profD.path, "Directory pref should match file chosen");
MockFilePicker.returnFiles = [curProcD];
MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
is(input.value, profD.path, "Label value should not have changed");
is(input.tooltipText, profD.path, "Label tooltip should not have changed");
is(Services.prefs.getCharPref("extensions.inlinesettings1.directory"), profD.path, "Directory pref should not have changed");
} finally {
button = gManagerWindow.document.getElementById("detail-prefs-btn");
is_element_hidden(button, "Preferences button should not be visible");
gCategoryUtilities.openType("extension", run_next_test);
}
});
});
// Tests for the setting.xml bindings introduced after Mozilla 7
add_test(function() {
observer.checkHidden("inlinesettings1@tests.mozilla.org");
var addon = get_addon_element(gManagerWindow, "inlinesettings3@tests.mozilla.org");
addon.parentNode.ensureElementIsVisible(addon);
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
wait_for_view_load(gManagerWindow, function() {
observer.checkDisplayed("inlinesettings3@tests.mozilla.org");
var grid = gManagerWindow.document.getElementById("detail-grid");
var settings = grid.querySelectorAll("rows > setting");
is(settings.length, 4, "Grid should have settings children");
ok(settings[0].hasAttribute("first-row"), "First visible row should have first-row attribute");
Services.prefs.setBoolPref("extensions.inlinesettings3.radioBool", false);
var radios = settings[0].getElementsByTagName("radio");
isnot(radios[0].selected, true, "Correct radio button should be selected");
is(radios[1].selected, true, "Correct radio button should be selected");
EventUtils.synthesizeMouseAtCenter(radios[0], { clickCount: 1 }, gManagerWindow);
is(Services.prefs.getBoolPref("extensions.inlinesettings3.radioBool"), true, "Radio pref should have been updated");
EventUtils.synthesizeMouseAtCenter(radios[1], { clickCount: 1 }, gManagerWindow);
is(Services.prefs.getBoolPref("extensions.inlinesettings3.radioBool"), false, "Radio pref should have been updated");
ok(!settings[1].hasAttribute("first-row"), "Not the first row");
Services.prefs.setIntPref("extensions.inlinesettings3.radioInt", 5);
var radios = settings[1].getElementsByTagName("radio");
isnot(radios[0].selected, true, "Correct radio button should be selected");
is(radios[1].selected, true, "Correct radio button should be selected");
isnot(radios[2].selected, true, "Correct radio button should be selected");
EventUtils.synthesizeMouseAtCenter(radios[0], { clickCount: 1 }, gManagerWindow);
is(Services.prefs.getIntPref("extensions.inlinesettings3.radioInt"), 4, "Radio pref should have been updated");
EventUtils.synthesizeMouseAtCenter(radios[2], { clickCount: 1 }, gManagerWindow);
is(Services.prefs.getIntPref("extensions.inlinesettings3.radioInt"), 6, "Radio pref should have been updated");
ok(!settings[2].hasAttribute("first-row"), "Not the first row");
Services.prefs.setCharPref("extensions.inlinesettings3.radioString", "juliet");
var radios = settings[2].getElementsByTagName("radio");
isnot(radios[0].selected, true, "Correct radio button should be selected");
is(radios[1].selected, true, "Correct radio button should be selected");
isnot(radios[2].selected, true, "Correct radio button should be selected");
EventUtils.synthesizeMouseAtCenter(radios[0], { clickCount: 1 }, gManagerWindow);
is(Services.prefs.getCharPref("extensions.inlinesettings3.radioString"), "india", "Radio pref should have been updated");
EventUtils.synthesizeMouseAtCenter(radios[2], { clickCount: 1 }, gManagerWindow);
is(Services.prefs.getCharPref("extensions.inlinesettings3.radioString"), "kilo", "Radio pref should have been updated");
ok(!settings[3].hasAttribute("first-row"), "Not the first row");
Services.prefs.setIntPref("extensions.inlinesettings3.menulist", 8);
var input = settings[3].firstElementChild;
is(input.value, "8", "Menulist should have initial value");
input.focus();
EventUtils.synthesizeKey("n", {}, gManagerWindow);
is(input.value, "9", "Menulist should have updated value");
is(Services.prefs.getIntPref("extensions.inlinesettings3.menulist"), 9, "Menulist pref should have been updated");
button = gManagerWindow.document.getElementById("detail-prefs-btn");
is_element_hidden(button, "Preferences button should not be visible");
gCategoryUtilities.openType("extension", run_next_test);
});
});
// Addon with inline preferences as optionsURL
add_test(function() {
observer.checkHidden("inlinesettings3@tests.mozilla.org");
var addon = get_addon_element(gManagerWindow, "inlinesettings2@tests.mozilla.org");
addon.parentNode.ensureElementIsVisible(addon);
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
wait_for_view_load(gManagerWindow, function() {
observer.checkDisplayed("inlinesettings2@tests.mozilla.org");
var grid = gManagerWindow.document.getElementById("detail-grid");
var settings = grid.querySelectorAll("rows > setting");
is(settings.length, 5, "Grid should have settings children");
var node = settings[0];
node = settings[0];
is_element_hidden(node, "Unsupported settings should not be visible");
ok(!node.hasAttribute("first-row"), "Hidden row is not the first row");
node = settings[1];
is(node.nodeName, "setting", "Should be a setting node");
ok(node.hasAttribute("first-row"), "First visible row should have first-row attribute");
var description = gManagerWindow.document.getAnonymousElementByAttribute(node, "class", "preferences-description");
is(description.textContent, "Description Attribute", "Description node should contain description");
node = settings[2];
is(node.nodeName, "setting", "Should be a setting node");
ok(!node.hasAttribute("first-row"), "Not the first row");
description = gManagerWindow.document.getAnonymousElementByAttribute(node, "class", "preferences-description");
is(description.textContent, "Description Text Node", "Description node should contain description");
node = settings[3];
is(node.nodeName, "setting", "Should be a setting node");
ok(!node.hasAttribute("first-row"), "Not the first row");
description = gManagerWindow.document.getAnonymousElementByAttribute(node, "class", "preferences-description");
is(description.textContent, "This is a test, all this text should be visible", "Description node should contain description");
var button = node.firstElementChild;
isnot(button, null, "There should be a button");
node = settings[4];
is_element_hidden(node, "Unsupported settings should not be visible");
ok(!node.hasAttribute("first-row"), "Hidden row is not the first row");
var button = gManagerWindow.document.getElementById("detail-prefs-btn");
is_element_hidden(button, "Preferences button should not be visible");
gCategoryUtilities.openType("extension", run_next_test);
});
});
// Addon with non-inline preferences as optionsURL
add_test(function() {
observer.checkHidden("inlinesettings2@tests.mozilla.org");
var addon = get_addon_element(gManagerWindow, "noninlinesettings@tests.mozilla.org");
addon.parentNode.ensureElementIsVisible(addon);
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
wait_for_view_load(gManagerWindow, function() {
observer.checkNotDisplayed();
var grid = gManagerWindow.document.getElementById("detail-grid");
var settings = grid.querySelectorAll("rows > setting");
is(settings.length, 0, "Grid should not have settings children");
var button = gManagerWindow.document.getElementById("detail-prefs-btn");
is_element_visible(button, "Preferences button should be visible");
gCategoryUtilities.openType("extension", run_next_test);
});
});
// Addon with options.xul, disabling and enabling should hide and show settings UI
add_test(function() {
observer.checkNotHidden();
var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
addon.parentNode.ensureElementIsVisible(addon);
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
wait_for_view_load(gManagerWindow, function() {
observer.checkDisplayed("inlinesettings1@tests.mozilla.org");
is(gManagerWindow.gViewController.currentViewId,
"addons://detail/inlinesettings1%40tests.mozilla.org",
"Current view should not scroll to preferences");
checkScrolling(false);
var grid = gManagerWindow.document.getElementById("detail-grid");
var settings = grid.querySelectorAll("rows > setting");
is(settings.length, SETTINGS_ROWS, "Grid should have settings children");
// disable
var button = gManagerWindow.document.getElementById("detail-disable-btn");
button.focus(); // make sure it's in view
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
observer.checkHidden("inlinesettings1@tests.mozilla.org");
settings = grid.querySelectorAll("rows > setting");
is(settings.length, 0, "Grid should not have settings children");
gCategoryUtilities.openType("extension", function() {
var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
addon.parentNode.ensureElementIsVisible(addon);
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
is_element_hidden(button, "Preferences button should not be visible");
button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
wait_for_view_load(gManagerWindow, function() {
var grid = gManagerWindow.document.getElementById("detail-grid");
var settings = grid.querySelectorAll("rows > setting");
is(settings.length, 0, "Grid should not have settings children");
// enable
var button = gManagerWindow.document.getElementById("detail-enable-btn");
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
observer.callback = function() {
observer.checkDisplayed("inlinesettings1@tests.mozilla.org");
settings = grid.querySelectorAll("rows > setting");
is(settings.length, SETTINGS_ROWS, "Grid should have settings children");
gCategoryUtilities.openType("extension", run_next_test);
};
});
});
});
});
// Addon with options.xul that requires a restart to disable,
// disabling and enabling should not hide and show settings UI.
add_test(function() {
observer.checkHidden("inlinesettings1@tests.mozilla.org");
var addon = get_addon_element(gManagerWindow, "inlinesettings2@tests.mozilla.org");
addon.parentNode.ensureElementIsVisible(addon);
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
wait_for_view_load(gManagerWindow, function() {
observer.checkDisplayed("inlinesettings2@tests.mozilla.org");
var grid = gManagerWindow.document.getElementById("detail-grid");
var settings = grid.querySelectorAll("rows > setting");
ok(settings.length > 0, "Grid should have settings children");
// disable
var button = gManagerWindow.document.getElementById("detail-disable-btn");
button.focus(); // make sure it's in view
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
observer.checkNotHidden();
settings = grid.querySelectorAll("rows > setting");
ok(settings.length > 0, "Grid should still have settings children");
// cancel pending disable
button = gManagerWindow.document.getElementById("detail-enable-btn");
button.focus(); // make sure it's in view
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
observer.checkNotDisplayed();
gCategoryUtilities.openType("extension", run_next_test);
});
});

View File

@ -35,11 +35,13 @@ add_test(function() {
AddonManager.getAddonByID(testPluginId, function(testPlugin) {
let pluginEl = get_addon_element(gManagerWindow, testPluginId);
is(pluginEl.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, "Options should be inline type");
is(pluginEl.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE_INFO, "Options should be inline info type");
pluginEl.parentNode.ensureElementIsVisible(pluginEl);
let button = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "preferences-btn");
is_element_visible(button, "Preferences button should be visible");
is_element_hidden(button, "Preferences button should be hidden");
button = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "details-btn");
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
wait_for_view_load(gManagerWindow, function() {

View File

@ -101,6 +101,39 @@ function getUninstallNewVersion() {
return Services.prefs.getIntPref("bootstraptest.uninstall_newversion");
}
function do_check_bootstrappedPref(aCallback) {
let data = "{}";
try {
// This is ok to fail, as the pref won't exist on a fresh profile.
data = Services.prefs.getCharPref("extensions.bootstrappedAddons");
} catch (e) {}
data = JSON.parse(data);
AddonManager.getAddonsByTypes(["extension"], function(aAddons) {
for (let addon of aAddons) {
if (!addon.id.endsWith("@tests.mozilla.org"))
continue;
if (!addon.isActive)
continue;
if (addon.operationsRequiringRestart != AddonManager.OP_NEEDS_RESTART_NONE)
continue;
do_check_true(addon.id in data);
let addonData = data[addon.id];
delete data[addon.id];
do_check_eq(addonData.version, addon.version);
do_check_eq(addonData.type, addon.type);
let file = addon.getResourceURI().QueryInterface(Components.interfaces.nsIFileURL).file;
do_check_eq(addonData.descriptor, file.persistentDescriptor);
}
do_check_eq(Object.keys(data).length, 0);
aCallback();
});
}
function run_test() {
do_test_pending();
@ -120,7 +153,7 @@ function run_test() {
file.leafName = "extensions.ini";
do_check_false(file.exists());
run_test_1();
do_check_bootstrappedPref(run_test_1);
}
// Tests that installing doesn't require a restart
@ -161,8 +194,11 @@ function run_test_1() {
do_check_eq(getActiveVersion(), -1);
waitForPref("bootstraptest.active_version", function() {
check_test_1(addon.syncGUID);
do_check_bootstrappedPref(function() {
check_test_1(addon.syncGUID);
});
});
});
install.install();
});
@ -243,7 +279,7 @@ function run_test_2() {
do_check_true(newb1.userDisabled);
do_check_false(newb1.isActive);
run_test_3();
do_check_bootstrappedPref(run_test_3);
});
});
}
@ -273,7 +309,7 @@ function run_test_3() {
do_check_true(b1.userDisabled);
do_check_false(b1.isActive);
run_test_4();
do_check_bootstrappedPref(run_test_4);
});
}
@ -310,7 +346,7 @@ function run_test_4() {
do_check_false(newb1.userDisabled);
do_check_true(newb1.isActive);
run_test_5();
do_check_bootstrappedPref(run_test_5);
});
});
}
@ -338,7 +374,7 @@ function run_test_5() {
do_check_true(b1.isActive);
do_check_false(isExtensionInAddonsList(profileDir, b1.id));
run_test_6();
do_check_bootstrappedPref(run_test_6);
});
}
@ -390,7 +426,7 @@ function check_test_6() {
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
do_check_in_crash_annotation("bootstrap1@tests.mozilla.org", "2.0");
run_test_7();
do_check_bootstrappedPref(run_test_7);
});
}
@ -408,7 +444,7 @@ function run_test_7() {
AddonManager.OP_NEEDS_RESTART_UNINSTALL, 0);
b1.uninstall();
check_test_7();
do_check_bootstrappedPref(check_test_7);
});
}
@ -428,7 +464,7 @@ function check_test_7() {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(newb1) {
do_check_eq(newb1, null);
run_test_8();
do_check_bootstrappedPref(run_test_8);
});
});
}
@ -455,7 +491,7 @@ function run_test_8() {
do_check_eq(getStartupOldVersion(), 0);
do_check_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
run_test_9();
do_check_bootstrappedPref(run_test_9);
});
}
@ -471,7 +507,7 @@ function run_test_9() {
do_check_eq(b1, null);
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
run_test_10();
do_check_bootstrappedPref(run_test_10);
});
}
@ -573,7 +609,7 @@ function check_test_10_pt2() {
do_check_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "2.0");
run_test_11();
do_check_bootstrappedPref(run_test_11);
});
}
@ -609,7 +645,7 @@ function check_test_11() {
do_check_eq(getActiveVersion(), 0);
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
run_test_12();
do_check_bootstrappedPref(run_test_12);
}
// Tests that bootstrapped extensions are correctly loaded even if the app is
@ -637,7 +673,7 @@ function run_test_12() {
b1.uninstall();
restartManager();
run_test_13();
do_check_bootstrappedPref(run_test_13);
});
}
@ -700,10 +736,12 @@ function check_test_13() {
do_check_eq(getActiveVersion(), 0); // Should not have called startup though
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "3.0");
b1.uninstall();
restartManager();
do_check_bootstrappedPref(function() {
b1.uninstall();
restartManager();
run_test_14();
run_test_14();
});
});
});
});
@ -729,9 +767,11 @@ function run_test_14() {
do_check_eq(getActiveVersion(), 0); // Should not have called startup though
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "3.0");
b1.uninstall();
do_check_bootstrappedPref(function() {
b1.uninstall();
run_test_15();
run_test_15();
});
});
}
@ -788,20 +828,22 @@ function check_test_15() {
do_check_eq(getInstalledVersion(), 2);
do_check_eq(getActiveVersion(), 0);
restartManager();
do_check_bootstrappedPref(function() {
restartManager();
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
do_check_neq(b1, null);
do_check_eq(b1.version, "2.0");
do_check_false(b1.appDisabled);
do_check_true(b1.userDisabled);
do_check_false(b1.isActive);
do_check_eq(getInstalledVersion(), 2);
do_check_eq(getActiveVersion(), 0);
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
do_check_neq(b1, null);
do_check_eq(b1.version, "2.0");
do_check_false(b1.appDisabled);
do_check_true(b1.userDisabled);
do_check_false(b1.isActive);
do_check_eq(getInstalledVersion(), 2);
do_check_eq(getActiveVersion(), 0);
b1.uninstall();
b1.uninstall();
run_test_16();
run_test_16();
});
});
});
}
@ -872,7 +914,7 @@ function run_test_17() {
do_check_eq(b1.version, "1.0");
do_check_true(b1.isActive);
run_test_18();
do_check_bootstrappedPref(run_test_18);
});
}
@ -899,7 +941,7 @@ function run_test_18() {
do_check_eq(getInstallOldVersion(), 1);
do_check_eq(getStartupOldVersion(), 1);
run_test_19();
do_check_bootstrappedPref(run_test_19);
});
});
}
@ -942,7 +984,7 @@ function check_test_19() {
do_check_eq(getInstallOldVersion(), 0);
do_check_eq(getStartupOldVersion(), 0);
run_test_20();
do_check_bootstrappedPref(run_test_20);
});
}
@ -1011,11 +1053,12 @@ function run_test_21() {
do_check_eq(getStartupReason(), APP_STARTUP);
do_check_eq(getStartupOldVersion(), 0);
manuallyUninstall(userExtDir, "bootstrap1@tests.mozilla.org");
do_check_bootstrappedPref(function() {
manuallyUninstall(userExtDir, "bootstrap1@tests.mozilla.org");
restartManager();
run_test_22();
restartManager();
run_test_22();
});
});
}
@ -1069,9 +1112,11 @@ function run_test_22() {
do_check_eq(getStartupReason(), APP_STARTUP);
do_check_eq(getStartupOldVersion(), 0);
b1.uninstall();
do_check_bootstrappedPref(function() {
b1.uninstall();
run_test_23();
run_test_23();
});
});
});
}
@ -1115,7 +1160,7 @@ function run_test_23() {
"onInstallEnded",
], function() {
do_check_true(addon.hasResource("install.rdf"));
check_test_23();
do_check_bootstrappedPref(check_test_23);
});
});
install.install();
@ -1171,35 +1216,35 @@ function run_test_24() {
do_check_eq(getActiveVersion(), 1);
do_check_eq(getInstalledVersion2(), 1);
do_check_eq(getActiveVersion2(), 1);
resetPrefs();
restartManager();
do_check_eq(getInstalledVersion(), -1);
do_check_eq(getActiveVersion(), 1);
do_check_eq(getInstalledVersion2(), -1);
do_check_eq(getActiveVersion2(), 1);
shutdownManager();
do_check_eq(getInstalledVersion(), -1);
do_check_eq(getActiveVersion(), 0);
do_check_eq(getInstalledVersion2(), -1);
do_check_eq(getActiveVersion2(), 0);
// Break the preferece
let bootstrappedAddons = JSON.parse(Services.prefs.getCharPref("extensions.bootstrappedAddons"));
bootstrappedAddons["bootstrap1@tests.mozilla.org"].descriptor += "foo";
Services.prefs.setCharPref("extensions.bootstrappedAddons", JSON.stringify(bootstrappedAddons));
startupManager(false);
do_check_eq(getInstalledVersion(), -1);
do_check_eq(getActiveVersion(), 1);
do_check_eq(getInstalledVersion2(), -1);
do_check_eq(getActiveVersion2(), 1);
run_test_25();
});
});
@ -1212,32 +1257,32 @@ function run_test_25() {
waitForPref("bootstraptest.active_version", function() {
do_check_eq(getInstalledVersion(), 1);
do_check_eq(getActiveVersion(), 1);
installAllFiles([do_get_addon("test_bootstrap1_4")], function() {
// Needs a restart to complete this so the old version stays running
do_check_eq(getInstalledVersion(), 1);
do_check_eq(getActiveVersion(), 1);
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
do_check_neq(b1, null);
do_check_eq(b1.version, "1.0");
do_check_true(b1.isActive);
do_check_true(hasFlag(b1.pendingOperations, AddonManager.PENDING_UPGRADE));
restartManager();
do_check_eq(getInstalledVersion(), 0);
do_check_eq(getUninstallReason(), ADDON_UPGRADE);
do_check_eq(getUninstallNewVersion(), 4);
do_check_eq(getActiveVersion(), 0);
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
do_check_neq(b1, null);
do_check_eq(b1.version, "4.0");
do_check_true(b1.isActive);
do_check_eq(b1.pendingOperations, AddonManager.PENDING_NONE);
run_test_26();
do_check_bootstrappedPref(run_test_26);
});
});
});
@ -1272,7 +1317,7 @@ function run_test_26() {
do_check_true(b1.isActive);
do_check_eq(b1.pendingOperations, AddonManager.PENDING_NONE);
run_test_27();
do_check_bootstrappedPref(run_test_27);
});
});
});
@ -1314,7 +1359,7 @@ function run_test_27() {
do_check_false(b1.isActive);
do_check_eq(b1.pendingOperations, AddonManager.PENDING_NONE);
run_test_28();
do_check_bootstrappedPref(run_test_28);
});
});
});
@ -1351,7 +1396,7 @@ function run_test_28() {
do_check_eq(getInstalledVersion(), 1);
do_check_eq(getActiveVersion(), 1);
do_test_finished();
do_check_bootstrappedPref(do_test_finished);
});
});
});

View File

@ -330,6 +330,18 @@ function run_test() {
name: "Test Addon 25"
}, profileDir);
writeInstallRDFForExtension({
id: "addon26@tests.mozilla.org",
version: "1.0",
optionsType: "4",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Addon 26"
}, profileDir, null, "options.xul");
do_test_pending();
startupManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
@ -356,10 +368,11 @@ function run_test() {
"addon22@tests.mozilla.org",
"addon23@tests.mozilla.org",
"addon24@tests.mozilla.org",
"addon25@tests.mozilla.org"],
"addon25@tests.mozilla.org",
"addon26@tests.mozilla.org"],
function([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20,
a21, a22, a23, a24, a25]) {
a21, a22, a23, a24, a25, a26]) {
do_check_neq(a1, null);
do_check_eq(a1.id, "addon1@tests.mozilla.org");
@ -540,6 +553,10 @@ function run_test() {
do_check_eq(a25.optionsType, null);
do_check_eq(a25.optionsURL, null);
do_check_neq(a26, null);
do_check_eq(a26.optionsType, AddonManager.OPTIONS_TYPE_INLINE_INFO);
do_check_neq(a26.optionsURL, null);
do_test_finished();
});
}

View File

@ -292,6 +292,12 @@
margin: 0;
}
@media (max-width: 600px) {
#header-search {
width: 12em;
}
}
.view-header {
padding: 4px;
margin: 0;

View File

@ -316,6 +316,12 @@
background-clip: padding-box;
}
@media (max-width: 600px) {
#header-search {
width: 12em;
}
}
#header-search[focused] {
box-shadow: @focusRingShadow@, inset 0 1px 1px rgba(0,0,0,0.15);
border-color: -moz-mac-focusring;

View File

@ -289,6 +289,12 @@
margin: 0;
}
@media (max-width: 600px) {
#header-search {
width: 12em;
}
}
@media (-moz-windows-default-theme) {
#header-search {
-moz-appearance: none;

View File

@ -21,7 +21,7 @@ namespace mozilla {
*/
struct Module
{
static const unsigned int kVersion = 22;
static const unsigned int kVersion = 23;
struct CIDEntry;