Merge latest green inbound changeset and mozilla-central

This commit is contained in:
Ed Morley 2013-07-22 14:45:43 +01:00
Родитель 9bcd0d6610 9fe8f2876f
Коммит 7be3034ecd
85 изменённых файлов: 7298 добавлений и 3889 удалений

Просмотреть файл

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1373408730000">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1374187152000">
<emItems>
<emItem blockID="i350" id="sqlmoz@facebook.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
@ -1052,6 +1052,9 @@
</targetApplication>
</versionRange>
</pluginItem>
<pluginItem blockID="p428">
<match name="filename" exp="np[dD]eployJava1\.dll" /> <versionRange severity="0" vulnerabilitystatus="2"></versionRange>
</pluginItem>
</pluginItems>
<gfxItems>

Просмотреть файл

@ -600,6 +600,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
});
XPCOMUtils.defineLazyGetter(this, 'supportsString', function() {
return Cc["@mozilla.org/supports-string;1"]
.createInstance(Ci.nsISupportsString);
});
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "console",
@ -719,7 +724,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
gcli.addCommand(commandSpec);
commands.push(commandSpec.name);
});
},
function onError(reason) {
console.error("OS.File.read(" + aFileEntry.path + ") failed.");
@ -733,7 +737,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
*/
gcli.addCommand({
name: "cmd",
get hidden() { return !prefBranch.prefHasUserValue(PREF_DIR); },
get hidden() {
return !prefBranch.prefHasUserValue(PREF_DIR);
},
description: gcli.lookup("cmdDesc")
});
@ -743,10 +749,49 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
gcli.addCommand({
name: "cmd refresh",
description: gcli.lookup("cmdRefreshDesc"),
get hidden() { return !prefBranch.prefHasUserValue(PREF_DIR); },
exec: function Command_cmdRefresh(args, context) {
get hidden() {
return !prefBranch.prefHasUserValue(PREF_DIR);
},
exec: function(args, context) {
let chromeWindow = context.environment.chromeDocument.defaultView;
CmdCommands.refreshAutoCommands(chromeWindow);
let dirName = prefBranch.getComplexValue(PREF_DIR,
Ci.nsISupportsString).data.trim();
return gcli.lookupFormat("cmdStatus", [ commands.length, dirName ]);
}
});
/**
* 'cmd setdir' command
*/
gcli.addCommand({
name: "cmd setdir",
description: gcli.lookup("cmdSetdirDesc"),
params: [
{
name: "directory",
description: gcli.lookup("cmdSetdirDirectoryDesc"),
type: {
name: "file",
filetype: "directory",
existing: "yes"
},
defaultValue: null
}
],
returnType: "string",
get hidden() {
return true; // !prefBranch.prefHasUserValue(PREF_DIR);
},
exec: function(args, context) {
supportsString.data = args.directory;
prefBranch.setComplexValue(PREF_DIR, Ci.nsISupportsString, supportsString);
let chromeWindow = context.environment.chromeDocument.defaultView;
CmdCommands.refreshAutoCommands(chromeWindow);
return gcli.lookupFormat("cmdStatus", [ commands.length, args.directory ]);
}
});
}(this));
@ -1493,7 +1538,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
params: [
{
name: "srcdir",
type: "string",
type: "string" /* {
name: "file",
filetype: "directory",
existing: "yes"
} */,
description: gcli.lookup("toolsSrcdirDir")
}
],

Просмотреть файл

@ -44,10 +44,14 @@ MOCHITEST_BROWSER_FILES = \
browser_cmd_screenshot.html \
browser_cmd_screenshot.js \
browser_cmd_settings.js \
browser_gcli_async.js \
browser_gcli_canon.js \
browser_gcli_cli.js \
browser_gcli_completion.js \
browser_gcli_date.js \
browser_gcli_exec.js \
browser_gcli_fail.js \
browser_gcli_file.js \
browser_gcli_focus.js \
browser_gcli_history.js \
browser_gcli_incomplete.js \

