зеркало из https://github.com/mozilla/gecko-dev.git
Merge latest green inbound changeset and mozilla-central
This commit is contained in:
Коммит
7be3034ecd
|
@ -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><</span><span save="${tag}" class="tagname theme-fg-color3"></span><span save="${attrList}"></span><span save="${newAttr}" class="newattr" tabindex="0"></span>></span>
|
||||
<span id="template-element" save="${elt}" class="editor"><span><</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">></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>="<span save="${val}" class="attrvalue theme-fg-color6"></span>"</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>¶m2=ü"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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче