mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
merge m-c to fx-team
This commit is contained in:
commit
bbaac6bbbf
@ -601,6 +601,16 @@ XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
|
||||
return;
|
||||
}
|
||||
|
||||
// replaces ~ with the home directory path in unix and windows
|
||||
if (dirName.indexOf("~") == 0) {
|
||||
let dirService = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties);
|
||||
let homeDirFile = dirService.get("Home", Ci.nsIFile);
|
||||
let homeDir = homeDirFile.path;
|
||||
dirName = dirName.substr(1);
|
||||
dirName = homeDir + dirName;
|
||||
}
|
||||
|
||||
let promise = OS.File.stat(dirName);
|
||||
promise = promise.then(
|
||||
function onSuccess(stat) {
|
||||
@ -770,69 +780,71 @@ XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "console",
|
||||
"resource://gre/modules/devtools/Console.jsm");
|
||||
|
||||
// We should really be using nsICookieManager so we can read more than just the
|
||||
// key/value of cookies. The difficulty is filtering the cookies that are
|
||||
// relevant to the current page. See
|
||||
// https://github.com/firebug/firebug/blob/master/extension/content/firebug/cookies/cookieObserver.js#L123
|
||||
// For details on how this is done with Firebug
|
||||
const cookieMgr = Cc["@mozilla.org/cookiemanager;1"]
|
||||
.getService(Ci.nsICookieManager2);
|
||||
|
||||
/**
|
||||
* 'cookie' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "cookie",
|
||||
description: gcli.lookup("cookieDesc"),
|
||||
manual: gcli.lookup("cookieManual")
|
||||
});
|
||||
|
||||
/**
|
||||
* The template for the 'cookie list' command.
|
||||
*/
|
||||
var cookieListHtml = "" +
|
||||
"<table>" +
|
||||
" <tr>" +
|
||||
" <th>" + gcli.lookup("cookieListOutKey") + "</th>" +
|
||||
" <th>" + gcli.lookup("cookieListOutValue") + "</th>" +
|
||||
" <th>" + gcli.lookup("cookieListOutActions") + "</th>" +
|
||||
" </tr>" +
|
||||
" <tr foreach='cookie in ${cookies}'>" +
|
||||
" <td>${cookie.key}</td>" +
|
||||
" <td>${cookie.value}</td>" +
|
||||
" <td>" +
|
||||
" <span class='gcli-out-shortcut' onclick='${onclick}'" +
|
||||
" data-command='cookie set ${cookie.key} '" +
|
||||
" >" + gcli.lookup("cookieListOutEdit") + "</span>" +
|
||||
" <span class='gcli-out-shortcut'" +
|
||||
" onclick='${onclick}' ondblclick='${ondblclick}'" +
|
||||
" data-command='cookie remove ${cookie.key}'" +
|
||||
" >" + gcli.lookup("cookieListOutRemove") + "</span>" +
|
||||
" </td>" +
|
||||
" </tr>" +
|
||||
"</table>" +
|
||||
* The template for the 'cookie list' command.
|
||||
*/
|
||||
let cookieListHtml = "" +
|
||||
"<ul class='gcli-cookielist-list'>" +
|
||||
" <li foreach='cookie in ${cookies}'>" +
|
||||
" <div>${cookie.name}=${cookie.value}</div>" +
|
||||
" <table class='gcli-cookielist-detail'>" +
|
||||
" <tr>" +
|
||||
" <td>" + gcli.lookup("cookieListOutHost") + "</td>" +
|
||||
" <td>${cookie.host}</td>" +
|
||||
" </tr>" +
|
||||
" <tr>" +
|
||||
" <td>" + gcli.lookup("cookieListOutPath") + "</td>" +
|
||||
" <td>${cookie.path}</td>" +
|
||||
" </tr>" +
|
||||
" <tr>" +
|
||||
" <td>" + gcli.lookup("cookieListOutExpires") + "</td>" +
|
||||
" <td>${cookie.expires}</td>" +
|
||||
" </tr>" +
|
||||
" <tr>" +
|
||||
" <td>" + gcli.lookup("cookieListOutAttributes") + "</td>" +
|
||||
" <td>${cookie.attrs}</td>" +
|
||||
" </tr>" +
|
||||
" <tr><td colspan='2'>" +
|
||||
" <span class='gcli-out-shortcut' onclick='${onclick}'" +
|
||||
" data-command='cookie set ${cookie.name} '" +
|
||||
" >" + gcli.lookup("cookieListOutEdit") + "</span>" +
|
||||
" <span class='gcli-out-shortcut'" +
|
||||
" onclick='${onclick}' ondblclick='${ondblclick}'" +
|
||||
" data-command='cookie remove ${cookie.name}'" +
|
||||
" >" + gcli.lookup("cookieListOutRemove") + "</span>" +
|
||||
" </td></tr>" +
|
||||
" </table>" +
|
||||
" </li>" +
|
||||
"</ul>" +
|
||||
"";
|
||||
|
||||
/**
|
||||
* 'cookie list' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "cookie list",
|
||||
description: gcli.lookup("cookieListDesc"),
|
||||
manual: gcli.lookup("cookieListManual"),
|
||||
returnType: "string",
|
||||
exec: function Command_cookieList(args, context) {
|
||||
// Parse out an array of { key:..., value:... } objects for each cookie
|
||||
var doc = context.environment.contentDocument;
|
||||
var cookies = doc.cookie.split("; ").map(function(cookieStr) {
|
||||
var equalsPos = cookieStr.indexOf("=");
|
||||
return {
|
||||
key: cookieStr.substring(0, equalsPos),
|
||||
value: cookieStr.substring(equalsPos + 1)
|
||||
};
|
||||
});
|
||||
gcli.addConverter({
|
||||
from: "cookies",
|
||||
to: "view",
|
||||
exec: function(cookies, context) {
|
||||
if (cookies.length == 0) {
|
||||
let host = context.environment.document.location.host;
|
||||
let msg = gcli.lookupFormat("cookieListOutNoneHost", [ host ]);
|
||||
return context.createView({ html: "<span>" + msg + "</span>" });
|
||||
}
|
||||
|
||||
for (let cookie of cookies) {
|
||||
cookie.expires = translateExpires(cookie.expires);
|
||||
|
||||
let noAttrs = !cookie.secure && !cookie.httpOnly && !cookie.sameDomain;
|
||||
cookie.attrs = (cookie.secure ? 'secure' : ' ') +
|
||||
(cookie.httpOnly ? 'httpOnly' : ' ') +
|
||||
(cookie.sameDomain ? 'sameDomain' : ' ') +
|
||||
(noAttrs ? gcli.lookup("cookieListOutNone") : ' ');
|
||||
}
|
||||
|
||||
return context.createView({
|
||||
html: cookieListHtml,
|
||||
data: {
|
||||
options: { allowEval: true },
|
||||
cookies: cookies,
|
||||
onclick: createUpdateHandler(context),
|
||||
ondblclick: createExecuteHandler(context),
|
||||
@ -842,37 +854,116 @@ XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
|
||||
});
|
||||
|
||||
/**
|
||||
* 'cookie remove' command
|
||||
*/
|
||||
* The cookie 'expires' value needs converting into something more readable
|
||||
*/
|
||||
function translateExpires(expires) {
|
||||
if (expires == 0) {
|
||||
return gcli.lookup("cookieListOutSession");
|
||||
}
|
||||
return new Date(expires).toLocaleString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given cookie matches a given host
|
||||
*/
|
||||
function isCookieAtHost(cookie, host) {
|
||||
if (cookie.host == null) {
|
||||
return host == null;
|
||||
}
|
||||
if (cookie.host.startsWith(".")) {
|
||||
return cookie.host === "." + host;
|
||||
}
|
||||
else {
|
||||
return cookie.host == host;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 'cookie' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "cookie",
|
||||
description: gcli.lookup("cookieDesc"),
|
||||
manual: gcli.lookup("cookieManual")
|
||||
});
|
||||
|
||||
/**
|
||||
* 'cookie list' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "cookie list",
|
||||
description: gcli.lookup("cookieListDesc"),
|
||||
manual: gcli.lookup("cookieListManual"),
|
||||
returnType: "cookies",
|
||||
exec: function Command_cookieList(args, context) {
|
||||
let host = context.environment.document.location.host;
|
||||
if (host == null) {
|
||||
throw new Error(gcli.lookup("cookieListOutNonePage"));
|
||||
}
|
||||
|
||||
let enm = cookieMgr.getCookiesFromHost(host);
|
||||
|
||||
let cookies = [];
|
||||
while (enm.hasMoreElements()) {
|
||||
let cookie = enm.getNext().QueryInterface(Ci.nsICookie);
|
||||
if (isCookieAtHost(cookie, host)) {
|
||||
cookies.push({
|
||||
host: cookie.host,
|
||||
name: cookie.name,
|
||||
value: cookie.value,
|
||||
path: cookie.path,
|
||||
expires: cookie.expires,
|
||||
secure: cookie.secure,
|
||||
httpOnly: cookie.httpOnly,
|
||||
sameDomain: cookie.sameDomain
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return cookies;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'cookie remove' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "cookie remove",
|
||||
description: gcli.lookup("cookieRemoveDesc"),
|
||||
manual: gcli.lookup("cookieRemoveManual"),
|
||||
params: [
|
||||
{
|
||||
name: "key",
|
||||
name: "name",
|
||||
type: "string",
|
||||
description: gcli.lookup("cookieRemoveKeyDesc"),
|
||||
}
|
||||
],
|
||||
exec: function Command_cookieRemove(args, context) {
|
||||
let document = context.environment.contentDocument;
|
||||
let expDate = new Date();
|
||||
expDate.setDate(expDate.getDate() - 1);
|
||||
document.cookie = escape(args.key) + "=; expires=" + expDate.toGMTString();
|
||||
let host = context.environment.document.location.host;
|
||||
let enm = cookieMgr.getCookiesFromHost(host);
|
||||
|
||||
let cookies = [];
|
||||
while (enm.hasMoreElements()) {
|
||||
let cookie = enm.getNext().QueryInterface(Components.interfaces.nsICookie);
|
||||
if (isCookieAtHost(cookie, host)) {
|
||||
if (cookie.name == args.name) {
|
||||
cookieMgr.remove(cookie.host, cookie.name, cookie.path, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'cookie set' command
|
||||
*/
|
||||
* 'cookie set' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "cookie set",
|
||||
description: gcli.lookup("cookieSetDesc"),
|
||||
manual: gcli.lookup("cookieSetManual"),
|
||||
params: [
|
||||
{
|
||||
name: "key",
|
||||
name: "name",
|
||||
type: "string",
|
||||
description: gcli.lookup("cookieSetKeyDesc")
|
||||
},
|
||||
@ -900,26 +991,47 @@ XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
|
||||
name: "secure",
|
||||
type: "boolean",
|
||||
description: gcli.lookup("cookieSetSecureDesc")
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "httpOnly",
|
||||
type: "boolean",
|
||||
description: gcli.lookup("cookieSetHttpOnlyDesc")
|
||||
},
|
||||
{
|
||||
name: "session",
|
||||
type: "boolean",
|
||||
description: gcli.lookup("cookieSetSessionDesc")
|
||||
},
|
||||
{
|
||||
name: "expires",
|
||||
type: "string",
|
||||
defaultValue: "Jan 17, 2038",
|
||||
description: gcli.lookup("cookieSetExpiresDesc")
|
||||
},
|
||||
]
|
||||
}
|
||||
],
|
||||
exec: function Command_cookieSet(args, context) {
|
||||
let document = context.environment.contentDocument;
|
||||
let host = context.environment.document.location.host;
|
||||
let time = Date.parse(args.expires) / 1000;
|
||||
|
||||
document.cookie = escape(args.key) + "=" + escape(args.value) +
|
||||
(args.domain ? "; domain=" + args.domain : "") +
|
||||
(args.path ? "; path=" + args.path : "") +
|
||||
(args.secure ? "; secure" : "");
|
||||
cookieMgr.add(args.domain ? "." + args.domain : host,
|
||||
args.path ? args.path : "/",
|
||||
args.name,
|
||||
args.value,
|
||||
args.secure,
|
||||
args.httpOnly,
|
||||
args.session,
|
||||
time);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Helper to find the 'data-command' attribute and call some action on it.
|
||||
* @see |updateCommand()| and |executeCommand()|
|
||||
*/
|
||||
* Helper to find the 'data-command' attribute and call some action on it.
|
||||
* @see |updateCommand()| and |executeCommand()|
|
||||
*/
|
||||
function withCommand(element, action) {
|
||||
var command = element.getAttribute("data-command");
|
||||
let command = element.getAttribute("data-command");
|
||||
if (!command) {
|
||||
command = element.querySelector("*[data-command]")
|
||||
.getAttribute("data-command");
|
||||
@ -934,11 +1046,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handler to update the requisition to contain the text held in the
|
||||
* first matching data-command attribute under the currentTarget of the event.
|
||||
* @param context Either a Requisition or an ExecutionContext or another object
|
||||
* that contains an |update()| function that follows a similar contract.
|
||||
*/
|
||||
* Create a handler to update the requisition to contain the text held in the
|
||||
* first matching data-command attribute under the currentTarget of the event.
|
||||
* @param context Either a Requisition or an ExecutionContext or another object
|
||||
* that contains an |update()| function that follows a similar contract.
|
||||
*/
|
||||
function createUpdateHandler(context) {
|
||||
return function(ev) {
|
||||
withCommand(ev.currentTarget, function(command) {
|
||||
@ -948,11 +1060,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handler to execute the text held in the data-command attribute
|
||||
* under the currentTarget of the event.
|
||||
* @param context Either a Requisition or an ExecutionContext or another object
|
||||
* that contains an |update()| function that follows a similar contract.
|
||||
*/
|
||||
* Create a handler to execute the text held in the data-command attribute
|
||||
* under the currentTarget of the event.
|
||||
* @param context Either a Requisition or an ExecutionContext or another object
|
||||
* that contains an |update()| function that follows a similar contract.
|
||||
*/
|
||||
function createExecuteHandler(context) {
|
||||
return function(ev) {
|
||||
withCommand(ev.currentTarget, function(command) {
|
||||
|
@ -34,6 +34,16 @@
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.gcli-cookielist-list {
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.gcli-cookielist-detail {
|
||||
padding-left: 20px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.gcli-row-out .nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -39,7 +39,7 @@ function test() {
|
||||
setup: 'cookie remove',
|
||||
check: {
|
||||
input: 'cookie remove',
|
||||
hints: ' <key>',
|
||||
hints: ' <name>',
|
||||
markup: 'VVVVVVVVVVVVV',
|
||||
status: 'ERROR'
|
||||
},
|
||||
@ -48,7 +48,7 @@ function test() {
|
||||
setup: 'cookie set',
|
||||
check: {
|
||||
input: 'cookie set',
|
||||
hints: ' <key> <value> [options]',
|
||||
hints: ' <name> <value> [options]',
|
||||
markup: 'VVVVVVVVVV',
|
||||
status: 'ERROR'
|
||||
},
|
||||
@ -70,17 +70,23 @@ function test() {
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
key: { value: 'fruit' },
|
||||
name: { value: 'fruit' },
|
||||
value: { value: 'ban' },
|
||||
secure: { value: false },
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
setup: "cookie list",
|
||||
exec: {
|
||||
output: 'No cookies found for host'
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: "cookie set fruit banana",
|
||||
check: {
|
||||
args: {
|
||||
key: { value: 'fruit' },
|
||||
name: { value: 'fruit' },
|
||||
value: { value: 'banana' },
|
||||
}
|
||||
},
|
||||
@ -91,20 +97,26 @@ function test() {
|
||||
{
|
||||
setup: "cookie list",
|
||||
exec: {
|
||||
output: /Key/
|
||||
output: [ /fruit=banana/, /Expires:/, /Edit/ ]
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: "cookie remove fruit",
|
||||
check: {
|
||||
args: {
|
||||
key: { value: 'fruit' },
|
||||
name: { value: 'fruit' },
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: ""
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: "cookie list",
|
||||
exec: {
|
||||
output: 'No cookies found for host'
|
||||
}
|
||||
},
|
||||
]);
|
||||
}).then(finish);
|
||||
}
|
||||
|
@ -199,5 +199,4 @@ exports.testAddRemove3 = function(options) {
|
||||
canon.onCanonChange.remove(canonChange);
|
||||
};
|
||||
|
||||
|
||||
// });
|
||||
|
@ -179,7 +179,7 @@ exports.testTsv = function(options) {
|
||||
cursor: 4,
|
||||
current: 'optionType',
|
||||
status: 'ERROR',
|
||||
predictions: [ 'option1', 'option2' ],
|
||||
predictions: [ 'option1', 'option2', 'option3' ],
|
||||
unassigned: [ ],
|
||||
tooltipState: 'true:importantFieldFlag',
|
||||
args: {
|
||||
@ -219,7 +219,7 @@ exports.testTsv = function(options) {
|
||||
cursor: 5,
|
||||
current: 'optionType',
|
||||
status: 'ERROR',
|
||||
predictions: [ 'option1', 'option2' ],
|
||||
predictions: [ 'option1', 'option2', 'option3' ],
|
||||
unassigned: [ ],
|
||||
tooltipState: 'true:importantFieldFlag',
|
||||
args: {
|
||||
@ -248,7 +248,7 @@ exports.testTsv = function(options) {
|
||||
cursor: 10,
|
||||
current: 'optionType',
|
||||
status: 'ERROR',
|
||||
predictions: [ 'option1', 'option2' ],
|
||||
predictions: [ 'option1', 'option2', 'option3' ],
|
||||
unassigned: [ ],
|
||||
tooltipState: 'true:importantFieldFlag',
|
||||
args: {
|
||||
|
@ -35,8 +35,10 @@ function test() {
|
||||
|
||||
'use strict';
|
||||
|
||||
// var mockCommands = require('gclitest/mockCommands');
|
||||
var nodetype = require('gcli/types/node');
|
||||
var canon = require('gcli/canon');
|
||||
// var assert = require('test/assert');
|
||||
// var mockCommands = require('gclitest/mockCommands');
|
||||
// var helpers = require('gclitest/helpers');
|
||||
|
||||
|
||||
@ -71,6 +73,16 @@ var mockDoc = {
|
||||
}
|
||||
};
|
||||
|
||||
exports.testParamGroup = function(options) {
|
||||
var tsg = canon.getCommand('tsg');
|
||||
|
||||
assert.is(tsg.params[0].groupName, null, 'tsg param 0 group null');
|
||||
assert.is(tsg.params[1].groupName, 'First', 'tsg param 1 group First');
|
||||
assert.is(tsg.params[2].groupName, 'First', 'tsg param 2 group First');
|
||||
assert.is(tsg.params[3].groupName, 'Second', 'tsg param 3 group Second');
|
||||
assert.is(tsg.params[4].groupName, 'Second', 'tsg param 4 group Second');
|
||||
};
|
||||
|
||||
exports.testWithHelpers = function(options) {
|
||||
return helpers.audit(options, [
|
||||
{
|
||||
|
@ -142,11 +142,13 @@ function checkPrediction(res, prediction) {
|
||||
var name = prediction.name;
|
||||
var value = prediction.value;
|
||||
|
||||
return res.parseString(name).then(function(conversion) {
|
||||
// resources don't need context so cheat and pass in null
|
||||
var context = null;
|
||||
return res.parseString(name, context).then(function(conversion) {
|
||||
assert.is(conversion.getStatus(), Status.VALID, 'status VALID for ' + name);
|
||||
assert.is(conversion.value, value, 'value for ' + name);
|
||||
|
||||
var strung = res.stringify(value);
|
||||
var strung = res.stringify(value, context);
|
||||
assert.is(strung, name, 'stringify for ' + name);
|
||||
|
||||
assert.is(typeof value.loadContents, 'function', 'resource for ' + name);
|
||||
|
@ -90,7 +90,7 @@ exports.testDefault = function(options) {
|
||||
|
||||
exports.testNullDefault = function(options) {
|
||||
forEachType(options, { defaultValue: null }, function(type) {
|
||||
assert.is(type.stringify(null), '', 'stringify(null) for ' + type.name);
|
||||
assert.is(type.stringify(null, null), '', 'stringify(null) for ' + type.name);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -31,6 +31,8 @@ let assert = { ok: ok, is: is, log: info };
|
||||
|
||||
var util = require('util/util');
|
||||
|
||||
var converters = require('gcli/converters');
|
||||
|
||||
/**
|
||||
* Warning: For use with Firefox Mochitests only.
|
||||
*
|
||||
@ -380,7 +382,7 @@ helpers._createDebugCheck = function(options) {
|
||||
output += ']);';
|
||||
|
||||
return output;
|
||||
}.bind(this), console.error);
|
||||
}.bind(this), util.errorHandler);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -723,32 +725,36 @@ helpers._exec = function(options, name, expected) {
|
||||
|
||||
var checkOutput = function() {
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var actualOutput = div.textContent.trim();
|
||||
var nodePromise = converters.convert(output.data, output.type, 'dom',
|
||||
options.display.requisition.context);
|
||||
nodePromise.then(function(node) {
|
||||
div.appendChild(node);
|
||||
var actualOutput = div.textContent.trim();
|
||||
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
assert.ok(false, 'html output for ' + name + ' against ' + match.source);
|
||||
log('Actual textContent');
|
||||
log(against);
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
assert.ok(false, 'html output for ' + name + ' against ' + match.source);
|
||||
log('Actual textContent');
|
||||
log(against);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof expected.output === 'string') {
|
||||
assert.is(actualOutput,
|
||||
expected.output,
|
||||
'html output for ' + name);
|
||||
}
|
||||
else if (Array.isArray(expected.output)) {
|
||||
expected.output.forEach(function(match) {
|
||||
doTest(match, actualOutput);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof expected.output === 'string') {
|
||||
assert.is(actualOutput,
|
||||
expected.output,
|
||||
'html output for ' + name);
|
||||
}
|
||||
else if (Array.isArray(expected.output)) {
|
||||
expected.output.forEach(function(match) {
|
||||
doTest(match, actualOutput);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
deferred.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
if (output.completed !== false) {
|
||||
|
@ -111,50 +111,34 @@ mockCommands.shutdown = function(opts) {
|
||||
|
||||
mockCommands.option1 = { type: types.getType('string') };
|
||||
mockCommands.option2 = { type: types.getType('number') };
|
||||
|
||||
var lastOption = undefined;
|
||||
var debug = false;
|
||||
mockCommands.option3 = { type: types.getType({
|
||||
name: 'selection',
|
||||
lookup: [
|
||||
{ name: 'one', value: 1 },
|
||||
{ name: 'two', value: 2 },
|
||||
{ name: 'three', value: 3 }
|
||||
]
|
||||
})};
|
||||
|
||||
mockCommands.optionType = new SelectionType({
|
||||
name: 'optionType',
|
||||
lookup: [
|
||||
{ name: 'option1', value: mockCommands.option1 },
|
||||
{ name: 'option2', value: mockCommands.option2 }
|
||||
],
|
||||
noMatch: function() {
|
||||
lastOption = undefined;
|
||||
if (debug) {
|
||||
console.log('optionType.noMatch: lastOption = undefined');
|
||||
}
|
||||
},
|
||||
stringify: function(option) {
|
||||
lastOption = option;
|
||||
if (debug) {
|
||||
console.log('optionType.stringify: lastOption = ', lastOption);
|
||||
}
|
||||
return SelectionType.prototype.stringify.call(this, option);
|
||||
},
|
||||
parse: function(arg) {
|
||||
var promise = SelectionType.prototype.parse.call(this, arg);
|
||||
promise.then(function(conversion) {
|
||||
lastOption = conversion.value;
|
||||
if (debug) {
|
||||
console.log('optionType.parse: lastOption = ', lastOption);
|
||||
}
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
{ name: 'option2', value: mockCommands.option2 },
|
||||
{ name: 'option3', value: mockCommands.option3 }
|
||||
]
|
||||
});
|
||||
|
||||
mockCommands.optionValue = new DelegateType({
|
||||
name: 'optionValue',
|
||||
delegateType: function() {
|
||||
if (lastOption && lastOption.type) {
|
||||
return lastOption.type;
|
||||
}
|
||||
else {
|
||||
return types.getType('blank');
|
||||
delegateType: function(context) {
|
||||
if (context != null) {
|
||||
var option = context.getArgsObject().optionType;
|
||||
if (option != null) {
|
||||
return option.type;
|
||||
}
|
||||
}
|
||||
return types.getType('blank');
|
||||
}
|
||||
});
|
||||
|
||||
@ -370,21 +354,18 @@ mockCommands.tsg = {
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'Second',
|
||||
params: [
|
||||
{
|
||||
name: 'txt2',
|
||||
type: 'string',
|
||||
defaultValue: 'd',
|
||||
description: 'txt2 param'
|
||||
},
|
||||
{
|
||||
name: 'num',
|
||||
type: { name: 'number', min: 40 },
|
||||
defaultValue: 42,
|
||||
description: 'num param'
|
||||
}
|
||||
]
|
||||
name: 'txt2',
|
||||
type: 'string',
|
||||
defaultValue: 'd',
|
||||
description: 'txt2 param',
|
||||
option: 'Second'
|
||||
},
|
||||
{
|
||||
name: 'num',
|
||||
type: { name: 'number', min: 40 },
|
||||
defaultValue: 42,
|
||||
description: 'num param',
|
||||
option: 'Second'
|
||||
}
|
||||
],
|
||||
exec: createExec('tsg')
|
||||
|
@ -31,6 +31,8 @@ let assert = { ok: ok, is: is, log: info };
|
||||
|
||||
var util = require('util/util');
|
||||
|
||||
var converters = require('gcli/converters');
|
||||
|
||||
/**
|
||||
* Warning: For use with Firefox Mochitests only.
|
||||
*
|
||||
@ -380,7 +382,7 @@ helpers._createDebugCheck = function(options) {
|
||||
output += ']);';
|
||||
|
||||
return output;
|
||||
}.bind(this), console.error);
|
||||
}.bind(this), util.errorHandler);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -723,32 +725,36 @@ helpers._exec = function(options, name, expected) {
|
||||
|
||||
var checkOutput = function() {
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var actualOutput = div.textContent.trim();
|
||||
var nodePromise = converters.convert(output.data, output.type, 'dom',
|
||||
options.display.requisition.context);
|
||||
nodePromise.then(function(node) {
|
||||
div.appendChild(node);
|
||||
var actualOutput = div.textContent.trim();
|
||||
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
assert.ok(false, 'html output for ' + name + ' against ' + match.source);
|
||||
log('Actual textContent');
|
||||
log(against);
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
assert.ok(false, 'html output for ' + name + ' against ' + match.source);
|
||||
log('Actual textContent');
|
||||
log(against);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof expected.output === 'string') {
|
||||
assert.is(actualOutput,
|
||||
expected.output,
|
||||
'html output for ' + name);
|
||||
}
|
||||
else if (Array.isArray(expected.output)) {
|
||||
expected.output.forEach(function(match) {
|
||||
doTest(match, actualOutput);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof expected.output === 'string') {
|
||||
assert.is(actualOutput,
|
||||
expected.output,
|
||||
'html output for ' + name);
|
||||
}
|
||||
else if (Array.isArray(expected.output)) {
|
||||
expected.output.forEach(function(match) {
|
||||
doTest(match, actualOutput);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
deferred.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
if (output.completed !== false) {
|
||||
|
@ -500,7 +500,8 @@ Toolbox.prototype = {
|
||||
let boundLoad = function() {
|
||||
iframe.removeEventListener("DOMContentLoaded", boundLoad, true);
|
||||
|
||||
definition.build(iframe.contentWindow, this).then(function(panel) {
|
||||
let built = definition.build(iframe.contentWindow, this);
|
||||
Promise.resolve(built).then(function(panel) {
|
||||
this._toolPanels.set(id, panel);
|
||||
|
||||
this.emit(id + "-ready", panel);
|
||||
|
@ -31,6 +31,8 @@ let assert = { ok: ok, is: is, log: info };
|
||||
|
||||
var util = require('util/util');
|
||||
|
||||
var converters = require('gcli/converters');
|
||||
|
||||
/**
|
||||
* Warning: For use with Firefox Mochitests only.
|
||||
*
|
||||
@ -380,7 +382,7 @@ helpers._createDebugCheck = function(options) {
|
||||
output += ']);';
|
||||
|
||||
return output;
|
||||
}.bind(this), console.error);
|
||||
}.bind(this), util.errorHandler);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -723,32 +725,36 @@ helpers._exec = function(options, name, expected) {
|
||||
|
||||
var checkOutput = function() {
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var actualOutput = div.textContent.trim();
|
||||
var nodePromise = converters.convert(output.data, output.type, 'dom',
|
||||
options.display.requisition.context);
|
||||
nodePromise.then(function(node) {
|
||||
div.appendChild(node);
|
||||
var actualOutput = div.textContent.trim();
|
||||
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
assert.ok(false, 'html output for ' + name + ' against ' + match.source);
|
||||
log('Actual textContent');
|
||||
log(against);
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
assert.ok(false, 'html output for ' + name + ' against ' + match.source);
|
||||
log('Actual textContent');
|
||||
log(against);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof expected.output === 'string') {
|
||||
assert.is(actualOutput,
|
||||
expected.output,
|
||||
'html output for ' + name);
|
||||
}
|
||||
else if (Array.isArray(expected.output)) {
|
||||
expected.output.forEach(function(match) {
|
||||
doTest(match, actualOutput);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof expected.output === 'string') {
|
||||
assert.is(actualOutput,
|
||||
expected.output,
|
||||
'html output for ' + name);
|
||||
}
|
||||
else if (Array.isArray(expected.output)) {
|
||||
expected.output.forEach(function(match) {
|
||||
doTest(match, actualOutput);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
deferred.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
if (output.completed !== false) {
|
||||
|
@ -18,16 +18,39 @@ XPCOMUtils.defineLazyGetter(this, "DebuggerServer", function () {
|
||||
return DebuggerServer;
|
||||
});
|
||||
|
||||
/**
|
||||
* Makes a structure representing an individual profile.
|
||||
*/
|
||||
function makeProfile(name) {
|
||||
return {
|
||||
name: name,
|
||||
timeStarted: null,
|
||||
timeEnded: null
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Object acting as a mediator between the ProfilerController and
|
||||
* DebuggerServer.
|
||||
*/
|
||||
function ProfilerConnection(client) {
|
||||
this.client = client;
|
||||
this.startTime = 0;
|
||||
}
|
||||
|
||||
ProfilerConnection.prototype = {
|
||||
actor: null,
|
||||
startTime: null,
|
||||
|
||||
/**
|
||||
* Returns how many milliseconds have passed since the connection
|
||||
* was started (start time is specificed by the startTime property).
|
||||
*
|
||||
* @return number
|
||||
*/
|
||||
get currentTime() {
|
||||
return (new Date()).getTime() - this.startTime;
|
||||
},
|
||||
|
||||
/**
|
||||
* Connects to a debugee and executes a callback when ready.
|
||||
@ -71,7 +94,13 @@ ProfilerConnection.prototype = {
|
||||
interval: 1,
|
||||
features: ["js"],
|
||||
};
|
||||
this.client.request(message, aCallback);
|
||||
|
||||
this.client.request(message, function () {
|
||||
// Record the current time so we could split profiler data
|
||||
// in chunks later.
|
||||
this.startTime = (new Date()).getTime();
|
||||
aCallback.apply(null, Array.slice(arguments));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
@ -113,9 +142,12 @@ ProfilerConnection.prototype = {
|
||||
*/
|
||||
function ProfilerController(target) {
|
||||
this.profiler = new ProfilerConnection(target.client);
|
||||
// Chrome debugging targets have already obtained a reference to the profiler
|
||||
// actor.
|
||||
this.pool = {};
|
||||
|
||||
// Chrome debugging targets have already obtained a reference to the
|
||||
// profiler actor.
|
||||
this._connected = !!target.chrome;
|
||||
|
||||
if (target.chrome) {
|
||||
this.profiler.actor = target.form.profilerActor;
|
||||
}
|
||||
@ -157,44 +189,118 @@ ProfilerController.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts the profiler.
|
||||
* Checks whether the profile is currently recording.
|
||||
*
|
||||
* @param function aCallback
|
||||
* @param object profile
|
||||
* An object made by calling makeProfile function.
|
||||
* @return boolean
|
||||
*/
|
||||
isProfileRecording: function PC_isProfileRecording(profile) {
|
||||
return profile.timeStarted !== null && profile.timeEnded === null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a new profile and starts the profiler, if needed.
|
||||
*
|
||||
* @param string name
|
||||
* Name of the profile.
|
||||
* @param function cb
|
||||
* Function to be called once the profiler is started
|
||||
* or we get an error. It will be called with a single
|
||||
* argument: an error object (may be null).
|
||||
*/
|
||||
start: function PC_start(aCallback) {
|
||||
this.profiler.startProfiler(function onStart(aResponse) {
|
||||
aCallback(aResponse.error);
|
||||
start: function PC_start(name, cb) {
|
||||
if (this.pool[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let profile = this.pool[name] = makeProfile(name);
|
||||
let profiler = this.profiler;
|
||||
|
||||
// If profile is already running, no need to do anything.
|
||||
if (this.isProfileRecording(profile)) {
|
||||
return void cb();
|
||||
}
|
||||
|
||||
this.isActive(function (err, isActive) {
|
||||
if (isActive) {
|
||||
profile.timeStarted = profiler.currentTime;
|
||||
return void cb();
|
||||
}
|
||||
|
||||
profiler.startProfiler(function onStart(aResponse) {
|
||||
if (aResponse.error) {
|
||||
return void cb(aResponse.error);
|
||||
}
|
||||
|
||||
profile.timeStarted = profiler.currentTime;
|
||||
cb();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Stops the profiler.
|
||||
*
|
||||
* @param function aCallback
|
||||
* @param string name
|
||||
* Name of the profile that needs to be stopped.
|
||||
* @param function cb
|
||||
* Function to be called once the profiler is stopped
|
||||
* or we get an error. It will be called with a single
|
||||
* argument: an error object (may be null).
|
||||
*/
|
||||
stop: function PC_stop(aCallback) {
|
||||
this.profiler.getProfileData(function onData(aResponse) {
|
||||
let data = aResponse.profile;
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("Failed to fetch profile data before stopping the profiler.");
|
||||
stop: function PC_stop(name, cb) {
|
||||
let profiler = this.profiler;
|
||||
let profile = this.pool[name];
|
||||
|
||||
if (!profile || !this.isProfileRecording(profile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let isRecording = function () {
|
||||
for (let name in this.pool) {
|
||||
if (this.isProfileRecording(this.pool[name])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
this.profiler.stopProfiler(function onStop(aResponse) {
|
||||
aCallback(aResponse.error, data);
|
||||
return false;
|
||||
}.bind(this);
|
||||
|
||||
let onStop = function (data) {
|
||||
if (isRecording()) {
|
||||
return void cb(null, data);
|
||||
}
|
||||
|
||||
profiler.stopProfiler(function onStopProfiler(response) {
|
||||
cb(response.error, data);
|
||||
});
|
||||
}.bind(this));
|
||||
}.bind(this);
|
||||
|
||||
profiler.getProfileData(function onData(aResponse) {
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("Failed to fetch profile data before stopping the profiler.");
|
||||
return void cb(aResponse.error, null);
|
||||
}
|
||||
|
||||
let data = aResponse.profile;
|
||||
profile.timeEnded = profiler.currentTime;
|
||||
|
||||
data.threads = data.threads.map(function (thread) {
|
||||
let samples = thread.samples.filter(function (sample) {
|
||||
return sample.time >= profile.timeStarted;
|
||||
});
|
||||
return { samples: samples };
|
||||
});
|
||||
|
||||
onStop(data);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Cleanup.
|
||||
*/
|
||||
destroy: function PC_destroy(aCallback) {
|
||||
destroy: function PC_destroy() {
|
||||
this.profiler.destroy();
|
||||
this.profiler = null;
|
||||
}
|
||||
|
@ -71,6 +71,8 @@ function ProfileUI(uid, panel) {
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -89,9 +91,10 @@ function ProfileUI(uid, panel) {
|
||||
// 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(function onStart() {
|
||||
this.panel.startProfiling(name, function onStart() {
|
||||
label.textContent = name + " *";
|
||||
this.panel.broadcast(this.uid, {task: "onStarted"});
|
||||
label.textContent = label.textContent + " *";
|
||||
this.emit("started");
|
||||
}.bind(this));
|
||||
|
||||
break;
|
||||
@ -99,9 +102,10 @@ function ProfileUI(uid, panel) {
|
||||
// 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(function onStop() {
|
||||
this.panel.stopProfiling(name, function onStop() {
|
||||
label.textContent = name;
|
||||
this.panel.broadcast(this.uid, {task: "onStopped"});
|
||||
label.textContent = label.textContent.replace(/\s\*$/, "");
|
||||
this.emit("stopped");
|
||||
}.bind(this));
|
||||
break;
|
||||
case "disabled":
|
||||
@ -372,8 +376,8 @@ ProfilerPanel.prototype = {
|
||||
* A function to call once we get the message
|
||||
* that profiling had been successfuly started.
|
||||
*/
|
||||
startProfiling: function PP_startProfiling(onStart) {
|
||||
this.controller.start(function (err) {
|
||||
startProfiling: function PP_startProfiling(name, onStart) {
|
||||
this.controller.start(name, function (err) {
|
||||
if (err) {
|
||||
Cu.reportError("ProfilerController.start: " + err.message);
|
||||
return;
|
||||
@ -392,7 +396,7 @@ ProfilerPanel.prototype = {
|
||||
* A function to call once we get the message
|
||||
* that profiling had been successfuly stopped.
|
||||
*/
|
||||
stopProfiling: function PP_stopProfiling(onStop) {
|
||||
stopProfiling: function PP_stopProfiling(name, onStop) {
|
||||
this.controller.isActive(function (err, isActive) {
|
||||
if (err) {
|
||||
Cu.reportError("ProfilerController.isActive: " + err.message);
|
||||
@ -403,18 +407,19 @@ ProfilerPanel.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
this.controller.stop(function (err, data) {
|
||||
this.controller.stop(name, function (err, data) {
|
||||
if (err) {
|
||||
Cu.reportError("ProfilerController.stop: " + err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
this.activeProfile.data = data;
|
||||
this.activeProfile.parse(data, function onParsed() {
|
||||
this.emit("parsed");
|
||||
}.bind(this));
|
||||
|
||||
onStop();
|
||||
this.emit("stopped");
|
||||
this.emit("stopped", data);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
|
@ -54,31 +54,20 @@ function onParentMessage(event) {
|
||||
var profilerMessage = document.getElementById("profilerMessage");
|
||||
var msg = JSON.parse(event.data);
|
||||
|
||||
if (msg.task !== "receiveProfileData" && !msg.isCurrent) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg.task) {
|
||||
case "onStarted":
|
||||
if (msg.isCurrent) {
|
||||
start.style.display = "none";
|
||||
start.querySelector("button").removeAttribute("disabled");
|
||||
stop.style.display = "inline";
|
||||
} else {
|
||||
start.querySelector("button").setAttribute("disabled", true);
|
||||
var text = gStrings.getFormatStr("profiler.alreadyRunning", [msg.uid]);
|
||||
profilerMessage.textContent = text;
|
||||
profilerMessage.style.display = "block";
|
||||
notifyParent("disabled");
|
||||
}
|
||||
start.style.display = "none";
|
||||
start.querySelector("button").removeAttribute("disabled");
|
||||
stop.style.display = "inline";
|
||||
break;
|
||||
case "onStopped":
|
||||
if (msg.isCurrent) {
|
||||
stop.style.display = "none";
|
||||
stop.querySelector("button").removeAttribute("disabled");
|
||||
start.style.display = "inline";
|
||||
} else {
|
||||
start.querySelector("button").removeAttribute("disabled");
|
||||
profilerMessage.textContent = "";
|
||||
profilerMessage.style.display = "none";
|
||||
notifyParent("enabled");
|
||||
}
|
||||
stop.style.display = "none";
|
||||
stop.querySelector("button").removeAttribute("disabled");
|
||||
start.style.display = "inline";
|
||||
break;
|
||||
case "receiveProfileData":
|
||||
loadProfile(JSON.stringify(msg.rawProfile));
|
||||
@ -267,4 +256,4 @@ function enterProgressUI() {
|
||||
Parser.updateLogSetting();
|
||||
|
||||
return reporter;
|
||||
}
|
||||
}
|
||||
|
@ -33,43 +33,44 @@ function getCleoControls(doc) {
|
||||
];
|
||||
}
|
||||
|
||||
function sendFromActiveProfile(msg) {
|
||||
let [win, doc] = getProfileInternals();
|
||||
|
||||
win.parent.postMessage({
|
||||
uid: gPanel.activeProfile.uid,
|
||||
status: msg
|
||||
}, "*");
|
||||
function sendFromProfile(uid, msg) {
|
||||
let [win, doc] = getProfileInternals(uid);
|
||||
win.parent.postMessage({ uid: uid, status: msg }, "*");
|
||||
}
|
||||
|
||||
function startProfiling() {
|
||||
gPanel.profiles.get(gUid).once("disabled", stopProfiling);
|
||||
sendFromActiveProfile("start");
|
||||
gPanel.profiles.get(gPanel.activeProfile.uid).once("started", function () {
|
||||
setTimeout(function () {
|
||||
sendFromProfile(2, "start");
|
||||
gPanel.profiles.get(2).once("started", function () setTimeout(stopProfiling, 50));
|
||||
}, 50);
|
||||
});
|
||||
sendFromProfile(gPanel.activeProfile.uid, "start");
|
||||
}
|
||||
|
||||
function stopProfiling() {
|
||||
let [win, doc] = getProfileInternals(gUid);
|
||||
let [btn, msg] = getCleoControls(doc);
|
||||
|
||||
ok(msg.textContent.match("Profile 1") !== null, "Message is visible");
|
||||
ok(btn.hasAttribute("disabled"), "Button is disabled");
|
||||
|
||||
is(gPanel.document.querySelector("li#profile-1 > h1").textContent,
|
||||
"Profile 1 *", "Profile 1 has a star next to it.");
|
||||
is(gPanel.document.querySelector("li#profile-2 > h1").textContent,
|
||||
"Profile 2", "Profile 2 doesn't have a star next to it.");
|
||||
"Profile 2 *", "Profile 2 has a star next to it.");
|
||||
|
||||
gPanel.profiles.get(gUid).once("enabled", confirmAndFinish);
|
||||
sendFromActiveProfile("stop");
|
||||
gPanel.profiles.get(gPanel.activeProfile.uid).once("stopped", function () {
|
||||
is(gPanel.document.querySelector("li#profile-1 > h1").textContent,
|
||||
"Profile 1", "Profile 1 doesn't have a star next to it anymore.");
|
||||
|
||||
sendFromProfile(2, "stop");
|
||||
gPanel.profiles.get(2).once("stopped", confirmAndFinish);
|
||||
});
|
||||
sendFromProfile(gPanel.activeProfile.uid, "stop");
|
||||
}
|
||||
|
||||
function confirmAndFinish() {
|
||||
function confirmAndFinish(ev, data) {
|
||||
let [win, doc] = getProfileInternals(gUid);
|
||||
let [btn, msg] = getCleoControls(doc);
|
||||
|
||||
ok(msg.style.display === "none", "Message is hidden");
|
||||
ok(!btn.hasAttribute("disabled"), "Button is enabled");
|
||||
|
||||
is(gPanel.document.querySelector("li#profile-1 > h1").textContent,
|
||||
"Profile 1", "Profile 1 doesn't have a star next to it.");
|
||||
is(gPanel.document.querySelector("li#profile-2 > h1").textContent,
|
||||
@ -80,4 +81,4 @@ function confirmAndFinish() {
|
||||
gTab = null;
|
||||
gUid = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ function test() {
|
||||
gTab = tab;
|
||||
gPanel = panel;
|
||||
|
||||
testInactive(testStart);
|
||||
testInactive(startFirstProfile);
|
||||
});
|
||||
}
|
||||
|
||||
@ -32,23 +32,33 @@ function testActive(next=function(){}) {
|
||||
});
|
||||
}
|
||||
|
||||
function testStart() {
|
||||
gPanel.controller.start(function (err) {
|
||||
ok(!err, "Profiler started without errors");
|
||||
testActive(testStop);
|
||||
function startFirstProfile() {
|
||||
gPanel.controller.start("Profile 1", function (err) {
|
||||
ok(!err, "Profile 1 started without errors");
|
||||
testActive(startSecondProfile);
|
||||
});
|
||||
}
|
||||
|
||||
function testStop() {
|
||||
gPanel.controller.stop(function (err, data) {
|
||||
ok(!err, "Profiler stopped without errors");
|
||||
function startSecondProfile() {
|
||||
gPanel.controller.start("Profile 2", function (err) {
|
||||
ok(!err, "Profile 2 started without errors");
|
||||
testActive(stopFirstProfile);
|
||||
});
|
||||
}
|
||||
|
||||
function stopFirstProfile() {
|
||||
gPanel.controller.stop("Profile 1", function (err, data) {
|
||||
ok(!err, "Profile 1 stopped without errors");
|
||||
ok(data, "Profiler returned some data");
|
||||
|
||||
testInactive(function () {
|
||||
tearDown(gTab, function () {
|
||||
gTab = null;
|
||||
gPanel = null;
|
||||
});
|
||||
});
|
||||
testActive(stopSecondProfile);
|
||||
});
|
||||
}
|
||||
|
||||
function stopSecondProfile() {
|
||||
gPanel.controller.stop("Profile 2", function (err, data) {
|
||||
ok(!err, "Profile 2 stopped without errors");
|
||||
ok(data, "Profiler returned some data");
|
||||
testInactive(tearDown.call(null, gTab, function () gTab = gPanel = null));
|
||||
});
|
||||
}
|
@ -80,4 +80,4 @@ function tearDown(tab, callback=function(){}) {
|
||||
|
||||
finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ let assert = { ok: ok, is: is, log: info };
|
||||
|
||||
var util = require('util/util');
|
||||
|
||||
var converters = require('gcli/converters');
|
||||
|
||||
/**
|
||||
* Warning: For use with Firefox Mochitests only.
|
||||
*
|
||||
@ -380,7 +382,7 @@ helpers._createDebugCheck = function(options) {
|
||||
output += ']);';
|
||||
|
||||
return output;
|
||||
}.bind(this), console.error);
|
||||
}.bind(this), util.errorHandler);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -723,32 +725,36 @@ helpers._exec = function(options, name, expected) {
|
||||
|
||||
var checkOutput = function() {
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var actualOutput = div.textContent.trim();
|
||||
var nodePromise = converters.convert(output.data, output.type, 'dom',
|
||||
options.display.requisition.context);
|
||||
nodePromise.then(function(node) {
|
||||
div.appendChild(node);
|
||||
var actualOutput = div.textContent.trim();
|
||||
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
assert.ok(false, 'html output for ' + name + ' against ' + match.source);
|
||||
log('Actual textContent');
|
||||
log(against);
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
assert.ok(false, 'html output for ' + name + ' against ' + match.source);
|
||||
log('Actual textContent');
|
||||
log(against);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof expected.output === 'string') {
|
||||
assert.is(actualOutput,
|
||||
expected.output,
|
||||
'html output for ' + name);
|
||||
}
|
||||
else if (Array.isArray(expected.output)) {
|
||||
expected.output.forEach(function(match) {
|
||||
doTest(match, actualOutput);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof expected.output === 'string') {
|
||||
assert.is(actualOutput,
|
||||
expected.output,
|
||||
'html output for ' + name);
|
||||
}
|
||||
else if (Array.isArray(expected.output)) {
|
||||
expected.output.forEach(function(match) {
|
||||
doTest(match, actualOutput);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
deferred.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
if (output.completed !== false) {
|
||||
|
@ -33,6 +33,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
|
||||
"resource:///modules/devtools/Target.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "require",
|
||||
"resource://gre/modules/devtools/Require.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
|
||||
let prefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefService);
|
||||
@ -44,6 +47,8 @@ XPCOMUtils.defineLazyGetter(this, "toolboxStrings", function () {
|
||||
return Services.strings.createBundle("chrome://browser/locale/devtools/toolbox.properties");
|
||||
});
|
||||
|
||||
const converters = require("gcli/converters");
|
||||
|
||||
/**
|
||||
* A collection of utilities to help working with commands
|
||||
*/
|
||||
@ -338,7 +343,7 @@ DeveloperToolbar.prototype.show = function DT_show(aFocus, aCallback)
|
||||
|
||||
this._input = this._doc.querySelector(".gclitoolbar-input-node");
|
||||
this.tooltipPanel = new TooltipPanel(this._doc, this._input, checkLoad);
|
||||
this.outputPanel = new OutputPanel(this._doc, this._input, checkLoad);
|
||||
this.outputPanel = new OutputPanel(this, checkLoad);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -369,16 +374,19 @@ DeveloperToolbar.prototype._onload = function DT_onload(aFocus)
|
||||
this.display.focusManager.addMonitoredElement(this.outputPanel._frame);
|
||||
this.display.focusManager.addMonitoredElement(this._element);
|
||||
|
||||
this.display.onVisibilityChange.add(this.outputPanel._visibilityChanged, this.outputPanel);
|
||||
this.display.onVisibilityChange.add(this.tooltipPanel._visibilityChanged, this.tooltipPanel);
|
||||
this.display.onVisibilityChange.add(this.outputPanel._visibilityChanged,
|
||||
this.outputPanel);
|
||||
this.display.onVisibilityChange.add(this.tooltipPanel._visibilityChanged,
|
||||
this.tooltipPanel);
|
||||
this.display.onOutput.add(this.outputPanel._outputChanged, this.outputPanel);
|
||||
|
||||
this._chromeWindow.getBrowser().tabContainer.addEventListener("TabSelect", this, false);
|
||||
this._chromeWindow.getBrowser().tabContainer.addEventListener("TabClose", this, false);
|
||||
this._chromeWindow.getBrowser().addEventListener("load", this, true);
|
||||
this._chromeWindow.getBrowser().addEventListener("beforeunload", this, true);
|
||||
let tabbrowser = this._chromeWindow.getBrowser();
|
||||
tabbrowser.tabContainer.addEventListener("TabSelect", this, false);
|
||||
tabbrowser.tabContainer.addEventListener("TabClose", this, false);
|
||||
tabbrowser.addEventListener("load", this, true);
|
||||
tabbrowser.addEventListener("beforeunload", this, true);
|
||||
|
||||
this._initErrorsCount(this._chromeWindow.getBrowser().selectedTab);
|
||||
this._initErrorsCount(tabbrowser.selectedTab);
|
||||
|
||||
this._element.hidden = false;
|
||||
|
||||
@ -495,13 +503,13 @@ DeveloperToolbar.prototype.destroy = function DT_destroy()
|
||||
return;
|
||||
}
|
||||
|
||||
this._chromeWindow.getBrowser().tabContainer.removeEventListener("TabSelect", this, false);
|
||||
this._chromeWindow.getBrowser().tabContainer.removeEventListener("TabClose", this, false);
|
||||
this._chromeWindow.getBrowser().removeEventListener("load", this, true);
|
||||
this._chromeWindow.getBrowser().removeEventListener("beforeunload", this, true);
|
||||
let tabbrowser = this._chromeWindow.getBrowser();
|
||||
tabbrowser.tabContainer.removeEventListener("TabSelect", this, false);
|
||||
tabbrowser.tabContainer.removeEventListener("TabClose", this, false);
|
||||
tabbrowser.removeEventListener("load", this, true);
|
||||
tabbrowser.removeEventListener("beforeunload", this, true);
|
||||
|
||||
let tabs = this._chromeWindow.getBrowser().tabs;
|
||||
Array.prototype.forEach.call(tabs, this._stopErrorsCount, this);
|
||||
Array.prototype.forEach.call(tabbrowser.tabs, this._stopErrorsCount, this);
|
||||
|
||||
this.display.focusManager.removeMonitoredElement(this.outputPanel._frame);
|
||||
this.display.focusManager.removeMonitoredElement(this._element);
|
||||
@ -700,10 +708,11 @@ function DT_resetErrorsCount(aTab)
|
||||
* @param aInput the input element that should get focus.
|
||||
* @param aLoadCallback called when the panel is loaded properly.
|
||||
*/
|
||||
function OutputPanel(aChromeDoc, aInput, aLoadCallback)
|
||||
function OutputPanel(aDevToolbar, aLoadCallback)
|
||||
{
|
||||
this._input = aInput;
|
||||
this._toolbar = aChromeDoc.getElementById("developer-toolbar");
|
||||
this._devtoolbar = aDevToolbar;
|
||||
this._input = this._devtoolbar._input;
|
||||
this._toolbar = this._devtoolbar._doc.getElementById("developer-toolbar");
|
||||
|
||||
this._loadCallback = aLoadCallback;
|
||||
|
||||
@ -721,7 +730,7 @@ function OutputPanel(aChromeDoc, aInput, aLoadCallback)
|
||||
|
||||
// TODO: Switch back from tooltip to panel when metacity focus issue is fixed:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=780102
|
||||
this._panel = aChromeDoc.createElement(isLinux ? "tooltip" : "panel");
|
||||
this._panel = this._devtoolbar._doc.createElement(isLinux ? "tooltip" : "panel");
|
||||
|
||||
this._panel.id = "gcli-output";
|
||||
this._panel.classList.add("gcli-panel");
|
||||
@ -743,7 +752,7 @@ function OutputPanel(aChromeDoc, aInput, aLoadCallback)
|
||||
|
||||
this._toolbar.parentElement.insertBefore(this._panel, this._toolbar);
|
||||
|
||||
this._frame = aChromeDoc.createElementNS(NS_XHTML, "iframe");
|
||||
this._frame = this._devtoolbar._doc.createElementNS(NS_XHTML, "iframe");
|
||||
this._frame.id = "gcli-output-frame";
|
||||
this._frame.setAttribute("src", "chrome://browser/content/devtools/commandlineoutput.xhtml");
|
||||
this._frame.setAttribute("sandbox", "allow-same-origin");
|
||||
@ -909,12 +918,28 @@ OutputPanel.prototype._outputChanged = function OP_outputChanged(aEvent)
|
||||
*/
|
||||
OutputPanel.prototype.update = function OP_update()
|
||||
{
|
||||
if (this.displayedOutput.data == null) {
|
||||
while (this._div.hasChildNodes()) {
|
||||
this._div.removeChild(this._div.firstChild);
|
||||
}
|
||||
} else {
|
||||
this.displayedOutput.toDom(this._div);
|
||||
// Empty this._div
|
||||
while (this._div.hasChildNodes()) {
|
||||
this._div.removeChild(this._div.firstChild);
|
||||
}
|
||||
|
||||
if (this.displayedOutput.data != null) {
|
||||
let requisition = this._devtoolbar.display.requisition;
|
||||
let nodePromise = converters.convert(this.displayedOutput.data,
|
||||
this.displayedOutput.type, 'dom',
|
||||
requisition.context);
|
||||
nodePromise.then(function(node) {
|
||||
while (this._div.hasChildNodes()) {
|
||||
this._div.removeChild(this._div.firstChild);
|
||||
}
|
||||
|
||||
var links = node.ownerDocument.querySelectorAll('*[href]');
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
links[i].setAttribute('target', '_blank');
|
||||
}
|
||||
|
||||
this._div.appendChild(node);
|
||||
}.bind(this));
|
||||
this.show();
|
||||
}
|
||||
};
|
||||
@ -951,6 +976,7 @@ OutputPanel.prototype.destroy = function OP_destroy()
|
||||
this._panel.removeChild(this._frame);
|
||||
this._toolbar.parentElement.removeChild(this._panel);
|
||||
|
||||
delete this._devtoolbar;
|
||||
delete this._input;
|
||||
delete this._toolbar;
|
||||
delete this._onload;
|
||||
|
@ -31,6 +31,8 @@ let assert = { ok: ok, is: is, log: info };
|
||||
|
||||
var util = require('util/util');
|
||||
|
||||
var converters = require('gcli/converters');
|
||||
|
||||
/**
|
||||
* Warning: For use with Firefox Mochitests only.
|
||||
*
|
||||
@ -380,7 +382,7 @@ helpers._createDebugCheck = function(options) {
|
||||
output += ']);';
|
||||
|
||||
return output;
|
||||
}.bind(this), console.error);
|
||||
}.bind(this), util.errorHandler);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -723,32 +725,36 @@ helpers._exec = function(options, name, expected) {
|
||||
|
||||
var checkOutput = function() {
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var actualOutput = div.textContent.trim();
|
||||
var nodePromise = converters.convert(output.data, output.type, 'dom',
|
||||
options.display.requisition.context);
|
||||
nodePromise.then(function(node) {
|
||||
div.appendChild(node);
|
||||
var actualOutput = div.textContent.trim();
|
||||
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
assert.ok(false, 'html output for ' + name + ' against ' + match.source);
|
||||
log('Actual textContent');
|
||||
log(against);
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
assert.ok(false, 'html output for ' + name + ' against ' + match.source);
|
||||
log('Actual textContent');
|
||||
log(against);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof expected.output === 'string') {
|
||||
assert.is(actualOutput,
|
||||
expected.output,
|
||||
'html output for ' + name);
|
||||
}
|
||||
else if (Array.isArray(expected.output)) {
|
||||
expected.output.forEach(function(match) {
|
||||
doTest(match, actualOutput);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof expected.output === 'string') {
|
||||
assert.is(actualOutput,
|
||||
expected.output,
|
||||
'html output for ' + name);
|
||||
}
|
||||
else if (Array.isArray(expected.output)) {
|
||||
expected.output.forEach(function(match) {
|
||||
doTest(match, actualOutput);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
deferred.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
if (output.completed !== false) {
|
||||
|
@ -15,6 +15,10 @@
|
||||
# or command parameter when no description has been provided.
|
||||
canonDescNone=(No description)
|
||||
|
||||
# LOCALIZATION NOTE (canonDefaultGroupName): The default name for a group of
|
||||
# parameters.
|
||||
canonDefaultGroupName=Options
|
||||
|
||||
# LOCALIZATION NOTE (cliEvalJavascript): The special '{' command allows entry
|
||||
# of JavaScript like traditional developer tool command lines. This describes
|
||||
# the '{' command.
|
||||
@ -239,9 +243,9 @@ prefShowSettingDesc=Setting to display
|
||||
# for help on what it does.
|
||||
prefShowSettingManual=The name of the setting to display
|
||||
|
||||
# LOCALIZATION NOTE (prefShowSettingValue): This is used to show the preference
|
||||
# name and the associated preference value. %1$S is replaced with the preference
|
||||
# name and %2$S is replaced with the preference value.
|
||||
# LOCALIZATION NOTE (prefShowSettingValue): This is used to show the
|
||||
# preference name and the associated preference value. %1$S is replaced with
|
||||
# the preference name and %2$S is replaced with the preference value.
|
||||
prefShowSettingValue=%1$S: %2$S
|
||||
|
||||
# LOCALIZATION NOTE (prefSetDesc): A very short description of the 'pref set'
|
||||
|
@ -736,17 +736,32 @@ cookieListDesc=Display cookies
|
||||
# command, displayed when the user asks for help on what it does.
|
||||
cookieListManual=Display a list of the cookies relevant to the current page.
|
||||
|
||||
# LOCALIZATION NOTE (cookieListOutKey) A heading used in the output from the
|
||||
# 'cookie list' command above a list of cookie keys
|
||||
cookieListOutKey=Key
|
||||
# LOCALIZATION NOTE (cookieListOutHost,cookieListOutPath,cookieListOutExpires,cookieListOutAttributes):
|
||||
# The 'cookie list' command has a number of headings for cookie properties.
|
||||
# Particular care should be taken in translating these strings as they have
|
||||
# references to names in the cookies spec.
|
||||
cookieListOutHost=Host:
|
||||
cookieListOutPath=Path:
|
||||
cookieListOutExpires=Expires:
|
||||
cookieListOutAttributes=Attributes:
|
||||
|
||||
# LOCALIZATION NOTE (cookieListOutValue) A heading used in the output from the
|
||||
# 'cookie list' command above a list of cookie values
|
||||
cookieListOutValue=Value
|
||||
# LOCALIZATION NOTE (cookieListOutNone) The output of the 'cookie list' command
|
||||
# uses this string when no cookie attributes (like httpOnly, secure, etc) apply
|
||||
cookieListOutNone=None
|
||||
|
||||
# LOCALIZATION NOTE (cookieListOutActions) A heading used in the output from the
|
||||
# 'cookie list' command above a list of actions to take on cookies
|
||||
cookieListOutActions=Actions
|
||||
# LOCALIZATION NOTE (cookieListOutSession) The output of the 'cookie list'
|
||||
# command uses this string to describe a cookie with an expiry value of '0'
|
||||
# that is to say it is a session cookie
|
||||
cookieListOutSession=At browser exit (session)
|
||||
|
||||
# LOCALIZATION NOTE (cookieListOutNonePage) The output of the 'cookie list'
|
||||
# command uses this string for pages like 'about:blank' which can't contain
|
||||
# cookies
|
||||
cookieListOutNonePage=No cookies found for this page
|
||||
|
||||
# LOCALIZATION NOTE (cookieListOutNoneHost) The output of the 'cookie list'
|
||||
# command uses this string when there are no cookies on a given web page
|
||||
cookieListOutNoneHost=No cookies found for host %1$S
|
||||
|
||||
# LOCALIZATION NOTE (cookieListOutEdit) A title used in the output from the
|
||||
# 'cookie list' command on a button which can be used to edit cookie values
|
||||
@ -808,6 +823,21 @@ cookieSetDomainDesc=The domain of the cookie to set
|
||||
# when the user is using this command.
|
||||
cookieSetSecureDesc=Only transmitted over https
|
||||
|
||||
# LOCALIZATION NOTE (cookieSetHttpOnlyDesc) A very short string to describe the
|
||||
# 'httpOnly' parameter to the 'cookie set' command, which is displayed in a dialog
|
||||
# when the user is using this command.
|
||||
cookieSetHttpOnlyDesc=Not accessible from client side script
|
||||
|
||||
# LOCALIZATION NOTE (cookieSetSessionDesc) A very short string to describe the
|
||||
# 'session' parameter to the 'cookie set' command, which is displayed in a dialog
|
||||
# when the user is using this command.
|
||||
cookieSetSessionDesc=Only valid for the lifetime of the browser session
|
||||
|
||||
# LOCALIZATION NOTE (cookieSetExpiresDesc) A very short string to describe the
|
||||
# 'expires' parameter to the 'cookie set' command, which is displayed in a dialog
|
||||
# when the user is using this command.
|
||||
cookieSetExpiresDesc=The expiry date of the cookie (quoted RFC2822 or ISO 8601 date)
|
||||
|
||||
# LOCALIZATION NOTE (jsbDesc) A very short description of the
|
||||
# 'jsb' command. This string is designed to be shown in a menu
|
||||
# alongside the command name, which is why it should be as short as possible.
|
||||
|
@ -74,6 +74,12 @@ function fmt(aStr, aMaxLen, aMinLen, aOptions) {
|
||||
* The constructor name
|
||||
*/
|
||||
function getCtorName(aObj) {
|
||||
if (aObj === null) {
|
||||
return "null";
|
||||
}
|
||||
if (aObj === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
if (aObj.constructor && aObj.constructor.name) {
|
||||
return aObj.constructor.name;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user