Просмотреть файл

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {

Просмотреть файл

@ -217,10 +217,11 @@ exports.testAltCanon = function(options) {
var commandSpecs = altCanon.getCommandSpecs();
assert.is(JSON.stringify(commandSpecs),
'{"tss":{"name":"tss","params":[' +
'{"name":"str","type":"string"},' +
'{"name":"num","type":"number"},' +
'{"name":"opt","type":{"name":"selection","data":["1","2","3"]}}]}}',
'{"tss":{"name":"tss","description":"(No description)","params":[' +
'{"name":"str","type":"string","description":"(No description)"},' +
'{"name":"num","type":"number","description":"(No description)"},' +
'{"name":"opt","type":{"name":"selection","data":["1","2","3"]},"description":"(No description)"}'+
'],"isParent":false}}',
'JSON.stringify(commandSpecs)');
var remoter = function(args, context) {

Просмотреть файл

@ -37,26 +37,17 @@ function test() {
// var helpers = require('gclitest/helpers');
// var mockCommands = require('gclitest/mockCommands');
var cli = require('gcli/cli');
var origLogErrors = undefined;
exports.setup = function(options) {
mockCommands.setup();
origLogErrors = cli.logErrors;
cli.logErrors = false;
};
exports.shutdown = function(options) {
mockCommands.shutdown();
cli.logErrors = origLogErrors;
origLogErrors = undefined;
};
exports.testBaseline = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
// These 3 establish a baseline for comparison when we have used the
// context command
{
@ -100,7 +91,7 @@ exports.testBaseline = function(options) {
};
exports.testContext = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
// Use the 'tsn' context
{
setup: 'context tsn',

Просмотреть файл

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {
@ -80,8 +90,10 @@ exports.testIncrement = function(options) {
};
exports.testInput = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
// See bug 892901
skipRemainingIf: options.isFirefox,
setup: 'tsdate 2001-01-01 1980-01-03',
check: {
input: 'tsdate 2001-01-01 1980-01-03',
@ -132,8 +144,10 @@ exports.testInput = function(options) {
};
exports.testIncrDecr = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
// See bug 892901
skipRemainingIf: options.isFirefox,
setup: 'tsdate 2001-01-01<UP>',
check: {
input: 'tsdate 2001-01-02',
@ -224,14 +238,14 @@ exports.testIncrDecr = function(options) {
message: ''
},
d2: {
value: function(d1) {
assert.is(d1.getFullYear(), 2000, 'd1 year');
assert.is(d1.getMonth(), 1, 'd1 month');
assert.is(d1.getDate(), 28, 'd1 date');
assert.is(d1.getHours(), 0, 'd1 hours');
assert.is(d1.getMinutes(), 0, 'd1 minutes');
assert.is(d1.getSeconds(), 0, 'd1 seconds');
assert.is(d1.getMilliseconds(), 0, 'd1 millis');
value: function(d2) {
assert.is(d2.getFullYear(), 2000, 'd2 year');
assert.is(d2.getMonth(), 1, 'd2 month');
assert.is(d2.getDate(), 28, 'd2 date');
assert.is(d2.getHours(), 0, 'd2 hours');
assert.is(d2.getMinutes(), 0, 'd2 minutes');
assert.is(d2.getSeconds(), 0, 'd2 seconds');
assert.is(d2.getMilliseconds(), 0, 'd2 millis');
},
arg: ' "2000-02-28"',
status: 'VALID',

Просмотреть файл

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {
@ -27,22 +37,13 @@ function test() {
// var helpers = require('gclitest/helpers');
// var mockCommands = require('gclitest/mockCommands');
var cli = require('gcli/cli');
var origLogErrors = undefined;
exports.setup = function(options) {
mockCommands.setup();
origLogErrors = cli.logErrors;
cli.logErrors = false;
};
exports.shutdown = function(options) {
mockCommands.shutdown();
cli.logErrors = origLogErrors;
origLogErrors = undefined;
};
exports.testBasic = function(options) {

Просмотреть файл

@ -0,0 +1,848 @@
/*
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {
// <INJECTED SOURCE:START>
// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
// DO NOT EDIT IT DIRECTLY
var exports = {};
const TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFile.js</p>";
function test() {
helpers.addTabWithToolbar(TEST_URI, function(options) {
return helpers.runTests(options, exports);
}).then(finish);
}
// <INJECTED SOURCE:END>
'use strict';
// var helpers = require('gclitest/helpers');
// var mockCommands = require('gclitest/mockCommands');
exports.setup = function(options) {
mockCommands.setup();
};
exports.shutdown = function(options) {
mockCommands.shutdown();
};
var local = false;
exports.testBasic = function(options) {
var isPhantomjsFromFilesystem = (!options.isHttp && options.isPhantomjs);
return helpers.audit(options, [
{
// These tests require us to be using node directly or to be in
// phantomjs connected to an allowexec enabled node server or to be in
// firefox. In short they only don't work when in phantomjs reading
// from the filesystem, but they do work in Firefox
skipRemainingIf: isPhantomjsFromFilesystem || options.isFirefox,
setup: 'tsfile open /',
check: {
input: 'tsfile open /',
hints: '',
markup: 'VVVVVVVVVVVVI',
cursor: 13,
current: 'p1',
status: 'ERROR',
message: '\'/\' is not a file',
args: {
command: { name: 'tsfile open' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' is not a file'
}
}
}
},
{
setup: 'tsfile open /zxcv',
check: {
input: 'tsfile open /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVIIIII',
cursor: 17,
current: 'p1',
status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile open' },
p1: {
value: undefined,
arg: ' /zxcv',
status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: !local,
setup: 'tsfile open /mach_kernel',
check: {
input: 'tsfile open /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
cursor: 24,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile open' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile saveas /',
check: {
input: 'tsfile saveas /',
hints: '',
markup: 'VVVVVVVVVVVVVVI',
cursor: 15,
current: 'p1',
status: 'ERROR',
message: '\'/\' already exists',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' already exists'
}
}
}
},
{
setup: 'tsfile saveas /zxcv',
check: {
input: 'tsfile saveas /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVVVVVVVV',
cursor: 19,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile saveas /mach_kernel',
check: {
input: 'tsfile saveas /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVIIIIIIIIIIII',
cursor: 26,
current: 'p1',
status: 'ERROR',
message: '\'/mach_kernel\' already exists',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: undefined,
arg: ' /mach_kernel',
status: 'INCOMPLETE',
message: '\'/mach_kernel\' already exists'
}
}
}
},
{
setup: 'tsfile save /',
check: {
input: 'tsfile save /',
hints: '',
markup: 'VVVVVVVVVVVVI',
cursor: 13,
current: 'p1',
status: 'ERROR',
message: '\'/\' is not a file',
args: {
command: { name: 'tsfile save' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' is not a file'
}
}
}
},
{
setup: 'tsfile save /zxcv',
check: {
input: 'tsfile save /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVVVVVV',
cursor: 17,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile save' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile save /mach_kernel',
check: {
input: 'tsfile save /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
cursor: 24,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile save' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile cd /',
check: {
input: 'tsfile cd /',
hints: '',
markup: 'VVVVVVVVVVV',
cursor: 11,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile cd' },
p1: {
value: '/',
arg: ' /',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile cd /zxcv',
check: {
input: 'tsfile cd /zxcv',
// hints: ' -> /dev/',
markup: 'VVVVVVVVVVIIIII',
cursor: 15,
current: 'p1',
status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile cd' },
p1: {
value: undefined,
arg: ' /zxcv',
status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: true || !local,
setup: 'tsfile cd /etc/passwd',
check: {
input: 'tsfile cd /etc/passwd',
hints: ' -> /etc/pam.d/',
markup: 'VVVVVVVVVVIIIIIIIIIII',
cursor: 21,
current: 'p1',
status: 'ERROR',
message: '\'/etc/passwd\' is not a directory',
args: {
command: { name: 'tsfile cd' },
p1: {
value: undefined,
arg: ' /etc/passwd',
status: 'INCOMPLETE',
message: '\'/etc/passwd\' is not a directory'
}
}
}
},
{
setup: 'tsfile mkdir /',
check: {
input: 'tsfile mkdir /',
hints: '',
markup: 'VVVVVVVVVVVVVI',
cursor: 14,
current: 'p1',
status: 'ERROR',
message: ''/' already exists',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' already exists'
}
}
}
},
{
setup: 'tsfile mkdir /zxcv',
check: {
input: 'tsfile mkdir /zxcv',
// hints: ' -> /dev/',
markup: 'VVVVVVVVVVVVVVVVVV',
cursor: 18,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile mkdir /mach_kernel',
check: {
input: 'tsfile mkdir /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVIIIIIIIIIIII',
cursor: 25,
current: 'p1',
status: 'ERROR',
message: '\'/mach_kernel\' already exists',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: undefined,
arg: ' /mach_kernel',
status: 'INCOMPLETE',
message: '\'/mach_kernel\' already exists'
}
}
}
},
{
setup: 'tsfile rm /',
check: {
input: 'tsfile rm /',
hints: '',
markup: 'VVVVVVVVVVV',
cursor: 11,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile rm' },
p1: {
value: '/',
arg: ' /',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile rm /zxcv',
check: {
input: 'tsfile rm /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVIIIII',
cursor: 15,
current: 'p1',
status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile rm' },
p1: {
value: undefined,
arg: ' /zxcv',
status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: !local,
setup: 'tsfile rm /mach_kernel',
check: {
input: 'tsfile rm /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVV',
cursor: 22,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile rm' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
}
]);
};
exports.testFirefoxBasic = function(options) {
return helpers.audit(options, [
{
// These tests are just like the ones above tailored for running in
// Firefox
skipRemainingIf: true,
// skipRemainingIf: !options.isFirefox,
skipIf: true,
setup: 'tsfile open /',
check: {
input: 'tsfile open /',
hints: '',
markup: 'VVVVVVVVVVVVI',
cursor: 13,
current: 'p1',
status: 'ERROR',
message: '\'/\' is not a file',
args: {
command: { name: 'tsfile open' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' is not a file'
}
}
}
},
{
skipIf: true,
setup: 'tsfile open /zxcv',
check: {
input: 'tsfile open /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVIIIII',
cursor: 17,
current: 'p1',
status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile open' },
p1: {
value: undefined,
arg: ' /zxcv',
status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: !local,
setup: 'tsfile open /mach_kernel',
check: {
input: 'tsfile open /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
cursor: 24,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile open' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: true,
setup: 'tsfile saveas /',
check: {
input: 'tsfile saveas /',
hints: '',
markup: 'VVVVVVVVVVVVVVI',
cursor: 15,
current: 'p1',
status: 'ERROR',
message: '\'/\' already exists',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' already exists'
}
}
}
},
{
skipIf: true,
setup: 'tsfile saveas /zxcv',
check: {
input: 'tsfile saveas /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVVVVVVVV',
cursor: 19,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile saveas /mach_kernel',
check: {
input: 'tsfile saveas /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVIIIIIIIIIIII',
cursor: 26,
current: 'p1',
status: 'ERROR',
message: '\'/mach_kernel\' already exists',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: undefined,
arg: ' /mach_kernel',
status: 'INCOMPLETE',
message: '\'/mach_kernel\' already exists'
}
}
}
},
{
skipIf: true,
setup: 'tsfile save /',
check: {
input: 'tsfile save /',
hints: '',
markup: 'VVVVVVVVVVVVI',
cursor: 13,
current: 'p1',
status: 'ERROR',
message: '\'/\' is not a file',
args: {
command: { name: 'tsfile save' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' is not a file'
}
}
}
},
{
skipIf: true,
setup: 'tsfile save /zxcv',
check: {
input: 'tsfile save /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVVVVVV',
cursor: 17,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile save' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile save /mach_kernel',
check: {
input: 'tsfile save /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
cursor: 24,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile save' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile cd /',
check: {
input: 'tsfile cd /',
hints: '',
markup: 'VVVVVVVVVVV',
cursor: 11,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile cd' },
p1: {
value: '/',
arg: ' /',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile cd /zxcv',
check: {
input: 'tsfile cd /zxcv',
// hints: ' -> /dev/',
// markup: 'VVVVVVVVVVIIIII',
cursor: 15,
current: 'p1',
// status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile cd' },
p1: {
value: undefined,
arg: ' /zxcv',
// status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: true || !local,
setup: 'tsfile cd /etc/passwd',
check: {
input: 'tsfile cd /etc/passwd',
hints: ' -> /etc/pam.d/',
markup: 'VVVVVVVVVVIIIIIIIIIII',
cursor: 21,
current: 'p1',
status: 'ERROR',
message: '\'/etc/passwd\' is not a directory',
args: {
command: { name: 'tsfile cd' },
p1: {
value: undefined,
arg: ' /etc/passwd',
status: 'INCOMPLETE',
message: '\'/etc/passwd\' is not a directory'
}
}
}
},
{
setup: 'tsfile mkdir /',
check: {
input: 'tsfile mkdir /',
hints: '',
markup: 'VVVVVVVVVVVVVI',
cursor: 14,
current: 'p1',
status: 'ERROR',
message: ''/' already exists',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' already exists'
}
}
}
},
{
setup: 'tsfile mkdir /zxcv',
check: {
input: 'tsfile mkdir /zxcv',
// hints: ' -> /dev/',
markup: 'VVVVVVVVVVVVVVVVVV',
cursor: 18,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile mkdir /mach_kernel',
check: {
input: 'tsfile mkdir /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVIIIIIIIIIIII',
cursor: 25,
current: 'p1',
status: 'ERROR',
message: '\'/mach_kernel\' already exists',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: undefined,
arg: ' /mach_kernel',
status: 'INCOMPLETE',
message: '\'/mach_kernel\' already exists'
}
}
}
},
{
skipIf: true,
setup: 'tsfile rm /',
check: {
input: 'tsfile rm /',
hints: '',
markup: 'VVVVVVVVVVV',
cursor: 11,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile rm' },
p1: {
value: '/',
arg: ' /',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: true,
setup: 'tsfile rm /zxcv',
check: {
input: 'tsfile rm /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVIIIII',
cursor: 15,
current: 'p1',
status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile rm' },
p1: {
value: undefined,
arg: ' /zxcv',
status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: !local,
setup: 'tsfile rm /mach_kernel',
check: {
input: 'tsfile rm /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVV',
cursor: 22,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile rm' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
}
]);
};
// });

Просмотреть файл

@ -0,0 +1,57 @@
/*
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {
// <INJECTED SOURCE:START>
// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
// DO NOT EDIT IT DIRECTLY
var exports = {};
const TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFileparser.js</p>";
function test() {
helpers.addTabWithToolbar(TEST_URI, function(options) {
return helpers.runTests(options, exports);
}).then(finish);
}
// <INJECTED SOURCE:END>
'use strict';
// var assert = require('test/assert');
var fileparser = require('util/fileparser');
var local = false;
exports.testGetPredictor = function(options) {
if (!options.isNode || !local) {
return;
}
var options = { filetype: 'file', existing: 'yes' };
var predictor = fileparser.getPredictor('/usr/locl/bin/nmp', options);
return predictor().then(function(replies) {
assert.is(replies[0].name,
'/usr/local/bin/npm',
'predict npm');
});
};
// });

Просмотреть файл

@ -0,0 +1,78 @@
/*
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {
// <INJECTED SOURCE:START>
// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
// DO NOT EDIT IT DIRECTLY
var exports = {};
const TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFilesystem.js</p>";
function test() {
helpers.addTabWithToolbar(TEST_URI, function(options) {
return helpers.runTests(options, exports);
}).then(finish);
}
// <INJECTED SOURCE:END>
'use strict';
// var assert = require('test/assert');
// var helpers = require('gclitest/helpers');
var filesystem = require('util/filesystem');
exports.testSplit = function(options) {
if (!options.isNode) {
return;
}
helpers.arrayIs(filesystem.split('', '/'),
[ '.' ],
'split <blank>');
helpers.arrayIs(filesystem.split('a', '/'),
[ 'a' ],
'split a');
helpers.arrayIs(filesystem.split('a/b/c', '/'),
[ 'a', 'b', 'c' ],
'split a/b/c');
helpers.arrayIs(filesystem.split('/a/b/c/', '/'),
[ 'a', 'b', 'c' ],
'split a/b/c');
helpers.arrayIs(filesystem.split('/a/b///c/', '/'),
[ 'a', 'b', 'c' ],
'split a/b/c');
};
exports.testJoin = function(options) {
if (!options.isNode) {
return;
}
assert.is(filesystem.join('usr', 'local', 'bin'),
'usr/local/bin',
'join to usr/local/bin');
};
// });

Просмотреть файл

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {

Просмотреть файл

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {

Просмотреть файл

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {

Просмотреть файл

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {

Просмотреть файл

@ -48,6 +48,7 @@ exports.shutdown = function(options) {
};
exports.testRemote = function(options) {
var connected = false;
return helpers.audit(options, [
{
skipRemainingIf: !options.isHttp,
@ -65,6 +66,72 @@ exports.testRemote = function(options) {
unassigned: [ ],
}
},
{
setup: 'connect remote',
check: {
input: 'connect remote',
hints: ' [options]',
markup: 'VVVVVVVVVVVVVV',
cursor: 14,
current: 'prefix',
status: 'VALID',
options: [ ],
message: '',
predictions: [ ],
unassigned: [ ],
args: {
command: { name: 'connect' },
prefix: { value: 'remote', arg: ' remote', status: 'VALID', message: '' },
host: { value: undefined, arg: '', status: 'VALID', message: '' },
port: { value: undefined, arg: '', status: 'VALID', message: '' },
}
},
exec: {
completed: false,
error: false
},
post: function(output, data) {
connected = !output.error;
if (!connected) {
console.log('Failure from "connect remote". Run server with "node gcli server start --websocket --allowexec" to allow remote command testing');
}
}
},
{
// We do a connect-disconnect dance for 2 reasons, partly re-establishing
// a connection is a good test, and secondly it lets us have minimal
// testing on the first connection so we don't need to turn websockets
// on all the time
setup: 'disconnect remote --force',
skipRemainingIf: !connected,
check: {
input: 'disconnect remote --force',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV',
cursor: 25,
current: 'force',
status: 'VALID',
message: '',
unassigned: [ ],
args: {
command: { name: 'disconnect' },
prefix: {
value: function(connection) {
assert.is(connection.prefix, 'remote', 'disconnecting remote');
},
arg: ' remote',
status: 'VALID',
message: ''
}
}
},
exec: {
output: /^Removed [0-9]* commands.$/,
completed: true,
type: 'string',
error: false
}
},
{
setup: 'connect remote',
check: {

Просмотреть файл

@ -35,7 +35,7 @@ function test() {
'use strict';
// var assert = require('test/assert');
var spell = require('gcli/types/spell');
var spell = require('util/spell');
exports.testSpellerSimple = function(options) {
var alternatives = Object.keys(options.window);
@ -54,5 +54,34 @@ exports.testSpellerSimple = function(options) {
assert.is(spell.correct('=========', alternatives), undefined);
};
exports.testRank = function(options) {
var distances = spell.rank('fred', [ 'banana', 'fred', 'ed', 'red', 'FRED' ]);
assert.is(distances.length, 5, 'rank length');
assert.is(distances[0].name, 'fred', 'fred name #0');
assert.is(distances[1].name, 'FRED', 'FRED name #1');
assert.is(distances[2].name, 'red', 'red name #2');
assert.is(distances[3].name, 'ed', 'ed name #3');
assert.is(distances[4].name, 'banana', 'banana name #4');
assert.is(distances[0].dist, 0, 'fred dist 0');
assert.is(distances[1].dist, 4, 'FRED dist 4');
assert.is(distances[2].dist, 10, 'red dist 10');
assert.is(distances[3].dist, 20, 'ed dist 20');
assert.is(distances[4].dist, 100, 'banana dist 100');
};
exports.testRank2 = function(options) {
var distances = spell.rank('caps', [ 'CAPS', 'false' ]);
assert.is(JSON.stringify(distances),
'[{"name":"CAPS","dist":4},{"name":"false","dist":50}]',
'spell.rank("caps", [ "CAPS", "false" ]');
};
exports.testDistancePrefix = function(options) {
assert.is(spell.distancePrefix('fred', 'freddy'), 0, 'distancePrefix fred');
assert.is(spell.distancePrefix('FRED', 'freddy'), 4, 'distancePrefix FRED');
};
// });

Просмотреть файл

@ -47,7 +47,7 @@ exports.shutdown = function(options) {
};
exports.testNewLine = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
setup: 'echo a\\nb',
check: {
@ -72,7 +72,7 @@ exports.testNewLine = function(options) {
};
exports.testTab = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
setup: 'echo a\\tb',
check: {
@ -97,7 +97,7 @@ exports.testTab = function(options) {
};
exports.testEscape = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
// What's typed is actually:
// tsrsrsr a\\ b c
@ -143,7 +143,7 @@ exports.testEscape = function(options) {
};
exports.testBlank = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
setup: 'tsrsrsr a "" c',
check: {
@ -213,7 +213,7 @@ exports.testBlank = function(options) {
};
exports.testBlankWithParam = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
setup: 'tsrsrsr a --p3',
check: {

Просмотреть файл

@ -30,6 +30,7 @@ let promise = (Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js",
let assert = { ok: ok, is: is, log: info };
var util = require('util/util');
var cli = require('gcli/cli');
var converters = require('gcli/converters');
@ -566,7 +567,7 @@ helpers._check = function(options, name, checks) {
if ('predictions' in checks) {
var predictionsCheck = function(actualPredictions) {
helpers._arrayIs(actualPredictions,
helpers.arrayIs(actualPredictions,
checks.predictions,
'predictions' + suffix);
};
@ -585,7 +586,7 @@ helpers._check = function(options, name, checks) {
}
if ('unassigned' in checks) {
helpers._arrayIs(helpers._actual.unassigned(options),
helpers.arrayIs(helpers._actual.unassigned(options),
checks.unassigned,
'unassigned' + suffix);
}
@ -613,7 +614,7 @@ helpers._check = function(options, name, checks) {
}
if ('options' in checks) {
helpers._arrayIs(helpers._actual.options(options),
helpers.arrayIs(helpers._actual.options(options),
checks.options,
'options' + suffix);
}
@ -718,6 +719,11 @@ helpers._exec = function(options, name, expected) {
return promise.resolve({});
}
var origLogErrors = cli.logErrors;
if (expected.error) {
cli.logErrors = false;
}
var output;
try {
output = options.display.requisition.exec({ hidden: true });
@ -726,6 +732,9 @@ helpers._exec = function(options, name, expected) {
assert.ok(false, 'Failure executing \'' + name + '\': ' + ex);
util.errorHandler(ex);
if (expected.error) {
cli.logErrors = origLogErrors;
}
return promise.resolve({});
}
@ -737,10 +746,17 @@ helpers._exec = function(options, name, expected) {
if (!options.window.document.createElement) {
assert.log('skipping output tests (missing doc.createElement) for ' + name);
if (expected.error) {
cli.logErrors = origLogErrors;
}
return promise.resolve({ output: output });
}
if (!('output' in expected)) {
if (expected.error) {
cli.logErrors = origLogErrors;
}
return promise.resolve({ output: output });
}
@ -788,6 +804,9 @@ helpers._exec = function(options, name, expected) {
doTest(expected.output, actualOutput);
}
if (expected.error) {
cli.logErrors = origLogErrors;
}
return { output: output, text: actualOutput };
});
};
@ -940,17 +959,6 @@ helpers.audit = function(options, audits) {
log('- START \'' + name + '\' in ' + assert.currentTest);
}
if (audit.skipIf) {
var skip = (typeof audit.skipIf === 'function') ?
audit.skipIf(options) :
!!audit.skipIf;
if (skip) {
var reason = audit.skipIf.name ? 'due to ' + audit.skipIf.name : '';
assert.log('Skipped ' + name + ' ' + reason);
return promise.resolve(undefined);
}
}
if (audit.skipRemainingIf) {
var skipRemainingIf = (typeof audit.skipRemainingIf === 'function') ?
audit.skipRemainingIf(options) :
@ -964,6 +972,17 @@ helpers.audit = function(options, audits) {
}
}
if (audit.skipIf) {
var skip = (typeof audit.skipIf === 'function') ?
audit.skipIf(options) :
!!audit.skipIf;
if (skip) {
var reason = audit.skipIf.name ? 'due to ' + audit.skipIf.name : '';
assert.log('Skipped ' + name + ' ' + reason);
return promise.resolve(undefined);
}
}
if (skipReason != null) {
assert.log('Skipped ' + name + ' ' + skipReason);
return promise.resolve(undefined);
@ -1008,7 +1027,7 @@ helpers.audit = function(options, audits) {
/**
* Compare 2 arrays.
*/
helpers._arrayIs = function(actual, expected, message) {
helpers.arrayIs = function(actual, expected, message) {
assert.ok(Array.isArray(actual), 'actual is not an array: ' + message);
assert.ok(Array.isArray(expected), 'expected is not an array: ' + message);

Просмотреть файл

@ -482,6 +482,116 @@ var tsfail = {
}
};
var tsfile = {
item: 'command',
name: 'tsfile',
description: 'test file params',
};
var tsfileOpen = {
item: 'command',
name: 'tsfile open',
description: 'a file param in open mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'file',
existing: 'yes'
}
}
],
exec: createExec('tsfile open')
};
var tsfileSaveas = {
item: 'command',
name: 'tsfile saveas',
description: 'a file param in saveas mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'file',
existing: 'no'
}
}
],
exec: createExec('tsfile saveas')
};
var tsfileSave = {
item: 'command',
name: 'tsfile save',
description: 'a file param in save mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'file',
existing: 'maybe'
}
}
],
exec: createExec('tsfile save')
};
var tsfileCd = {
item: 'command',
name: 'tsfile cd',
description: 'a file param in cd mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'directory',
existing: 'yes'
}
}
],
exec: createExec('tsfile cd')
};
var tsfileMkdir = {
item: 'command',
name: 'tsfile mkdir',
description: 'a file param in mkdir mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'directory',
existing: 'no'
}
}
],
exec: createExec('tsfile mkdir')
};
var tsfileRm = {
item: 'command',
name: 'tsfile rm',
description: 'a file param in rm mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'any',
existing: 'yes'
}
}
],
exec: createExec('tsfile rm')
};
mockCommands.commands = {};
/**
@ -533,6 +643,13 @@ mockCommands.setup = function(opts) {
mockCommands.commands.tslong = canon.addCommand(tslong);
mockCommands.commands.tsdate = canon.addCommand(tsdate);
mockCommands.commands.tsfail = canon.addCommand(tsfail);
mockCommands.commands.tsfile = canon.addCommand(tsfile);
mockCommands.commands.tsfileOpen = canon.addCommand(tsfileOpen);
mockCommands.commands.tsfileSaveas = canon.addCommand(tsfileSaveas);
mockCommands.commands.tsfileSave = canon.addCommand(tsfileSave);
mockCommands.commands.tsfileCd = canon.addCommand(tsfileCd);
mockCommands.commands.tsfileMkdir = canon.addCommand(tsfileMkdir);
mockCommands.commands.tsfileRm = canon.addCommand(tsfileRm);
};
mockCommands.shutdown = function(opts) {
@ -564,6 +681,13 @@ mockCommands.shutdown = function(opts) {
canon.removeCommand(tslong);
canon.removeCommand(tsdate);
canon.removeCommand(tsfail);
canon.removeCommand(tsfile);
canon.removeCommand(tsfileOpen);
canon.removeCommand(tsfileSaveas);
canon.removeCommand(tsfileSave);
canon.removeCommand(tsfileCd);
canon.removeCommand(tsfileMkdir);
canon.removeCommand(tsfileRm);
types.removeType(mockCommands.optionType);
types.removeType(mockCommands.optionValue);

Просмотреть файл

@ -707,6 +707,7 @@ FilterView.prototype = {
this._searchbox = document.getElementById("searchbox");
this._searchboxHelpPanel = document.getElementById("searchbox-help-panel");
this._filterLabel = document.getElementById("filter-label");
this._globalOperatorButton = document.getElementById("global-operator-button");
this._globalOperatorLabel = document.getElementById("global-operator-label");
this._functionOperatorButton = document.getElementById("function-operator-button");
@ -737,6 +738,8 @@ FilterView.prototype = {
this._lineOperatorButton.setAttribute("label", SEARCH_LINE_FLAG);
this._variableOperatorButton.setAttribute("label", SEARCH_VARIABLE_FLAG);
this._filterLabel.setAttribute("value",
L10N.getFormatStr("searchPanelFilter", this._fileSearchKey));
this._globalOperatorLabel.setAttribute("value",
L10N.getFormatStr("searchPanelGlobal", this._globalSearchKey));
this._functionOperatorLabel.setAttribute("value",
@ -780,7 +783,7 @@ FilterView.prototype = {
placeholder = L10N.getFormatStr("emptyChromeGlobalsFilterText", this._fileSearchKey);
break;
case DebuggerView.Sources:
placeholder = L10N.getFormatStr("emptyFilterText", this._fileSearchKey);
placeholder = L10N.getFormatStr("emptySearchText", this._fileSearchKey);
break;
}
this._searchbox.setAttribute("placeholder", placeholder);

Просмотреть файл

@ -310,8 +310,11 @@
noautofocus="true"
position="before_start">
<vbox>
<label id="searchbox-panel-description"
value="&debuggerUI.searchPanelTitle;"/>
<hbox>
<label id="filter-label"/>
</hbox>
<label id="searchbox-panel-operators"
value="&debuggerUI.searchPanelOperators;"/>
<hbox align="center">
<button id="global-operator-button"
class="searchbox-panel-operator-button"

Просмотреть файл

@ -106,6 +106,8 @@ MOCHITEST_BROWSER_TESTS = \
browser_dbg_source_maps-01.js \
browser_dbg_source_maps-02.js \
browser_dbg_step-out.js \
browser_dbg_event-listeners.js \
browser_dbg_break-on-dom-event.js \
head.js \
$(NULL)
@ -145,6 +147,7 @@ MOCHITEST_BROWSER_PAGES = \
test-location-changes-bp.html \
test-step-out.html \
test-pause-exceptions-reload.html \
test-event-listeners.html \
$(NULL)
# Bug 888811 & bug 891176:

Просмотреть файл

@ -0,0 +1,158 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that the break-on-dom-events request works.
var gClient = null;
var gTab = null;
var gThreadClient = null;
var gInput = null;
var gButton = null;
const DEBUGGER_TAB_URL = EXAMPLE_URL + "test-event-listeners.html";
function test()
{
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(type, traits) {
gTab = addTab(DEBUGGER_TAB_URL, function() {
attach_thread_actor_for_url(gClient,
DEBUGGER_TAB_URL,
function(threadClient) {
gThreadClient = threadClient;
gInput = content.document.querySelector("input");
gButton = content.document.querySelector("button");
testBreakOnAll();
});
});
});
}
// Test pause on all events.
function testBreakOnAll()
{
gClient.addOneTimeListener("paused", function(event, packet) {
is(packet.why.type, "debuggerStatement", "debugger statement was hit.");
// Test calling pauseOnDOMEvents from a paused state.
gThreadClient.pauseOnDOMEvents("*", function(packet) {
is(packet, undefined, "The pause-on-any-event request completed successfully.");
gClient.addOneTimeListener("paused", function(event, packet) {
is(packet.why.type, "pauseOnDOMEvents", "A hidden breakpoint was hit.");
is(packet.frame.callee.name, "keyupHandler", "The keyupHandler is entered.");
gThreadClient.resume(function() {
gClient.addOneTimeListener("paused", function(event, packet) {
is(packet.why.type, "pauseOnDOMEvents", "A hidden breakpoint was hit.");
is(packet.frame.callee.name, "clickHandler", "The clickHandler is entered.");
gThreadClient.resume(function() {
gClient.addOneTimeListener("paused", function(event, packet) {
is(packet.why.type, "pauseOnDOMEvents", "A hidden breakpoint was hit.");
is(packet.frame.callee.name, "onchange", "The onchange handler is entered.");
gThreadClient.resume(testBreakOnDisabled);
});
gInput.focus();
gInput.value = "foo";
gInput.blur();
});
});
EventUtils.sendMouseEvent({ type: "click" }, gButton);
});
});
gThreadClient.resume(function() {
gInput.focus();
EventUtils.synthesizeKey("e", {}, content);
});
});
});
EventUtils.sendMouseEvent({ type: "click" }, gButton);
}
// Test that removing events from the array disables them.
function testBreakOnDisabled()
{
// Test calling pauseOnDOMEvents from a running state.
gThreadClient.pauseOnDOMEvents(["click"], function(packet) {
is(packet.error, undefined, "The pause-on-click-only request completed successfully.");
gClient.addListener("paused", unexpectedListener);
// This non-capturing event listener is guaranteed to run after the page's
// capturing one had a chance to execute and modify window.foobar.
gInput.addEventListener("keyup", function tempHandler() {
gInput.removeEventListener("keyup", tempHandler, false);
is(content.wrappedJSObject.foobar, "keyupHandler", "No hidden breakpoint was hit.");
gClient.removeListener("paused", unexpectedListener);
testBreakOnNone();
}, false);
gInput.focus();
EventUtils.synthesizeKey("e", {}, content);
});
}
// Test that specifying an empty event array clears all hidden breakpoints.
function testBreakOnNone()
{
// Test calling pauseOnDOMEvents from a running state.
gThreadClient.pauseOnDOMEvents([], function(packet) {
is(packet.error, undefined, "The pause-on-none request completed successfully.");
gClient.addListener("paused", unexpectedListener);
// This non-capturing event listener is guaranteed to run after the page's
// capturing one had a chance to execute and modify window.foobar.
gInput.addEventListener("keyup", function tempHandler() {
gInput.removeEventListener("keyup", tempHandler, false);
is(content.wrappedJSObject.foobar, "keyupHandler", "No hidden breakpoint was hit.");
gClient.removeListener("paused", unexpectedListener);
testBreakOnClick();
}, false);
gInput.focus();
EventUtils.synthesizeKey("g", {}, content);
});
}
function unexpectedListener(event, packet, callback) {
gClient.removeListener("paused", unexpectedListener);
ok(false, "An unexpected hidden breakpoint was hit.");
gThreadClient.resume(testBreakOnClick);
}
// Test pause on a single event.
function testBreakOnClick()
{
// Test calling pauseOnDOMEvents from a running state.
gThreadClient.pauseOnDOMEvents(["click"], function(packet) {
is(packet.error, undefined, "The pause-on-click request completed successfully.");
gClient.addOneTimeListener("paused", function(event, packet) {
is(packet.why.type, "pauseOnDOMEvents", "A hidden breakpoint was hit.");
is(packet.frame.callee.name, "clickHandler", "The clickHandler is entered.");
gThreadClient.resume(function() {
gClient.close(finish);
});
});
EventUtils.sendMouseEvent({ type: "click" }, gButton);
});
}
registerCleanupFunction(function() {
removeTab(gTab);
gTab = null;
gClient = null;
gThreadClient = null;
gInput = null;
gButton = null;
});

Просмотреть файл

@ -54,35 +54,33 @@ function test() {
cmd("dbg step out", function() {
is(output.value, "step out", "debugger stepped out");
cmd("dbg continue", function() {
cmd("dbg continue", function() {
is(output.value, "dbg continue", "debugger continued");
is(output.value, "dbg continue", "debugger continued");
function closeDebugger(cb) {
helpers.audit(options, [{
setup: "dbg close",
completed: false,
exec: { output: "" }
}]);
function closeDebugger(cb) {
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.");
cb();
} else {
toolbox.on("destroyed", function () {
ok(true, "Debugger was closed.");
cb();
} else {
toolbox.on("destroyed", function () {
ok(true, "Debugger was closed.");
cb();
});
}
});
}
}
// We're closing the debugger twice to make sure
// 'dbg close' doesn't error when toolbox is already
// closed. See bug 884638 for more info.
// We're closing the debugger twice to make sure
// 'dbg close' doesn't error when toolbox is already
// closed. See bug 884638 for more info.
closeDebugger(() => {
closeDebugger(() => deferred.resolve());
});
closeDebugger(() => {
closeDebugger(() => deferred.resolve());
});
});
});

Просмотреть файл

@ -0,0 +1,91 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that the eventListeners request works.
var gClient = null;
var gTab = null;
var gThreadClient = null;
const DEBUGGER_TAB_URL = EXAMPLE_URL + "test-event-listeners.html";
function test()
{
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
gTab = addTab(DEBUGGER_TAB_URL, function() {
attach_thread_actor_for_url(gClient,
DEBUGGER_TAB_URL,
function(threadClient) {
gThreadClient = threadClient;
testEventListeners();
});
});
});
}
function testEventListeners()
{
gClient.addOneTimeListener("paused", function(aEvent, aPacket) {
is(aPacket.why.type, "debuggerStatement", "debugger statement was hit.");
gThreadClient.eventListeners(function(aPacket) {
is(aPacket.listeners.length, 4, "Found all event listeners.");
let types = [];
for (let l of aPacket.listeners) {
let node = l.node;
ok(node, "There is a node property.");
ok(node.object, "There is a node object property.");
ok(node.selector == "window" ||
content.document.querySelectorAll(node.selector).length == 1,
"The node property is a unique CSS selector");
ok(l.function, "There is a function property.");
is(l.function.type, "object", "The function form is of type 'object'.");
is(l.function.class, "Function", "The function form is of class 'Function'.");
is(l.function.url, DEBUGGER_TAB_URL, "The function url is correct.");
is(l.allowsUntrusted, true,
"allowsUntrusted property has the right value.");
is(l.inSystemEventGroup, false,
"inSystemEventGroup property has the right value.");
types.push(l.type);
if (l.type == "keyup") {
is(l.capturing, true, "Capturing property has the right value.");
is(l.isEventHandler, false,
"isEventHandler property has the right value.");
} else if (l.type == "load") {
is(l.capturing, false, "Capturing property has the right value.");
is(l.isEventHandler, false,
"isEventHandler property has the right value.");
} else {
is(l.capturing, false, "Capturing property has the right value.");
is(l.isEventHandler, true,
"isEventHandler property has the right value.");
}
}
ok(types.indexOf("click") != -1, "Found the click handler.");
ok(types.indexOf("change") != -1, "Found the change handler.");
ok(types.indexOf("keyup") != -1, "Found the keyup handler.");
finish_test();
});
});
EventUtils.sendMouseEvent({ type: "click" },
content.document.querySelector("button"));
}
function finish_test()
{
gThreadClient.resume(function() {
gClient.close(finish);
});
}
registerCleanupFunction(function() {
removeTab(gTab);
gTab = null;
gClient = null;
gThreadClient = null;
});

Просмотреть файл

@ -37,6 +37,13 @@ let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
Services.prefs.setBoolPref("devtools.debugger.log", true);
// Redeclare dbg_assert with a fatal behavior.
function dbg_assert(cond, e) {
if (!cond) {
throw e;
}
}
registerCleanupFunction(function() {
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", gEnableRemote);
Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
@ -143,11 +150,11 @@ function attach_tab_actor_for_url(aClient, aURL, aCallback) {
function attach_thread_actor_for_url(aClient, aURL, aCallback) {
attach_tab_actor_for_url(aClient, aURL, function(aTabActor, aResponse) {
aClient.attachThread(actor.threadActor, function(aResponse, aThreadClient) {
aClient.attachThread(aResponse.threadActor, function(aResponse, aThreadClient) {
// We don't care about the pause right now (use
// get_actor_for_url() if you do), so resume it.
aThreadClient.resume(function(aResponse) {
aCallback(actor);
aCallback(aThreadClient);
});
});
});

Просмотреть файл

@ -0,0 +1,37 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset='utf-8'/>
<title>Debugger Test for Event Listeners</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="text/javascript">
window.addEventListener("load", function() {
function initialSetup(event) {
debugger;
var button = document.querySelector("button");
button.onclick = clickHandler;
}
function clickHandler(event) {
window.foobar = "clickHandler";
}
function changeHandler(event) {
window.foobar = "changeHandler";
}
function keyupHandler(event) {
window.foobar = "keyupHandler";
}
var button = document.querySelector("button");
button.onclick = initialSetup;
var input = document.querySelector("input");
input.addEventListener("keyup", keyupHandler, true);
window.changeHandler = changeHandler;
});
</script>
</head>
<body>
<button>Click me!</button>
<input type="text" onchange="changeHandler()">
</body>
</html>

Просмотреть файл

@ -22,6 +22,7 @@ MOCHITEST_BROWSER_FILES = \
browser_toolbox_tool_ready.js \
browser_toolbox_sidebar.js \
browser_toolbox_window_shortcuts.js \
browser_toolbox_tabsswitch_shortcuts.js \
browser_toolbox_window_title_changes.js \
browser_toolbox_options.js \
browser_toolbox_options_disablejs.js \

Просмотреть файл

@ -0,0 +1,88 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
let Toolbox = devtools.Toolbox;
let toolbox, toolIDs, idIndex, secondTime = false,
reverse = false, nextKey = null, prevKey = null;
function test() {
waitForExplicitFinish();
addTab("about:blank", function() {
toolIDs = [tool.id for (tool of gDevTools.getToolDefinitionArray())];
let target = TargetFactory.forTab(gBrowser.selectedTab);
idIndex = 0;
gDevTools.showToolbox(target, toolIDs[0], Toolbox.HostType.BOTTOM)
.then(testShortcuts);
});
}
function testShortcuts(aToolbox, aIndex) {
if (aIndex == toolIDs.length) {
aIndex = 0;
if (secondTime) {
secondTime = false;
reverse = true;
aIndex = toolIDs.length - 2;
}
else {
secondTime = true;
}
}
else if (aIndex == -1) {
aIndex = toolIDs.length - 1;
if (secondTime) {
tidyUp();
return;
}
secondTime = true;
}
toolbox = aToolbox;
if (!nextKey) {
nextKey = toolbox.doc.getElementById("toolbox-next-tool-key")
.getAttribute("key");
prevKey = toolbox.doc.getElementById("toolbox-previous-tool-key")
.getAttribute("key");
}
info("Toolbox fired a `ready` event");
toolbox.once("select", onSelect);
if (aIndex != null) {
// This if block is to allow the call of onSelect without shortcut press for
// the first time. That happens because on opening of toolbox, one tool gets
// selected atleast.
let key = (reverse ? prevKey: nextKey);
let modifiers = {
accelKey: true
};
idIndex = aIndex;
info("Testing shortcut to switch to tool " + aIndex + ":" + toolIDs[aIndex] +
" using key " + key);
EventUtils.synthesizeKey(key, modifiers, toolbox.doc.defaultView);
}
}
function onSelect(event, id) {
info("toolbox-select event from " + id);
is(toolIDs.indexOf(id), idIndex,
"Correct tool is selected on pressing the shortcut for " + id);
// Execute soon to reset the stack trace.
executeSoon(() => {
testShortcuts(toolbox, idIndex + (reverse ? -1: 1));
});
}
function tidyUp() {
toolbox.destroy().then(function() {
gBrowser.removeCurrentTab();
toolbox = toolIDs = idIndex = Toolbox = secondTime = reverse = nextKey =
prevKey = null;
finish();
});
}

Просмотреть файл

@ -17,8 +17,7 @@ function test() {
addTab("about:blank", function() {
toolIDs = [];
for (let [id, definition] of gDevTools._tools) {
// Skipping Profiler due to bug 838069. Re-enable when bug 845752 is fixed
if (definition.key && id != "jsprofiler") {
if (definition.key) {
toolIDs.push(id);
}
}

Просмотреть файл

@ -207,6 +207,7 @@ Toolbox.prototype = {
this._buildTabs();
this._buildButtons();
this._addKeysToWindow();
this._addToolSwitchingKeys();
this._telemetry.toolOpened("toolbox");
@ -230,6 +231,13 @@ Toolbox.prototype = {
}.bind(this, "options"), true);
},
_addToolSwitchingKeys: function TBOX__addToolSwitchingKeys() {
let nextKey = this.doc.getElementById("toolbox-next-tool-key");
nextKey.addEventListener("command", this.selectNextTool.bind(this), true);
let prevKey = this.doc.getElementById("toolbox-previous-tool-key");
prevKey.addEventListener("command", this.selectPreviousTool.bind(this), true);
},
/**
* Adds the keys and commands to the Toolbox Window in window mode.
*/
@ -539,6 +547,26 @@ Toolbox.prototype = {
});
},
/**
* Loads the tool next to the currently selected tool.
*/
selectNextTool: function TBOX_selectNextTool() {
let selected = this.doc.querySelector(".devtools-tab[selected]");
let next = selected.nextSibling || selected.parentNode.firstChild;
let tool = next.getAttribute("toolid");
return this.selectTool(tool);
},
/**
* Loads the tool just left to the currently selected tool.
*/
selectPreviousTool: function TBOX_selectPreviousTool() {
let selected = this.doc.querySelector(".devtools-tab[selected]");
let previous = selected.previousSibling || selected.parentNode.lastChild;
let tool = previous.getAttribute("toolid");
return this.selectTool(tool);
},
/**
* Highlights the tool's tab if it is not the currently selected tool.
*
@ -744,7 +772,7 @@ Toolbox.prototype = {
gDevTools.off("tool-registered", this._toolRegistered);
gDevTools.off("tool-unregistered", this._toolUnregistered);
// Revert docShell.allowJavascript back to it's original value if it was
// Revert docShell.allowJavascript back to its original value if it was
// changed via the Disable JS option.
if (typeof this._origAllowJavascript != "undefined") {
let docShell = this._host.hostTab.linkedBrowser.docShell;
@ -755,7 +783,12 @@ Toolbox.prototype = {
let outstanding = [];
for (let [id, panel] of this._toolPanels) {
outstanding.push(panel.destroy());
try {
outstanding.push(panel.destroy());
} catch(e) {
// We don't want to stop here if any panel fail to close.
console.error(e);
}
}
let container = this.doc.getElementById("toolbox-buttons");

Просмотреть файл

@ -23,6 +23,14 @@
key="&toolboxOptionsButton.key;"
oncommand="void(0);"
modifiers="shift, accel"/>
<key id="toolbox-next-tool-key"
key="&toolboxNextTool.key;"
oncommand="void(0);"
modifiers="accel"/>
<key id="toolbox-previous-tool-key"
key="&toolboxPreviousTool.key;"
oncommand="void(0);"
modifiers="accel"/>
</keyset>
<notificationbox id="toolbox-notificationbox" flex="1">

Просмотреть файл

@ -229,6 +229,13 @@ Highlighter.prototype = {
*/
invalidateSize: function Highlighter_invalidateSize()
{
let canHiglightNode = this.selection.isNode() &&
this.selection.isConnected() &&
this.selection.isElementNode();
if (!canHiglightNode)
return;
// The highlighter runs locally while the selection runs remotely,
// so we can't quite trust the selection's isConnected to protect us
// here, do the check manually.
@ -238,13 +245,6 @@ Highlighter.prototype = {
return;
}
let canHiglightNode = this.selection.isNode() &&
this.selection.isConnected() &&
this.selection.isElementNode();
if (!canHiglightNode)
return;
let clientRect = this.selection.node.getBoundingClientRect();
let rect = LayoutHelpers.getDirtyRect(this.selection.node);
this.highlightRectangle(rect);

Просмотреть файл

@ -141,7 +141,7 @@ InspectorPanel.prototype = {
this.highlighter.unlock();
}
this.markup.expandNode(this.selection.node);
this.markup.expandNode(this.selection.nodeFront);
this.emit("ready");
deferred.resolve(this);
@ -157,14 +157,24 @@ InspectorPanel.prototype = {
* Return a promise that will resolve to the default node for selection.
*/
_getDefaultNodeForSelection : function() {
if (this._defaultNode) {
return this._defaultNode;
}
let walker = this.walker;
// if available set body node as default selected node
// else set documentElement
return this.walker.querySelector(this.walker.rootNode, "body").then(front => {
return walker.querySelector(this.walker.rootNode, "body").then(front => {
if (front) {
return front;
}
return this.walker.documentElement(this.walker.rootNode);
});
}).then(node => {
if (walker !== this.walker) {
promise.reject(null);
}
this._defaultNode = node;
return node;
})
},
/**
@ -214,18 +224,19 @@ InspectorPanel.prototype = {
} else if (this.target.window) {
searchDoc = this.target.window.document;
} else {
return;
searchDoc = null;
}
// Initiate the selectors search object.
let setNodeFunction = function(node) {
this.selection.setNode(node, "selectorsearch");
let setNodeFunction = function(eventName, node) {
this.selection.setNodeFront(node, "selectorsearch");
}.bind(this);
if (this.searchSuggestions) {
this.searchSuggestions.destroy();
this.searchSuggestions = null;
}
this.searchBox = this.panelDoc.getElementById("inspector-searchbox");
this.searchSuggestions = new SelectorSearch(searchDoc, this.searchBox, setNodeFunction);
this.searchSuggestions = new SelectorSearch(this, searchDoc, this.searchBox);
this.searchSuggestions.on("node-selected", setNodeFunction);
},
/**
@ -276,6 +287,7 @@ InspectorPanel.prototype = {
let newWindow = payload._navPayload || payload;
this.walker.release().then(null, console.error);
this.walker = null;
this._defaultNode = null;
this.selection.setNodeFront(null);
this.selection.setWalker(null);
this._destroyMarkup();
@ -297,7 +309,7 @@ InspectorPanel.prototype = {
this._initMarkup();
this.once("markuploaded", () => {
this.markup.expandNode(this.selection.node);
this.markup.expandNode(this.selection.nodeFront);
this.setupSearchBox();
});
});
@ -391,7 +403,7 @@ InspectorPanel.prototype = {
onDetached: function InspectorPanel_onDetached(event, parentNode) {
this.cancelLayoutChange();
this.breadcrumbs.cutAfter(this.breadcrumbs.indexOf(parentNode));
this.selection.setNodeFront(parentNode, "detached");
this.selection.setNodeFront(parentNode ? parentNode : this._defaultNode, "detached");
},
/**
@ -624,10 +636,7 @@ InspectorPanel.prototype = {
if (!this.selection.isNode()) {
return;
}
let toCopy = this.selection.node.innerHTML;
if (toCopy) {
clipboardHelper.copyString(toCopy);
}
this._copyLongStr(this.walker.innerHTML(this.selection.nodeFront));
},
/**
@ -638,10 +647,17 @@ InspectorPanel.prototype = {
if (!this.selection.isNode()) {
return;
}
let toCopy = this.selection.node.outerHTML;
if (toCopy) {
clipboardHelper.copyString(toCopy);
}
this._copyLongStr(this.walker.outerHTML(this.selection.nodeFront));
},
_copyLongStr: function(promise) {
return promise.then(longstr => {
return longstr.string().then(toCopy => {
longstr.release().then(null, console.error);
clipboardHelper.copyString(toCopy);
});
}).then(null, console.error);
},
/**
@ -668,17 +684,13 @@ InspectorPanel.prototype = {
return;
}
let toDelete = this.selection.node;
let parent = this.selection.node.parentNode;
// If the markup panel is active, use the markup panel to delete
// the node, making this an undoable action.
if (this.markup) {
this.markup.deleteNode(toDelete);
this.markup.deleteNode(this.selection.nodeFront);
} else {
// remove the node from content
parent.removeChild(toDelete);
this.walker.removeNode(this.selection.nodeFront);
}
},

Просмотреть файл

@ -5,6 +5,8 @@
"use strict";
const {Cu} = require("chrome");
const EventEmitter = require("devtools/shared/event-emitter");
const promise = require("sdk/core/promise");
loader.lazyGetter(this, "AutocompletePopup", () => {
return Cu.import("resource:///modules/devtools/AutocompletePopup.jsm", {}).AutocompletePopup;
@ -17,18 +19,19 @@ const MAX_SUGGESTIONS = 15;
* Converts any input box on a page to a CSS selector search and suggestion box.
*
* @constructor
* @param InspectorPanel aInspector
* The InspectorPanel whose `walker` attribute should be used for
* document traversal.
* @param nsIDOMDocument aContentDocument
* The content document which inspector is attached to.
* The content document which inspector is attached to, or null if
* a remote document.
* @param nsiInputElement aInputNode
* The input element to which the panel will be attached and from where
* search input will be taken.
* @param Function aCallback
* The method to callback when a search is available.
* This method is called with the matched node as the first argument.
*/
function SelectorSearch(aContentDocument, aInputNode, aCallback) {
function SelectorSearch(aInspector, aContentDocument, aInputNode) {
this.inspector = aInspector;
this.doc = aContentDocument;
this.callback = aCallback;
this.searchBox = aInputNode;
this.panelDoc = this.searchBox.ownerDocument;
@ -62,12 +65,20 @@ function SelectorSearch(aContentDocument, aInputNode, aCallback) {
// event listeners.
this.searchBox.addEventListener("command", this._onHTMLSearch, true);
this.searchBox.addEventListener("keypress", this._onSearchKeypress, true);
// For testing, we need to be able to wait for the most recent node request
// to finish. Tests can watch this promise for that.
this._lastQuery = promise.resolve(null);
EventEmitter.decorate(this);
}
exports.SelectorSearch = SelectorSearch;
SelectorSearch.prototype = {
get walker() this.inspector.walker,
// The possible states of the query.
States: {
CLASS: "class",
@ -168,7 +179,13 @@ SelectorSearch.prototype = {
this.panelDoc = null;
this._searchResults = null;
this._searchSuggestions = null;
this.callback = null;
EventEmitter.decorate(this);
},
_selectResult: function(index) {
return this._searchResults.item(index).then(node => {
this.emit("node-selected", node);
});
},
/**
@ -181,6 +198,7 @@ SelectorSearch.prototype = {
return;
}
this._lastSearched = query;
this._searchResults = null;
this._searchIndex = 0;
if (query.length == 0) {
@ -194,54 +212,68 @@ SelectorSearch.prototype = {
}
this.searchBox.setAttribute("filled", true);
try {
this._searchResults = this.doc.querySelectorAll(query);
}
catch (ex) {
this._searchResults = [];
}
if (this._searchResults.length > 0) {
this._lastValidSearch = query;
// Even though the selector matched atleast one node, there is still
// possibility of suggestions.
if (query.match(/[\s>+]$/)) {
// If the query has a space or '>' at the end, create a selector to match
// the children of the selector inside the search box by adding a '*'.
this._lastValidSearch += "*";
}
else if (query.match(/[\s>+][\.#a-zA-Z][\.#>\s+]*$/)) {
// If the query is a partial descendant selector which does not matches
// any node, remove the last incomplete part and add a '*' to match
// everything. For ex, convert 'foo > b' to 'foo > *' .
let lastPart = query.match(/[\s>+][\.#a-zA-Z][^>\s+]*$/)[0];
this._lastValidSearch = query.slice(0, -1 * lastPart.length + 1) + "*";
let queryList = null;
this._lastQuery = this.walker.querySelectorAll(this.walker.rootNode, query).then(list => {
return list;
}, (err) => {
// Failures are ok here, just use a null item list;
return null;
}).then(queryList => {
// Value has changed since we started this request, we're done.
if (query != this.searchBox.value) {
if (queryList) {
queryList.release();
}
return promise.reject(null);
}
if (!query.slice(-1).match(/[\.#\s>+]/)) {
// Hide the popup if we have some matching nodes and the query is not
// ending with [.# >] which means that the selector is not at the
// beginning of a new class, tag or id.
if (this.searchPopup.isOpen) {
this.searchPopup.hidePopup();
this._searchResults = queryList;
if (this._searchResults && this._searchResults.length > 0) {
this._lastValidSearch = query;
// Even though the selector matched atleast one node, there is still
// possibility of suggestions.
if (query.match(/[\s>+]$/)) {
// If the query has a space or '>' at the end, create a selector to match
// the children of the selector inside the search box by adding a '*'.
this._lastValidSearch += "*";
}
else if (query.match(/[\s>+][\.#a-zA-Z][\.#>\s+]*$/)) {
// If the query is a partial descendant selector which does not matches
// any node, remove the last incomplete part and add a '*' to match
// everything. For ex, convert 'foo > b' to 'foo > *' .
let lastPart = query.match(/[\s>+][\.#a-zA-Z][^>\s+]*$/)[0];
this._lastValidSearch = query.slice(0, -1 * lastPart.length + 1) + "*";
}
if (!query.slice(-1).match(/[\.#\s>+]/)) {
// Hide the popup if we have some matching nodes and the query is not
// ending with [.# >] which means that the selector is not at the
// beginning of a new class, tag or id.
if (this.searchPopup.isOpen) {
this.searchPopup.hidePopup();
}
}
else {
this.showSuggestions();
}
this.searchBox.classList.remove("devtools-no-search-result");
return this._selectResult(0);
}
else {
if (query.match(/[\s>+]$/)) {
this._lastValidSearch = query + "*";
}
else if (query.match(/[\s>+][\.#a-zA-Z][\.#>\s+]*$/)) {
let lastPart = query.match(/[\s+>][\.#a-zA-Z][^>\s+]*$/)[0];
this._lastValidSearch = query.slice(0, -1 * lastPart.length + 1) + "*";
}
this.searchBox.classList.add("devtools-no-search-result");
this.showSuggestions();
}
this.searchBox.classList.remove("devtools-no-search-result");
this.callback(this._searchResults[0]);
}
else {
if (query.match(/[\s>+]$/)) {
this._lastValidSearch = query + "*";
}
else if (query.match(/[\s>+][\.#a-zA-Z][\.#>\s+]*$/)) {
let lastPart = query.match(/[\s+>][\.#a-zA-Z][^>\s+]*$/)[0];
this._lastValidSearch = query.slice(0, -1 * lastPart.length + 1) + "*";
}
this.searchBox.classList.add("devtools-no-search-result");
this.showSuggestions();
}
return undefined;
});
},
/**
@ -252,7 +284,7 @@ SelectorSearch.prototype = {
switch(aEvent.keyCode) {
case aEvent.DOM_VK_ENTER:
case aEvent.DOM_VK_RETURN:
if (query == this._lastSearched) {
if (query == this._lastSearched && this._searchResults) {
this._searchIndex = (this._searchIndex + 1) % this._searchResults.length;
}
else {
@ -315,8 +347,8 @@ SelectorSearch.prototype = {
aEvent.preventDefault();
aEvent.stopPropagation();
if (this._searchResults.length > 0) {
this.callback(this._searchResults[this._searchIndex]);
if (this._searchResults && this._searchResults.length > 0) {
this._lastQuery = this._selectResult(this._searchIndex);
}
},
@ -442,6 +474,9 @@ SelectorSearch.prototype = {
* searchbox.
*/
showSuggestions: function SelectorSearch_showSuggestions() {
if (!this.walker.isLocal()) {
return;
}
let query = this.searchBox.value;
if (this._lastValidSearch != "" &&
this._lastToLastValidSearch != this._lastValidSearch) {

Просмотреть файл

@ -43,6 +43,7 @@ MOCHITEST_BROWSER_FILES := \
browser_inspector_bug_831693_search_suggestions.html \
browser_inspector_bug_835722_infobar_reappears.js \
browser_inspector_bug_840156_destroy_after_navigation.js \
browser_inspector_reload.js \
head.js \
$(NULL)

Просмотреть файл

@ -68,6 +68,7 @@ function test()
{
inspector = aInspector;
inspector.selection.setNode($("b1"));
searchBox =
inspector.panelWin.document.getElementById("inspector-searchbox");
@ -95,15 +96,18 @@ function test()
if (event.type == "keypress" && keypressStates.indexOf(state) == -1) {
return;
}
executeSoon(function() {
let [key, id, isValid] = keyStates[state];
info(inspector.selection.node.id + " is selected with text " +
inspector.searchBox.value);
is(inspector.selection.node, $(id),
"Correct node is selected for state " + state);
is(!searchBox.classList.contains("devtools-no-search-result"), isValid,
"Correct searchbox result state for state " + state);
checkStateAndMoveOn(state + 1);
inspector.searchSuggestions._lastQuery.then(() => {
executeSoon(() => {
let [key, id, isValid] = keyStates[state];
info(inspector.selection.node.id + " is selected with text " +
inspector.searchBox.value);
is(inspector.selection.node, $(id),
"Correct node is selected for state " + state);
is(!searchBox.classList.contains("devtools-no-search-result"), isValid,
"Correct searchbox result state for state " + state);
checkStateAndMoveOn(state + 1);
});
});
}

Просмотреть файл

@ -27,20 +27,21 @@ function test()
{
inspector = aInspector;
inspector.selection.setNode(node);
inspector.once("inspector-updated", () => {
let parentNode = node.parentNode;
parentNode.removeChild(node);
let parentNode = node.parentNode;
parentNode.removeChild(node);
let tmp = {};
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm", tmp);
ok(!tmp.LayoutHelpers.isNodeConnected(node), "Node considered as disconnected.");
let tmp = {};
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm", tmp);
ok(!tmp.LayoutHelpers.isNodeConnected(node), "Node considered as disconnected.");
// Wait for the selection to process the mutation
inspector.walker.on("mutations", () => {
is(inspector.selection.node, parentNode, "parent of selection got selected");
finishUp();
// Wait for the inspector to process the mutation
inspector.once("inspector-updated", () => {
is(inspector.selection.node, parentNode, "parent of selection got selected");
finishUp();
});
});
}
};
function finishUp() {
node = null;

Просмотреть файл

@ -60,6 +60,7 @@ function test()
function startTest(aInspector)
{
inspector = aInspector;
searchBox =
inspector.panelWin.document.getElementById("inspector-searchbox");
popup = inspector.searchSuggestions.searchPopup;
@ -85,7 +86,7 @@ function test()
}
function checkState(event) {
executeSoon(function() {
inspector.searchSuggestions._lastQuery.then(() => {
let [key, suggestions] = keyStates[state];
let actualSuggestions = popup.getItems();
is(popup._panel.state == "open" || popup._panel.state == "showing"

Просмотреть файл

@ -87,7 +87,7 @@ function test()
}
function checkState(event) {
executeSoon(function() {
inspector.searchSuggestions._lastQuery.then(() => {
let [key, suggestions] = keyStates[state];
let actualSuggestions = popup.getItems();
is(popup._panel.state == "open" || popup._panel.state == "showing"

Просмотреть файл

@ -72,10 +72,13 @@ function testHighlighter(node)
is(getHighlitNode(), node, "Right node is highlighted");
}
let callNo = 0;
function testMarkupView(node)
{
let i = getActiveInspector();
is(i.markup._selectedContainer.node, node, "Right node is selected in the markup view");
try {
is(i.markup._selectedContainer.node.rawNode(), node, "Right node is selected in the markup view");
} catch(ex) { console.error(ex); }
}
function testBreadcrumbs(node)
@ -91,7 +94,15 @@ function _clickOnInspectMenuItem(node) {
document.popupNode = node;
var contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
var contextMenu = new nsContextMenu(contentAreaContextMenu);
return contextMenu.inspectNode();
var promise = devtools.require("sdk/core/promise");
var deferred = promise.defer();
contextMenu.inspectNode().then(() => {
let i = getActiveInspector();
i.once("inspector-updated", () => {
deferred.resolve(undefined);
});
});
return deferred.promise;
}
function runContextMenuTest()

Просмотреть файл

@ -53,21 +53,23 @@ function test() {
function checkElementMenuItems() {
info("Checking context menu entries for p tag");
inspector.selection.setNode(doc.querySelector("p"));
let tag = getMarkupTagNodeContaining("p");
inspector.once("inspector-updated", () => {
let tag = getMarkupTagNodeContaining("p");
// Right-click p tag
contextMenuClick(tag);
// Right-click p tag
contextMenuClick(tag);
checkEnabled("node-menu-copyinner");
checkEnabled("node-menu-copyouter");
checkEnabled("node-menu-copyuniqueselector");
checkEnabled("node-menu-delete");
checkEnabled("node-menu-copyinner");
checkEnabled("node-menu-copyouter");
checkEnabled("node-menu-copyuniqueselector");
checkEnabled("node-menu-delete");
for (let name of ["hover", "active", "focus"]) {
checkEnabled("node-menu-pseudo-" + name);
}
for (let name of ["hover", "active", "focus"]) {
checkEnabled("node-menu-pseudo-" + name);
}
testCopyInnerMenu();
testCopyInnerMenu();
});
}
function testCopyInnerMenu() {
@ -101,7 +103,7 @@ function test() {
let deleteNode = inspector.panelDoc.getElementById("node-menu-delete");
ok(deleteNode, "the popup menu has a delete menu item");
inspector.selection.once("detached", deleteTest);
inspector.once("markupmutation", deleteTest);
let commandEvent = document.createEvent("XULCommandEvent");
commandEvent.initCommandEvent("command", true, true, window, 0, false, false,

Просмотреть файл

@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
function test() {
let inspector, toolbox;
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
waitForFocus(function() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
startInspectorTests(toolbox);
}).then(null, console.error);
}, content);
}, true);
content.location = "data:text/html,<p>p</p>";
function startInspectorTests(aToolbox)
{
toolbox = aToolbox;
inspector = toolbox.getCurrentPanel();
info("Inspector started");
let p = content.document.querySelector("p");
inspector.selection.setNode(p);
inspector.once("inspector-updated", () => {
is(inspector.selection.node, p, "Node selected.");
inspector.once("markuploaded", onReload);
content.location.reload();
});
}
function onReload() {
info("Page reloaded");
let p = content.document.querySelector("p");
inspector.selection.setNode(p);
inspector.once("inspector-updated", () => {
is(inspector.selection.node, p, "Node re-selected.");
toolbox.destroy();
gBrowser.removeCurrentTab();
finish();
});
}
}

Просмотреть файл

@ -18,6 +18,15 @@ ul.children:not([expanded]) {
display: inline-block;
width: 1em;
height: 1ex;
margin-right: -1em;
}
.newattr:focus {
margin-right: 0;
}
.closing-bracket {
pointer-events: none;
}
.summary {
@ -28,10 +37,6 @@ ul.children:not([expanded]) {
display: none;
}
#root {
margin-right: 80px;
}
/* Preview */
#previewbar {

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -23,7 +23,7 @@
<li id="template-more-nodes" class="more-nodes devtools-class-comment" save="${elt}"><span>${showing}</span> <button href="#" onclick="${allButtonClick}">${showAll}</button></li>
</ul>
<span id="template-element" save="${elt}" class="editor"><span>&lt;</span><span save="${tag}" class="tagname theme-fg-color3"></span><span save="${attrList}"></span><span save="${newAttr}" class="newattr" tabindex="0"></span>&gt;</span>
<span id="template-element" save="${elt}" class="editor"><span>&lt;</span><span save="${tag}" class="tagname theme-fg-color3"></span><span save="${attrList}"></span><span save="${newAttr}" class="newattr" tabindex="0"></span><span class="closing-bracket">&gt;</span></span>
<span id="template-attribute" save="${attr}" data-attr="${attrName}" class="attreditor" style="display:none"> <span class="editable" save="${inner}" tabindex="0"><span save="${name}" class="attrname theme-fg-color2"></span>=&quot;<span save="${val}" class="attrvalue theme-fg-color6"></span>&quot;</span></span>

Просмотреть файл

@ -78,7 +78,7 @@ function test() {
},
execute: function(after) {
inspector.once("markupmutation", after);
let editor = markup.getContainer(doc.querySelector("#node1")).editor;
let editor = getContainerForRawNode(markup, doc.querySelector("#node1")).editor;
let attr = editor.attrs["class"].querySelector(".editable");
editField(attr, 'class="changednode1"');
},
@ -89,7 +89,6 @@ function test() {
});
}
},
{
desc: 'Try changing an attribute to a quote (") - this should result ' +
'in it being set to an empty string',
@ -100,10 +99,10 @@ function test() {
});
},
execute: function(after) {
let editor = markup.getContainer(doc.querySelector("#node22")).editor;
let editor = getContainerForRawNode(markup, doc.querySelector("#node22")).editor;
let attr = editor.attrs["class"].querySelector(".editable");
editField(attr, 'class="""');
executeSoon(after);
inspector.once("markupmutation", after);
},
after: function() {
assertAttributes(doc.querySelector("#node22"), {
@ -123,7 +122,7 @@ function test() {
},
execute: function(after) {
inspector.once("markupmutation", after);
let editor = markup.getContainer(doc.querySelector("#node4")).editor;
let editor = getContainerForRawNode(markup, doc.querySelector("#node4")).editor;
let attr = editor.attrs["class"].querySelector(".editable");
editField(attr, '');
},
@ -143,7 +142,7 @@ function test() {
},
execute: function(after) {
inspector.once("markupmutation", after);
let editor = markup.getContainer(doc.querySelector("#node14")).editor;
let editor = getContainerForRawNode(markup, doc.querySelector("#node14")).editor;
let attr = editor.newAttr;
editField(attr, 'class="newclass" style="color:green"');
},
@ -166,10 +165,10 @@ function test() {
});
},
execute: function(after) {
let editor = markup.getContainer(doc.querySelector("#node23")).editor;
let editor = getContainerForRawNode(markup, doc.querySelector("#node23")).editor;
let attr = editor.newAttr;
editField(attr, 'class="newclass" style="""');
executeSoon(after);
inspector.once("markupmutation", after);
},
after: function() {
assertAttributes(doc.querySelector("#node23"), {
@ -188,10 +187,10 @@ function test() {
});
},
execute: function(after) {
let editor = markup.getContainer(doc.querySelector("#node24")).editor;
let editor = getContainerForRawNode(markup, doc.querySelector("#node24")).editor;
let attr = editor.attrs["id"].querySelector(".editable");
editField(attr, attr.textContent + ' class="""');
executeSoon(after);
inspector.once("markupmutation", after);
},
after: function() {
assertAttributes(doc.querySelector("#node24"), {
@ -210,7 +209,7 @@ function test() {
execute: function(after) {
inspector.once("markupmutation", after);
let node = doc.querySelector('.node6').firstChild;
let editor = markup.getContainer(node).editor;
let editor = getContainerForRawNode(markup, node).editor;
let field = editor.elt.querySelector("pre");
editField(field, "New text");
},
@ -229,7 +228,7 @@ function test() {
},
execute: function(after) {
inspector.once("markupmutation", after);
let editor = markup.getContainer(doc.querySelector("#node25")).editor;
let editor = getContainerForRawNode(markup, doc.querySelector("#node25")).editor;
let attr = editor.newAttr;
editField(attr, 'src="somefile.html?param1=<a>&param2=&uuml;"bl\'ah"');
},
@ -260,40 +259,44 @@ function test() {
}
function startTests() {
let startNode = doc.documentElement.cloneNode();
markup = inspector.markup;
markup.expandAll();
markup.expandAll().then(() => {
let cursor = 0;
let cursor = 0;
function nextEditTest() {
executeSoon(function() {
if (cursor >= edits.length) {
addAttributes();
} else {
let step = edits[cursor++];
info("START " + step.desc);
if (step.setup) {
step.setup();
}
step.before();
info("before execute");
step.execute(function() {
info("after execute");
step.after();
ok(markup.undo.canUndo(), "Should be able to undo.");
markup.undo.undo();
function nextEditTest() {
executeSoon(function() {
if (cursor >= edits.length) {
addAttributes();
} else {
let step = edits[cursor++];
info("START " + step.desc);
if (step.setup) {
step.setup();
}
step.before();
ok(markup.undo.canRedo(), "Should be able to redo.");
markup.undo.redo();
step.after();
info("END " + step.desc);
nextEditTest();
});
}
});
}
nextEditTest();
info("before execute");
step.execute(function() {
info("after execute");
step.after();
ok(markup.undo.canUndo(), "Should be able to undo.");
markup.undo.undo();
inspector.once("markupmutation", () => {
step.before();
ok(markup.undo.canRedo(), "Should be able to redo.");
markup.undo.redo();
inspector.once("markupmutation", () => {
step.after();
info("END " + step.desc);
nextEditTest();
});
});
});
}
});
}
nextEditTest();
});
}
function addAttributes() {
@ -307,11 +310,8 @@ function test() {
id: "node18",
});
/**
* XXX: disabled until the remote markup view is enabled
* is(inspector.highlighter.nodeInfo.classesBox.textContent, "",
* "No classes in the infobar before edit.");
*/
is(inspector.highlighter.nodeInfo.classesBox.textContent, "",
"No classes in the infobar before edit.");
},
execute: function(after) {
inspector.once("markupmutation", function() {
@ -319,7 +319,7 @@ function test() {
// not just the markupview (which happens in this event loop)
executeSoon(after);
});
let editor = markup.getContainer(doc.querySelector("#node18")).editor;
let editor = getContainerForRawNode(markup, doc.querySelector("#node18")).editor;
let attr = editor.attrs["id"].querySelector(".editable");
editField(attr, attr.textContent + ' class="newclass" style="color:green"');
},
@ -330,11 +330,8 @@ function test() {
style: "color:green"
});
/**
* XXX: disabled until the remote markup view is enabled
*is(inspector.highlighter.nodeInfo.classesBox.textContent, ".newclass",
* "Correct classes in the infobar after edit.");
*/
is(inspector.highlighter.nodeInfo.classesBox.textContent, ".newclass",
"Correct classes in the infobar after edit.");
}
};
testAsyncSetup(test, editTagName);
@ -348,7 +345,7 @@ function test() {
},
before: function() {
let node = doc.querySelector("#retag-me");
let container = markup.getContainer(node);
let container = getContainerForRawNode(markup, node);
is(node.tagName, "DIV", "retag-me should be a div.");
ok(container.selected, "retag-me should be selected.");
@ -359,13 +356,13 @@ function test() {
execute: function(after) {
inspector.once("markupmutation", after);
let node = doc.querySelector("#retag-me");
let editor = markup.getContainer(node).editor;
let editor = getContainerForRawNode(markup, node).editor;
let field = editor.tag;
editField(field, "p");
},
after: function() {
let node = doc.querySelector("#retag-me");
let container = markup.getContainer(node);
let container = getContainerForRawNode(markup, node);
is(node.tagName, "P", "retag-me should be a p.");
ok(container.selected, "retag-me should be selected.");
ok(container.expanded, "retag-me should be expanded.");
@ -399,10 +396,12 @@ function test() {
info("START " + test.desc);
test.before();
inspector.selection.once("new-node", function BIMET_testAsyncExecNewNode() {
inspector.once("inspector-updated", function BIMET_testAsyncExecNewNode() {
test.executeCont();
test.after();
undoRedo(test, callback);
inspector.once("markupmutation", () => {
test.after();
undoRedo(test, callback);
});
});
executeSoon(function BIMET_setNode1() {
test.execute();
@ -412,7 +411,7 @@ function test() {
function testAsyncSetup(test, callback) {
info("START " + test.desc);
inspector.selection.once("new-node", function BIMET_testAsyncSetupNewNode() {
inspector.once("inspector-updated", function BIMET_testAsyncSetupNewNode() {
test.before();
test.execute(function() {
test.after();
@ -427,11 +426,11 @@ function test() {
function undoRedo(test, callback) {
ok(markup.undo.canUndo(), "Should be able to undo.");
markup.undo.undo();
executeSoon(function() {
inspector.once("markupmutation", () => {
test.before();
ok(markup.undo.canRedo(), "Should be able to redo.");
markup.undo.redo();
executeSoon(function() {
inspector.once("markupmutation", () => {
test.after();
info("END " + test.desc);
callback();

Просмотреть файл

@ -10,6 +10,10 @@ http://creativecommons.org/publicdomain/zero/1.0/ */
* - Compare it to the real dom with isEqualNode.
*/
function fail(err) {
ok(false, err)
}
function test() {
waitForExplicitFinish();
@ -45,10 +49,13 @@ function test() {
// Verify that the markup in the tool is the same as the markup in the document.
function checkMarkup()
{
markup.expandAll();
return markup.expandAll().then(checkMarkup2);
}
function checkMarkup2()
{
let contentNode = doc.querySelector("body");
let panelNode = markup._containers.get(contentNode).elt;
let panelNode = getContainerForRawNode(markup, contentNode).elt;
let parseNode = parseDoc.querySelector("body");
// Grab the text from the markup panel...
@ -154,8 +161,9 @@ function test() {
function startTests() {
markup = inspector.markup;
checkMarkup();
nextStep(0);
checkMarkup().then(() => {
nextStep(0);
}).then(null, fail);
}
function nextStep(cursor) {
@ -166,8 +174,9 @@ function test() {
mutations[cursor]();
inspector.once("markupmutation", function() {
executeSoon(function() {
checkMarkup();
nextStep(cursor + 1);
checkMarkup().then(() => {
nextStep(cursor + 1);
}).then(null, fail);
});
});
}

Просмотреть файл

@ -84,7 +84,7 @@ function test() {
var target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
inspector = toolbox.getCurrentPanel();
startNavigation();
inspector.once("inspector-updated", startNavigation);
});
}
@ -126,7 +126,7 @@ function test() {
break;
}
executeSoon(function BIMNT_newNode() {
inspector.markup._waitForChildren().then(() => executeSoon(function BIMNT_newNode() {
let node = inspector.selection.node;
if (className == "*comment*") {
@ -140,7 +140,7 @@ function test() {
}
nextStep(cursor + 1);
});
}));
}
function finishUp() {

Просмотреть файл

@ -25,7 +25,7 @@ function test() {
function assertChildren(expected)
{
let container = markup.getContainer(doc.querySelector("body"));
let container = getContainerForRawNode(markup, doc.querySelector("body"));
let found = [];
for (let child of container.children.children) {
if (child.classList.contains("more-nodes")) {
@ -34,16 +34,24 @@ function test() {
found += child.container.node.getAttribute("id");
}
}
is(expected, found, "Got the expected children.");
is(found, expected, "Got the expected children.");
}
function forceReload()
{
let container = markup.getContainer(doc.querySelector("body"));
let container = getContainerForRawNode(markup, doc.querySelector("body"));
container.childrenDirty = true;
}
let selections = [
{
desc: "Select the last item",
selector: "#z",
before: function() {},
after: function() {
assertChildren("*more*vwxyz");
}
},
{
desc: "Select the first item",
selector: "#a",
@ -97,18 +105,9 @@ function test() {
function setupTest() {
var target = TargetFactory.forTab(gBrowser.selectedTab);
let toolbox = gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
toolbox.once("inspector-selected", function SE_selected(id, aInspector) {
inspector = aInspector;
markup = inspector.markup;
runNextSelection();
});
});
}
function runTests() {
inspector.selection.once("new-node", startTests);
executeSoon(function() {
inspector.selection.setNode(doc.body);
inspector = toolbox.getCurrentPanel();
markup = inspector.markup;
inspector.once("inspector-updated", runNextSelection);
});
}
@ -121,7 +120,7 @@ function test() {
info(selection.desc);
selection.before();
inspector.selection.once("new-node", function() {
inspector.once("inspector-updated", function() {
selection.after();
runNextSelection();
});
@ -131,11 +130,13 @@ function test() {
function clickMore() {
info("Check that clicking more loads the whole thing.");
// Make sure that clicking the "more" button loads all the nodes.
let container = markup.getContainer(doc.querySelector("body"));
let container = getContainerForRawNode(markup, doc.querySelector("body"));
let button = container.elt.querySelector("button");
button.click();
assertChildren("abcdefghijklmnopqrstuvwxyz");
finishUp();
markup._waitForChildren().then(() => {
assertChildren("abcdefghijklmnopqrstuvwxyz");
finishUp();
});
}
function finishUp() {

Просмотреть файл

@ -16,3 +16,39 @@ function clearUserPrefs()
}
registerCleanupFunction(clearUserPrefs);
Services.prefs.setBoolPref("devtools.debugger.log", true);
SimpleTest.registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.debugger.log");
});
function getContainerForRawNode(markupView, rawNode) {
let front = markupView.walker.frontForRawNode(rawNode);
let container = markupView.getContainer(front);
return container;
}
Services.prefs.setBoolPref("devtools.debugger.log", true);
SimpleTest.registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.debugger.log");
});
function getContainerForRawNode(markupView, rawNode) {
let front = markupView.walker.frontForRawNode(rawNode);
let container = markupView.getContainer(front);
return container;
}
Services.prefs.setBoolPref("devtools.debugger.log", true);
SimpleTest.registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.debugger.log");
});
function getContainerForRawNode(markupView, rawNode) {
let front = markupView.walker.frontForRawNode(rawNode);
let container = markupView.getContainer(front);
return container;
}

Просмотреть файл

@ -23,8 +23,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
"resource://gre/modules/devtools/NetworkHelper.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
"@mozilla.org/widget/clipboardhelper;1",
"nsIClipboardHelper");
"@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
const NET_STRINGS_URI = "chrome://browser/locale/devtools/netmonitor.properties";
const LISTENERS = [ "NetworkActivity" ];

Просмотреть файл

@ -368,7 +368,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
copyUrl: function() {
let selected = this.selectedItem.attachment;
clipboardHelper.copyString(selected.url, this.document);
clipboardHelper.copyString(selected.url, document);
},
/**

Просмотреть файл

@ -12,21 +12,25 @@ function test() {
let { NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
waitForNetworkEvents(aMonitor, 1).then(() => {
let imageRequest = RequestsMenu.getItemAtIndex(0);
RequestsMenu.selectedItem = imageRequest;
let requestItem = RequestsMenu.getItemAtIndex(0);
RequestsMenu.selectedItem = requestItem;
waitForClipboard(RequestsMenu.selectedItem.attachment.url, function(){ RequestsMenu.copyUrl() } , cleanUp, cleanUp);
waitForClipboard(requestItem.attachment.url, function setup() {
RequestsMenu.copyUrl();
}, function onSuccess() {
ok(true, "Clipboard contains the currently selected item's url.");
cleanUp();
}, function onFailure() {
ok(false, "Copying the currently selected item's url was unsuccessful.");
cleanUp();
});
});
aDebuggee.performRequests(1);
function cleanUp(){
teardown(aMonitor);
finish();
teardown(aMonitor).then(finish);
}
});
}

Просмотреть файл

@ -146,7 +146,7 @@ function ResponsiveUI(aWindow, aTab)
this.customPreset.width = bbox.width - 40; // horizontal padding of the container
this.customPreset.height = bbox.height - 80; // vertical padding + toolbar height
this.currentPresetKey = this.customPreset.key;
this.currentPresetKey = this.presets[1].key; // most common preset
}
this.container.setAttribute("responsivemode", "true");

Просмотреть файл

@ -137,7 +137,8 @@ function test() {
info("XXX BUG 851296: 'on' received.");
executeSoon(onUIOpen2);
});
synthesizeKeyFromKeyTag("key_responsiveUI");
//XXX BUG 851296: synthesizeKeyFromKeyTag("key_responsiveUI");
mgr.toggle(window, gBrowser.selectedTab);
info("XXX BUG 851296: restart() finished.");
}

Просмотреть файл

@ -51,9 +51,9 @@
<!ENTITY debuggerUI.showOriginalSource "Show original sources">
<!ENTITY debuggerUI.showOriginalSource.key "O">
<!-- LOCALIZATION NOTE (debuggerUI.searchPanelTitle): This is the text that
- appears in the filter panel popup as a description. -->
<!ENTITY debuggerUI.searchPanelTitle "Operators">
<!-- LOCALIZATION NOTE (debuggerUI.searchPanelOperators): This is the text that
- appears in the filter panel popup as a header for the operators part. -->
<!ENTITY debuggerUI.searchPanelOperators "Operators:">
<!-- LOCALIZATION NOTE (debuggerUI.searchFile): This is the text that appears
- in the source editor's context menu for the scripts search operation. -->

Просмотреть файл

@ -73,9 +73,9 @@ noMatchingSourcesText=No matching sources.
# global search results when there are no matching strings after filtering.
noMatchingStringsText=No matches found
# LOCALIZATION NOTE (emptyFilterText): This is the text that appears in the
# LOCALIZATION NOTE (emptySearchText): This is the text that appears in the
# filter text box when it is empty and the scripts container is selected.
emptyFilterText=Filter scripts (%S)
emptySearchText=Search scripts (%S)
# LOCALIZATION NOTE (emptyChromeGlobalsFilterText): This is the text that
# appears in the filter text box when it is empty and the chrome globals
@ -86,6 +86,10 @@ emptyChromeGlobalsFilterText=Filter chrome globals (%S)
# appears in the filter text box for the variables view container.
emptyVariablesFilterText=Filter variables
# LOCALIZATION NOTE (searchPanelFilter): This is the text that appears in the
# filter panel popup for the filter scripts operation.
searchPanelFilter=Filter scripts (%S)
# LOCALIZATION NOTE (searchPanelGlobal): This is the text that appears in the
# filter panel popup for the global search operation.
searchPanelGlobal=Search in all files (%S)

Просмотреть файл

@ -11,509 +11,320 @@
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
# LOCALIZATION NOTE (canonDescNone): Short string used to describe any command
# or command parameter when no description has been provided.
# For each command there are in general two strings. As an example consider
# the 'pref' command.
# commandDesc (e.g. prefDesc for the command 'pref'): this string contains a
# very short description of the command. It's designed to be shown in a menu
# alongside the command name, which is why it should be as short as possible.
# commandManual (e.g. prefManual for the command 'pref'): this string will
# contain a fuller description of the command. It's diplayed when the user
# asks for help about a specific command (e.g. 'help pref').
# LOCALIZATION NOTE: This message is used to describe any command or command
# parameter when no description has been provided.
canonDescNone=(No description)
# LOCALIZATION NOTE (canonDefaultGroupName): The default name for a group of
# parameters.
# LOCALIZATION NOTE: The default name for a group of parameters.
canonDefaultGroupName=Options
# LOCALIZATION NOTE (canonProxyDesc): A very short description of a set of
# remote commands. This string is designed to be shown in a menu alongside the
# command name, which is why it should be as short as possible. See
# canonProxyManual for a fuller description of what it does.
# LOCALIZATION NOTE (canonProxyDesc, canonProxyManual): These commands are
# used to execute commands on a remote system (using a proxy). Parameters: %S
# is the name of the remote system.
canonProxyDesc=Execute a command on %S
# LOCALIZATION NOTE (canonProxyManual): A fuller description of a set of
# remote commands. Displayed when the user asks for help on what it does.
canonProxyManual=A set of commands that are executed on a remote system. The remote system is reached via %S
# LOCALIZATION NOTE (canonProxyExists): An error message displayed when we try
# to add new command (via a proxy) where one already exists in that name.
# LOCALIZATION NOTE: This error message is displayed when we try to add a new
# command (using a proxy) where one already exists with the same name.
canonProxyExists=There is already a command called '%S'
# LOCALIZATION NOTE (cliEvalJavascript): The special '{' command allows entry
# of JavaScript like traditional developer tool command lines. This describes
# the '{' command.
# LOCALIZATION NOTE: This message describes the '{' command, which allows
# entry of JavaScript like traditional developer tool command lines.
cliEvalJavascript=Enter JavaScript directly
# LOCALIZATION NOTE (cliUnusedArg): When the command line has more arguments
# than the current command can understand this is the error message shown to
# the user.
# LOCALIZATION NOTE: This message is displayed when the command line has more
# arguments than the current command can understand.
cliUnusedArg=Too many arguments
# LOCALIZATION NOTE (cliOptions): The title of the dialog which displays the
# options that are available to the current command.
# LOCALIZATION NOTE: The title of the dialog which displays the options that
# are available to the current command.
cliOptions=Available Options
# LOCALIZATION NOTE (fieldSelectionSelect): When a command has a parameter
# that has a number of pre-defined options the user interface presents these
# in a drop-down menu, where the first 'option' is an indicator that a
# selection should be made. This string describes that first option.
# LOCALIZATION NOTE: Error message given when a file argument points to a file
# that does not exist, but should (e.g. for use with File->Open) %1$S is a
# filename
fileErrNotExists='%1$S' doesn't exist
# LOCALIZATION NOTE: Error message given when a file argument points to a file
# that exists, but should not (e.g. for use with File->Save As) %1$S is a
# filename
fileErrExists='%1$S' already exists
# LOCALIZATION NOTE: Error message given when a file argument points to a
# non-file, when a file is needed. %1$S is a filename
fileErrIsNotFile='%1$S' is not a file
# LOCALIZATION NOTE: Error message given when a file argument points to a
# non-directory, when a directory is needed (e.g. for use with 'cd') %1$S is a
# filename
fileErrIsNotDirectory='%1$S' is not a directory
# LOCALIZATION NOTE: Error message given when a file argument does not match
# the specified regular expression %1$S is a filename %2$S is a regular
# expression
fileErrDoesntMatch='%1$S' does not match '%2$S'
# LOCALIZATION NOTE: When a command has a parameter that has a number of
# pre-defined options the user interface presents these in a drop-down menu,
# where the first 'option' is an indicator that a selection should be made.
# This string describes that first option.
fieldSelectionSelect=Select a %S…
# LOCALIZATION NOTE (fieldArrayAdd): When a command has a parameter that can
# be repeated a number of times (e.g. like the 'cat a.txt b.txt' command) the
# user interface presents buttons to add and remove arguments. This string is
# used to add arguments.
# LOCALIZATION NOTE (fieldArrayAdd, fieldArrayDel): When a command has a
# parameter that can be repeated multiple times (e.g. like the 'cat a.txt
# b.txt' command) the user interface presents buttons to add and remove
# arguments. This string is used to add arguments.
fieldArrayAdd=Add
# LOCALIZATION NOTE (fieldArrayDel): When a command has a parameter that can
# be repeated a number of times (e.g. like the 'cat a.txt b.txt' command) the
# user interface presents buttons to add and remove arguments. This string is
# used to remove arguments.
fieldArrayDel=Delete
# LOCALIZATION NOTE (fieldMenuMore): When the menu has displayed all the
# matches that it should (i.e. about 10 items) then we display this to alert
# the user that more matches are available.
# LOCALIZATION NOTE: When the menu has displayed all the matches that it
# should (i.e. about 10 items) then we display this to alert the user that
# more matches are available.
fieldMenuMore=More matches, keep typing
# LOCALIZATION NOTE (jstypeParseScope): The command line provides completion
# for JavaScript commands, however there are times when the scope of what
# we're completing against can't be used. This error message is displayed when
# this happens.
# LOCALIZATION NOTE: The command line provides completion for JavaScript
# commands, however there are times when the scope of what we're completing
# against can't be used. This error message is displayed when this happens.
jstypeParseScope=Scope lost
# LOCALIZATION NOTE (jstypeParseMissing): When the command line is doing
# JavaScript completion, sometimes the property to be completed does not
# exist. This error message is displayed when this happens.
# LOCALIZATION NOTE (jstypeParseMissing, jstypeBeginSyntax,
# jstypeBeginUnterm): These error messages are displayed when the command line
# is doing JavaScript completion and encounters errors.
jstypeParseMissing=Can't find property '%S'
# LOCALIZATION NOTE (jstypeBeginSyntax): When the command line is doing
# JavaScript completion using invalid JavaScript, this error message is
# displayed.
jstypeBeginSyntax=Syntax error
# LOCALIZATION NOTE (jstypeBeginUnterm): When the command line is doing
# JavaScript completion using a string that is not properly terminated, this
# error message is displayed.
jstypeBeginUnterm=Unterminated string literal
# LOCALIZATION NOTE (jstypeParseError): If the system for providing JavaScript
# completions encounters and error it displays this.
# LOCALIZATION NOTE: This message is displayed if the system for providing
# JavaScript completions encounters and error it displays this.
jstypeParseError=Error
# LOCALIZATION NOTE (typesNumberNan): When the command line is passed a
# number, however the input string is not a valid number, this error message
# is displayed.
# LOCALIZATION NOTE (typesNumberNan, typesNumberNotInt2, typesDateNan): These
# error messages are displayed when the command line is passed a variable
# which has the wrong format and can't be converted. Parameters: %S is the
# passed variable.
typesNumberNan=Can't convert "%S" to a number.
# LOCALIZATION NOTE (typesNumberMax): When the command line is passed a
# number, but the number is bigger than the largest allowed number, this error
# message is displayed.
typesNumberMax=%1$S is greater than maximum allowed: %2$S.
# LOCALIZATION NOTE (typesNumberMin): When the command line is passed a
# number, but the number is lower than the smallest allowed number, this error
# message is displayed.
typesNumberMin=%1$S is smaller than minimum allowed: %2$S.
# LOCALIZATION NOTE (typesNumberNotInt2): When the command line is passed a
# number, but the number has a decimal part and floats are not allowed.
typesNumberNotInt2=Can't convert "%S" to an integer.
# LOCALIZATION NOTE (typesDateNan): When the command line is passed a date,
# however the input string is not a valid date, this error message is
# displayed.
typesDateNan=Can't convert "%S" to a date.
# LOCALIZATION NOTE (typesDateMax): When the command line is passed a date,
# but the number is later than the latest allowed date, this error message is
# displayed.
# LOCALIZATION NOTE (typesNumberMax, typesNumberMin, typesDateMax,
# typesDateMin): These error messages are displayed when the command line is
# passed a variable which has a value out of range (number or date).
# Parameters: %1$S is the passed variable, %2$S is the limit value.
typesNumberMax=%1$S is greater than maximum allowed: %2$S.
typesNumberMin=%1$S is smaller than minimum allowed: %2$S.
typesDateMax=%1$S is later than maximum allowed: %2$S.
# LOCALIZATION NOTE (typesDateMin): When the command line is passed a date,
# but the date is earlier than the earliest allowed number, this error message
# is displayed.
typesDateMin=%1$S is earlier than minimum allowed: %2$S.
# LOCALIZATION NOTE (typesSelectionNomatch): When the command line is passed
# an option with a limited number of correct values, but the passed value is
# not one of them, this error message is displayed.
# LOCALIZATION NOTE: This error message is displayed when the command line is
# passed an option with a limited number of correct values, but the passed
# value is not one of them.
typesSelectionNomatch=Can't use '%S'.
# LOCALIZATION NOTE (nodeParseSyntax): When the command line is expecting a
# CSS query string, however the passed string is not valid, this error message
# is displayed.
# LOCALIZATION NOTE: This error message is displayed when the command line is
# expecting a CSS query string, however the passed string is not valid.
nodeParseSyntax=Syntax error in CSS query
# LOCALIZATION NOTE (nodeParseMultiple): When the command line is expecting a
# CSS string that matches a single node, but more than one node matches, this
# error message is displayed.
# LOCALIZATION NOTE (nodeParseMultiple, nodeParseNone): These error messages
# are displayed when the command line is expecting a CSS string that matches a
# single node, but more nodes (or none) match.
nodeParseMultiple=Too many matches (%S)
# LOCALIZATION NOTE (nodeParseNone): When the command line is expecting a CSS
# string that matches a single node, but no nodes match, this error message is
# displayed.
nodeParseNone=No matches
# LOCALIZATION NOTE (helpDesc): A very short description of the 'help'
# 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. See helpManual for a
# fuller description of what it does.
# LOCALIZATION NOTE (helpDesc, helpManual, helpSearchDesc, helpSearchManual3):
# These strings describe the "help" command, used to display a description of
# a command (e.g. "help pref"), and its parameter 'search'.
helpDesc=Get help on the available commands
# LOCALIZATION NOTE (helpManual): A fuller description of the 'help' command.
# Displayed when the user asks for help on what it does.
helpManual=Provide help either on a specific command (if a search string is provided and an exact match is found) or on the available commands (if a search string is not provided, or if no exact match is found).
# LOCALIZATION NOTE (helpSearchDesc): A very short description of the 'search'
# parameter to the 'help' command. See helpSearchManual3 for a fuller
# description of what it does. This string is designed to be shown in a dialog
# with restricted space, which is why it should be as short as possible.
helpSearchDesc=Search string
# LOCALIZATION NOTE (helpSearchManual3): A fuller description of the 'search'
# parameter to the 'help' command. Displayed when the user asks for help on
# what it does.
helpSearchManual3=search string to use in narrowing down the displayed commands. Regular expressions not supported.
# LOCALIZATION NOTE (helpManSynopsis): A heading shown at the top of a help
# page for a command in the console It labels a summary of the parameters to
# the command
# LOCALIZATION NOTE (helpManSynopsis, helpManDescription, helpManParameters):
# These strings are displayed in the help page for a command in the console.
helpManSynopsis=Synopsis
# LOCALIZATION NOTE (helpManDescription): A heading shown in a help page for a
# command in the console. This heading precedes the top level description.
helpManDescription=Description
# LOCALIZATION NOTE (helpManParameters): A heading shown above the parameters
# in a help page for a command in the console.
helpManParameters=Parameters
# LOCALIZATION NOTE (helpManNone): Some text shown under the parameters
# heading in a help page for a command which has no parameters.
# LOCALIZATION NOTE: This message is displayed in the help page if the command
# has no parameters.
helpManNone=None
# LOCALIZATION NOTE (helpListAll): The heading shown in response to the 'help'
# LOCALIZATION NOTE: This message is displayed in response to the 'help'
# command when used without a filter, just above the list of known commands.
helpListAll=Available Commands:
# LOCALIZATION NOTE (helpListPrefix): The heading shown in response to the
# 'help <search>' command (i.e. with a search string), just above the list of
# matching commands.
helpListPrefix=Commands starting with '%1$S':
# LOCALIZATION NOTE (helpListPrefix, helpListNone): These messages are
# displayed in response to the 'help <search>' command (i.e. with a search
# string), just above the list of matching commands. Parameters: %S is the
# search string.
helpListPrefix=Commands starting with '%S':
helpListNone=No commands starting with '%S'
# LOCALIZATION NOTE (helpListNone): The heading shown in response to the 'help
# <search>' command (i.e. with a search string), when there are no matching
# commands.
helpListNone=No commands starting with '%1$S'
# LOCALIZATION NOTE (helpManRequired): When the 'help x' command wants to show
# the manual for the 'x' command it needs to be able to describe the
# parameters as either required or optional, or if they have a default value.
# See also 'helpManOptional' and 'helpManDefault'.
# LOCALIZATION NOTE (helpManRequired, helpManOptional, helpManDefault): When
# the 'help x' command wants to show the manual for the 'x' command, it needs
# to be able to describe the parameters as either required or optional, or if
# they have a default value.
helpManRequired=required
# LOCALIZATION NOTE (helpManOptional): See description of 'helpManRequired'
helpManOptional=optional
helpManDefault=optional, default=%S
# LOCALIZATION NOTE (helpManDefault): See description of 'helpManRequired'. %1$
# S is the default value
helpManDefault=optional, default=%1$S
# LOCALIZATION NOTE (subCommands): Text shown as part of the output of the
# 'help' command when the command in question has sub-commands, before a list
# of the matching sub-commands
# LOCALIZATION NOTE: Text shown as part of the output of the 'help' command
# when the command in question has sub-commands, before a list of the matching
# sub-commands.
subCommands=Sub-Commands
# LOCALIZATION NOTE (subCommandsNone): Text shown as part of the output of the
# 'help' command when the command in question should have sub-commands but in
# fact has none
# LOCALIZATION NOTE: Text shown as part of the output of the 'help' command
# when the command in question should have sub-commands but in fact has none.
subCommandsNone=None
# LOCALIZATION NOTE (contextDesc): A very short description of the 'context'
# 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. See contextManual for
# a fuller description of what it does.
# LOCALIZATION NOTE (contextDesc, contextManual, contextPrefixDesc): These
# strings are used to describe the 'context' command and its 'prefix'
# parameter. See localization comment for 'connect' for an explanation about
# 'prefix'.
contextDesc=Concentrate on a group of commands
# LOCALIZATION NOTE (contextManual): A fuller description of the 'context'
# command. Displayed when the user asks for help on what it does.
contextManual=Setup a default prefix to future commands. For example 'context git' would allow you to type 'commit' rather than 'git commit'.
# LOCALIZATION NOTE (contextPrefixDesc): A short description of the 'prefix'
# parameter to the 'context' command. This string is designed to be shown in a
# dialog with restricted space, which is why it should be as short as
# possible.
contextPrefixDesc=The command prefix
# LOCALIZATION NOTE (contextNotParentError): An error message displayed during
# the processing of the 'context' command, when the found command is not a
# parent command.
contextNotParentError=Can't use '%1$S' as a prefix because it is not a parent command.
# LOCALIZATION NOTE: This message message displayed during the processing of
# the 'context' command, when the found command is not a parent command.
contextNotParentError=Can't use '%S' as a prefix because it is not a parent command.
# LOCALIZATION NOTE (contextReply): A message displayed during the processing
# of the 'context' command, to indicate success.
contextReply=Using %1$S as a command prefix
# LOCALIZATION NOTE (contextEmptyReply): A message displayed during the
# processing of the 'context' command, to indicate that there is no command
# prefix
# LOCALIZATION NOTE (contextReply, contextEmptyReply): These messages are
# displayed during the processing of the 'context' command, to indicate
# success or that there is no command prefix.
contextReply=Using %S as a command prefix
contextEmptyReply=Command prefix is unset
# LOCALIZATION NOTE (connectDesc): A very short description of the 'connect'
# 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. See connectManual for
# a fuller description of what it does.
# LOCALIZATION NOTE (connectDesc, connectManual, connectPrefixDesc,
# connectPortDesc, connectHostDesc, connectDupReply): These strings describe
# the 'connect' command and all its available parameters. A 'prefix' is an
# alias for the remote server (think of it as a "connection name"), and it
# allows to identify a specific server when connected to multiple remote
# servers.
connectDesc=Proxy commands to server
# LOCALIZATION NOTE (connectManual): A fuller description of the 'connect'
# command. Displayed when the user asks for help on what it does.
connectManual=Connect to the server, creating local versions of the commands on the server. Remote commands initially have a prefix to distinguish them from local commands (but see the context command to get past this)
# LOCALIZATION NOTE (connectPrefixDesc): A short description of the 'prefix'
# parameter to the 'connect' command. This string is designed to be shown in a
# dialog with restricted space, which is why it should be as short as
# possible.
connectPrefixDesc=Parent prefix for imported commands
# LOCALIZATION NOTE (connectPortDesc): A short description of the 'port'
# parameter to the 'connect' command. This string is designed to be shown in a
# dialog with restricted space, which is why it should be as short as
# possible.
connectPortDesc=The TCP port to listen on
# LOCALIZATION NOTE (connectHostDesc): A short description of the 'host'
# parameter to the 'connect' command. This string is designed to be shown in a
# dialog with restricted space, which is why it should be as short as
# possible.
connectHostDesc=The hostname to bind to
# LOCALIZATION NOTE (connectDupReply): An error condition from executing the
# 'connect' command
connectDupReply=Connection called %S already exists.
# LOCALIZATION NOTE (connectReply): The output of the 'connect' command,
# telling the user what it has done.
# LOCALIZATION NOTE: The output of the 'connect' command, telling the user
# what it has done. Parameters: %S is the prefix command. See localization
# comment for 'connect' for an explanation about 'prefix'.
connectReply=Added %S commands.
# LOCALIZATION NOTE (disconnectDesc): A very short description of the
# 'disconnect' 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.
# See connectManual for a fuller description of what it does.
disconnectDesc=Proxy commands to server
# LOCALIZATION NOTE (disconnectManual): A fuller description of the
# 'disconnect' command. Displayed when the user asks for help on what it does.
disconnectManual=Connect to the server, creating local versions of the commands on the server. Remote commands initially have a prefix to distinguish them from local commands (but see the context command to get past this)
# LOCALIZATION NOTE (disconnectPrefixDesc): A short description of the
# 'prefix' parameter to the 'disconnect' command. This string is designed to
# be shown in a dialog with restricted space, which is why it should be as
# short as possible.
# LOCALIZATION NOTE (disconnectDesc2, disconnectManual2, disconnectPrefixDesc,
# disconnectForceDesc): These strings describe the 'disconnect' command and
# all its available parameters. See localization comment for 'connect' for an
# explanation about 'prefix'.
disconnectDesc2=Disconnect from server
disconnectManual2=Disconnect from a server currently connected for remote commands execution
disconnectPrefixDesc=Parent prefix for imported commands
# LOCALIZATION NOTE (disconnectForceDesc): A short description of the 'force'
# parameter to the 'disconnect' command. This string is designed to be shown
# in a dialog with restricted space, which is why it should be as short as
# possible.
disconnectForceDesc=Ignore outstanding requests
# LOCALIZATION NOTE (disconnectReply): The output of the 'disconnect' command,
# telling the user what it's done.
# LOCALIZATION NOTE: This is the output of the 'disconnect' command,
# explaining the user what has been done. Parameters: %S is the number of
# commands removed.
disconnectReply=Removed %S commands.
# LOCALIZATION NOTE (disconnectOutstanding): An error message displayed when
# the user attempts to disconnect before all requests have completed. %1$S is
# a list of commands which are incomplete
disconnectOutstanding=Outstanding requests (%1$S)
# LOCALIZATION NOTE: This error message is displayed when the user attempts to
# disconnect before all requests have completed. Parameters: %S is a list of
# incomplete requests.
disconnectOutstanding=Outstanding requests (%S)
# LOCALIZATION NOTE (prefDesc): A very short description of the 'pref'
# 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. See prefManual for a
# fuller description of what it does.
# LOCALIZATION NOTE (prefDesc, prefManual, prefListDesc, prefListManual,
# prefListSearchDesc, prefListSearchManual, prefShowDesc, prefShowManual,
# prefShowSettingDesc, prefShowSettingManual): These strings describe the
# 'pref' command and all its available sub-commands and parameters.
prefDesc=Commands to control settings
# LOCALIZATION NOTE (prefManual): A fuller description of the 'pref' command.
# Displayed when the user asks for help on what it does.
prefManual=Commands to display and alter preferences both for GCLI and the surrounding environment
# LOCALIZATION NOTE (prefListDesc): A very short description of the 'pref
# list' 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. See
# prefListManual for a fuller description of what it does.
prefListDesc=Display available settings
# LOCALIZATION NOTE (prefListManual): A fuller description of the 'pref list'
# command. Displayed when the user asks for help on what it does.
prefListManual=Display a list of preferences, optionally filtered when using the 'search' parameter
# LOCALIZATION NOTE (prefListSearchDesc): A short description of the 'search'
# parameter to the 'pref list' command. See prefListSearchManual for a fuller
# description of what it does. This string is designed to be shown in a dialog
# with restricted space, which is why it should be as short as possible.
prefListSearchDesc=Filter the list of settings displayed
# LOCALIZATION NOTE (prefListSearchManual): A fuller description of the
# 'search' parameter to the 'pref list' command. Displayed when the user asks
# for help on what it does.
prefListSearchManual=Search for the given string in the list of available preferences
# LOCALIZATION NOTE (prefShowDesc): A very short description of the 'pref
# show' 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. See
# prefShowManual for a fuller description of what it does.
prefShowDesc=Display setting value
# LOCALIZATION NOTE (prefShowManual): A fuller description of the 'pref show'
# command. Displayed when the user asks for help on what it does.
prefShowManual=Display the value of a given preference
# LOCALIZATION NOTE (prefShowSettingDesc): A short description of the
# 'setting' parameter to the 'pref show' command. See prefShowSettingManual
# for a fuller description of what it does. This string is designed to be
# shown in a dialog with restricted space, which is why it should be as short
# as possible.
prefShowSettingDesc=Setting to display
# LOCALIZATION NOTE (prefShowSettingManual): A fuller description of the
# 'setting' parameter to the 'pref show' command. Displayed when the user asks
# 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: This message is used to show the preference name and the
# associated preference value. Parameters: %1$S is the preference name, %2$S
# is the preference value.
prefShowSettingValue=%1$S: %2$S
# LOCALIZATION NOTE (prefSetDesc): A very short description of the 'pref set'
# 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. See prefSetManual for
# a fuller description of what it does.
# LOCALIZATION NOTE (prefSetDesc, prefSetManual, prefSetSettingDesc,
# prefSetSettingManual, prefSetValueDesc, prefSetValueManual): These strings
# describe the 'pref set' command and all its parameters.
prefSetDesc=Alter a setting
# LOCALIZATION NOTE (prefSetManual): A fuller description of the 'pref set'
# command. Displayed when the user asks for help on what it does.
prefSetManual=Alter preferences defined by the environment
# LOCALIZATION NOTE (prefSetSettingDesc): A short description of the 'setting'
# parameter to the 'pref set' command. See prefSetSettingManual for a fuller
# description of what it does. This string is designed to be shown in a dialog
# with restricted space, which is why it should be as short as possible.
prefSetSettingDesc=Setting to alter
# LOCALIZATION NOTE (prefSetSettingManual): A fuller description of the
# 'setting' parameter to the 'pref set' command. Displayed when the user asks
# for help on what it does.
prefSetSettingManual=The name of the setting to alter.
# LOCALIZATION NOTE (prefSetValueDesc): A short description of the 'value'
# parameter to the 'pref set' command. See prefSetValueManual for a fuller
# description of what it does. This string is designed to be shown in a dialog
# with restricted space, which is why it should be as short as possible.
prefSetValueDesc=New value for setting
# LOCALIZATION NOTE (prefSetValueManual): A fuller description of the 'value'
# parameter to the 'pref set' command. Displayed when the user asks for help
# on what it does.
prefSetValueManual=The new value for the specified setting
# LOCALIZATION NOTE (prefSetCheckHeading): Title displayed to the user the
# first time they try to alter a setting This is displayed directly above
# prefSetCheckBody and prefSetCheckGo.
# LOCALIZATION NOTE (prefSetCheckHeading, prefSetCheckBody, prefSetCheckGo):
# These strings are displayed to the user the first time they try to alter a
# setting.
prefSetCheckHeading=This might void your warranty!
# LOCALIZATION NOTE (prefSetCheckBody): The main text of the warning displayed
# to the user the first time they try to alter a setting. See also
# prefSetCheckHeading and prefSetCheckGo.
prefSetCheckBody=Changing these advanced settings can be harmful to the stability, security, and performance of this application. You should only continue if you are sure of what you are doing.
# LOCALIZATION NOTE (prefSetCheckGo): The text to enable preference editing.
# Displayed in a button directly under prefSetCheckHeading and
# prefSetCheckBody
prefSetCheckGo=I'll be careful, I promise!
# LOCALIZATION NOTE (prefResetDesc): A very short description of the 'pref
# reset' 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. See
# prefResetManual for a fuller description of what it does.
# LOCALIZATION NOTE (prefResetDesc, prefResetManual, prefResetSettingDesc,
# prefResetSettingManual): These strings describe the 'pref reset' command and
# all its parameters.
prefResetDesc=Reset a setting
# LOCALIZATION NOTE (prefResetManual): A fuller description of the 'pref
# reset' command. Displayed when the user asks for help on what it does.
prefResetManual=Reset the value of a setting to the system defaults
# LOCALIZATION NOTE (prefResetSettingDesc): A short description of the
# 'setting' parameter to the 'pref reset' command. See prefResetSettingManual
# for a fuller description of what it does. This string is designed to be
# shown in a dialog with restricted space, which is why it should be as short
# as possible.
prefResetSettingDesc=Setting to reset
# LOCALIZATION NOTE (prefResetSettingManual): A fuller description of the
# 'setting' parameter to the 'pref reset' command. Displayed when the user
# asks for help on what it does.
prefResetSettingManual=The name of the setting to reset to the system default value
# LOCALIZATION NOTE (prefOutputFilter): Displayed in the output from the 'pref
# LOCALIZATION NOTE: This string is displayed in the output from the 'pref
# list' command as a label to an input element that allows the user to filter
# the results
# the results.
prefOutputFilter=Filter
# LOCALIZATION NOTE (prefOutputName): Displayed in the output from the 'pref
# list' command as a heading to a table. The column contains the names of the
# available preferences
# LOCALIZATION NOTE (prefOutputName, prefOutputValue): These strings are
# displayed in the output from the 'pref list' command as table headings.
prefOutputName=Name
# LOCALIZATION NOTE (prefOutputValue): Displayed in the output from the 'pref
# list' command as a heading to a table. The column contains the values of the
# available preferences
prefOutputValue=Value
# LOCALIZATION NOTE (introDesc): A very short description of the 'intro'
# 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. See introManual for a
# fuller description of what it does.
# LOCALIZATION NOTE (introDesc, introManual): These strings describe the
# 'intro' command. The localization of 'Got it!' should be the same used in
# introTextGo.
introDesc=Show the opening message
# LOCALIZATION NOTE (introManual): A fuller description of the 'intro'
# command. Displayed when the user asks for help on what it does.
introManual=Redisplay the message that is shown to new users until they click the 'Got it!' button
# LOCALIZATION NOTE (introTextOpening2): The 'intro text' opens when the user
# LOCALIZATION NOTE (introTextOpening2, introTextCommands, introTextKeys2,
# introTextF1Escape, introTextGo): These strings are displayed when the user
# first opens the developer toolbar to explain the command line, and is shown
# each time it is opened until the user clicks the 'Got it!' button. This
# string is the opening paragraph of the intro text.
# each time it is opened until the user clicks the 'Got it!' button.
introTextOpening2=This command line is designed for developers. It focuses on speed of input over JavaScript syntax and a rich display over monospace output.
# LOCALIZATION NOTE (introTextCommands): For information about the 'intro
# text' see introTextOpening2. The second paragraph is in 2 sections, the
# first section points the user to the 'help' command.
introTextCommands=For a list of commands type
# LOCALIZATION NOTE (introTextKeys2): For information about the 'intro text'
# see introTextOpening2. The second section in the second paragraph points the
# user to the F1/Escape keys which show and hide hints.
introTextKeys2=, or to show/hide command hints press
# LOCALIZATION NOTE (introTextF1Escape): For information about the 'intro
# text' see introTextOpening2. This string is used with introTextKeys2, and
# contains the keys that are pressed to open and close hints.
introTextF1Escape=F1/Escape
# LOCALIZATION NOTE (introTextGo): For information about the 'intro text' see
# introTextOpening2. The text on the button that dismisses the intro text.
introTextGo=Got it!
# LOCALIZATION NOTE (hideIntroDesc): Short description of the 'hideIntro'
# setting. Displayed when the user asks for help on the settings.
# LOCALIZATION NOTE: This is a short description of the 'hideIntro' setting.
hideIntroDesc=Show the initial welcome message
# LOCALIZATION NOTE (eagerHelperDesc): Short description of the 'eagerHelper'
# setting. Displayed when the user asks for help on the settings. eagerHelper
# allows users to select between showing no tooltips, permanent tooltips, and
# only important tooltips
# LOCALIZATION NOTE: This is a description of the 'eagerHelper' setting. It's
# displayed when the user asks for help on the settings. eagerHelper allows
# users to select between showing no tooltips, permanent tooltips, and only
# important tooltips.
eagerHelperDesc=How eager are the tooltips
# LOCALIZATION NOTE (allowSetDesc): Short description of the 'allowSetDesc'
# setting. Displayed when the user asks for help on the settings.
# LOCALIZATION NOTE: This is a short description of the 'allowSetDesc'
# setting.
allowSetDesc=Has the user enabled the 'pref set' command?
# LOCALIZATION NOTE (introBody): The text displayed at the top of the output
# for the help command, just before the list of commands. This text is wrapped
# inside a link to a localized MDN article
# LOCALIZATION NOTE: This text is displayed at the top of the output for the
# help command, just before the list of commands. This text is wrapped inside
# a link to a localized MDN article.
introBody=For more information see MDN.

Просмотреть файл

@ -504,6 +504,21 @@ cmdDesc=Manipulate the commands
# name, which is why it should be as short as possible.
cmdRefreshDesc=Re-read mozcmd directory
# LOCALIZATION NOTE (cmdStatus) When the we load new commands from mozcmd
# directory, we report on how many we loaded. %1$S is a count of the number
# of loaded commands, and %2$S is the directory we loaded from.
cmdStatus=Read %1$S commands from '%2$S'
# LOCALIZATION NOTE (cmdSetdirDesc)
cmdSetdirDesc=Setup a mozcmd directory
# LOCALIZATION NOTE (cmdSetdirManual)
cmdSetdirManual=A 'mozcmd' directory is an easy way to create new custom commands for the Firefox command line. For more information see the <a href="https://developer.mozilla.org/en-US/docs/Tools/GCLI/Customization">MDN documentation</a>.
# LOCALIZATION NOTE (cmdSetdirDirectoryDesc) The description of the directory
# parameter to the 'cmd setdir' command.
cmdSetdirDirectoryDesc=Directory containing .mozcmd files
# LOCALIZATION NOTE (addonDesc) A very short description of the 'addon'
# 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.

Просмотреть файл

@ -9,6 +9,8 @@
<!ENTITY toolboxCloseButton.tooltip "Close Developer Tools">
<!ENTITY toolboxOptionsButton.key "O">
<!ENTITY toolboxNextTool.key "]">
<!ENTITY toolboxPreviousTool.key "[">
<!-- LOCALIZATION NOTE (options.context.advancedSettings): This is the label for
- the heading of the advanced settings group in the options panel. -->

Просмотреть файл

@ -103,8 +103,12 @@
-moz-margin-start: 1px;
}
#searchbox-panel-description {
margin-top: 0;
#filter-label {
-moz-margin-start: 2px;
}
#searchbox-panel-operators {
margin-top: 5px;
margin-bottom: 8px;
-moz-margin-start: 2px;
}

Просмотреть файл

@ -105,8 +105,12 @@
-moz-margin-start: 1px;
}
#searchbox-panel-description {
margin-top: 0;
#filter-label {
-moz-margin-start: 2px;
}
#searchbox-panel-operators {
margin-top: 5px;
margin-bottom: 8px;
-moz-margin-start: 2px;
}

Просмотреть файл

@ -44,7 +44,7 @@
}
.theme-selected {
background: #26384E;
background: #26394D;
}
.theme-bg-darker {

Просмотреть файл

@ -44,7 +44,7 @@
}
.theme-selected {
background-color: hsl(0,0%,90%);
background-color: #CCC;
}
.theme-bg-darker {

Просмотреть файл

@ -11,10 +11,6 @@
cursor: pointer;
}
.selected {
background-color: hsl(0,0%,90%);
}
/* Give some padding to focusable elements to match the editor input
* that will replace them. */
span[tabindex] {

Просмотреть файл

@ -103,8 +103,12 @@
-moz-margin-start: 1px;
}
#searchbox-panel-description {
margin-top: 0;
#filter-label {
-moz-margin-start: 2px;
}
#searchbox-panel-operators {
margin-top: 5px;
margin-bottom: 8px;
-moz-margin-start: 2px;
}

Просмотреть файл

@ -1,5 +1,4 @@
accounts.google.com: max-age too low: 2592000
aladdinschools.appspot.com: did not receive HSTS header
alpha.irccloud.com: could not connect to host
api.mega.co.nz: could not connect to host
api.recurly.com: did not receive HSTS header
@ -17,9 +16,7 @@ cert.se: max-age too low: 2628001
checkout.google.com: did not receive HSTS header
chrome-devtools-frontend.appspot.com: did not receive HSTS header
chrome.google.com: did not receive HSTS header
chromiumcodereview.appspot.com: did not receive HSTS header
code.google.com: did not receive HSTS header
codereview.appspot.com: did not receive HSTS header
codereview.chromium.org: did not receive HSTS header
crypto.is: did not receive HSTS header
csawctf.poly.edu: did not receive HSTS header
@ -30,7 +27,6 @@ dropcam.com: did not receive HSTS header
emailprivacytester.com: max-age too low: 8640000
encrypted.google.com: did not receive HSTS header
epoxate.com: max-age too low: 259200
factor.cc: could not connect to host
fatzebra.com.au: did not receive HSTS header
fj.simple.com: did not receive HSTS header
gmail.com: did not receive HSTS header
@ -60,6 +56,8 @@ openshift.redhat.com: did not receive HSTS header
ottospora.nl: could not connect to host
packagist.org: max-age too low: 2592000
passwd.io: could not connect to host
paymill.com: did not receive HSTS header
paymill.de: did not receive HSTS header
paypal.com: max-age too low: 14400
piratenlogin.de: could not connect to host
plus.google.com: did not receive HSTS header
@ -103,3 +101,4 @@ www.paycheckrecords.com: max-age too low: 86400
www.paypal.com: max-age too low: 14400
www.sandbox.mydigipass.com: could not connect to host
www.surfeasy.com: did not receive HSTS header
zoo24.de: did not receive HSTS header

Просмотреть файл

@ -8,7 +8,7 @@
/*****************************************************************************/
#include "mozilla/StandardInteger.h"
const PRTime gPreloadListExpirationTime = INT64_C(1384596271277000);
const PRTime gPreloadListExpirationTime = INT64_C(1385202156273000);
class nsSTSPreload
{
@ -18,6 +18,7 @@ class nsSTSPreload
};
static const nsSTSPreload kSTSPreloadList[] = {
{ "aladdinschools.appspot.com", false },
{ "alpha.irccloud.com", false },
{ "api.intercom.io", false },
{ "app.recurly.com", false },
@ -32,7 +33,9 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "business.medbank.com.mt", true },
{ "carezone.com", false },
{ "check.torproject.org", false },
{ "chromiumcodereview.appspot.com", false },
{ "cloudsecurityalliance.org", true },
{ "codereview.appspot.com", false },
{ "conformal.com", true },
{ "controlcenter.gigahost.dk", true },
{ "crate.io", true },
@ -82,10 +85,9 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "paste.linode.com", false },
{ "pastebin.linode.com", false },
{ "pay.gigahost.dk", true },
{ "paymill.com", true },
{ "paymill.de", true },
{ "piratenlogin.de", true },
{ "pixi.me", true },
{ "rapidresearch.me", true },
{ "riseup.net", true },
{ "roundcube.mayfirst.org", false },
{ "sandbox.mydigipass.com", false },
@ -122,5 +124,4 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "www.therapynotes.com", false },
{ "www.torproject.org", false },
{ "www.twitter.com", false },
{ "zoo24.de", true },
};

Просмотреть файл

@ -3166,6 +3166,18 @@
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'navigateTo' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_LOCAL_EVENTLISTENERS_MS": {
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took an 'eventListeners' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_REMOTE_EVENTLISTENERS_MS": {
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took an 'eventListeners' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_LOCAL_DETACH_MS": {
"kind": "exponential",
"high": "10000",

Просмотреть файл

@ -20,6 +20,7 @@ this.EXPORTED_SYMBOLS = ["DebuggerTransport",
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
const { defer, resolve, reject } = promise;
@ -199,6 +200,7 @@ const UnsolicitedPauses = {
"resumeLimit": "resumeLimit",
"debuggerStatement": "debuggerStatement",
"breakpoint": "breakpoint",
"DOMEvent": "DOMEvent",
"watchpoint": "watchpoint",
"exception": "exception"
};
@ -1023,6 +1025,7 @@ ThreadClient.prototype = {
get paused() { return this._state === "paused"; },
_pauseOnExceptions: false,
_pauseOnDOMEvents: null,
_actor: null,
get actor() { return this._actor; },
@ -1058,7 +1061,15 @@ ThreadClient.prototype = {
// further requests that should only be sent in the paused state.
this._state = "resuming";
aPacket.pauseOnExceptions = this._pauseOnExceptions;
if (!aPacket.resumeLimit) {
delete aPacket.resumeLimit;
}
if (this._pauseOnExceptions) {
aPacket.pauseOnExceptions = this._pauseOnExceptions;
}
if (this._pauseOnDOMEvents) {
aPacket.pauseOnDOMEvents = this._pauseOnDOMEvents;
}
return aPacket;
},
after: function (aResponse) {
@ -1147,6 +1158,33 @@ ThreadClient.prototype = {
});
},
/**
* Enable pausing when the specified DOM events are triggered. Disabling
* pausing on an event can be realized by calling this method with the updated
* array of events that doesn't contain it.
*
* @param array|string events
* An array of strings, representing the DOM event types to pause on,
* or "*" to pause on all DOM events. Pass an empty array to
* completely disable pausing on DOM events.
* @param function onResponse
* Called with the response packet in a future turn of the event loop.
*/
pauseOnDOMEvents: function (events, onResponse) {
this._pauseOnDOMEvents = events;
// If the debuggee is paused, the value of the array will be communicated in
// the next resumption. Otherwise we have to force a pause in order to send
// the array.
if (this.paused)
return void setTimeout(onResponse, 0);
this.interrupt(response => {
// Can't continue if pausing failed.
if (response.error)
return void onResponse(response);
this.resume(onResponse);
});
},
/**
* Send a clientEvaluate packet to the debuggee. Response
* will be a resume packet.
@ -1272,6 +1310,18 @@ ThreadClient.prototype = {
telemetry: "THREADGRIPS"
}),
/**
* Return the event listeners defined on the page.
*
* @param aOnResponse Function
* Called with the thread's response.
*/
eventListeners: DebuggerClient.requester({
type: "eventListeners"
}, {
telemetry: "EVENTLISTENERS"
}),
/**
* Request the loaded sources for the current thread.
*

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1381,6 +1381,46 @@ var WalkerActor = protocol.ActorClass({
}
}),
/**
* Removes a node from its parent node.
*
* @returns The node's nextSibling before it was removed.
*/
removeNode: method(function(node) {
if ((node.rawNode.ownerDocument &&
node.rawNode.ownerDocument.documentElement === this.rawNode) ||
node.rawNode.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE) {
throw Error("Cannot remove document or document elements.");
}
let nextSibling = this.nextSibling(node);
if (node.rawNode.parentNode) {
node.rawNode.parentNode.removeChild(node.rawNode);
// Mutation events will take care of the rest.
}
return nextSibling;
}, {
request: {
node: Arg(0, "domnode")
},
response: {
nextSibling: RetVal("domnode", { optional: true })
}
}),
/**
* Insert a node into the DOM.
*/
insertBefore: method(function(node, parent, sibling) {
parent.rawNode.insertBefore(node.rawNode, sibling ? sibling.rawNode : null);
}, {
request: {
node: Arg(0, "domnode"),
parent: Arg(1, "domnode"),
sibling: Arg(2, "domnode", { optional: true })
},
response: {}
}),
/**
* Get any pending mutation records. Must be called by the client after
* the `new-mutations` notification is received. Returns an array of
@ -2003,7 +2043,7 @@ function nodeDocument(node) {
function DocumentWalker(aNode, aShow, aFilter, aExpandEntityReferences)
{
let doc = nodeDocument(aNode);
this.walker = doc.createTreeWalker(nodeDocument(aNode),
this.walker = doc.createTreeWalker(doc,
aShow, aFilter, aExpandEntityReferences);
this.walker.currentNode = aNode;
this.filter = aFilter;

Просмотреть файл

@ -31,10 +31,13 @@ function ThreadActor(aHooks, aGlobal)
this._environmentActors = [];
this._hooks = aHooks;
this.global = aGlobal;
// A map of actorID -> actor for breakpoints created and managed by the server.
this._hiddenBreakpoints = new Map();
this.findGlobals = this.globalManager.findGlobals.bind(this);
this.onNewGlobal = this.globalManager.onNewGlobal.bind(this);
this.onNewSource = this.onNewSource.bind(this);
this._allEventsListener = this._allEventsListener.bind(this);
this._options = {
useSourceMaps: false
@ -85,14 +88,18 @@ ThreadActor.prototype = {
/**
* Add a debuggee global to the Debugger object.
*
* @returns the Debugger.Object that corresponds to the global.
*/
addDebuggee: function TA_addDebuggee(aGlobal) {
let globalDebugObject;
try {
this.dbg.addDebuggee(aGlobal);
globalDebugObject = this.dbg.addDebuggee(aGlobal);
} catch (e) {
// Ignore attempts to add the debugger's compartment as a debuggee.
dumpn("Ignoring request to add the debugger's compartment as a debuggee");
}
return globalDebugObject;
},
/**
@ -122,15 +129,18 @@ ThreadActor.prototype = {
/**
* Add the provided window and all windows in its frame tree as debuggees.
*
* @returns the Debugger.Object that corresponds to the window.
*/
_addDebuggees: function TA__addDebuggees(aWindow) {
this.addDebuggee(aWindow);
let globalDebugObject = this.addDebuggee(aWindow);
let frames = aWindow.frames;
if (frames) {
for (let i = 0; i < frames.length; i++) {
this._addDebuggees(frames[i]);
}
}
return globalDebugObject;
},
/**
@ -139,7 +149,7 @@ ThreadActor.prototype = {
*/
globalManager: {
findGlobals: function TA_findGlobals() {
this._addDebuggees(this.global);
this.globalDebugObject = this._addDebuggees(this.global);
},
/**
@ -413,12 +423,31 @@ ThreadActor.prototype = {
stepFrame.onPop = onPop;
}
}
} else {
// Clear any previous stepping hooks on a plain resumption.
let frame = this.youngestFrame;
while (frame) {
frame.onStep = undefined;
frame.onPop = undefined;
frame = frame.older;
}
}
if (aRequest) {
this._options.pauseOnExceptions = aRequest.pauseOnExceptions;
this.maybePauseOnExceptions();
// Break-on-DOMEvents is only supported in content debugging.
let events = aRequest.pauseOnDOMEvents;
if (this.global && events &&
(events == "*" ||
(Array.isArray(events) && events.length))) {
this._pauseOnDOMEvents = events;
let els = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService);
els.addListenerForAllEvents(this.global, this._allEventsListener, true);
}
}
let packet = this._resumed();
DebuggerServer.xpcInspector.exitNestedEventLoop();
return packet;
@ -433,6 +462,86 @@ ThreadActor.prototype = {
}
},
/**
* A listener that gets called for every event fired on the page, when a list
* of interesting events was provided with the pauseOnDOMEvents property. It
* is used to set server-managed breakpoints on any existing event listeners
* for those events.
*
* @param Event event
* The event that was fired.
*/
_allEventsListener: function(event) {
if (this._pauseOnDOMEvents == "*" ||
this._pauseOnDOMEvents.indexOf(event.type) != -1) {
for (let listener of this._getAllEventListeners(event.target)) {
if (event.type == listener.type || this._pauseOnDOMEvents == "*") {
this._breakOnEnter(listener.script);
}
}
}
},
/**
* Return an array containing all the event listeners attached to the
* specified event target and its ancestors in the event target chain.
*
* @param EventTarget eventTarget
* The target the event was dispatched on.
* @returns Array
*/
_getAllEventListeners: function(eventTarget) {
let els = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService);
let targets = els.getEventTargetChainFor(eventTarget);
let listeners = [];
for (let target of targets) {
let handlers = els.getListenerInfoFor(target);
for (let handler of handlers) {
// Null is returned for all-events handlers, and native event listeners
// don't provide any listenerObject, which makes them not that useful to
// a JS debugger.
if (!handler || !handler.listenerObject || !handler.type)
continue;
// Create a listener-like object suitable for our purposes.
let l = Object.create(null);
l.type = handler.type;
let listener = handler.listenerObject;
l.script = this.globalDebugObject.makeDebuggeeValue(listener).script;
// Chrome listeners won't be converted to debuggee values, since their
// compartment is not added as a debuggee.
if (!l.script)
continue;
listeners.push(l);
}
}
return listeners;
},
/**
* Set a breakpoint on the first bytecode offset in the provided script.
*/
_breakOnEnter: function(script) {
let offsets = script.getAllOffsets();
for (let line = 0, n = offsets.length; line < n; line++) {
if (offsets[line]) {
let location = { url: script.url, line: line };
let resp = this._createAndStoreBreakpoint(location);
dbg_assert(!resp.actualLocation, "No actualLocation should be returned");
if (resp.error) {
reportError(new Error("Unable to set breakpoint on event listener"));
return;
}
let bpActor = this._breakpointStore[location.url][location.line].actor;
dbg_assert(bpActor, "Breakpoint actor must be created");
this._hiddenBreakpoints.set(bpActor.actorID, bpActor);
break;
}
}
},
/**
* Helper method that returns the next frame when stepping.
*/
@ -568,19 +677,7 @@ ThreadActor.prototype = {
return { error: "noScript" };
}
// Add the breakpoint to the store for later reuse, in case it belongs to a
// script that hasn't appeared yet.
if (!this._breakpointStore[aLocation.url]) {
this._breakpointStore[aLocation.url] = [];
}
let scriptBreakpoints = this._breakpointStore[aLocation.url];
scriptBreakpoints[line] = {
url: aLocation.url,
line: line,
column: aLocation.column
};
let response = this._setBreakpoint(aLocation);
let response = this._createAndStoreBreakpoint(aLocation);
// If the original location of our generated location is different from
// the original location we attempted to set the breakpoint on, we will
// need to know so that we can set actualLocation on the response.
@ -609,6 +706,25 @@ ThreadActor.prototype = {
});
},
/**
* Create a breakpoint at the specified location and store it in the cache.
*/
_createAndStoreBreakpoint: function (aLocation) {
// Add the breakpoint to the store for later reuse, in case it belongs to
// a script that hasn't appeared yet.
if (!this._breakpointStore[aLocation.url]) {
this._breakpointStore[aLocation.url] = [];
}
let scriptBreakpoints = this._breakpointStore[aLocation.url];
scriptBreakpoints[aLocation.line] = {
url: aLocation.url,
line: aLocation.line,
column: aLocation.column
};
return this._setBreakpoint(aLocation);
},
/**
* Set a breakpoint using the jsdbg2 API. If the line on which the breakpoint
* is being set contains no code, then the breakpoint will slide down to the
@ -828,6 +944,59 @@ ThreadActor.prototype = {
}
},
/**
* Handle a protocol request to retrieve all the event listeners on the page.
*/
onEventListeners: function TA_onEventListeners(aRequest) {
// This request is only supported in content debugging.
if (!this.global) {
return {
error: "notImplemented",
message: "eventListeners request is only supported in content debugging"
}
}
let els = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService);
let nodes = this.global.document.getElementsByTagName("*");
nodes = [this.global].concat([].slice.call(nodes));
let listeners = [];
for (let node of nodes) {
let handlers = els.getListenerInfoFor(node);
for (let handler of handlers) {
// Create a form object for serializing the listener via the protocol.
let listenerForm = Object.create(null);
let listener = handler.listenerObject;
// Native event listeners don't provide any listenerObject and are not
// that useful to a JS debugger.
if (!listener) {
continue;
}
// There will be no tagName if the event listener is set on the window.
let selector = node.tagName ? findCssSelector(node) : "window";
let nodeDO = this.globalDebugObject.makeDebuggeeValue(node);
listenerForm.node = {
selector: selector,
object: this.createValueGrip(nodeDO)
};
listenerForm.type = handler.type;
listenerForm.capturing = handler.capturing;
listenerForm.allowsUntrusted = handler.allowsUntrusted;
listenerForm.inSystemEventGroup = handler.inSystemEventGroup;
listenerForm.isEventHandler = !!node["on" + listenerForm.type];
// Get the Debugger.Object for the listener object.
let listenerDO = this.globalDebugObject.makeDebuggeeValue(listener);
listenerForm.function = this.createValueGrip(listenerDO);
listeners.push(listenerForm);
}
}
return { listeners: listeners };
},
/**
* Return the Debug.Frame for a frame mentioned by the protocol.
*/
@ -862,6 +1031,18 @@ ThreadActor.prototype = {
aFrame.onStep = undefined;
aFrame.onPop = undefined;
}
// Clear DOM event breakpoints.
// XPCShell tests don't use actual DOM windows for globals and cause
// removeListenerForAllEvents to throw.
if (this.global && !this.global.toString().contains("Sandbox")) {
let els = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService);
els.removeListenerForAllEvents(this.global, this._allEventsListener, true);
for (let [,bp] of this._hiddenBreakpoints) {
bp.onDelete();
}
this._hiddenBreakpoints.clear();
}
this._state = "paused";
@ -871,7 +1052,7 @@ ThreadActor.prototype = {
// Create the actor pool that will hold the pause actor and its
// children.
dbg_assert(!this._pausePool);
dbg_assert(!this._pausePool, "No pause pool should exist yet");
this._pausePool = new ActorPool(this.conn);
this.conn.addActorPool(this._pausePool);
@ -880,7 +1061,7 @@ ThreadActor.prototype = {
this._pausePool.threadActor = this;
// Create the pause actor itself...
dbg_assert(!this._pauseActor);
dbg_assert(!this._pauseActor, "No pause actor should exist yet");
this._pauseActor = new PauseActor(this._pausePool);
this._pausePool.addActor(this._pauseActor);
@ -912,7 +1093,7 @@ ThreadActor.prototype = {
requestor.connection = this.conn;
DebuggerServer.xpcInspector.enterNestedEventLoop(requestor);
dbg_assert(this.state === "running");
dbg_assert(this.state === "running", "Should be in the running state");
if (this._hooks.postNest) {
this._hooks.postNest(nestData)
@ -1218,7 +1399,9 @@ ThreadActor.prototype = {
* The stack frame that contained the debugger statement.
*/
onDebuggerStatement: function TA_onDebuggerStatement(aFrame) {
if (this.sources.isBlackBoxed(aFrame.script.url)) {
// Don't pause if we are currently stepping (in or over) or the frame is
// black-boxed.
if (this.sources.isBlackBoxed(aFrame.script.url) || aFrame.onStep) {
return undefined;
}
return this._pauseAndRespond(aFrame, { type: "debuggerStatement" });
@ -1348,6 +1531,7 @@ ThreadActor.prototype.requestTypes = {
"clientEvaluate": ThreadActor.prototype.onClientEvaluate,
"frames": ThreadActor.prototype.onFrames,
"interrupt": ThreadActor.prototype.onInterrupt,
"eventListeners": ThreadActor.prototype.onEventListeners,
"releaseMany": ThreadActor.prototype.onReleaseMany,
"setBreakpoint": ThreadActor.prototype.onSetBreakpoint,
"sources": ThreadActor.prototype.onSources,
@ -1583,6 +1767,12 @@ ObjectActor.prototype = {
if (desc && desc.value && typeof desc.value == "string") {
g.userDisplayName = this.threadActor.createValueGrip(desc.value);
}
// Add source location information.
if (this.obj.script) {
g.url = this.obj.script.url;
g.line = this.obj.script.startLine;
}
}
return g;
@ -2192,12 +2382,21 @@ BreakpointActor.prototype = {
* The stack frame that contained the breakpoint.
*/
hit: function BA_hit(aFrame) {
if (this.threadActor.sources.isBlackBoxed(this.location.url)) {
// Don't pause if we are currently stepping (in or over) or the frame is
// black-boxed.
if (this.threadActor.sources.isBlackBoxed(this.location.url) ||
aFrame.onStep) {
return undefined;
}
// TODO: add the rest of the breakpoints on that line (bug 676602).
let reason = { type: "breakpoint", actors: [ this.actorID ] };
let reason = {};
if (this.threadActor._hiddenBreakpoints.has(this.actorID)) {
reason.type = "pauseOnDOMEvents";
} else {
reason.type = "breakpoint";
// TODO: add the rest of the breakpoints on that line (bug 676602).
reason.actors = [ this.actorID ];
}
return this.threadActor._pauseAndRespond(aFrame, reason, (aPacket) => {
let { url, line } = aPacket.frame.where;
return this.threadActor.sources.getOriginalLocation(url, line)
@ -2632,7 +2831,7 @@ ThreadSources.prototype = {
if (aScript.url in this._sourceMapsByGeneratedSource) {
return this._sourceMapsByGeneratedSource[aScript.url];
}
dbg_assert(aScript.sourceMapURL);
dbg_assert(aScript.sourceMapURL, "Script should have a sourceMapURL");
let sourceMapURL = this._normalize(aScript.sourceMapURL, aScript.url);
let map = this._fetchSourceMap(sourceMapURL)
.then((aSourceMap) => {
@ -2770,7 +2969,7 @@ ThreadSources.prototype = {
* Normalize multiple relative paths towards the base paths on the right.
*/
_normalize: function TS__normalize(...aURLs) {
dbg_assert(aURLs.length > 1);
dbg_assert(aURLs.length > 1, "Should have more than 1 URL");
let base = Services.io.newURI(aURLs.pop(), null, null);
let url;
while ((url = aURLs.pop())) {
@ -2939,3 +3138,80 @@ function reportError(aError, aPrefix="") {
Cu.reportError(msg);
dumpn(msg);
}
// The following are copied here verbatim from css-logic.js, until we create a
// server-friendly helper module.
/**
* Find a unique CSS selector for a given element
* @returns a string such that ele.ownerDocument.querySelector(reply) === ele
* and ele.ownerDocument.querySelectorAll(reply).length === 1
*/
function findCssSelector(ele) {
var document = ele.ownerDocument;
if (ele.id && document.getElementById(ele.id) === ele) {
return '#' + ele.id;
}
// Inherently unique by tag name
var tagName = ele.tagName.toLowerCase();
if (tagName === 'html') {
return 'html';
}
if (tagName === 'head') {
return 'head';
}
if (tagName === 'body') {
return 'body';
}
if (ele.parentNode == null) {
console.log('danger: ' + tagName);
}
// We might be able to find a unique class name
var selector, index, matches;
if (ele.classList.length > 0) {
for (var i = 0; i < ele.classList.length; i++) {
// Is this className unique by itself?
selector = '.' + ele.classList.item(i);
matches = document.querySelectorAll(selector);
if (matches.length === 1) {
return selector;
}
// Maybe it's unique with a tag name?
selector = tagName + selector;
matches = document.querySelectorAll(selector);
if (matches.length === 1) {
return selector;
}
// Maybe it's unique using a tag name and nth-child
index = positionInNodeList(ele, ele.parentNode.children) + 1;
selector = selector + ':nth-child(' + index + ')';
matches = document.querySelectorAll(selector);
if (matches.length === 1) {
return selector;
}
}
}
// So we can be unique w.r.t. our parent, and use recursion
index = positionInNodeList(ele, ele.parentNode.children) + 1;
selector = findCssSelector(ele.parentNode) + ' > ' +
tagName + ':nth-child(' + index + ')';
return selector;
};
/**
* Find the position of [element] in [nodeList].
* @returns an index of the match, or -1 if there is no match
*/
function positionInNodeList(element, nodeList) {
for (var i = 0; i < nodeList.length; i++) {
if (element === nodeList[i]) {
return i;
}
}
return -1;
}

Просмотреть файл

@ -16,11 +16,13 @@ MOCHITEST_CHROME_FILES = \
inspector-traversal-data.html \
test_inspector-changeattrs.html \
test_inspector-changevalue.html \
test_inspector-insert.html \
test_inspector-mutations-attr.html \
test_inspector-mutations-childlist.html \
test_inspector-mutations-frameload.html \
test_inspector-mutations-value.html \
test_inspector-release.html \
test_inspector-remove.html \
test_inspector-retain.html \
test_inspector-pseudoclass-lock.html \
test_inspector-traversal.html \

Просмотреть файл

@ -0,0 +1,96 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=
-->
<head>
<meta charset="utf-8">
<title>Test for Bug </title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
<script type="application/javascript;version=1.8">
Components.utils.import("resource://gre/modules/devtools/Loader.jsm");
const promise = devtools.require("sdk/core/promise");
const inspector = devtools.require("devtools/server/actors/inspector");
window.onload = function() {
SimpleTest.waitForExplicitFinish();
runNextTest();
}
var gWalker = null;
var gClient = null;
function assertOwnership() {
return assertOwnershipTrees(gWalker);
}
addTest(function setup() {
let url = document.getElementById("inspectorContent").href;
attachURL(url, function(err, client, tab, doc) {
gInspectee = doc;
let {InspectorFront} = devtools.require("devtools/server/actors/inspector");
let inspector = InspectorFront(client, tab);
promiseDone(inspector.getWalker().then(walker => {
ok(walker, "getWalker() should return an actor.");
gClient = client;
gWalker = walker;
}).then(runNextTest));
});
});
addTest(function testRearrange() {
let longlist = null;
let nodeA = null;
let nextNode = null;
promiseDone(gWalker.querySelector(gWalker.rootNode, "#longlist").then(listFront => {
longlist = listFront;
}).then(() => {
return gWalker.children(longlist);
}).then(response => {
nodeA = response.nodes[0];
is(nodeA.id, "a", "Got the expected node.");
// Move nodeA to the end of the list.
return gWalker.insertBefore(nodeA, longlist, null);
}).then(() => {
ok(!gInspectee.querySelector("#a").nextSibling, "a should now be at the end of the list.");
return gWalker.children(longlist);
}).then(response => {
is(nodeA, response.nodes[response.nodes.length - 1], "a should now be the last returned child.");
// Now move it to the middle of the list.
nextNode = response.nodes[13];
return gWalker.insertBefore(nodeA, longlist, nextNode);
}).then(response => {
let sibling = inspector._documentWalker(gInspectee.querySelector("#a")).nextSibling();
is(sibling, nextNode.rawNode(), "Node should match the expected next node.");
return gWalker.children(longlist);
}).then(response => {
is(nodeA, response.nodes[13], "a should be where we expect it.");
is(nextNode, response.nodes[14], "next node should be where we expect it.");
}).then(runNextTest));
});
addTest(function cleanup() {
delete gWalker;
delete gClient;
runNextTest();
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
<a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,96 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=
-->
<head>
<meta charset="utf-8">
<title>Test for Bug </title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
<script type="application/javascript;version=1.8">
Components.utils.import("resource://gre/modules/devtools/Loader.jsm");
const promise = devtools.require("sdk/core/promise");
const inspector = devtools.require("devtools/server/actors/inspector");
window.onload = function() {
SimpleTest.waitForExplicitFinish();
runNextTest();
}
var gWalker = null;
var gClient = null;
function assertOwnership() {
return assertOwnershipTrees(gWalker);
}
addTest(function setup() {
let url = document.getElementById("inspectorContent").href;
attachURL(url, function(err, client, tab, doc) {
gInspectee = doc;
let {InspectorFront} = devtools.require("devtools/server/actors/inspector");
let inspector = InspectorFront(client, tab);
promiseDone(inspector.getWalker().then(walker => {
ok(walker, "getWalker() should return an actor.");
gClient = client;
gWalker = walker;
}).then(runNextTest));
});
});
addTest(function testRemoveSubtree() {
let originalOwnershipSize = 0;
let longlist = null;
let longlistID = null;
let nextSibling = gInspectee.querySelector("#longlist").nextSibling;
// Duplicate the walker logic to skip blank nodes...
while (nextSibling && nextSibling.nodeType === Components.interfaces.nsIDOMNode.TEXT_NODE && !/[^\s]/.exec(nextSibling.nodeValue)) {
nextSibling = nextSibling.nextSibling;
}
promiseDone(gWalker.querySelector(gWalker.rootNode, "#longlist").then(listFront => {
longlist = listFront;
longlistID = longlist.actorID;
}).then(() => {
return gWalker.children(longlist);
}).then((items)=> {
originalOwnershipSize = assertOwnership();
ok(originalOwnershipSize > 26, "Should have at least 26 items in our ownership tree");
return gWalker.removeNode(longlist);
}).then(nextSiblingFront => {
is(nextSiblingFront.rawNode(), nextSibling, "Should have returned the next sibling.");
return waitForMutation(gWalker, isChildList);
}).then(() => {
// Our ownership size should now be 26 fewer (we forgot about #longlist + 26 children, but learned about #longlist's next sibling)
let newOwnershipSize = assertOwnership();
is(newOwnershipSize, originalOwnershipSize - 26, "Ownership tree should have dropped by 27 nodes");
// Now verify that some nodes have gone away
return checkMissing(gClient, longlistID);
}).then(runNextTest));
});
addTest(function cleanup() {
delete gWalker;
delete gClient;
runNextTest();
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
<a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -43,6 +43,13 @@ function scriptErrorFlagsToKind(aFlags) {
return kind;
}
// Redeclare dbg_assert with a fatal behavior.
function dbg_assert(cond, e) {
if (!cond) {
throw e;
}
}
// Register a console listener, so console messages don't just disappear
// into the ether.
let errorCount = 0;

Просмотреть файл

@ -151,11 +151,7 @@ function runTest(aOnSteppedLocation, aOnDebuggerStatementFrames, aFinishedCallba
do_check_eq(aPacket.why.type, "debuggerStatement");
gThreadClient.getFrames(0, 100, function ({frames}) {
aOnDebuggerStatementFrames(frames);
// We hit the breakpoint once more on the way out
gClient.addOneTimeListener("paused", function () {
gThreadClient.resume(aFinishedCallback);
});
gThreadClient.resume();
gThreadClient.resume(aFinishedCallback);
});
});
gThreadClient.resume();

Просмотреть файл

@ -0,0 +1,105 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that execution doesn't pause twice while stepping, when encountering
* either a breakpoint or a debugger statement.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_simple_breakpoint();
});
});
do_test_pending();
}
function test_simple_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let path = getFilePath('test_breakpoint-13.js');
let location = { url: path, line: gDebuggee.line0 + 2};
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check that the stepping worked.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 5);
do_check_eq(aPacket.why.type, "resumeLimit");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Entered the foo function call frame.
do_check_eq(aPacket.frame.where.line, location.line);
do_check_neq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.type, "resumeLimit");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check that the breakpoint wasn't the reason for this pause, but
// that the frame is about to be popped while stepping.
do_check_eq(aPacket.frame.where.line, location.line);
do_check_neq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.type, "resumeLimit");
do_check_eq(aPacket.why.frameFinished.return.type, "undefined");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// The foo function call frame was just popped from the stack.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 5);
do_check_eq(aPacket.why.type, "resumeLimit");
do_check_eq(aPacket.poppedFrames.length, 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check that the debugger statement wasn't the reason for this pause.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 6);
do_check_neq(aPacket.why.type, "debuggerStatement");
do_check_eq(aPacket.why.type, "resumeLimit");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check that the debugger statement wasn't the reason for this pause.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 7);
do_check_neq(aPacket.why.type, "debuggerStatement");
do_check_eq(aPacket.why.type, "resumeLimit");
// Remove the breakpoint and finish.
bpClient.remove(() => gThreadClient.resume(() => finishClient(gClient)));
});
// Step past the debugger statement.
gThreadClient.stepIn();
});
// Step into the debugger statement.
gThreadClient.stepIn();
});
// Get back to the frame above.
gThreadClient.stepIn();
});
// Step to the end of the function call frame.
gThreadClient.stepIn();
});
// Step into the function call.
gThreadClient.stepIn();
});
// Step into the next line with the function call.
gThreadClient.stepIn();
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2 <-- Breakpoint is set here.
"}\n" + // line0 + 3
"debugger;\n" + // line0 + 4
"foo();\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"var b = 2;\n"); // line0 + 7
}

Просмотреть файл

@ -0,0 +1,103 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that a breakpoint or a debugger statement cause execution to pause even
* in a stepped-over function.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_simple_breakpoint();
});
});
do_test_pending();
}
function test_simple_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let path = getFilePath('test_breakpoint-14.js');
let location = { url: path, line: gDebuggee.line0 + 2};
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check that the stepping worked.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 5);
do_check_eq(aPacket.why.type, "resumeLimit");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Reached the breakpoint.
do_check_eq(aPacket.frame.where.line, location.line);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_neq(aPacket.why.type, "resumeLimit");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// The frame is about to be popped while stepping.
do_check_eq(aPacket.frame.where.line, location.line);
do_check_neq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.type, "resumeLimit");
do_check_eq(aPacket.why.frameFinished.return.type, "undefined");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// The foo function call frame was just popped from the stack.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 5);
do_check_eq(aPacket.why.type, "resumeLimit");
do_check_eq(aPacket.poppedFrames.length, 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check that the debugger statement wasn't the reason for this pause.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 6);
do_check_neq(aPacket.why.type, "debuggerStatement");
do_check_eq(aPacket.why.type, "resumeLimit");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check that the debugger statement wasn't the reason for this pause.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 7);
do_check_neq(aPacket.why.type, "debuggerStatement");
do_check_eq(aPacket.why.type, "resumeLimit");
// Remove the breakpoint and finish.
bpClient.remove(() => gThreadClient.resume(() => finishClient(gClient)));
});
// Step past the debugger statement.
gThreadClient.stepOver();
});
// Step over the debugger statement.
gThreadClient.stepOver();
});
// Get back to the frame above.
gThreadClient.stepOver();
});
// Step to the end of the function call frame.
gThreadClient.stepOver();
});
// Step over the function call.
gThreadClient.stepOver();
});
// Step over to the next line with the function call.
gThreadClient.stepOver();
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2 <-- Breakpoint is set here.
"}\n" + // line0 + 3
"debugger;\n" + // line0 + 4
"foo();\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"var b = 2;\n"); // line0 + 7
}

Просмотреть файл

@ -81,6 +81,12 @@ reason = bug 820380
[test_breakpoint-12.js]
skip-if = toolkit == "gonk"
reason = bug 820380
[test_breakpoint-13.js]
skip-if = toolkit == "gonk"
reason = bug 820380
[test_breakpoint-14.js]
skip-if = toolkit == "gonk"
reason = bug 820380
[test_listsources-01.js]
[test_listsources-02.js]
[test_listsources-03.js]

Просмотреть файл

@ -172,6 +172,60 @@ this.Promise = Object.freeze({
PromiseWalker.completePromise(promise, STATUS_REJECTED, aReason);
return promise;
},
/**
* Returns a promise that is resolved or rejected when all values are
* resolved or any is rejected.
*
* @param aValues
* Array of promises that may be pending, resolved, or rejected. When
* all are resolved or any is rejected, the returned promise will be
* resolved or rejected as well.
*
* @return A new promise that is fulfilled when all values are resolved or
* that is rejected when any of the values are rejected. Its
* resolution value will be an array of all resolved values in the
* given order, or undefined if aValues is an empty array. The reject
* reason will be forwarded from the first promise in the list of
* given promises to be rejected.
*/
every: function (aValues)
{
if (!Array.isArray(aValues)) {
throw new Error("Promise.every() expects an array of promises or values.");
}
if (!aValues.length) {
return Promise.resolve(undefined);
}
let countdown = aValues.length;
let deferred = Promise.defer();
let resolutionValues = new Array(countdown);
function checkForCompletion(aValue, aIndex) {
resolutionValues[aIndex] = aValue;
if (--countdown === 0) {
deferred.resolve(resolutionValues);
}
}
for (let i = 0; i < aValues.length; i++) {
let index = i;
let value = aValues[i];
let resolve = val => checkForCompletion(val, index);
if (value && typeof(value.then) == "function") {
value.then(resolve, deferred.reject);
} else {
// Given value is not a promise, forward it as a resolution value.
resolve(value);
}
}
return deferred.promise;
},
});
////////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -8,8 +8,6 @@ Components.utils.import("resource://gre/modules/Promise.jsm");
//// Test runner
let run_promise_tests = function run_promise_tests(tests, cb) {
let timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
let loop = function loop(index) {
if (index >= tests.length) {
if (cb) {
@ -585,6 +583,84 @@ tests.push(
return promise;
}));
// Test that the values of the promise return by Promise.every() are kept in the
// given order even if the given promises are resolved in arbitrary order
tests.push(
make_promise_test(function every_resolve(test) {
let d1 = Promise.defer();
let d2 = Promise.defer();
let d3 = Promise.defer();
d3.resolve(4);
d2.resolve(2);
do_execute_soon(() => d1.resolve(1));
let promises = [d1.promise, d2.promise, 3, d3.promise];
return Promise.every(promises).then(
function onResolve([val1, val2, val3, val4]) {
do_check_eq(val1, 1);
do_check_eq(val2, 2);
do_check_eq(val3, 3);
do_check_eq(val4, 4);
}
);
}));
// Test that rejecting one of the promises passed to Promise.every()
// rejects the promise return by Promise.every()
tests.push(
make_promise_test(function every_reject(test) {
let error = new Error("Boom");
let d1 = Promise.defer();
let d2 = Promise.defer();
let d3 = Promise.defer();
d3.resolve(3);
d2.resolve(2);
do_execute_soon(() => d1.reject(error));
let promises = [d1.promise, d2.promise, d3.promise];
return Promise.every(promises).then(
function onResolve() {
do_throw("Incorrect call to onResolve listener");
},
function onReject(reason) {
do_check_eq(reason, error, "Rejection lead to the expected reason");
}
);
}));
// Test that passing only values (not promises) to Promise.every()
// forwards them all as resolution values.
tests.push(
make_promise_test(function every_resolve_no_promises(test) {
try {
Promise.every(null);
do_check_true(false, "every() should only accept arrays.");
} catch (e) {
do_check_true(true, "every() fails when first the arg is not an array.");
}
let p1 = Promise.every([]).then(
function onResolve(val) {
do_check_eq(typeof(val), "undefined");
}
);
let p2 = Promise.every([1, 2, 3]).then(
function onResolve([val1, val2, val3]) {
do_check_eq(val1, 1);
do_check_eq(val2, 2);
do_check_eq(val3, 3);
}
);
return Promise.every([p1, p2]);
}));
function run_test()
{
do_test_pending();