зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound and mozilla-central.
(The mozilla-central side of the merge is entirely a merge from fx-team into mozilla-central.)
This commit is contained in:
Коммит
3d0109705b
|
@ -1032,7 +1032,6 @@ pref("devtools.toolbox.host", "bottom");
|
|||
pref("devtools.toolbox.selectedTool", "webconsole");
|
||||
pref("devtools.toolbox.toolbarSpec", '["paintflashing toggle","tilt toggle","scratchpad","resize toggle"]');
|
||||
pref("devtools.toolbox.sideEnabled", true);
|
||||
pref("devtools.toolbox.disabledTools", "[]");
|
||||
|
||||
// Enable the Inspector
|
||||
pref("devtools.inspector.enabled", true);
|
||||
|
|
|
@ -30,6 +30,7 @@ MOCHITEST_BROWSER_FILES = \
|
|||
browser_input.js \
|
||||
browser_input_sample.html \
|
||||
browser_pageshow.js \
|
||||
browser_windowRestore_perwindowpb.js \
|
||||
browser_248970_b_perwindowpb.js \
|
||||
browser_248970_b_sample.html \
|
||||
browser_339445.js \
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/* 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/. */
|
||||
|
||||
// This test checks that closed private windows can't be restored
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Purging the list of closed windows
|
||||
while(ss.getClosedWindowCount() > 0)
|
||||
ss.forgetClosedWindow(0);
|
||||
|
||||
// Load a private window, then close it
|
||||
// and verify it doesn't get remembered for restoring
|
||||
var win = OpenBrowserWindow({private: true});
|
||||
|
||||
whenWindowLoaded(win, function onload() {
|
||||
info("The private window got loaded");
|
||||
win.addEventListener("SSWindowClosing", function onclosing() {
|
||||
win.removeEventListener("SSWindowClosing", onclosing, false);
|
||||
executeSoon(function () {
|
||||
is (ss.getClosedWindowCount(), 0,
|
||||
"The private window should not have been stored");
|
||||
finish();
|
||||
});
|
||||
}, false);
|
||||
win.close();
|
||||
});
|
||||
}
|
|
@ -9,12 +9,14 @@ const BRAND_SHORT_NAME = Cc["@mozilla.org/intl/stringbundle;1"]
|
|||
.createBundle("chrome://branding/locale/brand.properties")
|
||||
.GetStringFromName("brandShortName");
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "CmdAddonFlags", "CmdCommands" ];
|
||||
this.EXPORTED_SYMBOLS = [ "CmdAddonFlags", "CmdCommands", "DEFAULT_DEBUG_PORT", "connect" ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
Cu.import("resource://gre/modules/osfile.jsm")
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/gcli.jsm");
|
||||
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
|
||||
|
@ -425,7 +427,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
description: gcli.lookup("calllogStartDesc"),
|
||||
|
||||
exec: function(args, context) {
|
||||
let contentWindow = context.environment.contentDocument.defaultView;
|
||||
let contentWindow = context.environment.window;
|
||||
|
||||
let dbg = new Debugger(contentWindow);
|
||||
dbg.onEnterFrame = function(frame) {
|
||||
|
@ -529,7 +531,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
],
|
||||
exec: function(args, context) {
|
||||
let globalObj;
|
||||
let contentWindow = context.environment.contentDocument.defaultView;
|
||||
let contentWindow = context.environment.window;
|
||||
|
||||
if (args.sourceType == "jsm") {
|
||||
try {
|
||||
|
@ -817,8 +819,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
name: "console clear",
|
||||
description: gcli.lookup("consoleclearDesc"),
|
||||
exec: function Command_consoleClear(args, context) {
|
||||
let window = context.environment.contentDocument.defaultView;
|
||||
let hud = HUDService.getHudByWindow(window);
|
||||
let hud = HUDService.getHudByWindow(context.environment.window);
|
||||
// hud will be null if the web console has not been opened for this window
|
||||
if (hud) {
|
||||
hud.jsterm.clearOutput();
|
||||
|
@ -976,7 +977,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
returnType: "cookies",
|
||||
exec: function Command_cookieList(args, context) {
|
||||
let host = context.environment.document.location.host;
|
||||
if (host == null) {
|
||||
if (host == null || host == "") {
|
||||
throw new Error(gcli.lookup("cookieListOutNonePage"));
|
||||
}
|
||||
|
||||
|
@ -1023,7 +1024,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
|
||||
let cookies = [];
|
||||
while (enm.hasMoreElements()) {
|
||||
let cookie = enm.getNext().QueryInterface(Components.interfaces.nsICookie);
|
||||
let cookie = enm.getNext().QueryInterface(Ci.nsICookie);
|
||||
if (isCookieAtHost(cookie, host)) {
|
||||
if (cookie.name == args.name) {
|
||||
cookieMgr.remove(cookie.host, cookie.name, cookie.path, false);
|
||||
|
@ -1156,30 +1157,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
}
|
||||
}(this));
|
||||
|
||||
/* CmdEcho ----------------------------------------------------------------- */
|
||||
|
||||
(function(module) {
|
||||
/**
|
||||
* 'echo' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "echo",
|
||||
description: gcli.lookup("echoDesc"),
|
||||
params: [
|
||||
{
|
||||
name: "message",
|
||||
type: "string",
|
||||
description: gcli.lookup("echoMessageDesc")
|
||||
}
|
||||
],
|
||||
returnType: "string",
|
||||
hidden: true,
|
||||
exec: function Command_echo(args, context) {
|
||||
return args.message;
|
||||
}
|
||||
});
|
||||
}(this));
|
||||
|
||||
/* CmdExport --------------------------------------------------------------- */
|
||||
|
||||
(function(module) {
|
||||
|
@ -1403,7 +1380,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
},
|
||||
],
|
||||
exec: function(args, context) {
|
||||
let document = context.environment.contentDocument;
|
||||
let searchTextNodes = !args.attrOnly;
|
||||
let searchAttributes = !args.contentOnly;
|
||||
let regexOptions = args.ignoreCase ? 'ig' : 'g';
|
||||
|
@ -1413,7 +1389,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
attributeRegex = new RegExp(args.attributes, regexOptions);
|
||||
}
|
||||
|
||||
let root = args.root || document;
|
||||
let root = args.root || context.environment.document;
|
||||
let elements = root.querySelectorAll(args.selector);
|
||||
elements = Array.prototype.slice.call(elements);
|
||||
|
||||
|
@ -1498,8 +1474,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
},
|
||||
],
|
||||
exec: function(args, context) {
|
||||
let document = context.environment.contentDocument;
|
||||
let root = args.root || document;
|
||||
let root = args.root || context.environment.document;
|
||||
let elements = Array.prototype.slice.call(root.querySelectorAll(args.search));
|
||||
|
||||
let removed = 0;
|
||||
|
@ -1555,9 +1530,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
},
|
||||
],
|
||||
exec: function(args, context) {
|
||||
let document = context.environment.contentDocument;
|
||||
|
||||
let root = args.root || document;
|
||||
let root = args.root || context.environment.document;
|
||||
let regexOptions = args.ignoreCase ? 'ig' : 'g';
|
||||
let attributeRegex = new RegExp(args.searchAttributes, regexOptions);
|
||||
let elements = root.querySelectorAll(args.searchElements);
|
||||
|
@ -1622,22 +1595,21 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
],
|
||||
returnType: "string",
|
||||
exec: function(args, context) {
|
||||
let promise = context.createPromise();
|
||||
let existsPromise = OS.File.exists(args.srcdir + "/CLOBBER");
|
||||
existsPromise.then(function(exists) {
|
||||
return OS.File.exists(args.srcdir + "/CLOBBER").then(function(exists) {
|
||||
if (exists) {
|
||||
var str = Cc["@mozilla.org/supports-string;1"]
|
||||
let str = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
str.data = args.srcdir;
|
||||
Services.prefs.setComplexValue("devtools.loader.srcdir",
|
||||
Components.interfaces.nsISupportsString, str);
|
||||
Ci.nsISupportsString, str);
|
||||
devtools.reload();
|
||||
promise.resolve(gcli.lookupFormat("toolsSrcdirReloaded", [args.srcdir]));
|
||||
return;
|
||||
|
||||
let msg = gcli.lookupFormat("toolsSrcdirReloaded", [args.srcdir]);
|
||||
throw new Error(msg);
|
||||
}
|
||||
promise.reject(gcli.lookupFormat("toolsSrcdirNotFound", [args.srcdir]));
|
||||
|
||||
return gcli.lookupFormat("toolsSrcdirNotFound", [args.srcdir]);
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1682,7 +1654,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
* >> restart --nocache
|
||||
* - restarts immediately and starts Firefox without using cache
|
||||
*/
|
||||
|
||||
gcli.addCommand({
|
||||
name: "restart",
|
||||
description: gcli.lookupFormat("restartBrowserDesc", [BRAND_SHORT_NAME]),
|
||||
|
@ -1733,7 +1704,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
name: "screenshot",
|
||||
description: gcli.lookup("screenshotDesc"),
|
||||
manual: gcli.lookup("screenshotManual"),
|
||||
returnType: "html",
|
||||
returnType: "dom",
|
||||
params: [
|
||||
{
|
||||
name: "filename",
|
||||
|
@ -1788,7 +1759,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
throw new Error(gcli.lookup("screenshotSelectorChromeConflict"));
|
||||
}
|
||||
var document = args.chrome? context.environment.chromeDocument
|
||||
: context.environment.contentDocument;
|
||||
: context.environment.document;
|
||||
if (args.delay > 0) {
|
||||
var deferred = context.defer();
|
||||
document.defaultView.setTimeout(function Command_screenshotDelay() {
|
||||
|
@ -1803,9 +1774,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
args.fullpage, args.selector);
|
||||
}
|
||||
},
|
||||
grabScreen:
|
||||
function Command_screenshotGrabScreen(document, filename, clipboard,
|
||||
fullpage, node) {
|
||||
grabScreen: function(document, filename, clipboard, fullpage, node) {
|
||||
let window = document.defaultView;
|
||||
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
let left = 0;
|
||||
|
@ -1948,13 +1917,53 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
});
|
||||
}(this));
|
||||
|
||||
|
||||
/* Remoting ----------------------------------------------------------- */
|
||||
|
||||
const { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
|
||||
/**
|
||||
* 'listen' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "listen",
|
||||
description: gcli.lookup("listenDesc"),
|
||||
manual: gcli.lookup("listenManual"),
|
||||
params: [
|
||||
{
|
||||
name: "port",
|
||||
type: "number",
|
||||
get defaultValue() {
|
||||
return Services.prefs.getIntPref("devtools.debugger.chrome-debugging-port");
|
||||
},
|
||||
description: gcli.lookup("listenPortDesc"),
|
||||
}
|
||||
],
|
||||
exec: function Command_screenshot(args, context) {
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
var reply = DebuggerServer.openListener(args.port);
|
||||
if (!reply) {
|
||||
throw new Error(gcli.lookup("listenDisabledOutput"));
|
||||
}
|
||||
|
||||
if (DebuggerServer.initialized) {
|
||||
return gcli.lookupFormat("listenInitOutput", [ '' + args.port ]);
|
||||
}
|
||||
|
||||
return gcli.lookup("listenNoInitOutput");
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/* CmdPaintFlashing ------------------------------------------------------- */
|
||||
|
||||
(function(module) {
|
||||
/**
|
||||
* 'paintflashing' command
|
||||
*/
|
||||
|
||||
gcli.addCommand({
|
||||
name: 'paintflashing',
|
||||
description: gcli.lookup('paintflashingDesc')
|
||||
|
@ -1976,15 +1985,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
]
|
||||
}],
|
||||
exec: function(args, context) {
|
||||
var window;
|
||||
if (args.chrome) {
|
||||
window = context.environment.chromeDocument.defaultView;
|
||||
} else {
|
||||
window = context.environment.contentDocument.defaultView;
|
||||
}
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils).
|
||||
paintFlashing = true;
|
||||
var window = args.chrome ?
|
||||
context.environment.chromeWindow :
|
||||
context.environment.window;
|
||||
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.paintFlashing = true;
|
||||
onPaintFlashingChanged(context);
|
||||
}
|
||||
});
|
||||
|
@ -2005,14 +2012,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
]
|
||||
}],
|
||||
exec: function(args, context) {
|
||||
if (args.chrome) {
|
||||
var window = context.environment.chromeDocument.defaultView;
|
||||
} else {
|
||||
var window = context.environment.contentDocument.defaultView;
|
||||
}
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils).
|
||||
paintFlashing = false;
|
||||
var window = args.chrome ?
|
||||
context.environment.chromeWindow :
|
||||
context.environment.window;
|
||||
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.paintFlashing = false;
|
||||
onPaintFlashingChanged(context);
|
||||
}
|
||||
});
|
||||
|
@ -2041,7 +2047,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
},
|
||||
},
|
||||
tooltipText: gcli.lookup("paintflashingTooltip"),
|
||||
description: gcli.lookup('paintflashingOnDesc'),
|
||||
description: gcli.lookup('paintflashingToggleDesc'),
|
||||
manual: gcli.lookup('paintflashingManual'),
|
||||
exec: function(args, context) {
|
||||
var gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
|
||||
|
@ -2125,20 +2131,19 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
}],
|
||||
exec: function(args, context) {
|
||||
let utils;
|
||||
let promise = context.createPromise();
|
||||
let deferred = context.defer();
|
||||
|
||||
if (args.uri) {
|
||||
utils = new AppCacheUtils(args.uri);
|
||||
} else {
|
||||
let doc = context.environment.contentDocument;
|
||||
utils = new AppCacheUtils(doc);
|
||||
utils = new AppCacheUtils(context.environment.document);
|
||||
}
|
||||
|
||||
utils.validateManifest().then(function(errors) {
|
||||
promise.resolve([errors, utils.manifestURI || "-"]);
|
||||
deferred.resolve([errors, utils.manifestURI || "-"]);
|
||||
});
|
||||
|
||||
return promise;
|
||||
return deferred.promise;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2154,22 +2159,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
}
|
||||
});
|
||||
|
||||
gcli.addConverter({
|
||||
from: "appcacheentries",
|
||||
to: "view",
|
||||
exec: function(entries, context) {
|
||||
if (!entries) {
|
||||
return context.createView({
|
||||
html: "<span>" + gcli.lookup("appCacheManifestContainsErrors") + "</span>"
|
||||
});
|
||||
}
|
||||
|
||||
if (entries.length == 0) {
|
||||
return context.createView({
|
||||
html: "<span>" + gcli.lookup("appCacheNoResults") + "</span>"
|
||||
});
|
||||
}
|
||||
|
||||
let appcacheListEntries = "" +
|
||||
"<ul class='gcli-appcache-list'>" +
|
||||
" <li foreach='entry in ${entries}'>" +
|
||||
|
@ -2210,6 +2199,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
" </li>" +
|
||||
"</ul>";
|
||||
|
||||
gcli.addConverter({
|
||||
from: "appcacheentries",
|
||||
to: "view",
|
||||
exec: function(entries, context) {
|
||||
return context.createView({
|
||||
html: appcacheListEntries,
|
||||
data: {
|
||||
|
@ -2238,11 +2231,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
]
|
||||
}],
|
||||
exec: function(args, context) {
|
||||
let doc = context.environment.contentDocument;
|
||||
let utils = new AppCacheUtils();
|
||||
|
||||
let entries = utils.listEntries(args.search);
|
||||
return entries;
|
||||
return utils.listEntries(args.search);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2259,13 +2249,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
|
|||
}
|
||||
],
|
||||
exec: function(args, context) {
|
||||
let doc = context.environment.contentDocument;
|
||||
let utils = new AppCacheUtils();
|
||||
|
||||
let result = utils.viewEntry(args.key);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
return utils.viewEntry(args.key);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ MOCHITEST_BROWSER_FILES = \
|
|||
browser_cmd_appcache_valid_page2.html \
|
||||
browser_cmd_appcache_valid_page3.html \
|
||||
browser_cmd_commands.js \
|
||||
browser_cmd_cookie.html \
|
||||
browser_cmd_cookie.js \
|
||||
browser_cmd_jsb.js \
|
||||
browser_cmd_jsb_script.jsi \
|
||||
|
|
|
@ -16,13 +16,8 @@ function test() {
|
|||
tests.gatTest = function(options) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
// hack to reduce stack size as a result of bug 842347
|
||||
let onGatReadyInterjection = function() {
|
||||
executeSoon(onGatReady);
|
||||
};
|
||||
|
||||
let onGatReady = function() {
|
||||
Services.obs.removeObserver(onGatReadyInterjection, "gcli_addon_commands_ready");
|
||||
Services.obs.removeObserver(onGatReady, "gcli_addon_commands_ready");
|
||||
info("gcli_addon_commands_ready notification received, running tests");
|
||||
|
||||
let auditDone = helpers.audit(options, [
|
||||
|
@ -121,7 +116,7 @@ tests.gatTest = function(options) {
|
|||
});
|
||||
};
|
||||
|
||||
Services.obs.addObserver(onGatReadyInterjection, "gcli_addon_commands_ready", false);
|
||||
Services.obs.addObserver(onGatReady, "gcli_addon_commands_ready", false);
|
||||
|
||||
if (CmdAddonFlags.addonsLoaded) {
|
||||
info("The call to AddonManager.getAllAddons in BuiltinCommands.jsm is done.");
|
||||
|
|
|
@ -30,6 +30,25 @@ function test() {
|
|||
},
|
||||
},
|
||||
|
||||
{
|
||||
setup: function() {
|
||||
Services.prefs.setBoolPref("browser.cache.disk.enable", false);
|
||||
helpers.setInput(options, 'appcache list', 13);
|
||||
},
|
||||
check: {
|
||||
input: 'appcache list',
|
||||
markup: 'VVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {},
|
||||
},
|
||||
exec: {
|
||||
output: [ /cache is disabled/ ]
|
||||
},
|
||||
post: function(output) {
|
||||
Services.prefs.setBoolPref("browser.cache.disk.enable", true);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
setup: 'appcache list',
|
||||
check: {
|
||||
|
@ -56,8 +75,8 @@ function test() {
|
|||
exec: {
|
||||
output: [ /page1/, /page2/, /page3/ ]
|
||||
},
|
||||
post: function(output) {
|
||||
ok(!output.contains("index"), "index is not contained in output");
|
||||
post: function(output, text) {
|
||||
ok(!text.contains("index"), "index is not contained in output");
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -118,11 +137,11 @@ function test() {
|
|||
exec: {
|
||||
output: [ /no results/ ]
|
||||
},
|
||||
post: function(output) {
|
||||
ok(!output.contains("index"), "index is not contained in output");
|
||||
ok(!output.contains("page1"), "page1 is not contained in output");
|
||||
ok(!output.contains("page2"), "page1 is not contained in output");
|
||||
ok(!output.contains("page3"), "page1 is not contained in output");
|
||||
post: function(output, text) {
|
||||
ok(!text.contains("index"), "index is not contained in output");
|
||||
ok(!text.contains("page1"), "page1 is not contained in output");
|
||||
ok(!text.contains("page2"), "page1 is not contained in output");
|
||||
ok(!text.contains("page3"), "page1 is not contained in output");
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -15,17 +15,6 @@ function test() {
|
|||
}).then(finish);
|
||||
}
|
||||
|
||||
tests.testEcho = function(options) {
|
||||
return helpers.audit(options, [
|
||||
{
|
||||
setup: "echo message",
|
||||
exec: {
|
||||
output: "message",
|
||||
}
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
tests.testConsole = function(options) {
|
||||
let deferred = Promise.defer();
|
||||
let hud = null;
|
||||
|
@ -67,13 +56,8 @@ tests.testConsole = function(options) {
|
|||
}
|
||||
}
|
||||
]).then(function() {
|
||||
// FIXME: Remove this hack once bug 842347 is fixed
|
||||
// Gak - our promises impl causes so many stack frames that we blow up the
|
||||
// JS engine. Jumping to a new event with a truncated stack solves this.
|
||||
executeSoon(function() {
|
||||
deferred.resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
helpers.audit(options, [
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>GCLI cookie command test</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Cookie test</p>
|
||||
<p id=result></p>
|
||||
<script type="text/javascript">
|
||||
document.cookie = "zap=zep";
|
||||
document.cookie = "zip=zop";
|
||||
document.getElementById("result").innerHTML = document.cookie;
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
// Tests that the cookie commands works as they should
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,gcli-cookie";
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/"+
|
||||
"test/browser_cmd_cookie.html";
|
||||
|
||||
function test() {
|
||||
helpers.addTabWithToolbar(TEST_URI, function(options) {
|
||||
|
@ -79,14 +80,14 @@ function test() {
|
|||
{
|
||||
setup: "cookie list",
|
||||
exec: {
|
||||
output: 'No cookies found for host'
|
||||
output: [ /zap=zep/, /zip=zop/, /Edit/ ]
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: "cookie set fruit banana",
|
||||
setup: "cookie set zup banana",
|
||||
check: {
|
||||
args: {
|
||||
name: { value: 'fruit' },
|
||||
name: { value: 'zup' },
|
||||
value: { value: 'banana' },
|
||||
}
|
||||
},
|
||||
|
@ -97,24 +98,56 @@ function test() {
|
|||
{
|
||||
setup: "cookie list",
|
||||
exec: {
|
||||
output: [ /fruit=banana/, /Expires:/, /Edit/ ]
|
||||
output: [ /zap=zep/, /zip=zop/, /zup=banana/, /Edit/ ]
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: "cookie remove fruit",
|
||||
check: {
|
||||
args: {
|
||||
name: { value: 'fruit' },
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: ""
|
||||
}
|
||||
setup: "cookie remove zip",
|
||||
exec: { },
|
||||
},
|
||||
{
|
||||
setup: "cookie list",
|
||||
exec: {
|
||||
output: 'No cookies found for host'
|
||||
output: [ /zap=zep/, /zup=banana/, /Edit/ ]
|
||||
},
|
||||
post: function(output, text) {
|
||||
ok(!text.contains("zip"), "");
|
||||
ok(!text.contains("zop"), "");
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: "cookie remove zap",
|
||||
exec: { },
|
||||
},
|
||||
{
|
||||
setup: "cookie list",
|
||||
exec: {
|
||||
output: [ /zup=banana/, /Edit/ ]
|
||||
},
|
||||
post: function(output, text) {
|
||||
ok(!text.contains("zap"), "");
|
||||
ok(!text.contains("zep"), "");
|
||||
ok(!text.contains("zip"), "");
|
||||
ok(!text.contains("zop"), "");
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: "cookie remove zup",
|
||||
exec: { }
|
||||
},
|
||||
{
|
||||
setup: "cookie list",
|
||||
exec: {
|
||||
output: 'No cookies found for host example.com'
|
||||
},
|
||||
post: function(output, text) {
|
||||
ok(!text.contains("zap"), "");
|
||||
ok(!text.contains("zep"), "");
|
||||
ok(!text.contains("zip"), "");
|
||||
ok(!text.contains("zop"), "");
|
||||
ok(!text.contains("zup"), "");
|
||||
ok(!text.contains("banana"), "");
|
||||
ok(!text.contains("Edit"), "");
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -38,6 +38,7 @@ function test() {
|
|||
// var helpers = require('gclitest/helpers');
|
||||
var canon = require('gcli/canon');
|
||||
// var assert = require('test/assert');
|
||||
var Canon = canon.Canon;
|
||||
|
||||
var startCount = undefined;
|
||||
var events = undefined;
|
||||
|
@ -157,8 +158,6 @@ exports.testAddRemove2 = function(options) {
|
|||
return helpers.audit(options, [
|
||||
{
|
||||
setup: 'testadd',
|
||||
check: {
|
||||
},
|
||||
exec: {
|
||||
output: /^3$/
|
||||
},
|
||||
|
@ -199,4 +198,74 @@ exports.testAddRemove3 = function(options) {
|
|||
canon.onCanonChange.remove(canonChange);
|
||||
};
|
||||
|
||||
exports.testAltCanon = function(options) {
|
||||
var altCanon = new Canon();
|
||||
|
||||
var tss = {
|
||||
name: 'tss',
|
||||
params: [
|
||||
{ name: 'str', type: 'string' },
|
||||
{ name: 'num', type: 'number' },
|
||||
{ name: 'opt', type: { name: 'selection', data: [ '1', '2', '3' ] } },
|
||||
],
|
||||
exec: function(args, context) {
|
||||
return context.commandName + ':' +
|
||||
args.str + ':' + args.num + ':' + args.opt;
|
||||
}
|
||||
};
|
||||
altCanon.addCommand(tss);
|
||||
|
||||
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"]}}]}}',
|
||||
'JSON.stringify(commandSpecs)');
|
||||
|
||||
var remoter = function(args, context) {
|
||||
assert.is(context.commandName, 'tss', 'commandName is tss');
|
||||
|
||||
var cmd = altCanon.getCommand(context.commandName);
|
||||
return cmd.exec(args, context);
|
||||
};
|
||||
|
||||
canon.addProxyCommands('proxy', commandSpecs, remoter, 'test');
|
||||
|
||||
var parent = canon.getCommand('proxy');
|
||||
assert.is(parent.name, 'proxy', 'Parent command called proxy');
|
||||
|
||||
var child = canon.getCommand('proxy tss');
|
||||
assert.is(child.name, 'proxy tss', 'child command called proxy tss');
|
||||
|
||||
return helpers.audit(options, [
|
||||
{
|
||||
setup: 'proxy tss foo 6 3',
|
||||
check: {
|
||||
input: 'proxy tss foo 6 3',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVV',
|
||||
cursor: 17,
|
||||
status: 'VALID',
|
||||
args: {
|
||||
str: { value: 'foo', status: 'VALID' },
|
||||
num: { value: 6, status: 'VALID' },
|
||||
opt: { value: '3', status: 'VALID' }
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: 'tss:foo:6:3'
|
||||
},
|
||||
post: function() {
|
||||
canon.removeCommand('proxy');
|
||||
canon.removeCommand('proxy tss');
|
||||
|
||||
assert.is(canon.getCommand('proxy'), undefined, 'remove proxy');
|
||||
assert.is(canon.getCommand('proxy tss'), undefined, 'remove proxy tss');
|
||||
}
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
// });
|
||||
|
|
|
@ -758,7 +758,6 @@ exports.testSingleFloat = function(options) {
|
|||
current: '__command',
|
||||
status: 'ERROR',
|
||||
error: '',
|
||||
predictions: [ ],
|
||||
unassigned: [ ],
|
||||
args: {
|
||||
command: { name: 'tsf' },
|
||||
|
|
|
@ -519,9 +519,9 @@ exports.testSpaceComplete = function(options) {
|
|||
msg: { status: 'INCOMPLETE', message: '' },
|
||||
num: { status: 'VALID' },
|
||||
sel: { status: 'VALID' },
|
||||
bool: { value: false,status: 'VALID' },
|
||||
bool: { value: false, status: 'VALID' },
|
||||
num2: { status: 'VALID' },
|
||||
bool2: { value: false,status: 'VALID' },
|
||||
bool2: { value: false, status: 'VALID' },
|
||||
sel2: {
|
||||
value: 'with space',
|
||||
arg: ' --sel2 \'with space\' ',
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* 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-testContext.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');
|
||||
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, [
|
||||
// These 3 establish a baseline for comparison when we have used the
|
||||
// context command
|
||||
{
|
||||
setup: 'ext',
|
||||
check: {
|
||||
input: 'ext',
|
||||
hints: ' -> context',
|
||||
markup: 'III',
|
||||
message: '',
|
||||
predictions: [ 'context', 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend' ],
|
||||
unassigned: [ ],
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'ext test',
|
||||
check: {
|
||||
input: 'ext test',
|
||||
hints: '',
|
||||
markup: 'IIIVEEEE',
|
||||
status: 'ERROR',
|
||||
message: 'Too many arguments',
|
||||
unassigned: [ ' test' ],
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'tsn',
|
||||
check: {
|
||||
input: 'tsn',
|
||||
hints: '',
|
||||
markup: 'III',
|
||||
cursor: 3,
|
||||
current: '__command',
|
||||
status: 'ERROR',
|
||||
predictionsContains: [ 'tsn', 'tsn deep', 'tsn ext', 'tsn exte' ],
|
||||
args: {
|
||||
command: { name: 'tsn' },
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
exports.testContext = function(options) {
|
||||
helpers.audit(options, [
|
||||
// Use the 'tsn' context
|
||||
{
|
||||
setup: 'context tsn',
|
||||
check: {
|
||||
input: 'context tsn',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVV',
|
||||
message: '',
|
||||
predictionsContains: [ 'tsn', 'tsn deep', 'tsn ext', 'tsn exte' ],
|
||||
args: {
|
||||
command: { name: 'context' },
|
||||
prefix: {
|
||||
value: mockCommands.commands.tsn,
|
||||
status: 'VALID',
|
||||
message: ''
|
||||
},
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: 'Using tsn as a command prefix',
|
||||
completed: true,
|
||||
}
|
||||
},
|
||||
// For comparison with earlier
|
||||
{
|
||||
setup: 'ext',
|
||||
check: {
|
||||
input: 'ext',
|
||||
hints: ' <text>',
|
||||
markup: 'VVV',
|
||||
predictions: [ 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend' ],
|
||||
args: {
|
||||
command: { name: 'tsn ext' },
|
||||
text: {
|
||||
value: undefined,
|
||||
arg: '',
|
||||
status: 'INCOMPLETE',
|
||||
message: ''
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'ext test',
|
||||
check: {
|
||||
input: 'ext test',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVV',
|
||||
args: {
|
||||
command: { name: 'tsn ext' },
|
||||
text: {
|
||||
value: 'test',
|
||||
arg: ' test',
|
||||
status: 'VALID',
|
||||
message: ''
|
||||
},
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: 'Exec: tsnExt text=test',
|
||||
completed: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'tsn',
|
||||
check: {
|
||||
input: 'tsn',
|
||||
hints: '',
|
||||
markup: 'III',
|
||||
message: '',
|
||||
predictionsContains: [ 'tsn', 'tsn deep', 'tsn ext', 'tsn exte' ],
|
||||
args: {
|
||||
command: { name: 'tsn' },
|
||||
}
|
||||
}
|
||||
},
|
||||
// Does it actually work?
|
||||
{
|
||||
setup: 'tsb true',
|
||||
check: {
|
||||
input: 'tsb true',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVV',
|
||||
options: [ 'true' ],
|
||||
message: '',
|
||||
predictions: [ 'true' ],
|
||||
unassigned: [ ],
|
||||
args: {
|
||||
command: { name: 'tsb' },
|
||||
toggle: { value: true, arg: ' true', status: 'VALID', message: '' },
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
// Bug 866710 - GCLI should allow argument merging for non-string parameters
|
||||
setup: 'context tsn ext',
|
||||
skip: true
|
||||
},
|
||||
{
|
||||
setup: 'context "tsn ext"',
|
||||
check: {
|
||||
input: 'context "tsn ext"',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVV',
|
||||
message: '',
|
||||
predictions: [ ],
|
||||
unassigned: [ ],
|
||||
args: {
|
||||
command: { name: 'context' },
|
||||
prefix: {
|
||||
value: mockCommands.commands.tsnExt,
|
||||
status: 'VALID',
|
||||
message: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: 'Error: Can\'t use \'tsn ext\' as a prefix because it is not a parent command.',
|
||||
completed: true,
|
||||
error: true
|
||||
}
|
||||
},
|
||||
/*
|
||||
{
|
||||
setup: 'context "tsn deep"',
|
||||
check: {
|
||||
input: 'context "tsn deep"',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVV',
|
||||
status: 'ERROR',
|
||||
message: '',
|
||||
predictions: [ 'tsn deep' ],
|
||||
unassigned: [ ],
|
||||
args: {
|
||||
command: { name: 'context' },
|
||||
prefix: {
|
||||
value: mockCommands.commands.tsnDeep,
|
||||
status: 'VALID',
|
||||
message: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: '',
|
||||
completed: true,
|
||||
}
|
||||
},
|
||||
*/
|
||||
{
|
||||
setup: 'context',
|
||||
check: {
|
||||
input: 'context',
|
||||
hints: ' [prefix]',
|
||||
markup: 'VVVVVVV',
|
||||
status: 'VALID',
|
||||
unassigned: [ ],
|
||||
args: {
|
||||
command: { name: 'context' },
|
||||
prefix: { value: undefined, arg: '', status: 'VALID', message: '' },
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: 'Command prefix is unset',
|
||||
completed: true,
|
||||
type: 'string',
|
||||
error: false
|
||||
}
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
// });
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2009-2011 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE.txt or:
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
// 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-testFail.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');
|
||||
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) {
|
||||
return helpers.audit(options, [
|
||||
{
|
||||
setup: 'tsfail reject',
|
||||
exec: {
|
||||
completed: false,
|
||||
output: 'rejected promise',
|
||||
type: 'error',
|
||||
error: true
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'tsfail rejecttyped',
|
||||
exec: {
|
||||
completed: false,
|
||||
output: '54',
|
||||
type: 'number',
|
||||
error: true
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'tsfail throwerror',
|
||||
exec: {
|
||||
completed: true,
|
||||
output: 'Error: thrown error',
|
||||
type: 'error',
|
||||
error: true
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'tsfail throwstring',
|
||||
exec: {
|
||||
completed: true,
|
||||
output: 'thrown string',
|
||||
type: 'error',
|
||||
error: true
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'tsfail noerror',
|
||||
exec: {
|
||||
completed: true,
|
||||
output: 'no error',
|
||||
type: 'string',
|
||||
error: false
|
||||
}
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
// });
|
|
@ -40,22 +40,15 @@ var KeyEvent = require('util/util').KeyEvent;
|
|||
// var mockCommands = require('gclitest/mockCommands');
|
||||
|
||||
var latestEvent = undefined;
|
||||
var latestOutput = undefined;
|
||||
var latestData = undefined;
|
||||
|
||||
var outputted = function(ev) {
|
||||
function updateData() {
|
||||
latestData = latestOutput.data;
|
||||
}
|
||||
|
||||
if (latestOutput != null) {
|
||||
ev.output.onChange.remove(updateData);
|
||||
}
|
||||
|
||||
latestEvent = ev;
|
||||
latestOutput = ev.output;
|
||||
|
||||
ev.output.onChange.add(updateData);
|
||||
ev.output.promise.then(function() {
|
||||
latestData = ev.output.data;
|
||||
ev.output.onClose();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
@ -71,7 +64,6 @@ exports.shutdown = function(options) {
|
|||
|
||||
exports.testOutput = function(options) {
|
||||
latestEvent = undefined;
|
||||
latestOutput = undefined;
|
||||
latestData = undefined;
|
||||
|
||||
var inputter = options.display.inputter;
|
||||
|
@ -103,8 +95,6 @@ exports.testOutput = function(options) {
|
|||
var ev3 = { keyCode: KeyEvent.DOM_VK_ESCAPE };
|
||||
return inputter.handleKeyUp(ev3).then(function() {
|
||||
assert.ok(!focusManager._helpRequested, 'ESCAPE = anti help');
|
||||
|
||||
latestOutput.onClose();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ exports.testAllPredictions1 = function(options) {
|
|||
return;
|
||||
}
|
||||
|
||||
var resource = types.getType('resource');
|
||||
var resource = types.createType('resource');
|
||||
return resource.getLookup().then(function(opts) {
|
||||
assert.ok(opts.length > 1, 'have all resources');
|
||||
|
||||
|
@ -77,7 +77,7 @@ exports.testScriptPredictions = function(options) {
|
|||
return;
|
||||
}
|
||||
|
||||
var resource = types.getType({ name: 'resource', include: 'text/javascript' });
|
||||
var resource = types.createType({ name: 'resource', include: 'text/javascript' });
|
||||
return resource.getLookup().then(function(opts) {
|
||||
assert.ok(opts.length > 1, 'have js resources');
|
||||
|
||||
|
@ -93,7 +93,7 @@ exports.testStylePredictions = function(options) {
|
|||
return;
|
||||
}
|
||||
|
||||
var resource = types.getType({ name: 'resource', include: 'text/css' });
|
||||
var resource = types.createType({ name: 'resource', include: 'text/css' });
|
||||
return resource.getLookup().then(function(opts) {
|
||||
assert.ok(opts.length >= 1, 'have css resources');
|
||||
|
||||
|
@ -109,11 +109,11 @@ exports.testAllPredictions2 = function(options) {
|
|||
return;
|
||||
}
|
||||
|
||||
var scriptRes = types.getType({ name: 'resource', include: 'text/javascript' });
|
||||
var scriptRes = types.createType({ name: 'resource', include: 'text/javascript' });
|
||||
return scriptRes.getLookup().then(function(scriptOptions) {
|
||||
var styleRes = types.getType({ name: 'resource', include: 'text/css' });
|
||||
var styleRes = types.createType({ name: 'resource', include: 'text/css' });
|
||||
return styleRes.getLookup().then(function(styleOptions) {
|
||||
var allRes = types.getType({ name: 'resource' });
|
||||
var allRes = types.createType({ name: 'resource' });
|
||||
return allRes.getLookup().then(function(allOptions) {
|
||||
assert.is(scriptOptions.length + styleOptions.length,
|
||||
allOptions.length,
|
||||
|
@ -129,9 +129,9 @@ exports.testAllPredictions3 = function(options) {
|
|||
return;
|
||||
}
|
||||
|
||||
var res1 = types.getType({ name: 'resource' });
|
||||
var res1 = types.createType({ name: 'resource' });
|
||||
return res1.getLookup().then(function(options1) {
|
||||
var res2 = types.getType('resource');
|
||||
var res2 = types.createType('resource');
|
||||
return res2.getLookup().then(function(options2) {
|
||||
assert.is(options1.length, options2.length, 'type spec');
|
||||
});
|
||||
|
|
|
@ -36,6 +36,7 @@ function test() {
|
|||
'use strict';
|
||||
|
||||
// var assert = require('test/assert');
|
||||
var cli = require('gcli/cli');
|
||||
var Requisition = require('gcli/cli').Requisition;
|
||||
var canon = require('gcli/canon');
|
||||
// var mockCommands = require('gclitest/mockCommands');
|
||||
|
@ -51,26 +52,26 @@ exports.shutdown = function(options) {
|
|||
|
||||
exports.testSplitSimple = function(options) {
|
||||
var args;
|
||||
var requ = new Requisition();
|
||||
var requisition = new Requisition();
|
||||
|
||||
args = requ._tokenize('s');
|
||||
requ._split(args);
|
||||
args = cli.tokenize('s');
|
||||
requisition._split(args);
|
||||
assert.is(0, args.length);
|
||||
assert.is('s', requ.commandAssignment.arg.text);
|
||||
assert.is('s', requisition.commandAssignment.arg.text);
|
||||
};
|
||||
|
||||
exports.testFlatCommand = function(options) {
|
||||
var args;
|
||||
var requ = new Requisition();
|
||||
var requisition = new Requisition();
|
||||
|
||||
args = requ._tokenize('tsv');
|
||||
requ._split(args);
|
||||
args = cli.tokenize('tsv');
|
||||
requisition._split(args);
|
||||
assert.is(0, args.length);
|
||||
assert.is('tsv', requ.commandAssignment.value.name);
|
||||
assert.is('tsv', requisition.commandAssignment.value.name);
|
||||
|
||||
args = requ._tokenize('tsv a b');
|
||||
requ._split(args);
|
||||
assert.is('tsv', requ.commandAssignment.value.name);
|
||||
args = cli.tokenize('tsv a b');
|
||||
requisition._split(args);
|
||||
assert.is('tsv', requisition.commandAssignment.value.name);
|
||||
assert.is(2, args.length);
|
||||
assert.is('a', args[0].text);
|
||||
assert.is('b', args[1].text);
|
||||
|
@ -83,14 +84,14 @@ exports.testJavascript = function(options) {
|
|||
}
|
||||
|
||||
var args;
|
||||
var requ = new Requisition();
|
||||
var requisition = new Requisition();
|
||||
|
||||
args = requ._tokenize('{');
|
||||
requ._split(args);
|
||||
args = cli.tokenize('{');
|
||||
requisition._split(args);
|
||||
assert.is(1, args.length);
|
||||
assert.is('', args[0].text);
|
||||
assert.is('', requ.commandAssignment.arg.text);
|
||||
assert.is('{', requ.commandAssignment.value.name);
|
||||
assert.is('', requisition.commandAssignment.arg.text);
|
||||
assert.is('{', requisition.commandAssignment.value.name);
|
||||
};
|
||||
|
||||
// BUG 663081 - add tests for sub commands
|
||||
|
|
|
@ -36,19 +36,18 @@ function test() {
|
|||
'use strict';
|
||||
|
||||
// var assert = require('test/assert');
|
||||
var Requisition = require('gcli/cli').Requisition;
|
||||
var cli = require('gcli/cli');
|
||||
|
||||
exports.testBlanks = function(options) {
|
||||
var args;
|
||||
var requ = new Requisition();
|
||||
|
||||
args = requ._tokenize('');
|
||||
args = cli.tokenize('');
|
||||
assert.is(1, args.length);
|
||||
assert.is('', args[0].text);
|
||||
assert.is('', args[0].prefix);
|
||||
assert.is('', args[0].suffix);
|
||||
|
||||
args = requ._tokenize(' ');
|
||||
args = cli.tokenize(' ');
|
||||
assert.is(1, args.length);
|
||||
assert.is('', args[0].text);
|
||||
assert.is(' ', args[0].prefix);
|
||||
|
@ -57,16 +56,15 @@ exports.testBlanks = function(options) {
|
|||
|
||||
exports.testTokSimple = function(options) {
|
||||
var args;
|
||||
var requ = new Requisition();
|
||||
|
||||
args = requ._tokenize('s');
|
||||
args = cli.tokenize('s');
|
||||
assert.is(1, args.length);
|
||||
assert.is('s', args[0].text);
|
||||
assert.is('', args[0].prefix);
|
||||
assert.is('', args[0].suffix);
|
||||
assert.is('Argument', args[0].type);
|
||||
|
||||
args = requ._tokenize('s s');
|
||||
args = cli.tokenize('s s');
|
||||
assert.is(2, args.length);
|
||||
assert.is('s', args[0].text);
|
||||
assert.is('', args[0].prefix);
|
||||
|
@ -80,23 +78,22 @@ exports.testTokSimple = function(options) {
|
|||
|
||||
exports.testJavascript = function(options) {
|
||||
var args;
|
||||
var requ = new Requisition();
|
||||
|
||||
args = requ._tokenize('{x}');
|
||||
args = cli.tokenize('{x}');
|
||||
assert.is(1, args.length);
|
||||
assert.is('x', args[0].text);
|
||||
assert.is('{', args[0].prefix);
|
||||
assert.is('}', args[0].suffix);
|
||||
assert.is('ScriptArgument', args[0].type);
|
||||
|
||||
args = requ._tokenize('{ x }');
|
||||
args = cli.tokenize('{ x }');
|
||||
assert.is(1, args.length);
|
||||
assert.is('x', args[0].text);
|
||||
assert.is('{ ', args[0].prefix);
|
||||
assert.is(' }', args[0].suffix);
|
||||
assert.is('ScriptArgument', args[0].type);
|
||||
|
||||
args = requ._tokenize('{x} {y}');
|
||||
args = cli.tokenize('{x} {y}');
|
||||
assert.is(2, args.length);
|
||||
assert.is('x', args[0].text);
|
||||
assert.is('{', args[0].prefix);
|
||||
|
@ -107,7 +104,7 @@ exports.testJavascript = function(options) {
|
|||
assert.is('}', args[1].suffix);
|
||||
assert.is('ScriptArgument', args[1].type);
|
||||
|
||||
args = requ._tokenize('{x}{y}');
|
||||
args = cli.tokenize('{x}{y}');
|
||||
assert.is(2, args.length);
|
||||
assert.is('x', args[0].text);
|
||||
assert.is('{', args[0].prefix);
|
||||
|
@ -118,21 +115,21 @@ exports.testJavascript = function(options) {
|
|||
assert.is('}', args[1].suffix);
|
||||
assert.is('ScriptArgument', args[1].type);
|
||||
|
||||
args = requ._tokenize('{');
|
||||
args = cli.tokenize('{');
|
||||
assert.is(1, args.length);
|
||||
assert.is('', args[0].text);
|
||||
assert.is('{', args[0].prefix);
|
||||
assert.is('', args[0].suffix);
|
||||
assert.is('ScriptArgument', args[0].type);
|
||||
|
||||
args = requ._tokenize('{ ');
|
||||
args = cli.tokenize('{ ');
|
||||
assert.is(1, args.length);
|
||||
assert.is('', args[0].text);
|
||||
assert.is('{ ', args[0].prefix);
|
||||
assert.is('', args[0].suffix);
|
||||
assert.is('ScriptArgument', args[0].type);
|
||||
|
||||
args = requ._tokenize('{x');
|
||||
args = cli.tokenize('{x');
|
||||
assert.is(1, args.length);
|
||||
assert.is('x', args[0].text);
|
||||
assert.is('{', args[0].prefix);
|
||||
|
@ -142,30 +139,29 @@ exports.testJavascript = function(options) {
|
|||
|
||||
exports.testRegularNesting = function(options) {
|
||||
var args;
|
||||
var requ = new Requisition();
|
||||
|
||||
args = requ._tokenize('{"x"}');
|
||||
args = cli.tokenize('{"x"}');
|
||||
assert.is(1, args.length);
|
||||
assert.is('"x"', args[0].text);
|
||||
assert.is('{', args[0].prefix);
|
||||
assert.is('}', args[0].suffix);
|
||||
assert.is('ScriptArgument', args[0].type);
|
||||
|
||||
args = requ._tokenize('{\'x\'}');
|
||||
args = cli.tokenize('{\'x\'}');
|
||||
assert.is(1, args.length);
|
||||
assert.is('\'x\'', args[0].text);
|
||||
assert.is('{', args[0].prefix);
|
||||
assert.is('}', args[0].suffix);
|
||||
assert.is('ScriptArgument', args[0].type);
|
||||
|
||||
args = requ._tokenize('"{x}"');
|
||||
args = cli.tokenize('"{x}"');
|
||||
assert.is(1, args.length);
|
||||
assert.is('{x}', args[0].text);
|
||||
assert.is('"', args[0].prefix);
|
||||
assert.is('"', args[0].suffix);
|
||||
assert.is('Argument', args[0].type);
|
||||
|
||||
args = requ._tokenize('\'{x}\'');
|
||||
args = cli.tokenize('\'{x}\'');
|
||||
assert.is(1, args.length);
|
||||
assert.is('{x}', args[0].text);
|
||||
assert.is('\'', args[0].prefix);
|
||||
|
@ -175,23 +171,22 @@ exports.testRegularNesting = function(options) {
|
|||
|
||||
exports.testDeepNesting = function(options) {
|
||||
var args;
|
||||
var requ = new Requisition();
|
||||
|
||||
args = requ._tokenize('{{}}');
|
||||
args = cli.tokenize('{{}}');
|
||||
assert.is(1, args.length);
|
||||
assert.is('{}', args[0].text);
|
||||
assert.is('{', args[0].prefix);
|
||||
assert.is('}', args[0].suffix);
|
||||
assert.is('ScriptArgument', args[0].type);
|
||||
|
||||
args = requ._tokenize('{{x} {y}}');
|
||||
args = cli.tokenize('{{x} {y}}');
|
||||
assert.is(1, args.length);
|
||||
assert.is('{x} {y}', args[0].text);
|
||||
assert.is('{', args[0].prefix);
|
||||
assert.is('}', args[0].suffix);
|
||||
assert.is('ScriptArgument', args[0].type);
|
||||
|
||||
args = requ._tokenize('{{w} {{{x}}}} {y} {{{z}}}');
|
||||
args = cli.tokenize('{{w} {{{x}}}} {y} {{{z}}}');
|
||||
|
||||
assert.is(3, args.length);
|
||||
|
||||
|
@ -210,7 +205,7 @@ exports.testDeepNesting = function(options) {
|
|||
assert.is('}', args[2].suffix);
|
||||
assert.is('ScriptArgument', args[2].type);
|
||||
|
||||
args = requ._tokenize('{{w} {{{x}}} {y} {{{z}}}');
|
||||
args = cli.tokenize('{{w} {{{x}}} {y} {{{z}}}');
|
||||
|
||||
assert.is(1, args.length);
|
||||
|
||||
|
@ -222,10 +217,9 @@ exports.testDeepNesting = function(options) {
|
|||
|
||||
exports.testStrangeNesting = function(options) {
|
||||
var args;
|
||||
var requ = new Requisition();
|
||||
|
||||
// Note: When we get real JS parsing this should break
|
||||
args = requ._tokenize('{"x}"}');
|
||||
args = cli.tokenize('{"x}"}');
|
||||
|
||||
assert.is(2, args.length);
|
||||
|
||||
|
@ -242,9 +236,8 @@ exports.testStrangeNesting = function(options) {
|
|||
|
||||
exports.testComplex = function(options) {
|
||||
var args;
|
||||
var requ = new Requisition();
|
||||
|
||||
args = requ._tokenize(' 1234 \'12 34\'');
|
||||
args = cli.tokenize(' 1234 \'12 34\'');
|
||||
|
||||
assert.is(2, args.length);
|
||||
|
||||
|
@ -258,7 +251,7 @@ exports.testComplex = function(options) {
|
|||
assert.is('\'', args[1].suffix);
|
||||
assert.is('Argument', args[1].type);
|
||||
|
||||
args = requ._tokenize('12\'34 "12 34" \\'); // 12'34 "12 34" \
|
||||
args = cli.tokenize('12\'34 "12 34" \\'); // 12'34 "12 34" \
|
||||
|
||||
assert.is(3, args.length);
|
||||
|
||||
|
@ -280,9 +273,8 @@ exports.testComplex = function(options) {
|
|||
|
||||
exports.testPathological = function(options) {
|
||||
var args;
|
||||
var requ = new Requisition();
|
||||
|
||||
args = requ._tokenize('a\\ b \\t\\n\\r \\\'x\\\" \'d'); // a_b \t\n\r \'x\" 'd
|
||||
args = cli.tokenize('a\\ b \\t\\n\\r \\\'x\\\" \'d'); // a_b \t\n\r \'x\" 'd
|
||||
|
||||
assert.is(4, args.length);
|
||||
|
||||
|
|
|
@ -49,15 +49,22 @@ function forEachType(options, typeSpec, callback) {
|
|||
}
|
||||
else if (name === 'delegate') {
|
||||
typeSpec.delegateType = function() {
|
||||
return types.getType('string');
|
||||
return types.createType('string');
|
||||
};
|
||||
}
|
||||
else if (name === 'array') {
|
||||
typeSpec.subtype = 'string';
|
||||
}
|
||||
|
||||
var type = types.getType(typeSpec);
|
||||
var type = types.createType(typeSpec);
|
||||
callback(type);
|
||||
|
||||
// Clean up
|
||||
delete typeSpec.name;
|
||||
delete typeSpec.requisition;
|
||||
delete typeSpec.data;
|
||||
delete typeSpec.delegateType;
|
||||
delete typeSpec.subtype;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,10 @@ this.EXPORTED_SYMBOLS = [ 'helpers' ];
|
|||
var helpers = {};
|
||||
this.helpers = helpers;
|
||||
let require = (Cu.import("resource://gre/modules/devtools/Require.jsm", {})).require;
|
||||
Components.utils.import("resource:///modules/devtools/gcli.jsm", {});
|
||||
Components.utils.import("resource://gre/modules/devtools/gcli.jsm", {});
|
||||
|
||||
let console = (Cu.import("resource://gre/modules/devtools/Console.jsm", {})).console;
|
||||
let devtools = (Cu.import("resource:///modules/devtools/gDevTools.jsm", {})).devtools;
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let TargetFactory = (Cu.import("resource:///modules/devtools/gDevTools.jsm", {})).devtools.TargetFactory;
|
||||
|
||||
let Promise = (Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {})).Promise;
|
||||
let assert = { ok: ok, is: is, log: info };
|
||||
|
@ -158,6 +157,7 @@ helpers.runTests = function(options, tests) {
|
|||
});
|
||||
|
||||
var recover = function(error) {
|
||||
ok(false, error);
|
||||
console.error(error);
|
||||
};
|
||||
|
||||
|
@ -341,7 +341,7 @@ helpers._createDebugCheck = function(options) {
|
|||
output += ' current: \'' + helpers._actual.current(options) + '\',\n';
|
||||
output += ' status: \'' + helpers._actual.status(options) + '\',\n';
|
||||
output += ' options: ' + outputArray(helpers._actual.options(options)) + ',\n';
|
||||
output += ' error: \'' + helpers._actual.message(options) + '\',\n';
|
||||
output += ' message: \'' + helpers._actual.message(options) + '\',\n';
|
||||
output += ' predictions: ' + outputArray(predictions) + ',\n';
|
||||
output += ' unassigned: ' + outputArray(requisition._unassigned) + ',\n';
|
||||
output += ' outputState: \'' + helpers._actual.outputState(options) + '\',\n';
|
||||
|
@ -378,6 +378,8 @@ helpers._createDebugCheck = function(options) {
|
|||
output += ' exec: {\n';
|
||||
output += ' output: \'\',\n';
|
||||
output += ' completed: true,\n';
|
||||
output += ' type: \'string\',\n';
|
||||
output += ' error: false\n';
|
||||
output += ' }\n';
|
||||
output += ' }\n';
|
||||
output += ']);';
|
||||
|
@ -702,7 +704,7 @@ helpers._check = function(options, name, checks) {
|
|||
*/
|
||||
helpers._exec = function(options, name, expected) {
|
||||
if (expected == null) {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
var output = options.display.requisition.exec({ hidden: true });
|
||||
|
@ -715,20 +717,32 @@ helpers._exec = function(options, name, expected) {
|
|||
|
||||
if (!options.window.document.createElement) {
|
||||
assert.log('skipping output tests (missing doc.createElement) for ' + name);
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({ output: output });
|
||||
}
|
||||
|
||||
if (!('output' in expected)) {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({ output: output });
|
||||
}
|
||||
|
||||
var deferred = Promise.defer();
|
||||
|
||||
var checkOutput = function() {
|
||||
var div = options.window.document.createElement('div');
|
||||
var nodePromise = converters.convert(output.data, output.type, 'dom',
|
||||
options.display.requisition.context);
|
||||
nodePromise.then(function(node) {
|
||||
var conversionContext = options.display.requisition.conversionContext;
|
||||
|
||||
if ('type' in expected) {
|
||||
assert.is(output.type,
|
||||
expected.type,
|
||||
'output.type for: ' + name);
|
||||
}
|
||||
|
||||
if ('error' in expected) {
|
||||
assert.is(output.error,
|
||||
expected.error,
|
||||
'output.error for: ' + name);
|
||||
}
|
||||
|
||||
var convertPromise = converters.convert(output.data, output.type, 'dom',
|
||||
conversionContext);
|
||||
return convertPromise.then(function(node) {
|
||||
div.appendChild(node);
|
||||
var actualOutput = div.textContent.trim();
|
||||
|
||||
|
@ -757,24 +771,11 @@ helpers._exec = function(options, name, expected) {
|
|||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
|
||||
deferred.resolve(actualOutput);
|
||||
return { output: output, text: actualOutput };
|
||||
});
|
||||
};
|
||||
|
||||
if (output.completed !== false) {
|
||||
checkOutput();
|
||||
}
|
||||
else {
|
||||
var changed = function() {
|
||||
if (output.completed !== false) {
|
||||
checkOutput();
|
||||
output.onChange.remove(changed);
|
||||
}
|
||||
};
|
||||
output.onChange.add(changed);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return output.promise.then(checkOutput, checkOutput);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -789,15 +790,15 @@ helpers._setup = function(options, name, action) {
|
|||
return Promise.resolve(action());
|
||||
}
|
||||
|
||||
return Promise.reject('setup must be a string or a function');
|
||||
return Promise.reject('\'setup\' property must be a string or a function. Is ' + action);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to shutdown the test
|
||||
*/
|
||||
helpers._post = function(name, action, output) {
|
||||
helpers._post = function(name, action, data) {
|
||||
if (typeof action === 'function') {
|
||||
return Promise.resolve(action(output));
|
||||
return Promise.resolve(action(data.output, data.text));
|
||||
}
|
||||
return Promise.resolve(action);
|
||||
};
|
||||
|
@ -943,6 +944,8 @@ helpers.audit = function(options, audits) {
|
|||
if (typeof chunkLen !== 'number') {
|
||||
chunkLen = 1;
|
||||
}
|
||||
|
||||
if (assert.currentTest) {
|
||||
var responseTime = (new Date().getTime() - start) / chunkLen;
|
||||
totalResponseTime += responseTime;
|
||||
if (responseTime > maxResponseTime) {
|
||||
|
@ -950,12 +953,13 @@ helpers.audit = function(options, audits) {
|
|||
maxResponseCulprit = assert.currentTest + '/' + name;
|
||||
}
|
||||
averageOver++;
|
||||
}
|
||||
|
||||
var checkDone = helpers._check(options, name, audit.check);
|
||||
return checkDone.then(function() {
|
||||
var execDone = helpers._exec(options, name, audit.exec);
|
||||
return execDone.then(function(output) {
|
||||
return helpers._post(name, audit.post, output).then(function() {
|
||||
return execDone.then(function(data) {
|
||||
return helpers._post(name, audit.post, data).then(function() {
|
||||
if (assert.testLogging) {
|
||||
log('- END \'' + name + '\' in ' + assert.currentTest);
|
||||
}
|
||||
|
@ -963,9 +967,8 @@ helpers.audit = function(options, audits) {
|
|||
});
|
||||
});
|
||||
});
|
||||
}).then(null, function(ex) {
|
||||
console.error(ex.stack);
|
||||
throw(ex);
|
||||
}).then(function() {
|
||||
return options.display.inputter.setInput('');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -23,133 +23,56 @@
|
|||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
let { require: require, define: define } = Cu.import("resource://gre/modules/devtools/Require.jsm", {});
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm", {});
|
||||
Cu.import("resource://gre/modules/devtools/gcli.jsm", {});
|
||||
|
||||
// <INJECTED SOURCE:END>
|
||||
|
||||
var mockCommands = {};
|
||||
|
||||
// We use an alias for exports here because this module is used in Firefox
|
||||
// mochitests where we don't have define/require
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = require('util/util');
|
||||
var canon = require('gcli/canon');
|
||||
|
||||
var types = require('gcli/types');
|
||||
var SelectionType = require('gcli/types/selection').SelectionType;
|
||||
var DelegateType = require('gcli/types/basic').DelegateType;
|
||||
|
||||
mockCommands.option1 = { };
|
||||
mockCommands.option2 = { };
|
||||
mockCommands.option3 = { };
|
||||
|
||||
/**
|
||||
* Registration and de-registration.
|
||||
*/
|
||||
mockCommands.setup = function(opts) {
|
||||
// setup/shutdown needs to register/unregister types, however that means we
|
||||
// need to re-initialize mockCommands.option1 and mockCommands.option2 with
|
||||
// the actual types
|
||||
mockCommands.option1.type = types.getType('string');
|
||||
mockCommands.option2.type = types.getType('number');
|
||||
|
||||
types.registerType(mockCommands.optionType);
|
||||
types.registerType(mockCommands.optionValue);
|
||||
|
||||
canon.addCommand(mockCommands.tsv);
|
||||
canon.addCommand(mockCommands.tsr);
|
||||
canon.addCommand(mockCommands.tso);
|
||||
canon.addCommand(mockCommands.tse);
|
||||
canon.addCommand(mockCommands.tsj);
|
||||
canon.addCommand(mockCommands.tsb);
|
||||
canon.addCommand(mockCommands.tss);
|
||||
canon.addCommand(mockCommands.tsu);
|
||||
canon.addCommand(mockCommands.tsf);
|
||||
canon.addCommand(mockCommands.tsn);
|
||||
canon.addCommand(mockCommands.tsnDif);
|
||||
canon.addCommand(mockCommands.tsnExt);
|
||||
canon.addCommand(mockCommands.tsnExte);
|
||||
canon.addCommand(mockCommands.tsnExten);
|
||||
canon.addCommand(mockCommands.tsnExtend);
|
||||
canon.addCommand(mockCommands.tsnDeep);
|
||||
canon.addCommand(mockCommands.tsnDeepDown);
|
||||
canon.addCommand(mockCommands.tsnDeepDownNested);
|
||||
canon.addCommand(mockCommands.tsnDeepDownNestedCmd);
|
||||
canon.addCommand(mockCommands.tselarr);
|
||||
canon.addCommand(mockCommands.tsm);
|
||||
canon.addCommand(mockCommands.tsg);
|
||||
canon.addCommand(mockCommands.tshidden);
|
||||
canon.addCommand(mockCommands.tscook);
|
||||
canon.addCommand(mockCommands.tslong);
|
||||
};
|
||||
|
||||
mockCommands.shutdown = function(opts) {
|
||||
canon.removeCommand(mockCommands.tsv);
|
||||
canon.removeCommand(mockCommands.tsr);
|
||||
canon.removeCommand(mockCommands.tso);
|
||||
canon.removeCommand(mockCommands.tse);
|
||||
canon.removeCommand(mockCommands.tsj);
|
||||
canon.removeCommand(mockCommands.tsb);
|
||||
canon.removeCommand(mockCommands.tss);
|
||||
canon.removeCommand(mockCommands.tsu);
|
||||
canon.removeCommand(mockCommands.tsf);
|
||||
canon.removeCommand(mockCommands.tsn);
|
||||
canon.removeCommand(mockCommands.tsnDif);
|
||||
canon.removeCommand(mockCommands.tsnExt);
|
||||
canon.removeCommand(mockCommands.tsnExte);
|
||||
canon.removeCommand(mockCommands.tsnExten);
|
||||
canon.removeCommand(mockCommands.tsnExtend);
|
||||
canon.removeCommand(mockCommands.tsnDeep);
|
||||
canon.removeCommand(mockCommands.tsnDeepDown);
|
||||
canon.removeCommand(mockCommands.tsnDeepDownNested);
|
||||
canon.removeCommand(mockCommands.tsnDeepDownNestedCmd);
|
||||
canon.removeCommand(mockCommands.tselarr);
|
||||
canon.removeCommand(mockCommands.tsm);
|
||||
canon.removeCommand(mockCommands.tsg);
|
||||
canon.removeCommand(mockCommands.tshidden);
|
||||
canon.removeCommand(mockCommands.tscook);
|
||||
canon.removeCommand(mockCommands.tslong);
|
||||
|
||||
types.deregisterType(mockCommands.optionType);
|
||||
types.deregisterType(mockCommands.optionValue);
|
||||
};
|
||||
|
||||
|
||||
mockCommands.option1 = { type: types.getType('string') };
|
||||
mockCommands.option2 = { type: types.getType('number') };
|
||||
mockCommands.option3 = { type: types.getType({
|
||||
name: 'selection',
|
||||
lookup: [
|
||||
{ name: 'one', value: 1 },
|
||||
{ name: 'two', value: 2 },
|
||||
{ name: 'three', value: 3 }
|
||||
]
|
||||
})};
|
||||
|
||||
mockCommands.optionType = new SelectionType({
|
||||
mockCommands.optionType = {
|
||||
name: 'optionType',
|
||||
parent: 'selection',
|
||||
lookup: [
|
||||
{ name: 'option1', value: mockCommands.option1 },
|
||||
{ name: 'option2', value: mockCommands.option2 },
|
||||
{ name: 'option3', value: mockCommands.option3 }
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
mockCommands.optionValue = new DelegateType({
|
||||
mockCommands.optionValue = {
|
||||
name: 'optionValue',
|
||||
delegateType: function(context) {
|
||||
if (context != null) {
|
||||
var option = context.getArgsObject().optionType;
|
||||
parent: 'delegate',
|
||||
delegateType: function(executionContext) {
|
||||
if (executionContext != null) {
|
||||
var option = executionContext.getArgsObject().optionType;
|
||||
if (option != null) {
|
||||
return option.type;
|
||||
}
|
||||
}
|
||||
return types.getType('blank');
|
||||
return types.createType('blank');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
mockCommands.onCommandExec = util.createEvent('commands.onCommandExec');
|
||||
|
||||
function createExec(name) {
|
||||
return function(args, context) {
|
||||
return function(args, executionContext) {
|
||||
var data = {
|
||||
command: mockCommands[name],
|
||||
args: args,
|
||||
context: context
|
||||
context: executionContext
|
||||
};
|
||||
mockCommands.onCommandExec(data);
|
||||
var argsOut = Object.keys(args).map(function(key) {
|
||||
|
@ -159,7 +82,7 @@ function createExec(name) {
|
|||
};
|
||||
}
|
||||
|
||||
mockCommands.tsv = {
|
||||
var tsv = {
|
||||
name: 'tsv',
|
||||
params: [
|
||||
{ name: 'optionType', type: 'optionType' },
|
||||
|
@ -168,19 +91,19 @@ mockCommands.tsv = {
|
|||
exec: createExec('tsv')
|
||||
};
|
||||
|
||||
mockCommands.tsr = {
|
||||
var tsr = {
|
||||
name: 'tsr',
|
||||
params: [ { name: 'text', type: 'string' } ],
|
||||
exec: createExec('tsr')
|
||||
};
|
||||
|
||||
mockCommands.tso = {
|
||||
var tso = {
|
||||
name: 'tso',
|
||||
params: [ { name: 'text', type: 'string', defaultValue: null } ],
|
||||
exec: createExec('tso')
|
||||
};
|
||||
|
||||
mockCommands.tse = {
|
||||
var tse = {
|
||||
name: 'tse',
|
||||
params: [
|
||||
{ name: 'node', type: 'node' },
|
||||
|
@ -195,88 +118,88 @@ mockCommands.tse = {
|
|||
exec: createExec('tse')
|
||||
};
|
||||
|
||||
mockCommands.tsj = {
|
||||
var tsj = {
|
||||
name: 'tsj',
|
||||
params: [ { name: 'javascript', type: 'javascript' } ],
|
||||
exec: createExec('tsj')
|
||||
};
|
||||
|
||||
mockCommands.tsb = {
|
||||
var tsb = {
|
||||
name: 'tsb',
|
||||
params: [ { name: 'toggle', type: 'boolean' } ],
|
||||
exec: createExec('tsb')
|
||||
};
|
||||
|
||||
mockCommands.tss = {
|
||||
var tss = {
|
||||
name: 'tss',
|
||||
exec: createExec('tss')
|
||||
};
|
||||
|
||||
mockCommands.tsu = {
|
||||
var tsu = {
|
||||
name: 'tsu',
|
||||
params: [ { name: 'num', type: { name: 'number', max: 10, min: -5, step: 3 } } ],
|
||||
exec: createExec('tsu')
|
||||
};
|
||||
|
||||
mockCommands.tsf = {
|
||||
var tsf = {
|
||||
name: 'tsf',
|
||||
params: [ { name: 'num', type: { name: 'number', allowFloat: true, max: 11.5, min: -6.5, step: 1.5 } } ],
|
||||
exec: createExec('tsf')
|
||||
};
|
||||
|
||||
mockCommands.tsn = {
|
||||
var tsn = {
|
||||
name: 'tsn'
|
||||
};
|
||||
|
||||
mockCommands.tsnDif = {
|
||||
var tsnDif = {
|
||||
name: 'tsn dif',
|
||||
description: 'tsn dif',
|
||||
params: [ { name: 'text', type: 'string', description: 'tsn dif text' } ],
|
||||
exec: createExec('tsnDif')
|
||||
};
|
||||
|
||||
mockCommands.tsnExt = {
|
||||
var tsnExt = {
|
||||
name: 'tsn ext',
|
||||
params: [ { name: 'text', type: 'string' } ],
|
||||
exec: createExec('tsnExt')
|
||||
};
|
||||
|
||||
mockCommands.tsnExte = {
|
||||
var tsnExte = {
|
||||
name: 'tsn exte',
|
||||
params: [ { name: 'text', type: 'string' } ],
|
||||
exec: createExec('tsnExte')
|
||||
};
|
||||
|
||||
mockCommands.tsnExten = {
|
||||
var tsnExten = {
|
||||
name: 'tsn exten',
|
||||
params: [ { name: 'text', type: 'string' } ],
|
||||
exec: createExec('tsnExten')
|
||||
};
|
||||
|
||||
mockCommands.tsnExtend = {
|
||||
var tsnExtend = {
|
||||
name: 'tsn extend',
|
||||
params: [ { name: 'text', type: 'string' } ],
|
||||
exec: createExec('tsnExtend')
|
||||
};
|
||||
|
||||
mockCommands.tsnDeep = {
|
||||
var tsnDeep = {
|
||||
name: 'tsn deep'
|
||||
};
|
||||
|
||||
mockCommands.tsnDeepDown = {
|
||||
var tsnDeepDown = {
|
||||
name: 'tsn deep down'
|
||||
};
|
||||
|
||||
mockCommands.tsnDeepDownNested = {
|
||||
var tsnDeepDownNested = {
|
||||
name: 'tsn deep down nested'
|
||||
};
|
||||
|
||||
mockCommands.tsnDeepDownNestedCmd = {
|
||||
var tsnDeepDownNestedCmd = {
|
||||
name: 'tsn deep down nested cmd',
|
||||
exec: createExec('tsnDeepDownNestedCmd')
|
||||
};
|
||||
|
||||
mockCommands.tshidden = {
|
||||
var tshidden = {
|
||||
name: 'tshidden',
|
||||
hidden: true,
|
||||
params: [
|
||||
|
@ -308,7 +231,7 @@ mockCommands.tshidden = {
|
|||
exec: createExec('tshidden')
|
||||
};
|
||||
|
||||
mockCommands.tselarr = {
|
||||
var tselarr = {
|
||||
name: 'tselarr',
|
||||
params: [
|
||||
{ name: 'num', type: { name: 'selection', data: [ '1', '2', '3' ] } },
|
||||
|
@ -317,7 +240,7 @@ mockCommands.tselarr = {
|
|||
exec: createExec('tselarr')
|
||||
};
|
||||
|
||||
mockCommands.tsm = {
|
||||
var tsm = {
|
||||
name: 'tsm',
|
||||
description: 'a 3-param test selection|string|number',
|
||||
params: [
|
||||
|
@ -328,7 +251,7 @@ mockCommands.tsm = {
|
|||
exec: createExec('tsm')
|
||||
};
|
||||
|
||||
mockCommands.tsg = {
|
||||
var tsg = {
|
||||
name: 'tsg',
|
||||
description: 'a param group test',
|
||||
params: [
|
||||
|
@ -371,7 +294,7 @@ mockCommands.tsg = {
|
|||
exec: createExec('tsg')
|
||||
};
|
||||
|
||||
mockCommands.tscook = {
|
||||
var tscook = {
|
||||
name: 'tscook',
|
||||
description: 'param group test to catch problems with cookie command',
|
||||
params: [
|
||||
|
@ -411,10 +334,9 @@ mockCommands.tscook = {
|
|||
exec: createExec('tscook')
|
||||
};
|
||||
|
||||
mockCommands.tslong = {
|
||||
var tslong = {
|
||||
name: 'tslong',
|
||||
description: 'long param tests to catch problems with the jsb command',
|
||||
returnValue:'string',
|
||||
params: [
|
||||
{
|
||||
name: 'msg',
|
||||
|
@ -473,5 +395,146 @@ mockCommands.tslong = {
|
|||
exec: createExec('tslong')
|
||||
};
|
||||
|
||||
var tsfail = {
|
||||
name: 'tsfail',
|
||||
description: 'test errors',
|
||||
params: [
|
||||
{
|
||||
name: 'method',
|
||||
type: {
|
||||
name: 'selection',
|
||||
data: [
|
||||
'reject', 'rejecttyped',
|
||||
'throwerror', 'throwstring', 'throwinpromise',
|
||||
'noerror'
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
exec: function(args, context) {
|
||||
if (args.method === 'reject') {
|
||||
var deferred = context.defer();
|
||||
setTimeout(function() {
|
||||
deferred.reject('rejected promise');
|
||||
}, 10);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
if (args.method === 'rejecttyped') {
|
||||
var deferred = context.defer();
|
||||
setTimeout(function() {
|
||||
deferred.reject(context.typedData('number', 54));
|
||||
}, 10);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
if (args.method === 'throwinpromise') {
|
||||
var deferred = context.defer();
|
||||
setTimeout(function() {
|
||||
deferred.resolve('should be lost');
|
||||
}, 10);
|
||||
return deferred.promise.then(function() {
|
||||
var t = null;
|
||||
return t.foo;
|
||||
});
|
||||
}
|
||||
|
||||
if (args.method === 'throwerror') {
|
||||
throw new Error('thrown error');
|
||||
}
|
||||
|
||||
if (args.method === 'throwstring') {
|
||||
throw 'thrown string';
|
||||
}
|
||||
|
||||
return 'no error';
|
||||
}
|
||||
};
|
||||
|
||||
mockCommands.commands = {};
|
||||
|
||||
/**
|
||||
* Registration and de-registration.
|
||||
*/
|
||||
mockCommands.setup = function(opts) {
|
||||
// setup/shutdown needs to register/unregister types, however that means we
|
||||
// need to re-initialize mockCommands.option1 and mockCommands.option2 with
|
||||
// the actual types
|
||||
mockCommands.option1.type = types.createType('string');
|
||||
mockCommands.option2.type = types.createType('number');
|
||||
mockCommands.option3.type = types.createType({
|
||||
name: 'selection',
|
||||
lookup: [
|
||||
{ name: 'one', value: 1 },
|
||||
{ name: 'two', value: 2 },
|
||||
{ name: 'three', value: 3 }
|
||||
]
|
||||
});
|
||||
|
||||
types.addType(mockCommands.optionType);
|
||||
types.addType(mockCommands.optionValue);
|
||||
|
||||
mockCommands.commands.tsv = canon.addCommand(tsv);
|
||||
mockCommands.commands.tsr = canon.addCommand(tsr);
|
||||
mockCommands.commands.tso = canon.addCommand(tso);
|
||||
mockCommands.commands.tse = canon.addCommand(tse);
|
||||
mockCommands.commands.tsj = canon.addCommand(tsj);
|
||||
mockCommands.commands.tsb = canon.addCommand(tsb);
|
||||
mockCommands.commands.tss = canon.addCommand(tss);
|
||||
mockCommands.commands.tsu = canon.addCommand(tsu);
|
||||
mockCommands.commands.tsf = canon.addCommand(tsf);
|
||||
mockCommands.commands.tsn = canon.addCommand(tsn);
|
||||
mockCommands.commands.tsnDif = canon.addCommand(tsnDif);
|
||||
mockCommands.commands.tsnExt = canon.addCommand(tsnExt);
|
||||
mockCommands.commands.tsnExte = canon.addCommand(tsnExte);
|
||||
mockCommands.commands.tsnExten = canon.addCommand(tsnExten);
|
||||
mockCommands.commands.tsnExtend = canon.addCommand(tsnExtend);
|
||||
mockCommands.commands.tsnDeep = canon.addCommand(tsnDeep);
|
||||
mockCommands.commands.tsnDeepDown = canon.addCommand(tsnDeepDown);
|
||||
mockCommands.commands.tsnDeepDownNested = canon.addCommand(tsnDeepDownNested);
|
||||
mockCommands.commands.tsnDeepDownNestedCmd = canon.addCommand(tsnDeepDownNestedCmd);
|
||||
mockCommands.commands.tselarr = canon.addCommand(tselarr);
|
||||
mockCommands.commands.tsm = canon.addCommand(tsm);
|
||||
mockCommands.commands.tsg = canon.addCommand(tsg);
|
||||
mockCommands.commands.tshidden = canon.addCommand(tshidden);
|
||||
mockCommands.commands.tscook = canon.addCommand(tscook);
|
||||
mockCommands.commands.tslong = canon.addCommand(tslong);
|
||||
mockCommands.commands.tsfail = canon.addCommand(tsfail);
|
||||
};
|
||||
|
||||
mockCommands.shutdown = function(opts) {
|
||||
canon.removeCommand(tsv);
|
||||
canon.removeCommand(tsr);
|
||||
canon.removeCommand(tso);
|
||||
canon.removeCommand(tse);
|
||||
canon.removeCommand(tsj);
|
||||
canon.removeCommand(tsb);
|
||||
canon.removeCommand(tss);
|
||||
canon.removeCommand(tsu);
|
||||
canon.removeCommand(tsf);
|
||||
canon.removeCommand(tsn);
|
||||
canon.removeCommand(tsnDif);
|
||||
canon.removeCommand(tsnExt);
|
||||
canon.removeCommand(tsnExte);
|
||||
canon.removeCommand(tsnExten);
|
||||
canon.removeCommand(tsnExtend);
|
||||
canon.removeCommand(tsnDeep);
|
||||
canon.removeCommand(tsnDeepDown);
|
||||
canon.removeCommand(tsnDeepDownNested);
|
||||
canon.removeCommand(tsnDeepDownNestedCmd);
|
||||
canon.removeCommand(tselarr);
|
||||
canon.removeCommand(tsm);
|
||||
canon.removeCommand(tsg);
|
||||
canon.removeCommand(tshidden);
|
||||
canon.removeCommand(tscook);
|
||||
canon.removeCommand(tslong);
|
||||
canon.removeCommand(tsfail);
|
||||
|
||||
types.removeType(mockCommands.optionType);
|
||||
types.removeType(mockCommands.optionValue);
|
||||
|
||||
mockCommands.commands = {};
|
||||
};
|
||||
|
||||
|
||||
// });
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
this.EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/gcli.jsm");
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
|
||||
|
@ -157,7 +157,7 @@ gcli.addCommand({
|
|||
description: gcli.lookup("breakaddlineLineDesc")
|
||||
}
|
||||
],
|
||||
returnType: "html",
|
||||
returnType: "string",
|
||||
exec: function(args, context) {
|
||||
args.type = "line";
|
||||
|
||||
|
@ -201,7 +201,7 @@ gcli.addCommand({
|
|||
description: gcli.lookup("breakdelBreakidDesc")
|
||||
}
|
||||
],
|
||||
returnType: "html",
|
||||
returnType: "string",
|
||||
exec: function(args, context) {
|
||||
let dbg = getPanel(context, "jsdebugger");
|
||||
if (!dbg) {
|
||||
|
@ -381,7 +381,7 @@ gcli.addCommand({
|
|||
name: "dbg list",
|
||||
description: gcli.lookup("dbgListSourcesDesc"),
|
||||
params: [],
|
||||
returnType: "html",
|
||||
returnType: "dom",
|
||||
exec: function(args, context) {
|
||||
let dbg = getPanel(context, "jsdebugger");
|
||||
let doc = context.environment.chromeDocument;
|
||||
|
|
|
@ -797,7 +797,9 @@ StackFrames.prototype = {
|
|||
case "object":
|
||||
// Add nodes for every variable in scope.
|
||||
this.activeThread.pauseGrip(env.object).getPrototypeAndProperties(function(aResponse) {
|
||||
this._insertScopeVariables(aResponse.ownProperties, aScope);
|
||||
let { ownProperties, safeGetterValues } = aResponse;
|
||||
this._mergeSafeGetterValues(ownProperties, safeGetterValues);
|
||||
this._insertScopeVariables(ownProperties, aScope);
|
||||
|
||||
// Signal that variables have been fetched.
|
||||
window.dispatchEvent(document, "Debugger:FetchedVariables");
|
||||
|
@ -903,9 +905,11 @@ StackFrames.prototype = {
|
|||
let grip = aVar._sourceGrip;
|
||||
|
||||
this.activeThread.pauseGrip(grip).getPrototypeAndProperties(function(aResponse) {
|
||||
let { ownProperties, prototype } = aResponse;
|
||||
let { ownProperties, prototype, safeGetterValues } = aResponse;
|
||||
let sortable = VariablesView.NON_SORTABLE_CLASSES.indexOf(grip.class) == -1;
|
||||
|
||||
this._mergeSafeGetterValues(ownProperties, safeGetterValues);
|
||||
|
||||
// Add all the variable properties.
|
||||
if (ownProperties) {
|
||||
aVar.addProperties(ownProperties, {
|
||||
|
@ -932,6 +936,33 @@ StackFrames.prototype = {
|
|||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Merge the safe getter values descriptors into the "own properties" object
|
||||
* that comes from a "prototypeAndProperties" response packet. This is needed
|
||||
* for Variables View.
|
||||
*
|
||||
* @private
|
||||
* @param object aOwnProperties
|
||||
* The |ownProperties| object that will get the new safe getter values.
|
||||
* @param object aSafeGetterValues
|
||||
* The |safeGetterValues| object.
|
||||
*/
|
||||
_mergeSafeGetterValues:
|
||||
function SF__mergeSafeGetterValues(aOwnProperties, aSafeGetterValues) {
|
||||
// Merge the safe getter values into one object such that we can use it
|
||||
// in VariablesView.
|
||||
for (let name of Object.keys(aSafeGetterValues)) {
|
||||
if (name in aOwnProperties) {
|
||||
aOwnProperties[name].getterValue = aSafeGetterValues[name].getterValue;
|
||||
aOwnProperties[name].getterPrototypeLevel = aSafeGetterValues[name]
|
||||
.getterPrototypeLevel;
|
||||
}
|
||||
else {
|
||||
aOwnProperties[name] = aSafeGetterValues[name];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds the specified stack frame to the list.
|
||||
*
|
||||
|
|
|
@ -406,7 +406,6 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
|
|||
// Append a stack frame item to this container.
|
||||
let stackframeItem = this.push(frameView, {
|
||||
index: 0, /* specifies on which position should the item be appended */
|
||||
relaxed: true, /* this container should allow dupes & degenerates */
|
||||
attachment: {
|
||||
popup: menuEntry,
|
||||
depth: aDepth
|
||||
|
@ -946,7 +945,7 @@ FilterView.prototype = {
|
|||
view.node.hideEmptyGroups();
|
||||
|
||||
// Ensure the currently selected item is visible.
|
||||
view.node.ensureSelectionIsVisible(true);
|
||||
view.node.ensureSelectionIsVisible({ withGroup: true });
|
||||
|
||||
// Remember the previously searched file to avoid redundant filtering.
|
||||
this._prevSearchedFile = aFile;
|
||||
|
|
|
@ -56,10 +56,13 @@ function testFrameParameters()
|
|||
is(globalNodes[1].querySelector(".value").getAttribute("value"), "[object Object]",
|
||||
"Should have the right property value for |SpecialPowers|.");
|
||||
|
||||
is(globalNodes[3].querySelector(".name").getAttribute("value"), "document",
|
||||
let globalScopeObject = gDebugger.DebuggerView.Variables.getScopeForNode(globalScope);
|
||||
let documentNode = globalScopeObject.get("document");
|
||||
|
||||
is(documentNode.target.querySelector(".name").getAttribute("value"), "document",
|
||||
"Should have the right property name for |document|.");
|
||||
|
||||
is(globalNodes[3].querySelector(".value").getAttribute("value"), "[object HTMLDocument]",
|
||||
is(documentNode.target.querySelector(".value").getAttribute("value"), "[object HTMLDocument]",
|
||||
"Should have the right property value for |document|.");
|
||||
|
||||
let len = globalNodes.length - 1;
|
||||
|
|
|
@ -61,10 +61,13 @@ function testWithFrame()
|
|||
is(innerNodes[1].querySelector(".value").getAttribute("value"), "1",
|
||||
"Should have the right property value for |one|.");
|
||||
|
||||
is(globalNodes[3].querySelector(".name").getAttribute("value"), "document",
|
||||
let globalScopeObject = gDebugger.DebuggerView.Variables.getScopeForNode(globalScope);
|
||||
let documentNode = globalScopeObject.get("document");
|
||||
|
||||
is(documentNode.target.querySelector(".name").getAttribute("value"), "document",
|
||||
"Should have the right property name for |document|.");
|
||||
|
||||
is(globalNodes[3].querySelector(".value").getAttribute("value"), "[object HTMLDocument]",
|
||||
is(documentNode.target.querySelector(".value").getAttribute("value"), "[object HTMLDocument]",
|
||||
"Should have the right property value for |document|.");
|
||||
|
||||
let len = globalNodes.length - 1;
|
||||
|
|
|
@ -61,15 +61,17 @@ function testFrameParameters()
|
|||
is(anonymousNodes[2].querySelector(".value").getAttribute("value"), "[object Object]",
|
||||
"Should have the right property value for |buttonAsProto|.");
|
||||
|
||||
is(globalNodes[3].querySelector(".name").getAttribute("value"), "document",
|
||||
let globalScopeObject = gVars.getScopeForNode(globalScope);
|
||||
let documentNode = globalScopeObject.get("document");
|
||||
|
||||
is(documentNode.target.querySelector(".name").getAttribute("value"), "document",
|
||||
"Should have the right property name for |document|.");
|
||||
|
||||
is(globalNodes[3].querySelector(".value").getAttribute("value"), "[object HTMLDocument]",
|
||||
is(documentNode.target.querySelector(".value").getAttribute("value"), "[object HTMLDocument]",
|
||||
"Should have the right property value for |document|.");
|
||||
|
||||
let buttonNode = gVars.getItemForNode(anonymousNodes[1]);
|
||||
let buttonAsProtoNode = gVars.getItemForNode(anonymousNodes[2]);
|
||||
let documentNode = gVars.getItemForNode(globalNodes[3]);
|
||||
|
||||
is(buttonNode.expanded, false,
|
||||
"The buttonNode should not be expanded at this point.");
|
||||
|
@ -131,30 +133,46 @@ function testFrameParameters()
|
|||
.getAttribute("value").search(/object/) != -1,
|
||||
"'__proto__' in documentNode should be an object.");
|
||||
|
||||
let buttonProtoNode = buttonNode.get("__proto__");
|
||||
let buttonAsProtoProtoNode = buttonAsProtoNode.get("__proto__");
|
||||
let documentProtoNode = documentNode.get("__proto__");
|
||||
// Now the main course: make sure that the native getters for WebIDL
|
||||
// attributes have been called and a value has been returned.
|
||||
is(buttonNode.get("type").target.querySelector(".name")
|
||||
.getAttribute("value"), "type",
|
||||
"Should have the right property name for 'type' in buttonProtoNode.");
|
||||
is(buttonNode.get("type").target.querySelector(".value")
|
||||
.getAttribute("value"), '"submit"',
|
||||
"'type' in buttonProtoNode should have the right value.");
|
||||
is(buttonNode.get("formMethod").target.querySelector(".name")
|
||||
.getAttribute("value"), "formMethod",
|
||||
"Should have the right property name for 'formMethod' in buttonProtoNode.");
|
||||
is(buttonNode.get("formMethod").target.querySelector(".value")
|
||||
.getAttribute("value"), '""',
|
||||
"'formMethod' in buttonProtoNode should have the right value.");
|
||||
|
||||
is(documentNode.get("domain").target.querySelector(".name")
|
||||
.getAttribute("value"), "domain",
|
||||
"Should have the right property name for 'domain' in documentProtoNode.");
|
||||
is(documentNode.get("domain").target.querySelector(".value")
|
||||
.getAttribute("value"), '"example.com"',
|
||||
"'domain' in documentProtoNode should have the right value.");
|
||||
is(documentNode.get("cookie").target.querySelector(".name")
|
||||
.getAttribute("value"), "cookie",
|
||||
"Should have the right property name for 'cookie' in documentProtoNode.");
|
||||
is(documentNode.get("cookie").target.querySelector(".value")
|
||||
.getAttribute("value"), '""',
|
||||
"'cookie' in documentProtoNode should have the right value.");
|
||||
|
||||
let buttonAsProtoProtoNode = buttonAsProtoNode.get("__proto__");
|
||||
|
||||
is(buttonProtoNode.expanded, false,
|
||||
"The buttonProtoNode should not be expanded at this point.");
|
||||
is(buttonAsProtoProtoNode.expanded, false,
|
||||
"The buttonAsProtoProtoNode should not be expanded at this point.");
|
||||
is(documentProtoNode.expanded, false,
|
||||
"The documentProtoNode should not be expanded at this point.");
|
||||
|
||||
// Expand the prototypes of 'button', 'buttonAsProto' and 'document'
|
||||
// tree nodes. This causes their properties to be retrieved and
|
||||
// displayed.
|
||||
buttonProtoNode.expand();
|
||||
buttonAsProtoProtoNode.expand();
|
||||
documentProtoNode.expand();
|
||||
|
||||
is(buttonProtoNode.expanded, true,
|
||||
"The buttonProtoNode should be expanded at this point.");
|
||||
is(buttonAsProtoProtoNode.expanded, true,
|
||||
"The buttonAsProtoProtoNode should be expanded at this point.");
|
||||
is(documentProtoNode.expanded, true,
|
||||
"The documentProtoNode should be expanded at this point.");
|
||||
|
||||
|
||||
// Poll every few milliseconds until the properties are retrieved.
|
||||
|
@ -168,88 +186,29 @@ function testFrameParameters()
|
|||
window.clearInterval(intervalID1);
|
||||
return resumeAndFinish();
|
||||
}
|
||||
if (!buttonProtoNode._retrieved ||
|
||||
!buttonAsProtoProtoNode._retrieved ||
|
||||
!documentProtoNode._retrieved) {
|
||||
if (!buttonAsProtoProtoNode._retrieved) {
|
||||
return;
|
||||
}
|
||||
window.clearInterval(intervalID1);
|
||||
|
||||
// Now the main course: make sure that the native getters for WebIDL
|
||||
// attributes have been called and a value has been returned.
|
||||
is(buttonProtoNode.get("type").target.querySelector(".name")
|
||||
.getAttribute("value"), "type",
|
||||
"Should have the right property name for 'type' in buttonProtoNode.");
|
||||
is(buttonProtoNode.get("type").target.querySelector(".value")
|
||||
.getAttribute("value"), '"submit"',
|
||||
"'type' in buttonProtoNode should have the right value.");
|
||||
is(buttonProtoNode.get("formMethod").target.querySelector(".name")
|
||||
.getAttribute("value"), "formMethod",
|
||||
"Should have the right property name for 'formMethod' in buttonProtoNode.");
|
||||
is(buttonProtoNode.get("formMethod").target.querySelector(".value")
|
||||
.getAttribute("value"), '""',
|
||||
"'formMethod' in buttonProtoNode should have the right value.");
|
||||
|
||||
is(documentProtoNode.get("domain").target.querySelector(".name")
|
||||
.getAttribute("value"), "domain",
|
||||
"Should have the right property name for 'domain' in documentProtoNode.");
|
||||
is(documentProtoNode.get("domain").target.querySelector(".value")
|
||||
.getAttribute("value"), '"example.com"',
|
||||
"'domain' in documentProtoNode should have the right value.");
|
||||
is(documentProtoNode.get("cookie").target.querySelector(".name")
|
||||
.getAttribute("value"), "cookie",
|
||||
"Should have the right property name for 'cookie' in documentProtoNode.");
|
||||
is(documentProtoNode.get("cookie").target.querySelector(".value")
|
||||
.getAttribute("value"), '""',
|
||||
"'cookie' in documentProtoNode should have the right value.");
|
||||
|
||||
let buttonAsProtoProtoProtoNode = buttonAsProtoProtoNode.get("__proto__");
|
||||
|
||||
is(buttonAsProtoProtoProtoNode.expanded, false,
|
||||
"The buttonAsProtoProtoProtoNode should not be expanded at this point.");
|
||||
|
||||
// Expand the prototype of the prototype of 'buttonAsProto' tree
|
||||
// node. This causes its properties to be retrieved and displayed.
|
||||
buttonAsProtoProtoProtoNode.expand();
|
||||
|
||||
is(buttonAsProtoProtoProtoNode.expanded, true,
|
||||
"The buttonAsProtoProtoProtoNode should be expanded at this point.");
|
||||
|
||||
// Poll every few milliseconds until the properties are retrieved.
|
||||
// It's important to set the timer in the chrome window, because the
|
||||
// content window timers are disabled while the debuggee is paused.
|
||||
let count3 = 0;
|
||||
let intervalID2 = window.setInterval(function(){
|
||||
info("count3: " + count3);
|
||||
if (++count3 > 50) {
|
||||
ok(false, "Timed out while polling for the properties.");
|
||||
window.clearInterval(intervalID2);
|
||||
return resumeAndFinish();
|
||||
}
|
||||
if (!buttonAsProtoProtoProtoNode._retrieved) {
|
||||
return;
|
||||
}
|
||||
window.clearInterval(intervalID2);
|
||||
|
||||
// Test this more involved case that reuses an object that is
|
||||
// present in another cache line.
|
||||
is(buttonAsProtoProtoProtoNode.get("type").target.querySelector(".name")
|
||||
is(buttonAsProtoProtoNode.get("type").target.querySelector(".name")
|
||||
.getAttribute("value"), "type",
|
||||
"Should have the right property name for 'type' in buttonAsProtoProtoProtoNode.");
|
||||
is(buttonAsProtoProtoProtoNode.get("type").target.querySelector(".value")
|
||||
is(buttonAsProtoProtoNode.get("type").target.querySelector(".value")
|
||||
.getAttribute("value"), '"submit"',
|
||||
"'type' in buttonAsProtoProtoProtoNode should have the right value.");
|
||||
is(buttonAsProtoProtoProtoNode.get("formMethod").target.querySelector(".name")
|
||||
is(buttonAsProtoProtoNode.get("formMethod").target.querySelector(".name")
|
||||
.getAttribute("value"), "formMethod",
|
||||
"Should have the right property name for 'formMethod' in buttonAsProtoProtoProtoNode.");
|
||||
is(buttonAsProtoProtoProtoNode.get("formMethod").target.querySelector(".value")
|
||||
is(buttonAsProtoProtoNode.get("formMethod").target.querySelector(".value")
|
||||
.getAttribute("value"), '""',
|
||||
"'formMethod' in buttonAsProtoProtoProtoNode should have the right value.");
|
||||
|
||||
resumeAndFinish();
|
||||
}, 100);
|
||||
}, 100);
|
||||
}, 100);
|
||||
}}, 0);
|
||||
}, false);
|
||||
|
||||
|
|
|
@ -149,11 +149,11 @@ function testVariablesFiltering()
|
|||
"There should be 0 variables displayed in the test scope");
|
||||
is(loadScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
|
||||
"There should be 0 variables displayed in the load scope");
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 1,
|
||||
"There should be 1 variable displayed in the global scope");
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 3,
|
||||
"There should be 3 variables displayed in the global scope");
|
||||
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match])").length, 6,
|
||||
"There should be 6 properties displayed in the inner scope");
|
||||
ok(innerScope.querySelectorAll(".variables-view-property:not([non-match])").length > 6,
|
||||
"There should be more than 6 properties displayed in the inner scope");
|
||||
is(mathScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
"There should be 0 properties displayed in the math scope");
|
||||
is(testScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
|
@ -165,21 +165,19 @@ function testVariablesFiltering()
|
|||
|
||||
is(innerScope.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
|
||||
"this", "The only inner variable displayed should be 'this'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[0].getAttribute("value"),
|
||||
"window", "The first inner property displayed should be 'window'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[1].getAttribute("value"),
|
||||
"document", "The second inner property displayed should be 'document'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[2].getAttribute("value"),
|
||||
"location", "The third inner property displayed should be 'location'");
|
||||
"window", "The third inner property displayed should be 'window'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[3].getAttribute("value"),
|
||||
"__proto__", "The fourth inner property displayed should be '__proto__'");
|
||||
"document", "The fourth inner property displayed should be 'document'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[4].getAttribute("value"),
|
||||
"Location", "The fifth inner property displayed should be 'Location'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[5].getAttribute("value"),
|
||||
"Location", "The sixth inner property displayed should be 'Location'");
|
||||
"location", "The fifth inner property displayed should be 'location'");
|
||||
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
|
||||
"Location", "The only global variable displayed should be 'Location'");
|
||||
"location", "The first global variable displayed should be 'location'");
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[1].getAttribute("value"),
|
||||
"locationbar", "The second global variable displayed should be 'locationbar'");
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[2].getAttribute("value"),
|
||||
"Location", "The third global variable displayed should be 'Location'");
|
||||
}
|
||||
|
||||
function test2()
|
||||
|
@ -237,11 +235,11 @@ function testVariablesFiltering()
|
|||
"There should be 0 variables displayed in the test scope");
|
||||
is(loadScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
|
||||
"There should be 0 variables displayed in the load scope");
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 1,
|
||||
"There should be 1 variable displayed in the global scope");
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 3,
|
||||
"There should be 3 variables displayed in the global scope");
|
||||
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match])").length, 6,
|
||||
"There should be 6 properties displayed in the inner scope");
|
||||
ok(innerScope.querySelectorAll(".variables-view-property:not([non-match])").length > 6,
|
||||
"There should be more than 6 properties displayed in the inner scope");
|
||||
is(mathScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
"There should be 0 properties displayed in the math scope");
|
||||
is(testScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
|
@ -253,21 +251,19 @@ function testVariablesFiltering()
|
|||
|
||||
is(innerScope.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
|
||||
"this", "The only inner variable displayed should be 'this'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[0].getAttribute("value"),
|
||||
"window", "The first inner property displayed should be 'window'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[1].getAttribute("value"),
|
||||
"document", "The second inner property displayed should be 'document'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[2].getAttribute("value"),
|
||||
"location", "The third inner property displayed should be 'location'");
|
||||
"window", "The third inner property displayed should be 'window'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[3].getAttribute("value"),
|
||||
"__proto__", "The fourth inner property displayed should be '__proto__'");
|
||||
"document", "The fourth inner property displayed should be 'document'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[4].getAttribute("value"),
|
||||
"Location", "The fifth inner property displayed should be 'Location'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[5].getAttribute("value"),
|
||||
"Location", "The sixth inner property displayed should be 'Location'");
|
||||
"location", "The fifth inner property displayed should be 'location'");
|
||||
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
|
||||
"Location", "The only global variable displayed should be 'Location'");
|
||||
"location", "The first global variable displayed should be 'location'");
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[1].getAttribute("value"),
|
||||
"locationbar", "The second global variable displayed should be 'locationbar'");
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[2].getAttribute("value"),
|
||||
"Location", "The second global variable displayed should be 'Location'");
|
||||
}
|
||||
|
||||
var scopes = gDebugger.DebuggerView.Variables._list,
|
||||
|
|
|
@ -92,8 +92,8 @@ function testVariablesFiltering()
|
|||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 2,
|
||||
"There should be 2 variables displayed in the global scope");
|
||||
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match])").length, 8,
|
||||
"There should be 8 properties displayed in the inner scope");
|
||||
ok(innerScope.querySelectorAll(".variables-view-property:not([non-match])").length > 3,
|
||||
"There should be more than 3 properties displayed in the inner scope");
|
||||
is(mathScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
"There should be 0 properties displayed in the math scope");
|
||||
is(testScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
|
@ -111,16 +111,6 @@ function testVariablesFiltering()
|
|||
"window", "The second inner property displayed should be 'window'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[2].getAttribute("value"),
|
||||
"document", "The third inner property displayed should be 'document'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[3].getAttribute("value"),
|
||||
"location", "The fourth inner property displayed should be 'location'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[4].getAttribute("value"),
|
||||
"__proto__", "The fifth inner property displayed should be '__proto__'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[5].getAttribute("value"),
|
||||
"__proto__", "The sixth inner property displayed should be '__proto__'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[6].getAttribute("value"),
|
||||
"HTMLDocument", "The seventh inner property displayed should be 'HTMLDocument'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[7].getAttribute("value"),
|
||||
"HTMLDocument", "The eight inner property displayed should be 'HTMLDocument'");
|
||||
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
|
||||
"document", "The first global variable displayed should be 'document'");
|
||||
|
@ -168,8 +158,8 @@ function testVariablesFiltering()
|
|||
"The local scope 'this.window' should be expanded");
|
||||
is(documentItem.expanded, true,
|
||||
"The local scope 'this.window.document' should be expanded");
|
||||
is(locationItem.expanded, false,
|
||||
"The local scope 'this.window.document.location' should not be expanded");
|
||||
is(locationItem.expanded, true,
|
||||
"The local scope 'this.window.document.location' should be expanded");
|
||||
|
||||
documentItem.toggle();
|
||||
documentItem.toggle();
|
||||
|
@ -186,8 +176,8 @@ function testVariablesFiltering()
|
|||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 2,
|
||||
"There should be 2 variables displayed in the global scope");
|
||||
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match])").length, 8,
|
||||
"There should be 8 properties displayed in the inner scope");
|
||||
ok(innerScope.querySelectorAll(".variables-view-property:not([non-match])").length > 3,
|
||||
"There should be more than 3 properties displayed in the inner scope");
|
||||
is(mathScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
"There should be 0 properties displayed in the math scope");
|
||||
is(testScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
|
@ -205,16 +195,6 @@ function testVariablesFiltering()
|
|||
"window", "The second inner property displayed should be 'window'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[2].getAttribute("value"),
|
||||
"document", "The third inner property displayed should be 'document'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[3].getAttribute("value"),
|
||||
"location", "The fourth inner property displayed should be 'location'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[4].getAttribute("value"),
|
||||
"__proto__", "The fifth inner property displayed should be '__proto__'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[5].getAttribute("value"),
|
||||
"__proto__", "The sixth inner property displayed should be '__proto__'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[6].getAttribute("value"),
|
||||
"HTMLDocument", "The seventh inner property displayed should be 'HTMLDocument'");
|
||||
is(innerScope.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[7].getAttribute("value"),
|
||||
"HTMLDocument", "The eight inner property displayed should be 'HTMLDocument'");
|
||||
|
||||
is(globalScope.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
|
||||
"document", "The first global variable displayed should be 'document'");
|
||||
|
|
|
@ -127,8 +127,8 @@ function testVariablesFiltering()
|
|||
"There should be 0 properties displayed in the math scope");
|
||||
is(testScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
"There should be 0 properties displayed in the test scope");
|
||||
is(loadScope.querySelectorAll(".variables-view-property:not([non-match])").length, 1,
|
||||
"There should be 1 property displayed in the load scope");
|
||||
ok(loadScope.querySelectorAll(".variables-view-property:not([non-match])").length > 1,
|
||||
"There should be more than one property displayed in the load scope");
|
||||
isnot(globalScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
"There should be some properties displayed in the global scope");
|
||||
}
|
||||
|
@ -157,8 +157,8 @@ function testVariablesFiltering()
|
|||
"There should be 0 properties displayed in the math scope");
|
||||
is(testScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
"There should be 0 properties displayed in the test scope");
|
||||
is(loadScope.querySelectorAll(".variables-view-property:not([non-match])").length, 1,
|
||||
"There should be 1 property displayed in the load scope");
|
||||
ok(loadScope.querySelectorAll(".variables-view-property:not([non-match])").length > 1,
|
||||
"There should be more than one properties displayed in the load scope");
|
||||
isnot(globalScope.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
|
||||
"There should be some properties displayed in the global scope");
|
||||
}
|
||||
|
|
|
@ -183,6 +183,7 @@ function debug_tab_pane(aURL, aOnDebugging, aBeforeTabAdded) {
|
|||
info("Debugger has started");
|
||||
dbg._view.Variables.lazyEmpty = false;
|
||||
dbg._view.Variables.lazyAppend = false;
|
||||
dbg._view.Variables.lazyExpand = false;
|
||||
aOnDebugging(tab, debuggee, dbg);
|
||||
});
|
||||
});
|
||||
|
@ -206,6 +207,7 @@ function debug_remote(aURL, aOnDebugging, aBeforeTabAdded) {
|
|||
info("Remote Debugger has started");
|
||||
win._dbgwin.DebuggerView.Variables.lazyEmpty = false;
|
||||
win._dbgwin.DebuggerView.Variables.lazyAppend = false;
|
||||
win._dbgwin.DebuggerView.Variables.lazyExpand = false;
|
||||
aOnDebugging(tab, debuggee, win);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -21,11 +21,10 @@ this.EXPORTED_SYMBOLS = [ 'helpers' ];
|
|||
var helpers = {};
|
||||
this.helpers = helpers;
|
||||
let require = (Cu.import("resource://gre/modules/devtools/Require.jsm", {})).require;
|
||||
Components.utils.import("resource:///modules/devtools/gcli.jsm", {});
|
||||
Components.utils.import("resource://gre/modules/devtools/gcli.jsm", {});
|
||||
|
||||
let console = (Cu.import("resource://gre/modules/devtools/Console.jsm", {})).console;
|
||||
let devtools = (Cu.import("resource:///modules/devtools/gDevTools.jsm", {})).devtools;
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let TargetFactory = (Cu.import("resource:///modules/devtools/gDevTools.jsm", {})).devtools.TargetFactory;
|
||||
|
||||
let Promise = (Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {})).Promise;
|
||||
let assert = { ok: ok, is: is, log: info };
|
||||
|
@ -158,6 +157,7 @@ helpers.runTests = function(options, tests) {
|
|||
});
|
||||
|
||||
var recover = function(error) {
|
||||
ok(false, error);
|
||||
console.error(error);
|
||||
};
|
||||
|
||||
|
@ -341,7 +341,7 @@ helpers._createDebugCheck = function(options) {
|
|||
output += ' current: \'' + helpers._actual.current(options) + '\',\n';
|
||||
output += ' status: \'' + helpers._actual.status(options) + '\',\n';
|
||||
output += ' options: ' + outputArray(helpers._actual.options(options)) + ',\n';
|
||||
output += ' error: \'' + helpers._actual.message(options) + '\',\n';
|
||||
output += ' message: \'' + helpers._actual.message(options) + '\',\n';
|
||||
output += ' predictions: ' + outputArray(predictions) + ',\n';
|
||||
output += ' unassigned: ' + outputArray(requisition._unassigned) + ',\n';
|
||||
output += ' outputState: \'' + helpers._actual.outputState(options) + '\',\n';
|
||||
|
@ -378,6 +378,8 @@ helpers._createDebugCheck = function(options) {
|
|||
output += ' exec: {\n';
|
||||
output += ' output: \'\',\n';
|
||||
output += ' completed: true,\n';
|
||||
output += ' type: \'string\',\n';
|
||||
output += ' error: false\n';
|
||||
output += ' }\n';
|
||||
output += ' }\n';
|
||||
output += ']);';
|
||||
|
@ -702,7 +704,7 @@ helpers._check = function(options, name, checks) {
|
|||
*/
|
||||
helpers._exec = function(options, name, expected) {
|
||||
if (expected == null) {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
var output = options.display.requisition.exec({ hidden: true });
|
||||
|
@ -715,20 +717,32 @@ helpers._exec = function(options, name, expected) {
|
|||
|
||||
if (!options.window.document.createElement) {
|
||||
assert.log('skipping output tests (missing doc.createElement) for ' + name);
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({ output: output });
|
||||
}
|
||||
|
||||
if (!('output' in expected)) {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({ output: output });
|
||||
}
|
||||
|
||||
var deferred = Promise.defer();
|
||||
|
||||
var checkOutput = function() {
|
||||
var div = options.window.document.createElement('div');
|
||||
var nodePromise = converters.convert(output.data, output.type, 'dom',
|
||||
options.display.requisition.context);
|
||||
nodePromise.then(function(node) {
|
||||
var conversionContext = options.display.requisition.conversionContext;
|
||||
|
||||
if ('type' in expected) {
|
||||
assert.is(output.type,
|
||||
expected.type,
|
||||
'output.type for: ' + name);
|
||||
}
|
||||
|
||||
if ('error' in expected) {
|
||||
assert.is(output.error,
|
||||
expected.error,
|
||||
'output.error for: ' + name);
|
||||
}
|
||||
|
||||
var convertPromise = converters.convert(output.data, output.type, 'dom',
|
||||
conversionContext);
|
||||
return convertPromise.then(function(node) {
|
||||
div.appendChild(node);
|
||||
var actualOutput = div.textContent.trim();
|
||||
|
||||
|
@ -757,24 +771,11 @@ helpers._exec = function(options, name, expected) {
|
|||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
|
||||
deferred.resolve(actualOutput);
|
||||
return { output: output, text: actualOutput };
|
||||
});
|
||||
};
|
||||
|
||||
if (output.completed !== false) {
|
||||
checkOutput();
|
||||
}
|
||||
else {
|
||||
var changed = function() {
|
||||
if (output.completed !== false) {
|
||||
checkOutput();
|
||||
output.onChange.remove(changed);
|
||||
}
|
||||
};
|
||||
output.onChange.add(changed);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return output.promise.then(checkOutput, checkOutput);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -789,15 +790,15 @@ helpers._setup = function(options, name, action) {
|
|||
return Promise.resolve(action());
|
||||
}
|
||||
|
||||
return Promise.reject('setup must be a string or a function');
|
||||
return Promise.reject('\'setup\' property must be a string or a function. Is ' + action);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to shutdown the test
|
||||
*/
|
||||
helpers._post = function(name, action, output) {
|
||||
helpers._post = function(name, action, data) {
|
||||
if (typeof action === 'function') {
|
||||
return Promise.resolve(action(output));
|
||||
return Promise.resolve(action(data.output, data.text));
|
||||
}
|
||||
return Promise.resolve(action);
|
||||
};
|
||||
|
@ -943,6 +944,8 @@ helpers.audit = function(options, audits) {
|
|||
if (typeof chunkLen !== 'number') {
|
||||
chunkLen = 1;
|
||||
}
|
||||
|
||||
if (assert.currentTest) {
|
||||
var responseTime = (new Date().getTime() - start) / chunkLen;
|
||||
totalResponseTime += responseTime;
|
||||
if (responseTime > maxResponseTime) {
|
||||
|
@ -950,12 +953,13 @@ helpers.audit = function(options, audits) {
|
|||
maxResponseCulprit = assert.currentTest + '/' + name;
|
||||
}
|
||||
averageOver++;
|
||||
}
|
||||
|
||||
var checkDone = helpers._check(options, name, audit.check);
|
||||
return checkDone.then(function() {
|
||||
var execDone = helpers._exec(options, name, audit.exec);
|
||||
return execDone.then(function(output) {
|
||||
return helpers._post(name, audit.post, output).then(function() {
|
||||
return execDone.then(function(data) {
|
||||
return helpers._post(name, audit.post, data).then(function() {
|
||||
if (assert.testLogging) {
|
||||
log('- END \'' + name + '\' in ' + assert.currentTest);
|
||||
}
|
||||
|
@ -963,9 +967,8 @@ helpers.audit = function(options, audits) {
|
|||
});
|
||||
});
|
||||
});
|
||||
}).then(null, function(ex) {
|
||||
console.error(ex.stack);
|
||||
throw(ex);
|
||||
}).then(function() {
|
||||
return options.display.inputter.setInput('');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -222,8 +222,8 @@ DevTools.prototype = {
|
|||
*
|
||||
* Each toolDefinition has the following properties:
|
||||
* - id: Unique identifier for this tool (string|required)
|
||||
* - killswitch: Property name to allow us to turn this tool on/off globally
|
||||
* (string|required) (TODO: default to devtools.{id}.enabled?)
|
||||
* - visibilityswitch: Property name to allow us to hide this tool from the
|
||||
* DevTools Toolbox.
|
||||
* - icon: URL pointing to a graphic which will be used as the src for an
|
||||
* 16x16 img tag (string|required)
|
||||
* - url: URL pointing to a XUL/XHTML document containing the user interface
|
||||
|
@ -241,7 +241,7 @@ DevTools.prototype = {
|
|||
throw new Error("Invalid definition.id");
|
||||
}
|
||||
|
||||
toolDefinition.killswitch = toolDefinition.killswitch ||
|
||||
toolDefinition.visibilityswitch = toolDefinition.visibilityswitch ||
|
||||
"devtools." + toolId + ".enabled";
|
||||
this._tools.set(toolId, toolDefinition);
|
||||
|
||||
|
@ -307,21 +307,17 @@ DevTools.prototype = {
|
|||
*/
|
||||
getToolDefinitionMap: function DT_getToolDefinitionMap() {
|
||||
let tools = new Map();
|
||||
let disabledTools = [];
|
||||
try {
|
||||
disabledTools = JSON.parse(Services.prefs.getCharPref("devtools.toolbox.disabledTools"));
|
||||
} catch(ex) {}
|
||||
|
||||
for (let [key, value] of this._tools) {
|
||||
let enabled;
|
||||
|
||||
try {
|
||||
enabled = Services.prefs.getBoolPref(value.killswitch);
|
||||
enabled = Services.prefs.getBoolPref(value.visibilityswitch);
|
||||
} catch(e) {
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
if (enabled && disabledTools.indexOf(key) == -1) {
|
||||
if (enabled || value.id == "options") {
|
||||
tools.set(key, value);
|
||||
}
|
||||
}
|
||||
|
@ -454,7 +450,7 @@ DevTools.prototype = {
|
|||
destroy: function() {
|
||||
Services.obs.removeObserver(this.destroy, "quit-application");
|
||||
|
||||
for (let [key, tool] of this._tools) {
|
||||
for (let [key, tool] of this.getToolDefinitionMap()) {
|
||||
this.unregisterTool(key, true);
|
||||
}
|
||||
|
||||
|
@ -578,15 +574,23 @@ let gDevToolsBrowser = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Add the menuitem for a tool to all open browser windows. Also toggles the
|
||||
* kill switch preference of the tool.
|
||||
* Add the menuitem for a tool to all open browser windows.
|
||||
*
|
||||
* @param {object} toolDefinition
|
||||
* properties of the tool to add
|
||||
*/
|
||||
_addToolToWindows: function DT_addToolToWindows(toolDefinition) {
|
||||
// Set the kill switch pref boolean to true
|
||||
Services.prefs.setBoolPref(toolDefinition.killswitch, true);
|
||||
// No menu item or global shortcut is required for options panel.
|
||||
if (toolDefinition.id == "options") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if the tool is disabled.
|
||||
try {
|
||||
if (!Services.prefs.getBoolPref(toolDefinition.visibilityswitch)) {
|
||||
return;
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
// We need to insert the new tool in the right place, which means knowing
|
||||
// the tool that comes before the tool that we're trying to add
|
||||
|
@ -642,6 +646,17 @@ let gDevToolsBrowser = {
|
|||
let fragMenuItems = doc.createDocumentFragment();
|
||||
|
||||
for (let toolDefinition of gDevTools.getToolDefinitionArray()) {
|
||||
if (toolDefinition.id == "options") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if the tool is disabled.
|
||||
try {
|
||||
if (!Services.prefs.getBoolPref(toolDefinition.visibilityswitch)) {
|
||||
continue;
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
let elements = gDevToolsBrowser._createToolMenuElements(toolDefinition, doc);
|
||||
|
||||
if (!elements) {
|
||||
|
@ -714,7 +729,7 @@ let gDevToolsBrowser = {
|
|||
|
||||
let bc = doc.createElement("broadcaster");
|
||||
bc.id = "devtoolsMenuBroadcaster_" + id;
|
||||
bc.setAttribute("label", toolDefinition.label);
|
||||
bc.setAttribute("label", toolDefinition.menuLabel || toolDefinition.label);
|
||||
bc.setAttribute("command", cmd.id);
|
||||
|
||||
if (key) {
|
||||
|
@ -767,16 +782,12 @@ let gDevToolsBrowser = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Remove the menuitem for a tool to all open browser windows. Also sets the
|
||||
* kill switch boolean pref to false.
|
||||
* Remove the menuitem for a tool to all open browser windows.
|
||||
*
|
||||
* @param {object} toolId
|
||||
* @param {string} toolId
|
||||
* id of the tool to remove
|
||||
* @param {string} killswitch
|
||||
* The kill switch preference string of the tool
|
||||
*/
|
||||
_removeToolFromWindows: function DT_removeToolFromWindows(toolId, killswitch) {
|
||||
Services.prefs.setBoolPref(killswitch, false);
|
||||
_removeToolFromWindows: function DT_removeToolFromWindows(toolId) {
|
||||
for (let win of gDevToolsBrowser._trackedBrowserWindows) {
|
||||
gDevToolsBrowser._removeToolFromMenu(toolId, win.document);
|
||||
}
|
||||
|
@ -854,15 +865,10 @@ gDevTools.on("tool-registered", function(ev, toolId) {
|
|||
});
|
||||
|
||||
gDevTools.on("tool-unregistered", function(ev, toolId) {
|
||||
let killswitch;
|
||||
if (typeof toolId == "string") {
|
||||
killswitch = "devtools." + toolId + ".enabled";
|
||||
}
|
||||
else {
|
||||
killswitch = toolId.killswitch;
|
||||
if (typeof toolId != "string") {
|
||||
toolId = toolId.id;
|
||||
}
|
||||
gDevToolsBrowser._removeToolFromWindows(toolId, killswitch);
|
||||
gDevToolsBrowser._removeToolFromWindows(toolId);
|
||||
});
|
||||
|
||||
gDevTools.on("toolbox-ready", gDevToolsBrowser._updateMenuCheckbox);
|
||||
|
|
|
@ -20,7 +20,7 @@ function runTests(aTab) {
|
|||
let toolDefinition = {
|
||||
id: toolId,
|
||||
isTargetSupported: function() true,
|
||||
killswitch: "devtools.test-tool.enabled",
|
||||
visibilityswitch: "devtools.test-tool.enabled",
|
||||
url: "about:blank",
|
||||
label: "someLabel",
|
||||
build: function(iframeWindow, toolbox) {
|
||||
|
|
|
@ -26,24 +26,16 @@ function testSelectTool(aToolbox) {
|
|||
|
||||
function testOptionsShortcut() {
|
||||
ok(true, "Toolbox selected via selectTool method");
|
||||
toolbox.once("options-selected", testOptionsButtonClick);
|
||||
toolbox.once("options-selected", testOptions);
|
||||
toolbox.selectTool("webconsole")
|
||||
.then(() => synthesizeKeyFromKeyTag("toolbox-options-key", doc));
|
||||
}
|
||||
|
||||
function testOptionsButtonClick() {
|
||||
ok(true, "Toolbox selected via shortcut");
|
||||
toolbox.once("options-selected", testOptions);
|
||||
toolbox.selectTool("webconsole")
|
||||
.then(() => doc.getElementById("toolbox-tab-options").click());
|
||||
}
|
||||
|
||||
function testOptions(event, iframe) {
|
||||
function testOptions(event, tool) {
|
||||
ok(true, "Toolbox selected via button click");
|
||||
panelWin = iframe.contentWindow;
|
||||
let panelDoc = iframe.contentDocument;
|
||||
panelWin = tool.panelWin;
|
||||
// Testing pref changes
|
||||
let prefCheckboxes = panelDoc.querySelectorAll("checkbox[data-pref]");
|
||||
let prefCheckboxes = tool.panelDoc.querySelectorAll("checkbox[data-pref]");
|
||||
for (let checkbox of prefCheckboxes) {
|
||||
prefNodes.push(checkbox);
|
||||
prefValues.push(Services.prefs.getBoolPref(checkbox.getAttribute("data-pref")));
|
||||
|
|
|
@ -24,7 +24,7 @@ function test() {
|
|||
|
||||
let toolDefinition = {
|
||||
id: "fakeTool4242",
|
||||
killswitch: "devtools.fakeTool4242.enabled",
|
||||
visibilityswitch: "devtools.fakeTool4242.enabled",
|
||||
url: toolURL,
|
||||
label: "FAKE TOOL!!!",
|
||||
isTargetSupported: function() true,
|
||||
|
|
|
@ -16,7 +16,7 @@ function test() {
|
|||
const TOOL_ID_1 = "webconsole";
|
||||
const TOOL_ID_2 = "jsdebugger";
|
||||
|
||||
const LABEL_1 = "Web Console";
|
||||
const LABEL_1 = "Console";
|
||||
const LABEL_2 = "Debugger";
|
||||
|
||||
let toolbox;
|
||||
|
|
|
@ -4,51 +4,78 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { utils: Cu } = Components;
|
||||
const DISABLED_TOOLS = "devtools.toolbox.disabledTools";
|
||||
const {Cu} = require("chrome");
|
||||
|
||||
let Promise = require("sdk/core/promise");
|
||||
let EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource:///modules/devtools/gDevTools.jsm");
|
||||
|
||||
window.addEventListener("load", function onLoad() {
|
||||
window.removeEventListener("load", onLoad);
|
||||
setupToolsList();
|
||||
populatePreferences();
|
||||
});
|
||||
exports.OptionsPanel = OptionsPanel;
|
||||
|
||||
function setupToolsList() {
|
||||
let disabledTools = [];
|
||||
try {
|
||||
disabledTools = JSON.parse(Services.prefs.getCharPref(DISABLED_TOOLS));
|
||||
} catch(ex) {
|
||||
Cu.reportError("Error parsing pref " + DISABLED_TOOLS + " as JSON.");
|
||||
}
|
||||
let defaultToolsBox = document.getElementById("default-tools-box");
|
||||
let additionalToolsBox = document.getElementById("additional-tools-box");
|
||||
/**
|
||||
* Represents the Options Panel in the Toolbox.
|
||||
*/
|
||||
function OptionsPanel(iframeWindow, toolbox) {
|
||||
this.panelDoc = iframeWindow.document;
|
||||
this.panelWin = iframeWindow;
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
};
|
||||
|
||||
OptionsPanel.prototype = {
|
||||
|
||||
open: function OP_open() {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
this.setupToolsList();
|
||||
this.populatePreferences();
|
||||
|
||||
this.emit("ready");
|
||||
deferred.resolve(this);
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
setupToolsList: function OP_setupToolsList() {
|
||||
let defaultToolsBox = this.panelDoc.getElementById("default-tools-box");
|
||||
let additionalToolsBox = this.panelDoc.getElementById("additional-tools-box");
|
||||
|
||||
defaultToolsBox.textContent = "";
|
||||
additionalToolsBox.textContent = "";
|
||||
|
||||
let pref = function(key) {
|
||||
try {
|
||||
return Services.prefs.getBoolPref(key);
|
||||
}
|
||||
catch (ex) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
let onCheckboxClick = function(id) {
|
||||
if (disabledTools.indexOf(id) > -1) {
|
||||
disabledTools.splice(disabledTools.indexOf(id), 1);
|
||||
Services.prefs.setCharPref(DISABLED_TOOLS, JSON.stringify(disabledTools));
|
||||
let toolDefinition = gDevTools._tools.get(id);
|
||||
// Set the kill switch pref boolean to true
|
||||
Services.prefs.setBoolPref(toolDefinition.visibilityswitch, this.checked);
|
||||
if (this.checked) {
|
||||
gDevTools.emit("tool-registered", id);
|
||||
}
|
||||
else {
|
||||
disabledTools.push(id);
|
||||
Services.prefs.setCharPref(DISABLED_TOOLS, JSON.stringify(disabledTools));
|
||||
gDevTools.emit("tool-unregistered", gDevTools._tools.get(id));
|
||||
gDevTools.emit("tool-unregistered", toolDefinition);
|
||||
}
|
||||
};
|
||||
|
||||
// Populating the default tools lists
|
||||
for (let tool of gDevTools.getDefaultTools()) {
|
||||
let checkbox = document.createElement("checkbox");
|
||||
if (tool.id == "options") {
|
||||
continue;
|
||||
}
|
||||
let checkbox = this.panelDoc.createElement("checkbox");
|
||||
checkbox.setAttribute("id", tool.id);
|
||||
checkbox.setAttribute("label", tool.label);
|
||||
checkbox.setAttribute("tooltiptext", tool.tooltip || "");
|
||||
checkbox.setAttribute("checked", disabledTools.indexOf(tool.id) == -1);
|
||||
checkbox.addEventListener("command", onCheckboxClick.bind(null, tool.id));
|
||||
checkbox.setAttribute("checked", pref(tool.visibilityswitch));
|
||||
checkbox.addEventListener("command", onCheckboxClick.bind(checkbox, tool.id));
|
||||
defaultToolsBox.appendChild(checkbox);
|
||||
}
|
||||
|
||||
|
@ -56,12 +83,12 @@ function setupToolsList() {
|
|||
let atleastOneAddon = false;
|
||||
for (let tool of gDevTools.getAdditionalTools()) {
|
||||
atleastOneAddon = true;
|
||||
let checkbox = document.createElement("checkbox");
|
||||
let checkbox = this.panelDoc.createElement("checkbox");
|
||||
checkbox.setAttribute("id", tool.id);
|
||||
checkbox.setAttribute("label", tool.label);
|
||||
checkbox.setAttribute("tooltiptext", tool.tooltip || "");
|
||||
checkbox.setAttribute("checked", disabledTools.indexOf(tool.id) == -1);
|
||||
checkbox.addEventListener("command", onCheckboxClick.bind(null, tool.id));
|
||||
checkbox.setAttribute("checked", pref(tool.visibilityswitch));
|
||||
checkbox.addEventListener("command", onCheckboxClick.bind(checkbox, tool.id));
|
||||
additionalToolsBox.appendChild(checkbox);
|
||||
}
|
||||
|
||||
|
@ -70,11 +97,11 @@ function setupToolsList() {
|
|||
additionalToolsBox.previousSibling.style.display = "none";
|
||||
}
|
||||
|
||||
window.focus();
|
||||
}
|
||||
this.panelWin.focus();
|
||||
},
|
||||
|
||||
function populatePreferences() {
|
||||
let prefCheckboxes = document.querySelectorAll("checkbox[data-pref]");
|
||||
populatePreferences: function OP_populatePreferences() {
|
||||
let prefCheckboxes = this.panelDoc.querySelectorAll("checkbox[data-pref]");
|
||||
for (let checkbox of prefCheckboxes) {
|
||||
checkbox.checked = Services.prefs.getBoolPref(checkbox.getAttribute("data-pref"));
|
||||
checkbox.addEventListener("command", function() {
|
||||
|
@ -87,7 +114,7 @@ function populatePreferences() {
|
|||
gDevTools.emit("pref-changed", data);
|
||||
}.bind(checkbox));
|
||||
}
|
||||
let prefRadiogroups = document.querySelectorAll("radiogroup[data-pref]");
|
||||
let prefRadiogroups = this.panelDoc.querySelectorAll("radiogroup[data-pref]");
|
||||
for (let radiogroup of prefRadiogroups) {
|
||||
let selectedValue = Services.prefs.getCharPref(radiogroup.getAttribute("data-pref"));
|
||||
for (let radio of radiogroup.childNodes) {
|
||||
|
@ -107,4 +134,9 @@ function populatePreferences() {
|
|||
gDevTools.emit("pref-changed", data);
|
||||
}.bind(radiogroup));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function OP_destroy() {
|
||||
this.panelWin = this.panelDoc = null;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
<?xml-stylesheet rel="stylesheet" href="chrome://browser/skin/devtools/toolbox.css" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript;version=1.8" src="toolbox-options.js"></script>
|
||||
<hbox id="options-panel-container" flex="1">
|
||||
<hbox id="options-panel" flex="1">
|
||||
<vbox id="tools-box" class="options-vertical-pane" flex="1">
|
||||
|
|
|
@ -37,7 +37,7 @@ XPCOMUtils.defineLazyGetter(this, "toolboxStrings", function() {
|
|||
XPCOMUtils.defineLazyGetter(this, "Requisition", function() {
|
||||
let scope = {};
|
||||
Cu.import("resource://gre/modules/devtools/Require.jsm", scope);
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm", scope);
|
||||
Cu.import("resource://gre/modules/devtools/gcli.jsm", {});
|
||||
|
||||
let req = scope.require;
|
||||
return req('gcli/cli').Requisition;
|
||||
|
@ -220,14 +220,6 @@ Toolbox.prototype = {
|
|||
},
|
||||
|
||||
_buildOptions: function TBOX__buildOptions() {
|
||||
this.optionsButton = this.doc.getElementById("toolbox-tab-options");
|
||||
this.optionsButton.addEventListener("command", function() {
|
||||
this.selectTool("options");
|
||||
}.bind(this), false);
|
||||
|
||||
let iframe = this.doc.getElementById("toolbox-panel-iframe-options");
|
||||
this._toolPanels.set("options", iframe);
|
||||
|
||||
let key = this.doc.getElementById("toolbox-options-key");
|
||||
key.addEventListener("command", function(toolId) {
|
||||
this.selectTool(toolId);
|
||||
|
@ -358,7 +350,6 @@ Toolbox.prototype = {
|
|||
let radio = this.doc.createElement("radio");
|
||||
radio.className = "toolbox-tab devtools-tab";
|
||||
radio.id = "toolbox-tab-" + id;
|
||||
radio.setAttribute("flex", "1");
|
||||
radio.setAttribute("toolid", id);
|
||||
if (toolDefinition.ordinal == undefined || toolDefinition.ordinal < 0) {
|
||||
toolDefinition.ordinal = MAX_ORDINAL;
|
||||
|
@ -370,22 +361,30 @@ Toolbox.prototype = {
|
|||
this.selectTool(id);
|
||||
}.bind(this, id));
|
||||
|
||||
// spacer lets us center the image and label, while allowing cropping
|
||||
let spacer = this.doc.createElement("spacer");
|
||||
spacer.setAttribute("flex", "1");
|
||||
radio.appendChild(spacer);
|
||||
|
||||
if (toolDefinition.icon) {
|
||||
let image = this.doc.createElement("image");
|
||||
image.setAttribute("src", toolDefinition.icon);
|
||||
radio.appendChild(image);
|
||||
}
|
||||
|
||||
if (toolDefinition.label) {
|
||||
let label = this.doc.createElement("label");
|
||||
label.setAttribute("value", toolDefinition.label)
|
||||
label.setAttribute("crop", "end");
|
||||
label.setAttribute("flex", "1");
|
||||
radio.appendChild(label);
|
||||
radio.setAttribute("flex", "1");
|
||||
}
|
||||
|
||||
let vbox = this.doc.createElement("vbox");
|
||||
vbox.className = "toolbox-panel";
|
||||
vbox.id = "toolbox-panel-" + id;
|
||||
|
||||
radio.appendChild(label);
|
||||
|
||||
// If there is no tab yet, or the ordinal to be added is the largest one.
|
||||
if (tabs.childNodes.length == 0 ||
|
||||
|
@ -398,8 +397,7 @@ Toolbox.prototype = {
|
|||
Array.some(tabs.childNodes, (node, i) => {
|
||||
if (+node.getAttribute("ordinal") > toolDefinition.ordinal) {
|
||||
tabs.insertBefore(radio, node);
|
||||
deck.insertBefore(vbox, deck.childNodes[i + 1]);
|
||||
// + 1 because of options panel.
|
||||
deck.insertBefore(vbox, deck.childNodes[i]);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
@ -440,8 +438,9 @@ Toolbox.prototype = {
|
|||
|
||||
let tabstrip = this.doc.getElementById("toolbox-tabs");
|
||||
|
||||
// select the right tab
|
||||
let index = -1;
|
||||
// select the right tab, making 0th index the default tab if right tab not
|
||||
// found
|
||||
let index = 0;
|
||||
let tabs = tabstrip.childNodes;
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
if (tabs[i] === tab) {
|
||||
|
@ -453,15 +452,7 @@ Toolbox.prototype = {
|
|||
|
||||
// and select the right iframe
|
||||
let deck = this.doc.getElementById("toolbox-deck");
|
||||
// offset by 1 due to options panel
|
||||
if (id == "options") {
|
||||
deck.selectedIndex = 0;
|
||||
this.optionsButton.setAttribute("checked", true);
|
||||
}
|
||||
else {
|
||||
deck.selectedIndex = index != -1 ? index + 1: -1;
|
||||
this.optionsButton.removeAttribute("checked");
|
||||
}
|
||||
deck.selectedIndex = index;
|
||||
|
||||
let definition = gDevTools.getToolDefinitionMap().get(id);
|
||||
|
||||
|
@ -668,7 +659,7 @@ Toolbox.prototype = {
|
|||
|
||||
if (this.hostType == Toolbox.HostType.WINDOW) {
|
||||
let doc = this.doc.defaultView.parent.document;
|
||||
let key = doc.getElementById("key_" + id);
|
||||
let key = doc.getElementById("key_" + toolId);
|
||||
if (key) {
|
||||
key.parentNode.removeChild(key);
|
||||
}
|
||||
|
@ -709,7 +700,6 @@ Toolbox.prototype = {
|
|||
|
||||
let outstanding = [];
|
||||
|
||||
this._toolPanels.delete("options");
|
||||
for (let [id, panel] of this._toolPanels) {
|
||||
outstanding.push(panel.destroy());
|
||||
}
|
||||
|
|
|
@ -34,10 +34,6 @@
|
|||
<hbox id="toolbox-dock-buttons"/>
|
||||
</hbox>
|
||||
#endif
|
||||
<toolbarbutton id="toolbox-tab-options"
|
||||
autocheck="false"
|
||||
class="command-button toolbox-tab devtools-tab"
|
||||
tooltiptext="&toolboxOptionsButton.tooltip;"/>
|
||||
<hbox id="toolbox-tabs" flex="1">
|
||||
</hbox>
|
||||
<hbox id="toolbox-buttons" pack="end"/>
|
||||
|
@ -51,14 +47,6 @@
|
|||
#endif
|
||||
</toolbar>
|
||||
<deck id="toolbox-deck" flex="1">
|
||||
<vbox id="toolbox-panel-options"
|
||||
class="toolbox-panel">
|
||||
<iframe id="toolbox-panel-iframe-options"
|
||||
class="toolbox-panel-iframe"
|
||||
flex="1" forceOwnRefreshDriver=""
|
||||
src="chrome://browser/content/devtools/framework/toolbox-options.xul">
|
||||
</iframe>
|
||||
</vbox>
|
||||
</deck>
|
||||
</notificationbox>
|
||||
</window>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
this.EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/gcli.jsm");
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
|
||||
|
|
|
@ -21,11 +21,10 @@ this.EXPORTED_SYMBOLS = [ 'helpers' ];
|
|||
var helpers = {};
|
||||
this.helpers = helpers;
|
||||
let require = (Cu.import("resource://gre/modules/devtools/Require.jsm", {})).require;
|
||||
Components.utils.import("resource:///modules/devtools/gcli.jsm", {});
|
||||
Components.utils.import("resource://gre/modules/devtools/gcli.jsm", {});
|
||||
|
||||
let console = (Cu.import("resource://gre/modules/devtools/Console.jsm", {})).console;
|
||||
let devtools = (Cu.import("resource:///modules/devtools/gDevTools.jsm", {})).devtools;
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let TargetFactory = (Cu.import("resource:///modules/devtools/gDevTools.jsm", {})).devtools.TargetFactory;
|
||||
|
||||
let Promise = (Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {})).Promise;
|
||||
let assert = { ok: ok, is: is, log: info };
|
||||
|
@ -158,6 +157,7 @@ helpers.runTests = function(options, tests) {
|
|||
});
|
||||
|
||||
var recover = function(error) {
|
||||
ok(false, error);
|
||||
console.error(error);
|
||||
};
|
||||
|
||||
|
@ -341,7 +341,7 @@ helpers._createDebugCheck = function(options) {
|
|||
output += ' current: \'' + helpers._actual.current(options) + '\',\n';
|
||||
output += ' status: \'' + helpers._actual.status(options) + '\',\n';
|
||||
output += ' options: ' + outputArray(helpers._actual.options(options)) + ',\n';
|
||||
output += ' error: \'' + helpers._actual.message(options) + '\',\n';
|
||||
output += ' message: \'' + helpers._actual.message(options) + '\',\n';
|
||||
output += ' predictions: ' + outputArray(predictions) + ',\n';
|
||||
output += ' unassigned: ' + outputArray(requisition._unassigned) + ',\n';
|
||||
output += ' outputState: \'' + helpers._actual.outputState(options) + '\',\n';
|
||||
|
@ -378,6 +378,8 @@ helpers._createDebugCheck = function(options) {
|
|||
output += ' exec: {\n';
|
||||
output += ' output: \'\',\n';
|
||||
output += ' completed: true,\n';
|
||||
output += ' type: \'string\',\n';
|
||||
output += ' error: false\n';
|
||||
output += ' }\n';
|
||||
output += ' }\n';
|
||||
output += ']);';
|
||||
|
@ -702,7 +704,7 @@ helpers._check = function(options, name, checks) {
|
|||
*/
|
||||
helpers._exec = function(options, name, expected) {
|
||||
if (expected == null) {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
var output = options.display.requisition.exec({ hidden: true });
|
||||
|
@ -715,20 +717,32 @@ helpers._exec = function(options, name, expected) {
|
|||
|
||||
if (!options.window.document.createElement) {
|
||||
assert.log('skipping output tests (missing doc.createElement) for ' + name);
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({ output: output });
|
||||
}
|
||||
|
||||
if (!('output' in expected)) {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({ output: output });
|
||||
}
|
||||
|
||||
var deferred = Promise.defer();
|
||||
|
||||
var checkOutput = function() {
|
||||
var div = options.window.document.createElement('div');
|
||||
var nodePromise = converters.convert(output.data, output.type, 'dom',
|
||||
options.display.requisition.context);
|
||||
nodePromise.then(function(node) {
|
||||
var conversionContext = options.display.requisition.conversionContext;
|
||||
|
||||
if ('type' in expected) {
|
||||
assert.is(output.type,
|
||||
expected.type,
|
||||
'output.type for: ' + name);
|
||||
}
|
||||
|
||||
if ('error' in expected) {
|
||||
assert.is(output.error,
|
||||
expected.error,
|
||||
'output.error for: ' + name);
|
||||
}
|
||||
|
||||
var convertPromise = converters.convert(output.data, output.type, 'dom',
|
||||
conversionContext);
|
||||
return convertPromise.then(function(node) {
|
||||
div.appendChild(node);
|
||||
var actualOutput = div.textContent.trim();
|
||||
|
||||
|
@ -757,24 +771,11 @@ helpers._exec = function(options, name, expected) {
|
|||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
|
||||
deferred.resolve(actualOutput);
|
||||
return { output: output, text: actualOutput };
|
||||
});
|
||||
};
|
||||
|
||||
if (output.completed !== false) {
|
||||
checkOutput();
|
||||
}
|
||||
else {
|
||||
var changed = function() {
|
||||
if (output.completed !== false) {
|
||||
checkOutput();
|
||||
output.onChange.remove(changed);
|
||||
}
|
||||
};
|
||||
output.onChange.add(changed);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return output.promise.then(checkOutput, checkOutput);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -789,15 +790,15 @@ helpers._setup = function(options, name, action) {
|
|||
return Promise.resolve(action());
|
||||
}
|
||||
|
||||
return Promise.reject('setup must be a string or a function');
|
||||
return Promise.reject('\'setup\' property must be a string or a function. Is ' + action);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to shutdown the test
|
||||
*/
|
||||
helpers._post = function(name, action, output) {
|
||||
helpers._post = function(name, action, data) {
|
||||
if (typeof action === 'function') {
|
||||
return Promise.resolve(action(output));
|
||||
return Promise.resolve(action(data.output, data.text));
|
||||
}
|
||||
return Promise.resolve(action);
|
||||
};
|
||||
|
@ -943,6 +944,8 @@ helpers.audit = function(options, audits) {
|
|||
if (typeof chunkLen !== 'number') {
|
||||
chunkLen = 1;
|
||||
}
|
||||
|
||||
if (assert.currentTest) {
|
||||
var responseTime = (new Date().getTime() - start) / chunkLen;
|
||||
totalResponseTime += responseTime;
|
||||
if (responseTime > maxResponseTime) {
|
||||
|
@ -950,12 +953,13 @@ helpers.audit = function(options, audits) {
|
|||
maxResponseCulprit = assert.currentTest + '/' + name;
|
||||
}
|
||||
averageOver++;
|
||||
}
|
||||
|
||||
var checkDone = helpers._check(options, name, audit.check);
|
||||
return checkDone.then(function() {
|
||||
var execDone = helpers._exec(options, name, audit.exec);
|
||||
return execDone.then(function(output) {
|
||||
return helpers._post(name, audit.post, output).then(function() {
|
||||
return execDone.then(function(data) {
|
||||
return helpers._post(name, audit.post, data).then(function() {
|
||||
if (assert.testLogging) {
|
||||
log('- END \'' + name + '\' in ' + assert.currentTest);
|
||||
}
|
||||
|
@ -963,9 +967,8 @@ helpers.audit = function(options, audits) {
|
|||
});
|
||||
});
|
||||
});
|
||||
}).then(null, function(ex) {
|
||||
console.error(ex.stack);
|
||||
throw(ex);
|
||||
}).then(function() {
|
||||
return options.display.inputter.setInput('');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ Object.defineProperty(exports, "TargetFactory", {
|
|||
loader.lazyGetter(this, "osString", () => Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS);
|
||||
|
||||
// Panels
|
||||
loader.lazyGetter(this, "OptionsPanel", function() require("devtools/framework/toolbox-options").OptionsPanel);
|
||||
loader.lazyGetter(this, "InspectorPanel", function() require("devtools/inspector/inspector-panel").InspectorPanel);
|
||||
loader.lazyImporter(this, "WebConsolePanel", "resource:///modules/WebConsolePanel.jsm");
|
||||
loader.lazyImporter(this, "DebuggerPanel", "resource:///modules/devtools/DebuggerPanel.jsm");
|
||||
|
@ -37,12 +38,14 @@ loader.lazyImporter(this, "ProfilerPanel", "resource:///modules/devtools/Profile
|
|||
loader.lazyImporter(this, "NetMonitorPanel", "resource:///modules/devtools/NetMonitorPanel.jsm");
|
||||
|
||||
// Strings
|
||||
const toolboxProps = "chrome://browser/locale/devtools/toolbox.properties";
|
||||
const inspectorProps = "chrome://browser/locale/devtools/inspector.properties";
|
||||
const debuggerProps = "chrome://browser/locale/devtools/debugger.properties";
|
||||
const styleEditorProps = "chrome://browser/locale/devtools/styleeditor.properties";
|
||||
const webConsoleProps = "chrome://browser/locale/devtools/webconsole.properties";
|
||||
const profilerProps = "chrome://browser/locale/devtools/profiler.properties";
|
||||
const netMonitorProps = "chrome://browser/locale/devtools/netmonitor.properties";
|
||||
loader.lazyGetter(this, "toolboxStrings", () => Services.strings.createBundle(toolboxProps));
|
||||
loader.lazyGetter(this, "webConsoleStrings", () => Services.strings.createBundle(webConsoleProps));
|
||||
loader.lazyGetter(this, "debuggerStrings", () => Services.strings.createBundle(debuggerProps));
|
||||
loader.lazyGetter(this, "styleEditorStrings", () => Services.strings.createBundle(styleEditorProps));
|
||||
|
@ -54,15 +57,31 @@ let Tools = {};
|
|||
exports.Tools = Tools;
|
||||
|
||||
// Definitions
|
||||
Tools.options = {
|
||||
id: "options",
|
||||
ordinal: 0,
|
||||
url: "chrome://browser/content/devtools/framework/toolbox-options.xul",
|
||||
icon: "chrome://browser/skin/devtools/tool-options.png",
|
||||
tooltip: l10n("optionsButton.tooltip", toolboxStrings),
|
||||
isTargetSupported: function(target) {
|
||||
return true;
|
||||
},
|
||||
build: function(iframeWindow, toolbox) {
|
||||
let panel = new OptionsPanel(iframeWindow, toolbox);
|
||||
return panel.open();
|
||||
}
|
||||
}
|
||||
|
||||
Tools.webConsole = {
|
||||
id: "webconsole",
|
||||
key: l10n("cmd.commandkey", webConsoleStrings),
|
||||
accesskey: l10n("webConsoleCmd.accesskey", webConsoleStrings),
|
||||
modifiers: Services.appinfo.OS == "Darwin" ? "accel,alt" : "accel,shift",
|
||||
ordinal: 0,
|
||||
ordinal: 1,
|
||||
icon: "chrome://browser/skin/devtools/tool-webconsole.png",
|
||||
url: "chrome://browser/content/devtools/webconsole.xul",
|
||||
label: l10n("ToolboxWebconsole.label", webConsoleStrings),
|
||||
label: l10n("ToolboxTabWebconsole.label", webConsoleStrings),
|
||||
menuLabel: l10n("MenuWebconsole.label", webConsoleStrings),
|
||||
tooltip: l10n("ToolboxWebconsole.tooltip", webConsoleStrings),
|
||||
|
||||
isTargetSupported: function(target) {
|
||||
|
@ -74,33 +93,11 @@ Tools.webConsole = {
|
|||
}
|
||||
};
|
||||
|
||||
Tools.jsdebugger = {
|
||||
id: "jsdebugger",
|
||||
key: l10n("open.commandkey", debuggerStrings),
|
||||
accesskey: l10n("debuggerMenu.accesskey", debuggerStrings),
|
||||
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
|
||||
ordinal: 2,
|
||||
killswitch: "devtools.debugger.enabled",
|
||||
icon: "chrome://browser/skin/devtools/tool-debugger.png",
|
||||
url: "chrome://browser/content/devtools/debugger.xul",
|
||||
label: l10n("ToolboxDebugger.label", debuggerStrings),
|
||||
tooltip: l10n("ToolboxDebugger.tooltip", debuggerStrings),
|
||||
|
||||
isTargetSupported: function(target) {
|
||||
return true;
|
||||
},
|
||||
|
||||
build: function(iframeWindow, toolbox) {
|
||||
let panel = new DebuggerPanel(iframeWindow, toolbox);
|
||||
return panel.open();
|
||||
}
|
||||
};
|
||||
|
||||
Tools.inspector = {
|
||||
id: "inspector",
|
||||
accesskey: l10n("inspector.accesskey", inspectorStrings),
|
||||
key: l10n("inspector.commandkey", inspectorStrings),
|
||||
ordinal: 1,
|
||||
ordinal: 2,
|
||||
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
|
||||
icon: "chrome://browser/skin/devtools/tool-inspector.png",
|
||||
url: "chrome://browser/content/devtools/inspector/inspector.xul",
|
||||
|
@ -117,10 +114,32 @@ Tools.inspector = {
|
|||
}
|
||||
};
|
||||
|
||||
Tools.jsdebugger = {
|
||||
id: "jsdebugger",
|
||||
key: l10n("open.commandkey", debuggerStrings),
|
||||
accesskey: l10n("debuggerMenu.accesskey", debuggerStrings),
|
||||
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
|
||||
ordinal: 3,
|
||||
visibilityswitch: "devtools.debugger.enabled",
|
||||
icon: "chrome://browser/skin/devtools/tool-debugger.png",
|
||||
url: "chrome://browser/content/devtools/debugger.xul",
|
||||
label: l10n("ToolboxDebugger.label", debuggerStrings),
|
||||
tooltip: l10n("ToolboxDebugger.tooltip", debuggerStrings),
|
||||
|
||||
isTargetSupported: function(target) {
|
||||
return true;
|
||||
},
|
||||
|
||||
build: function(iframeWindow, toolbox) {
|
||||
let panel = new DebuggerPanel(iframeWindow, toolbox);
|
||||
return panel.open();
|
||||
}
|
||||
};
|
||||
|
||||
Tools.styleEditor = {
|
||||
id: "styleeditor",
|
||||
key: l10n("open.commandkey", styleEditorStrings),
|
||||
ordinal: 3,
|
||||
ordinal: 4,
|
||||
accesskey: l10n("open.accesskey", styleEditorStrings),
|
||||
modifiers: "shift",
|
||||
icon: "chrome://browser/skin/devtools/tool-styleeditor.png",
|
||||
|
@ -142,9 +161,9 @@ Tools.jsprofiler = {
|
|||
id: "jsprofiler",
|
||||
accesskey: l10n("profiler.accesskey", profilerStrings),
|
||||
key: l10n("profiler2.commandkey", profilerStrings),
|
||||
ordinal: 4,
|
||||
ordinal: 5,
|
||||
modifiers: "shift",
|
||||
killswitch: "devtools.profiler.enabled",
|
||||
visibilityswitch: "devtools.profiler.enabled",
|
||||
icon: "chrome://browser/skin/devtools/tool-profiler.png",
|
||||
url: "chrome://browser/content/devtools/profiler.xul",
|
||||
label: l10n("profiler.label", profilerStrings),
|
||||
|
@ -164,10 +183,10 @@ Tools.netMonitor = {
|
|||
id: "netmonitor",
|
||||
accesskey: l10n("netmonitor.accesskey", netMonitorStrings),
|
||||
key: l10n("netmonitor.commandkey", netMonitorStrings),
|
||||
ordinal: 5,
|
||||
ordinal: 6,
|
||||
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
|
||||
killswitch: "devtools.netmonitor.enabled",
|
||||
icon: "chrome://browser/skin/devtools/tool-profiler.png",
|
||||
visibilityswitch: "devtools.netmonitor.enabled",
|
||||
icon: "chrome://browser/skin/devtools/tool-network.png",
|
||||
url: "chrome://browser/content/devtools/netmonitor.xul",
|
||||
label: l10n("netmonitor.label", netMonitorStrings),
|
||||
tooltip: l10n("netmonitor.tooltip", netMonitorStrings),
|
||||
|
@ -183,6 +202,7 @@ Tools.netMonitor = {
|
|||
};
|
||||
|
||||
let defaultTools = [
|
||||
Tools.options,
|
||||
Tools.styleEditor,
|
||||
Tools.webConsole,
|
||||
Tools.jsdebugger,
|
||||
|
@ -201,7 +221,7 @@ var unloadObserver = {
|
|||
observe: function(subject, topic, data) {
|
||||
if (subject.wrappedJSObject === require("@loader/unload")) {
|
||||
Services.obs.removeObserver(unloadObserver, "sdk:loader:destroy");
|
||||
for (let definition of defaultTools) {
|
||||
for (let definition of gDevTools.getToolDefinitionArray()) {
|
||||
gDevTools.unregisterTool(definition.id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ let EventEmitter = require("devtools/shared/event-emitter");
|
|||
let {editableField, InplaceEditor} = require("devtools/shared/inplace-editor");
|
||||
|
||||
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
|
||||
Cu.import("resource:///modules/devtools/Templater.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/Templater.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,11 +5,19 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const EPSILON = 0.001;
|
||||
const RESIZE_REFRESH_RATE = 50; // ms
|
||||
const REQUESTS_REFRESH_RATE = 50; // ms
|
||||
const REQUESTS_HEADERS_SAFE_BOUNDS = 30; // px
|
||||
const REQUESTS_WATERFALL_SAFE_BOUNDS = 100; // px
|
||||
const REQUESTS_WATERFALL_BACKGROUND_PATTERN = [5, 250, 1000, 2000]; // ms
|
||||
const REQUESTS_WATERFALL_SAFE_BOUNDS = 90; // px
|
||||
const REQUESTS_WATERFALL_HEADER_TICKS_MULTIPLE = 5; // ms
|
||||
const REQUESTS_WATERFALL_HEADER_TICKS_SPACING_MIN = 60; // px
|
||||
const REQUESTS_WATERFALL_BACKGROUND_TICKS_MULTIPLE = 5; // ms
|
||||
const REQUESTS_WATERFALL_BACKGROUND_TICKS_SCALES = 3;
|
||||
const REQUESTS_WATERFALL_BACKGROUND_TICKS_SPACING_MIN = 10; // px
|
||||
const REQUESTS_WATERFALL_BACKGROUND_TICKS_OPACITY_MIN = 10; // byte
|
||||
const REQUESTS_WATERFALL_BACKGROUND_TICKS_OPACITY_ADD = 16; // byte
|
||||
const DEFAULT_HTTP_VERSION = "HTTP/1.1";
|
||||
const HEADERS_SIZE_DECIMALS = 3;
|
||||
const CONTENT_SIZE_DECIMALS = 2;
|
||||
|
@ -48,8 +56,6 @@ const GENERIC_VARIABLES_VIEW_SETTINGS = {
|
|||
switch: () => {}
|
||||
};
|
||||
|
||||
function $(aSelector, aTarget = document) aTarget.querySelector(aSelector);
|
||||
|
||||
/**
|
||||
* Object defining the network monitor view components.
|
||||
*/
|
||||
|
@ -157,6 +163,7 @@ let NetMonitorView = {
|
|||
$("#details-pane").selectedIndex = aTabIndex;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Lazily initializes and returns a promise for a SourceEditor instance.
|
||||
*
|
||||
|
@ -264,6 +271,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
|
||||
this.node = new SideMenuWidget($("#requests-menu-contents"), false);
|
||||
this.node.maintainSelectionVisible = false;
|
||||
this.node.autoscrollWithAppendedItems = true;
|
||||
|
||||
this.node.addEventListener("mousedown", this._onMouseDown, false);
|
||||
this.node.addEventListener("select", this._onSelect, false);
|
||||
|
@ -321,7 +329,6 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
|
||||
// Append a network request item to this container.
|
||||
let requestItem = this.push(menuView, {
|
||||
relaxed: true, /* this container should allow dupes & degenerates */
|
||||
attachment: {
|
||||
id: aId,
|
||||
startedDeltaMillis: unixTime - this._firstRequestStartedMillis,
|
||||
|
@ -332,10 +339,133 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
finalize: this._onRequestItemRemoved
|
||||
});
|
||||
|
||||
$("#details-pane-toggle").disabled = false;
|
||||
$(".requests-menu-empty-notice").hidden = true;
|
||||
|
||||
this._cache.set(aId, requestItem);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sorts all network requests in this container by a specified detail.
|
||||
*
|
||||
* @param string aType
|
||||
* Either "status", "method", "file", "domain", "type" or "size".
|
||||
*/
|
||||
sortBy: function NVRM_sortBy(aType) {
|
||||
let target = $("#requests-menu-" + aType + "-button");
|
||||
let headers = document.querySelectorAll(".requests-menu-header-button");
|
||||
|
||||
for (let header of headers) {
|
||||
if (header != target) {
|
||||
header.removeAttribute("sorted");
|
||||
header.removeAttribute("tooltiptext");
|
||||
}
|
||||
}
|
||||
|
||||
let direction = "";
|
||||
if (target) {
|
||||
if (!target.hasAttribute("sorted")) {
|
||||
target.setAttribute("sorted", direction = "ascending");
|
||||
target.setAttribute("tooltiptext", L10N.getStr("networkMenu.sortedAsc"));
|
||||
} else if (target.getAttribute("sorted") == "ascending") {
|
||||
target.setAttribute("sorted", direction = "descending");
|
||||
target.setAttribute("tooltiptext", L10N.getStr("networkMenu.sortedDesc"));
|
||||
} else {
|
||||
target.removeAttribute("sorted");
|
||||
target.removeAttribute("tooltiptext");
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by timing.
|
||||
if (!target || !direction) {
|
||||
this.sortContents(this._byTiming);
|
||||
}
|
||||
// Sort by whatever was requested.
|
||||
else switch (aType) {
|
||||
case "status":
|
||||
if (direction == "ascending") {
|
||||
this.sortContents(this._byStatus);
|
||||
} else {
|
||||
this.sortContents((a, b) => !this._byStatus(a, b));
|
||||
}
|
||||
break;
|
||||
case "method":
|
||||
if (direction == "ascending") {
|
||||
this.sortContents(this._byMethod);
|
||||
} else {
|
||||
this.sortContents((a, b) => !this._byMethod(a, b));
|
||||
}
|
||||
break;
|
||||
case "file":
|
||||
if (direction == "ascending") {
|
||||
this.sortContents(this._byFile);
|
||||
} else {
|
||||
this.sortContents((a, b) => !this._byFile(a, b));
|
||||
}
|
||||
break;
|
||||
case "domain":
|
||||
if (direction == "ascending") {
|
||||
this.sortContents(this._byDomain);
|
||||
} else {
|
||||
this.sortContents((a, b) => !this._byDomain(a, b));
|
||||
}
|
||||
break;
|
||||
case "type":
|
||||
if (direction == "ascending") {
|
||||
this.sortContents(this._byType);
|
||||
} else {
|
||||
this.sortContents((a, b) => !this._byType(a, b));
|
||||
}
|
||||
break;
|
||||
case "size":
|
||||
if (direction == "ascending") {
|
||||
this.sortContents(this._bySize);
|
||||
} else {
|
||||
this.sortContents((a, b) => !this._bySize(a, b));
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Predicates used when sorting items.
|
||||
*
|
||||
* @param MenuItem aFirst
|
||||
* The first menu item used in the comparison.
|
||||
* @param MenuItem aSecond
|
||||
* The second menu item used in the comparison.
|
||||
* @return number
|
||||
* -1 to sort aFirst to a lower index than aSecond
|
||||
* 0 to leave aFirst and aSecond unchanged with respect to each other
|
||||
* 1 to sort aSecond to a lower index than aFirst
|
||||
*/
|
||||
_byTiming: (aFirst, aSecond) =>
|
||||
aFirst.attachment.startedMillis > aSecond.attachment.startedMillis,
|
||||
|
||||
_byStatus: (aFirst, aSecond) =>
|
||||
aFirst.attachment.status > aSecond.attachment.status,
|
||||
|
||||
_byMethod: (aFirst, aSecond) =>
|
||||
aFirst.attachment.method > aSecond.attachment.method,
|
||||
|
||||
_byFile: (aFirst, aSecond) =>
|
||||
!aFirst.target || !aSecond.target ? -1 :
|
||||
$(".requests-menu-file", aFirst.target).getAttribute("value").toLowerCase() >
|
||||
$(".requests-menu-file", aSecond.target).getAttribute("value").toLowerCase(),
|
||||
|
||||
_byDomain: (aFirst, aSecond) =>
|
||||
!aFirst.target || !aSecond.target ? -1 :
|
||||
$(".requests-menu-domain", aFirst.target).getAttribute("value").toLowerCase() >
|
||||
$(".requests-menu-domain", aSecond.target).getAttribute("value").toLowerCase(),
|
||||
|
||||
_byType: (aFirst, aSecond) =>
|
||||
!aFirst.target || !aSecond.target ? -1 :
|
||||
$(".requests-menu-type", aFirst.target).getAttribute("value").toLowerCase() >
|
||||
$(".requests-menu-type", aSecond.target).getAttribute("value").toLowerCase(),
|
||||
|
||||
_bySize: (aFirst, aSecond) =>
|
||||
aFirst.attachment.contentSize > aSecond.attachment.contentSize,
|
||||
|
||||
/**
|
||||
* Schedules adding additional information to a network request.
|
||||
*
|
||||
|
@ -356,8 +486,8 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
if (!this.lazyUpdate) {
|
||||
return void this._flushRequests();
|
||||
}
|
||||
window.clearTimeout(this._updateTimeout);
|
||||
this._updateTimeout = window.setTimeout(this._flushRequests, REQUESTS_REFRESH_RATE);
|
||||
// Allow requests to settle down first.
|
||||
drain("update-requests", REQUESTS_REFRESH_RATE, () => this._flushRequests());
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -444,8 +574,12 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
NetMonitorView.NetworkDetails.populate(selectedItem.attachment);
|
||||
}
|
||||
}
|
||||
|
||||
// We're done flushing all the requests, clear the update queue.
|
||||
this._updateQueue = [];
|
||||
|
||||
// Make sure all the requests are sorted.
|
||||
this.sortContents();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -584,38 +718,19 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
},
|
||||
|
||||
/**
|
||||
* Rescales and redraws all the waterfalls in this container.
|
||||
* Rescales and redraws all the waterfall views in this container.
|
||||
*
|
||||
* @param boolean aReset
|
||||
* True if this container's width was changed.
|
||||
*/
|
||||
_flushWaterfallViews: function NVRM__flushWaterfallViews(aReset) {
|
||||
// To avoid expensive operations like getBoundingClientRect(), the
|
||||
// waterfalls width is cached. However, in certain scenarios like when
|
||||
// the window is resized, this needs to be invalidated.
|
||||
// To avoid expensive operations like getBoundingClientRect() and
|
||||
// rebuilding the waterfall background each time a new request comes in,
|
||||
// stuff is cached. However, in certain scenarios like when the window
|
||||
// is resized, this needs to be invalidated.
|
||||
if (aReset) {
|
||||
this._cachedWaterfallWidth = 0;
|
||||
|
||||
let table = $("#network-table");
|
||||
let toolbar = $("#requests-menu-toolbar");
|
||||
let columns = [
|
||||
[".requests-menu-waterfall", "waterfall-overflows"],
|
||||
[".requests-menu-size", "size-overflows"],
|
||||
[".requests-menu-type", "type-overflows"],
|
||||
[".requests-menu-domain", "domain-overflows"]
|
||||
];
|
||||
|
||||
// Flush headers.
|
||||
columns.forEach(([, attribute]) => table.removeAttribute(attribute));
|
||||
let availableWidth = toolbar.getBoundingClientRect().width;
|
||||
|
||||
// Hide overflowing columns.
|
||||
columns.forEach(([className, attribute]) => {
|
||||
let bounds = $(".requests-menu-header" + className).getBoundingClientRect();
|
||||
if (bounds.right > availableWidth - REQUESTS_HEADERS_SAFE_BOUNDS) {
|
||||
table.setAttribute(attribute, "");
|
||||
}
|
||||
});
|
||||
this._hideOverflowingColumns();
|
||||
}
|
||||
|
||||
// Determine the scaling to be applied to all the waterfalls so that
|
||||
|
@ -624,6 +739,11 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
let longestWidth = this._lastRequestEndedMillis - this._firstRequestStartedMillis;
|
||||
let scale = Math.min(Math.max(availableWidth / longestWidth, EPSILON), 1);
|
||||
|
||||
// Redraw and set the canvas background for each waterfall view.
|
||||
this._showWaterfallDivisionLabels(scale);
|
||||
this._drawWaterfallBackground(scale);
|
||||
this._flushWaterfallBackgrounds();
|
||||
|
||||
// Apply CSS transforms to each waterfall in this container totalTime
|
||||
// accurately translate and resize as needed.
|
||||
for (let [, { target, attachment }] of this._cache) {
|
||||
|
@ -651,6 +771,145 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the labels displayed on the waterfall header in this container.
|
||||
*
|
||||
* @param number aScale
|
||||
* The current waterfall scale.
|
||||
*/
|
||||
_showWaterfallDivisionLabels: function NVRM__showWaterfallDivisionLabels(aScale) {
|
||||
let container = $("#requests-menu-waterfall-header-box");
|
||||
let availableWidth = this._waterfallWidth - REQUESTS_WATERFALL_SAFE_BOUNDS;
|
||||
|
||||
// Nuke all existing labels.
|
||||
while (container.hasChildNodes()) {
|
||||
container.firstChild.remove();
|
||||
}
|
||||
|
||||
// Build new millisecond tick labels...
|
||||
let timingStep = REQUESTS_WATERFALL_HEADER_TICKS_MULTIPLE;
|
||||
let optimalTickIntervalFound = false;
|
||||
|
||||
while (!optimalTickIntervalFound) {
|
||||
// Ignore any divisions that would end up being too close to each other.
|
||||
let scaledStep = aScale * timingStep;
|
||||
if (scaledStep < REQUESTS_WATERFALL_HEADER_TICKS_SPACING_MIN) {
|
||||
timingStep <<= 1;
|
||||
continue;
|
||||
}
|
||||
optimalTickIntervalFound = true;
|
||||
|
||||
// Insert one label for each division on the current scale.
|
||||
let fragment = document.createDocumentFragment();
|
||||
|
||||
for (let x = 0; x < availableWidth; x += scaledStep) {
|
||||
let divisionMS = (x / aScale).toFixed(0);
|
||||
let translateX = "translateX(" + (x | 0) + "px)";
|
||||
|
||||
let node = document.createElement("label");
|
||||
let text = L10N.getFormatStr("networkMenu.divisionMS", divisionMS);
|
||||
node.className = "plain requests-menu-timings-division";
|
||||
node.style.transform = translateX;
|
||||
|
||||
node.setAttribute("value", text);
|
||||
fragment.appendChild(node);
|
||||
}
|
||||
container.appendChild(fragment);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the background displayed on each waterfall view in this container.
|
||||
*
|
||||
* @param number aScale
|
||||
* The current waterfall scale.
|
||||
*/
|
||||
_drawWaterfallBackground: function NVRM__drawWaterfallBackground(aScale) {
|
||||
if (!this._canvas || !this._ctx) {
|
||||
this._canvas = document.createElementNS(HTML_NS, "canvas");
|
||||
this._ctx = this._canvas.getContext("2d");
|
||||
}
|
||||
let canvas = this._canvas;
|
||||
let ctx = this._ctx;
|
||||
|
||||
// Nuke the context.
|
||||
let canvasWidth = canvas.width = this._waterfallWidth;
|
||||
let canvasHeight = canvas.height = 1; // Awww yeah, 1px, repeats on Y axis.
|
||||
|
||||
// Start over.
|
||||
let imageData = ctx.createImageData(canvasWidth, canvasHeight);
|
||||
let pixelArray = imageData.data;
|
||||
|
||||
let buf = new ArrayBuffer(pixelArray.length);
|
||||
let buf8 = new Uint8ClampedArray(buf);
|
||||
let data32 = new Uint32Array(buf);
|
||||
|
||||
// Build new millisecond tick lines...
|
||||
let timingStep = REQUESTS_WATERFALL_BACKGROUND_TICKS_MULTIPLE;
|
||||
let alphaComponent = REQUESTS_WATERFALL_BACKGROUND_TICKS_OPACITY_MIN;
|
||||
let optimalTickIntervalFound = false;
|
||||
|
||||
while (!optimalTickIntervalFound) {
|
||||
// Ignore any divisions that would end up being too close to each other.
|
||||
let scaledStep = aScale * timingStep;
|
||||
if (scaledStep < REQUESTS_WATERFALL_BACKGROUND_TICKS_SPACING_MIN) {
|
||||
timingStep <<= 1;
|
||||
continue;
|
||||
}
|
||||
optimalTickIntervalFound = true;
|
||||
|
||||
// Insert one pixel for each division on each scale.
|
||||
for (let i = 1; i <= REQUESTS_WATERFALL_BACKGROUND_TICKS_SCALES; i++) {
|
||||
let increment = scaledStep * Math.pow(2, i);
|
||||
for (let x = 0; x < canvasWidth; x += increment) {
|
||||
data32[x | 0] = (alphaComponent << 24) | (255 << 16) | (255 << 8) | 255;
|
||||
}
|
||||
alphaComponent += REQUESTS_WATERFALL_BACKGROUND_TICKS_OPACITY_ADD;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush the image data and cache the waterfall background.
|
||||
pixelArray.set(buf8);
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
this._cachedWaterfallBackground = "url(" + canvas.toDataURL() + ")";
|
||||
},
|
||||
|
||||
/**
|
||||
* Reapplies the current waterfall background on all request items.
|
||||
*/
|
||||
_flushWaterfallBackgrounds: function NVRM__flushWaterfallBackgrounds() {
|
||||
for (let [, { target }] of this._cache) {
|
||||
let waterfallNode = $(".requests-menu-waterfall", target);
|
||||
waterfallNode.style.backgroundImage = this._cachedWaterfallBackground;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides the overflowing columns in the requests table.
|
||||
*/
|
||||
_hideOverflowingColumns: function NVRM__hideOverflowingColumns() {
|
||||
let table = $("#network-table");
|
||||
let toolbar = $("#requests-menu-toolbar");
|
||||
let columns = [
|
||||
["#requests-menu-waterfall-header-box", "waterfall-overflows"],
|
||||
["#requests-menu-size-header-box", "size-overflows"],
|
||||
["#requests-menu-type-header-box", "type-overflows"],
|
||||
["#requests-menu-domain-header-box", "domain-overflows"]
|
||||
];
|
||||
|
||||
// Flush headers.
|
||||
columns.forEach(([, attribute]) => table.removeAttribute(attribute));
|
||||
let availableWidth = toolbar.getBoundingClientRect().width;
|
||||
|
||||
// Hide the columns.
|
||||
columns.forEach(([id, attribute]) => {
|
||||
let bounds = $(id).getBoundingClientRect();
|
||||
if (bounds.right > availableWidth - REQUESTS_HEADERS_SAFE_BOUNDS) {
|
||||
table.setAttribute(attribute, "");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Function called each time a network request item is removed.
|
||||
*
|
||||
|
@ -685,7 +944,8 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
* The resize listener for this container's window.
|
||||
*/
|
||||
_onResize: function NVRM__onResize(e) {
|
||||
this._flushWaterfallViews(true);
|
||||
// Allow requests to settle down first.
|
||||
drain("resize-events", RESIZE_REFRESH_RATE, () => this._flushWaterfallViews(true));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -721,7 +981,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
get _waterfallWidth() {
|
||||
if (this._cachedWaterfallWidth == 0) {
|
||||
let container = $("#requests-menu-toolbar");
|
||||
let waterfall = $("#requests-menu-waterfall-label");
|
||||
let waterfall = $("#requests-menu-waterfall-header-box");
|
||||
let containerBounds = container.getBoundingClientRect();
|
||||
let waterfallBounds = waterfall.getBoundingClientRect();
|
||||
this._cachedWaterfallWidth = containerBounds.width - waterfallBounds.left;
|
||||
|
@ -730,11 +990,15 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
},
|
||||
|
||||
_cache: null,
|
||||
_canvas: null,
|
||||
_ctx: null,
|
||||
_cachedWaterfallWidth: 0,
|
||||
_cachedWaterfallBackground: null,
|
||||
_firstRequestStartedMillis: -1,
|
||||
_lastRequestEndedMillis: -1,
|
||||
_updateQueue: [],
|
||||
_updateTimeout: null
|
||||
_updateTimeout: null,
|
||||
_resizeTimeout: null
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -1116,7 +1380,7 @@ create({ constructor: NetworkDetailsView, proto: MenuContainer.prototype }, {
|
|||
$("#response-content-textarea-box").hidden = false;
|
||||
NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
|
||||
aEditor.setMode(SourceEditor.MODES.TEXT);
|
||||
aEditor.setText(aString);
|
||||
aEditor.setText(NetworkHelper.convertToUnicode(aString, "UTF-8"));
|
||||
|
||||
// Maybe set a more appropriate mode in the Source Editor if possible.
|
||||
for (let key in CONTENT_MIME_TYPE_MAPPINGS) {
|
||||
|
@ -1213,6 +1477,22 @@ create({ constructor: NetworkDetailsView, proto: MenuContainer.prototype }, {
|
|||
_responseCookies: ""
|
||||
});
|
||||
|
||||
/**
|
||||
* DOM query helper.
|
||||
*/
|
||||
function $(aSelector, aTarget = document) aTarget.querySelector(aSelector);
|
||||
|
||||
/**
|
||||
* Helper for draining a rapid succession of events and invoking a callback
|
||||
* once everything settles down.
|
||||
*/
|
||||
function drain(aId, aWait, aCallback) {
|
||||
window.clearTimeout(drain.store.get(aId));
|
||||
drain.store.set(aId, window.setTimeout(aCallback, aWait));
|
||||
}
|
||||
|
||||
drain.store = new Map();
|
||||
|
||||
/**
|
||||
* Preliminary setup for the NetMonitorView object.
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
* 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/. */
|
||||
|
||||
#details-pane-toggle[disabled] {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#response-content-image-box {
|
||||
overflow: auto;
|
||||
}
|
||||
|
|
|
@ -22,34 +22,75 @@
|
|||
<toolbar id="requests-menu-toolbar"
|
||||
class="devtools-toolbar"
|
||||
align="center">
|
||||
<label id="requests-menu-status-and-method-label"
|
||||
class="plain requests-menu-header requests-menu-status-and-method"
|
||||
value="&netmonitorUI.toolbar.method;"
|
||||
crop="end"/>
|
||||
<label id="requests-menu-file-label"
|
||||
class="plain requests-menu-header requests-menu-file"
|
||||
value="&netmonitorUI.toolbar.file;"
|
||||
crop="end"/>
|
||||
<label id="requests-menu-domain-label"
|
||||
class="plain requests-menu-header requests-menu-domain"
|
||||
value="&netmonitorUI.toolbar.domain;"
|
||||
crop="end"/>
|
||||
<label id="requests-menu-type-label"
|
||||
class="plain requests-menu-header requests-menu-type"
|
||||
value="&netmonitorUI.toolbar.type;"
|
||||
crop="end"/>
|
||||
<label id="requests-menu-size-label"
|
||||
class="plain requests-menu-header requests-menu-size"
|
||||
value="&netmonitorUI.toolbar.size;"
|
||||
crop="end"/>
|
||||
<hbox id="toolbar-labels" flex="1">
|
||||
<hbox id="requests-menu-status-and-method-header-box"
|
||||
class="requests-menu-header requests-menu-status-and-method"
|
||||
align="center">
|
||||
<button id="requests-menu-status-button"
|
||||
class="requests-menu-header-button requests-menu-status"
|
||||
onclick="NetMonitorView.RequestsMenu.sortBy('status')">
|
||||
&netmonitorUI.toolbar.status;
|
||||
</button>
|
||||
<button id="requests-menu-method-button"
|
||||
class="requests-menu-header-button requests-menu-method"
|
||||
onclick="NetMonitorView.RequestsMenu.sortBy('method')"
|
||||
flex="1">
|
||||
&netmonitorUI.toolbar.method;
|
||||
</button>
|
||||
</hbox>
|
||||
<hbox id="requests-menu-file-header-box"
|
||||
class="requests-menu-header requests-menu-file"
|
||||
align="center">
|
||||
<button id="requests-menu-file-button"
|
||||
class="requests-menu-header-button requests-menu-file"
|
||||
onclick="NetMonitorView.RequestsMenu.sortBy('file')"
|
||||
flex="1">
|
||||
&netmonitorUI.toolbar.file;
|
||||
</button>
|
||||
</hbox>
|
||||
<hbox id="requests-menu-domain-header-box"
|
||||
class="requests-menu-header requests-menu-domain"
|
||||
align="center">
|
||||
<button id="requests-menu-domain-button"
|
||||
class="requests-menu-header-button requests-menu-domain"
|
||||
onclick="NetMonitorView.RequestsMenu.sortBy('domain')"
|
||||
flex="1">
|
||||
&netmonitorUI.toolbar.domain;
|
||||
</button>
|
||||
</hbox>
|
||||
<hbox id="requests-menu-type-header-box"
|
||||
class="requests-menu-header requests-menu-type"
|
||||
align="center">
|
||||
<button id="requests-menu-type-button"
|
||||
class="requests-menu-header-button requests-menu-type"
|
||||
onclick="NetMonitorView.RequestsMenu.sortBy('type')"
|
||||
flex="1">
|
||||
&netmonitorUI.toolbar.type;
|
||||
</button>
|
||||
</hbox>
|
||||
<hbox id="requests-menu-size-header-box"
|
||||
class="requests-menu-header requests-menu-size"
|
||||
align="center">
|
||||
<button id="requests-menu-size-button"
|
||||
class="requests-menu-header-button requests-menu-size"
|
||||
onclick="NetMonitorView.RequestsMenu.sortBy('size')"
|
||||
flex="1">
|
||||
&netmonitorUI.toolbar.size;
|
||||
</button>
|
||||
</hbox>
|
||||
<hbox id="requests-menu-waterfall-header-box"
|
||||
class="requests-menu-header requests-menu-waterfall"
|
||||
align="center">
|
||||
<label id="requests-menu-waterfall-label"
|
||||
class="plain requests-menu-header requests-menu-waterfall"
|
||||
value="&netmonitorUI.toolbar.waterfall;"
|
||||
crop="end"/>
|
||||
class="plain requests-menu-waterfall"
|
||||
value="&netmonitorUI.toolbar.waterfall;"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<spacer id="toolbar-spacer" flex="1"/>
|
||||
<toolbarbutton id="details-pane-toggle"
|
||||
class="devtools-toolbarbutton"
|
||||
tooltiptext="&netmonitorUI.panesButton.tooltip;"
|
||||
disabled="true"
|
||||
tabindex="0"/>
|
||||
</toolbar>
|
||||
<label class="plain requests-menu-empty-notice"
|
||||
|
@ -58,7 +99,7 @@
|
|||
<hbox id="requests-menu-item-template" hidden="true">
|
||||
<hbox class="requests-menu-subitem requests-menu-status-and-method"
|
||||
align="center">
|
||||
<hbox class="requests-menu-status"/>
|
||||
<box class="requests-menu-status"/>
|
||||
<label class="plain requests-menu-method"
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
|
@ -124,7 +165,7 @@
|
|||
align="center">
|
||||
<label class="plain tabpanel-summary-label"
|
||||
value="&netmonitorUI.summary.status;"/>
|
||||
<hbox id="headers-summary-status-circle"
|
||||
<box id="headers-summary-status-circle"
|
||||
class="requests-menu-status"/>
|
||||
<label id="headers-summary-status-value"
|
||||
class="plain tabpanel-summary-value"
|
||||
|
|
|
@ -12,6 +12,7 @@ include $(DEPTH)/config/autoconf.mk
|
|||
|
||||
MOCHITEST_BROWSER_TESTS = \
|
||||
browser_net_aaa_leaktest.js \
|
||||
browser_net_autoscroll.js \
|
||||
browser_net_simple-init.js \
|
||||
browser_net_page-nav.js \
|
||||
browser_net_prefs-and-l10n.js \
|
||||
|
@ -21,10 +22,15 @@ MOCHITEST_BROWSER_TESTS = \
|
|||
browser_net_simple-request-data.js \
|
||||
browser_net_simple-request-details.js \
|
||||
browser_net_content-type.js \
|
||||
browser_net_cyrillic.js \
|
||||
browser_net_status-codes.js \
|
||||
browser_net_post-data.js \
|
||||
browser_net_jsonp.js \
|
||||
browser_net_json-long.js \
|
||||
browser_net_timeline_ticks.js \
|
||||
browser_net_sort-01.js \
|
||||
browser_net_sort-02.js \
|
||||
browser_net_sort-03.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
|
@ -33,13 +39,17 @@ MOCHITEST_BROWSER_PAGES = \
|
|||
html_simple-test-page.html \
|
||||
html_navigate-test-page.html \
|
||||
html_content-type-test-page.html \
|
||||
html_cyrillic-test-page.html \
|
||||
html_status-codes-test-page.html \
|
||||
html_post-data-test-page.html \
|
||||
html_jsonp-test-page.html \
|
||||
html_json-long-test-page.html \
|
||||
html_sorting-test-page.html \
|
||||
html_infinite-get-page.html \
|
||||
sjs_simple-test-server.sjs \
|
||||
sjs_content-type-test-server.sjs \
|
||||
sjs_status-codes-test-server.sjs \
|
||||
sjs_sorting-test-server.sjs \
|
||||
$(NULL)
|
||||
|
||||
MOCHITEST_BROWSER_FILES_PARTS = MOCHITEST_BROWSER_TESTS MOCHITEST_BROWSER_PAGES
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Bug 863102 - Automatically scroll down upon new network requests.
|
||||
*/
|
||||
|
||||
function test() {
|
||||
let monitor, debuggee, requestsContainer, scrollTop;
|
||||
|
||||
initNetMonitor(INFINITE_GET_URL).then(([aTab, aDebuggee, aMonitor]) => {
|
||||
monitor = aMonitor;
|
||||
debuggee = aDebuggee;
|
||||
let win = monitor.panelWin;
|
||||
let topNode = win.document.getElementById("requests-menu-contents");
|
||||
requestsContainer = topNode.getElementsByTagName("scrollbox")[0];
|
||||
ok(!!requestsContainer, "Container element exists as expected.");
|
||||
})
|
||||
|
||||
// (1) Check that the scroll position is maintained at the bottom
|
||||
// when the requests overflow the vertical size of the container.
|
||||
.then(() => {
|
||||
debuggee.performRequests();
|
||||
return waitForRequestsToOverflowContainer(monitor, requestsContainer);
|
||||
}).then(() => {
|
||||
ok(scrolledToBottom(requestsContainer), "Scrolled to bottom on overflow.");
|
||||
})
|
||||
|
||||
// (2) Now set the scroll position somewhere in the middle and check
|
||||
// that additional requests do not change the scroll position.
|
||||
.then(() => {
|
||||
let children = requestsContainer.childNodes;
|
||||
let middleNode = children.item(children.length / 2);
|
||||
middleNode.scrollIntoView();
|
||||
ok(!scrolledToBottom(requestsContainer), "Not scrolled to bottom.");
|
||||
scrollTop = requestsContainer.scrollTop; // save for comparison later
|
||||
return waitForNetworkEvents(monitor, 8);
|
||||
}).then(() => {
|
||||
is(requestsContainer.scrollTop, scrollTop, "Did not scroll.");
|
||||
})
|
||||
|
||||
// (3) Now set the scroll position back at the bottom and check that
|
||||
// additional requests *do* cause the container to scroll down.
|
||||
.then(() => {
|
||||
requestsContainer.scrollTop = requestsContainer.scrollHeight;
|
||||
ok(scrolledToBottom(requestsContainer), "Set scroll position to bottom.");
|
||||
return waitForNetworkEvents(monitor, 8);
|
||||
}).then(() => {
|
||||
ok(scrolledToBottom(requestsContainer), "Still scrolled to bottom.");
|
||||
})
|
||||
|
||||
// Done; clean up.
|
||||
.then(() => {
|
||||
return teardown(monitor).then(finish);
|
||||
})
|
||||
|
||||
// Handle exceptions in the chain of promises.
|
||||
.then(null, (err) => {
|
||||
ok(false, err);
|
||||
finish();
|
||||
});
|
||||
|
||||
function waitForRequestsToOverflowContainer (aMonitor, aContainer) {
|
||||
return waitForNetworkEvents(aMonitor, 1).then(() => {
|
||||
if (aContainer.scrollHeight > aContainer.clientHeight) {
|
||||
// Wait for some more just for good measure.
|
||||
return waitForNetworkEvents(aMonitor, 8);
|
||||
} else {
|
||||
return waitForRequestsToOverflowContainer(aMonitor, aContainer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function scrolledToBottom(aElement) {
|
||||
return aElement.scrollTop + aElement.clientHeight >= aElement.scrollHeight;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if cyrillic text is rendered correctly in the source editor.
|
||||
*/
|
||||
|
||||
function test() {
|
||||
initNetMonitor(CYRILLIC_URL).then(([aTab, aDebuggee, aMonitor]) => {
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, L10N, SourceEditor, NetMonitorView } = aMonitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
waitForNetworkEvents(aMonitor, 1).then(() => {
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||
"GET", CONTENT_TYPE_SJS + "?fmt=txt", {
|
||||
status: 200,
|
||||
statusText: "DA DA DA"
|
||||
});
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.getElementById("details-pane-toggle"));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll("#details-pane tab")[3]);
|
||||
|
||||
NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
|
||||
is(aEditor.getText().indexOf("\u044F"), 26, // я
|
||||
"The text shown in the source editor is incorrect.");
|
||||
is(aEditor.getMode(), SourceEditor.MODES.TEXT,
|
||||
"The mode active in the source editor is incorrect.");
|
||||
|
||||
teardown(aMonitor).then(finish);
|
||||
});
|
||||
});
|
||||
|
||||
aDebuggee.performRequests();
|
||||
});
|
||||
}
|
|
@ -14,6 +14,9 @@ function test() {
|
|||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
is(document.querySelector("#details-pane-toggle")
|
||||
.hasAttribute("disabled"), true,
|
||||
"The pane toggle button should be disabled when the frontend is opened.");
|
||||
is(document.querySelector(".requests-menu-empty-notice")
|
||||
.hasAttribute("hidden"), false,
|
||||
"An empty notice should be displayed when the frontend is opened.");
|
||||
|
@ -23,6 +26,9 @@ function test() {
|
|||
"The details pane should be hidden when the frontend is opened.");
|
||||
|
||||
aMonitor.panelWin.once("NetMonitor:NetworkEvent", () => {
|
||||
is(document.querySelector("#details-pane-toggle")
|
||||
.hasAttribute("disabled"), false,
|
||||
"The pane toggle button should be enabled after the first request.");
|
||||
is(document.querySelector(".requests-menu-empty-notice")
|
||||
.hasAttribute("hidden"), true,
|
||||
"The empty notice should be hidden after the first request.");
|
||||
|
@ -32,6 +38,9 @@ function test() {
|
|||
"The details pane should still be hidden after the first request.");
|
||||
|
||||
aMonitor.panelWin.once("NetMonitor:NetworkEvent", () => {
|
||||
is(document.querySelector("#details-pane-toggle")
|
||||
.hasAttribute("disabled"), false,
|
||||
"The pane toggle button should be still be enabled after a reload.");
|
||||
is(document.querySelector(".requests-menu-empty-notice")
|
||||
.hasAttribute("hidden"), true,
|
||||
"The empty notice should be still hidden after a reload.");
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test if the sorting mechanism works correctly.
|
||||
*/
|
||||
|
||||
function test() {
|
||||
initNetMonitor(STATUS_CODES_URL).then(([aTab, aDebuggee, aMonitor]) => {
|
||||
info("Starting test... ");
|
||||
|
||||
let { L10N, NetMonitorView } = aMonitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
waitForNetworkEvents(aMonitor, 5).then(() => {
|
||||
testContents([0, 1, 2, 3, 4])
|
||||
.then(() => {
|
||||
info("Testing swap(0, 0)");
|
||||
RequestsMenu.swapItemsAtIndices(0, 0);
|
||||
return testContents([0, 1, 2, 3, 4]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(0, 1)");
|
||||
RequestsMenu.swapItemsAtIndices(0, 1);
|
||||
return testContents([1, 0, 2, 3, 4]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(0, 2)");
|
||||
RequestsMenu.swapItemsAtIndices(0, 2);
|
||||
return testContents([1, 2, 0, 3, 4]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(0, 3)");
|
||||
RequestsMenu.swapItemsAtIndices(0, 3);
|
||||
return testContents([1, 2, 3, 0, 4]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(0, 4)");
|
||||
RequestsMenu.swapItemsAtIndices(0, 4);
|
||||
return testContents([1, 2, 3, 4, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(1, 0)");
|
||||
RequestsMenu.swapItemsAtIndices(1, 0);
|
||||
return testContents([0, 2, 3, 4, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(1, 1)");
|
||||
RequestsMenu.swapItemsAtIndices(1, 1);
|
||||
return testContents([0, 2, 3, 4, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(1, 2)");
|
||||
RequestsMenu.swapItemsAtIndices(1, 2);
|
||||
return testContents([0, 1, 3, 4, 2]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(1, 3)");
|
||||
RequestsMenu.swapItemsAtIndices(1, 3);
|
||||
return testContents([0, 3, 1, 4, 2]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(1, 4)");
|
||||
RequestsMenu.swapItemsAtIndices(1, 4);
|
||||
return testContents([0, 3, 4, 1, 2]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(2, 0)");
|
||||
RequestsMenu.swapItemsAtIndices(2, 0);
|
||||
return testContents([2, 3, 4, 1, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(2, 1)");
|
||||
RequestsMenu.swapItemsAtIndices(2, 1);
|
||||
return testContents([1, 3, 4, 2, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(2, 2)");
|
||||
RequestsMenu.swapItemsAtIndices(2, 2);
|
||||
return testContents([1, 3, 4, 2, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(2, 3)");
|
||||
RequestsMenu.swapItemsAtIndices(2, 3);
|
||||
return testContents([1, 2, 4, 3, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(2, 4)");
|
||||
RequestsMenu.swapItemsAtIndices(2, 4);
|
||||
return testContents([1, 4, 2, 3, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(3, 0)");
|
||||
RequestsMenu.swapItemsAtIndices(3, 0);
|
||||
return testContents([1, 4, 2, 0, 3]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(3, 1)");
|
||||
RequestsMenu.swapItemsAtIndices(3, 1);
|
||||
return testContents([3, 4, 2, 0, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(3, 2)");
|
||||
RequestsMenu.swapItemsAtIndices(3, 2);
|
||||
return testContents([2, 4, 3, 0, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(3, 3)");
|
||||
RequestsMenu.swapItemsAtIndices(3, 3);
|
||||
return testContents([2, 4, 3, 0, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(3, 4)");
|
||||
RequestsMenu.swapItemsAtIndices(3, 4);
|
||||
return testContents([2, 3, 4, 0, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(4, 0)");
|
||||
RequestsMenu.swapItemsAtIndices(4, 0);
|
||||
return testContents([2, 3, 0, 4, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(4, 1)");
|
||||
RequestsMenu.swapItemsAtIndices(4, 1);
|
||||
return testContents([2, 3, 0, 1, 4]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(4, 2)");
|
||||
RequestsMenu.swapItemsAtIndices(4, 2);
|
||||
return testContents([4, 3, 0, 1, 2]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(4, 3)");
|
||||
RequestsMenu.swapItemsAtIndices(4, 3);
|
||||
return testContents([3, 4, 0, 1, 2]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing swap(4, 4)");
|
||||
RequestsMenu.swapItemsAtIndices(4, 4);
|
||||
return testContents([3, 4, 0, 1, 2]);
|
||||
})
|
||||
.then(() => {
|
||||
RequestsMenu.sortBy(null);
|
||||
return testContents([0, 1, 2, 3, 4]);
|
||||
})
|
||||
.then(() => {
|
||||
return teardown(aMonitor);
|
||||
})
|
||||
.then(finish);
|
||||
});
|
||||
|
||||
function testContents([a, b, c, d, e]) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
is(RequestsMenu.allItems.length, 5,
|
||||
"There should be a total of 5 items in the requests menu.");
|
||||
is(RequestsMenu.visibleItems.length, 5,
|
||||
"There should be a total of 5 visbile items in the requests menu.");
|
||||
|
||||
is(RequestsMenu.getItemAtIndex(0), RequestsMenu.allItems[0],
|
||||
"The requests menu items aren't ordered correctly. First item is misplaced.");
|
||||
is(RequestsMenu.getItemAtIndex(1), RequestsMenu.allItems[1],
|
||||
"The requests menu items aren't ordered correctly. Second item is misplaced.");
|
||||
is(RequestsMenu.getItemAtIndex(2), RequestsMenu.allItems[2],
|
||||
"The requests menu items aren't ordered correctly. Third item is misplaced.");
|
||||
is(RequestsMenu.getItemAtIndex(3), RequestsMenu.allItems[3],
|
||||
"The requests menu items aren't ordered correctly. Fourth item is misplaced.");
|
||||
is(RequestsMenu.getItemAtIndex(4), RequestsMenu.allItems[4],
|
||||
"The requests menu items aren't ordered correctly. Fifth item is misplaced.");
|
||||
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(a),
|
||||
"GET", STATUS_CODES_SJS + "?sts=100", {
|
||||
status: 101,
|
||||
statusText: "Switching Protocols",
|
||||
type: "plain",
|
||||
fullMimeType: "text/plain; charset=utf-8",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0),
|
||||
time: true
|
||||
});
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(b),
|
||||
"GET", STATUS_CODES_SJS + "?sts=200", {
|
||||
status: 202,
|
||||
statusText: "Created",
|
||||
type: "plain",
|
||||
fullMimeType: "text/plain; charset=utf-8",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.02),
|
||||
time: true
|
||||
});
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(c),
|
||||
"GET", STATUS_CODES_SJS + "?sts=300", {
|
||||
status: 303,
|
||||
statusText: "See Other",
|
||||
type: "plain",
|
||||
fullMimeType: "text/plain; charset=utf-8",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0),
|
||||
time: true
|
||||
});
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(d),
|
||||
"GET", STATUS_CODES_SJS + "?sts=400", {
|
||||
status: 404,
|
||||
statusText: "Not Found",
|
||||
type: "plain",
|
||||
fullMimeType: "text/plain; charset=utf-8",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.02),
|
||||
time: true
|
||||
});
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(e),
|
||||
"GET", STATUS_CODES_SJS + "?sts=500", {
|
||||
status: 501,
|
||||
statusText: "Not Implemented",
|
||||
type: "plain",
|
||||
fullMimeType: "text/plain; charset=utf-8",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.02),
|
||||
time: true
|
||||
});
|
||||
|
||||
executeSoon(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
aDebuggee.performRequests();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test if sorting columns in the network table works correctly.
|
||||
*/
|
||||
|
||||
function test() {
|
||||
initNetMonitor(SORTING_URL).then(([aTab, aDebuggee, aMonitor]) => {
|
||||
info("Starting test... ");
|
||||
|
||||
let { $, L10N, NetMonitorView } = aMonitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
waitForNetworkEvents(aMonitor, 5).then(() => {
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
|
||||
|
||||
isnot(RequestsMenu.selectedItem, null,
|
||||
"There should be a selected item in the requests menu.");
|
||||
is(RequestsMenu.selectedIndex, 0,
|
||||
"The first item should be selected in the requests menu.");
|
||||
is(NetMonitorView.detailsPaneHidden, false,
|
||||
"The details pane should not be hidden after toggle button was pressed.");
|
||||
|
||||
testHeaders();
|
||||
testContents([0, 2, 4, 3, 1])
|
||||
.then(() => {
|
||||
info("Testing status sort, ascending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-status-button"));
|
||||
testHeaders("status", "ascending");
|
||||
return testContents([0, 1, 2, 3, 4]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing status sort, descending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-status-button"));
|
||||
testHeaders("status", "descending");
|
||||
return testContents([4, 3, 2, 1, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Clearing status sort.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-status-button"));
|
||||
testHeaders();
|
||||
return testContents([0, 2, 4, 3, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing method sort, ascending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-method-button"));
|
||||
testHeaders("method", "ascending");
|
||||
return testContents([0, 1, 2, 3, 4]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing method sort, descending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-method-button"));
|
||||
testHeaders("method", "descending");
|
||||
return testContents([4, 3, 2, 1, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Clearing method sort.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-method-button"));
|
||||
testHeaders();
|
||||
return testContents([0, 2, 4, 3, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing file sort, ascending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-file-button"));
|
||||
testHeaders("file", "ascending");
|
||||
return testContents([0, 1, 2, 3, 4]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing file sort, descending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-file-button"));
|
||||
testHeaders("file", "descending");
|
||||
return testContents([4, 3, 2, 1, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Clearing file sort.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-file-button"));
|
||||
testHeaders();
|
||||
return testContents([0, 2, 4, 3, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing type sort, ascending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-type-button"));
|
||||
testHeaders("type", "ascending");
|
||||
return testContents([0, 1, 2, 3, 4]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing type sort, descending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-type-button"));
|
||||
testHeaders("type", "descending");
|
||||
return testContents([4, 3, 2, 1, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Clearing type sort.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-type-button"));
|
||||
testHeaders();
|
||||
return testContents([0, 2, 4, 3, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing size sort, ascending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
|
||||
testHeaders("size", "ascending");
|
||||
return testContents([0, 1, 2, 3, 4]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing size sort, descending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
|
||||
testHeaders("size", "descending");
|
||||
return testContents([4, 3, 2, 1, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
info("Clearing size sort.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
|
||||
testHeaders();
|
||||
return testContents([0, 2, 4, 3, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
return teardown(aMonitor);
|
||||
})
|
||||
.then(finish);
|
||||
});
|
||||
|
||||
function testHeaders(aSortType, aDirection) {
|
||||
let doc = aMonitor.panelWin.document;
|
||||
let target = doc.querySelector("#requests-menu-" + aSortType + "-button");
|
||||
let headers = doc.querySelectorAll(".requests-menu-header-button");
|
||||
|
||||
for (let header of headers) {
|
||||
if (header != target) {
|
||||
is(header.hasAttribute("sorted"), false,
|
||||
"The " + header.id + " header should not have a 'sorted' attribute.");
|
||||
is(header.hasAttribute("tooltiptext"), false,
|
||||
"The " + header.id + " header should not have a 'tooltiptext' attribute.");
|
||||
} else {
|
||||
is(header.getAttribute("sorted"), aDirection,
|
||||
"The " + header.id + " header has an incorrect 'sorted' attribute.");
|
||||
is(header.getAttribute("tooltiptext"), aDirection == "ascending"
|
||||
? L10N.getStr("networkMenu.sortedAsc")
|
||||
: L10N.getStr("networkMenu.sortedDesc"),
|
||||
"The " + header.id + " has an incorrect 'tooltiptext' attribute.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testContents([a, b, c, d, e]) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
isnot(RequestsMenu.selectedItem, null,
|
||||
"There should still be a selected item after sorting.");
|
||||
is(RequestsMenu.selectedIndex, a,
|
||||
"The first item should be still selected after sorting.");
|
||||
is(NetMonitorView.detailsPaneHidden, false,
|
||||
"The details pane should still be visible after sorting.");
|
||||
|
||||
is(RequestsMenu.allItems.length, 5,
|
||||
"There should be a total of 5 items in the requests menu.");
|
||||
is(RequestsMenu.visibleItems.length, 5,
|
||||
"There should be a total of 5 visbile items in the requests menu.");
|
||||
|
||||
is(RequestsMenu.getItemAtIndex(0), RequestsMenu.allItems[0],
|
||||
"The requests menu items aren't ordered correctly. First item is misplaced.");
|
||||
is(RequestsMenu.getItemAtIndex(1), RequestsMenu.allItems[1],
|
||||
"The requests menu items aren't ordered correctly. Second item is misplaced.");
|
||||
is(RequestsMenu.getItemAtIndex(2), RequestsMenu.allItems[2],
|
||||
"The requests menu items aren't ordered correctly. Third item is misplaced.");
|
||||
is(RequestsMenu.getItemAtIndex(3), RequestsMenu.allItems[3],
|
||||
"The requests menu items aren't ordered correctly. Fourth item is misplaced.");
|
||||
is(RequestsMenu.getItemAtIndex(4), RequestsMenu.allItems[4],
|
||||
"The requests menu items aren't ordered correctly. Fifth item is misplaced.");
|
||||
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(a),
|
||||
"GET1", SORTING_SJS + "?index=1", {
|
||||
status: 101,
|
||||
statusText: "Meh",
|
||||
type: "1",
|
||||
fullMimeType: "text/1",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0),
|
||||
time: true
|
||||
});
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(b),
|
||||
"GET2", SORTING_SJS + "?index=2", {
|
||||
status: 200,
|
||||
statusText: "Meh",
|
||||
type: "2",
|
||||
fullMimeType: "text/2",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.01),
|
||||
time: true
|
||||
});
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(c),
|
||||
"GET3", SORTING_SJS + "?index=3", {
|
||||
status: 300,
|
||||
statusText: "Meh",
|
||||
type: "3",
|
||||
fullMimeType: "text/3",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.02),
|
||||
time: true
|
||||
});
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(d),
|
||||
"GET4", SORTING_SJS + "?index=4", {
|
||||
status: 400,
|
||||
statusText: "Meh",
|
||||
type: "4",
|
||||
fullMimeType: "text/4",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.03),
|
||||
time: true
|
||||
});
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(e),
|
||||
"GET5", SORTING_SJS + "?index=5", {
|
||||
status: 500,
|
||||
statusText: "Meh",
|
||||
type: "5",
|
||||
fullMimeType: "text/5",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.04),
|
||||
time: true
|
||||
});
|
||||
|
||||
executeSoon(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
aDebuggee.performRequests();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test if sorting columns in the network table works correctly with new requests.
|
||||
*/
|
||||
|
||||
function test() {
|
||||
initNetMonitor(SORTING_URL).then(([aTab, aDebuggee, aMonitor]) => {
|
||||
info("Starting test... ");
|
||||
|
||||
let { $, L10N, NetMonitorView } = aMonitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
waitForNetworkEvents(aMonitor, 5).then(() => {
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
|
||||
|
||||
isnot(RequestsMenu.selectedItem, null,
|
||||
"There should be a selected item in the requests menu.");
|
||||
is(RequestsMenu.selectedIndex, 0,
|
||||
"The first item should be selected in the requests menu.");
|
||||
is(NetMonitorView.detailsPaneHidden, false,
|
||||
"The details pane should not be hidden after toggle button was pressed.");
|
||||
|
||||
testHeaders();
|
||||
testContents([0, 2, 4, 3, 1], 0)
|
||||
.then(() => {
|
||||
info("Testing status sort, ascending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-status-button"));
|
||||
testHeaders("status", "ascending");
|
||||
return testContents([0, 1, 2, 3, 4], 0);
|
||||
})
|
||||
.then(() => {
|
||||
info("Performing more requests.");
|
||||
aDebuggee.performRequests();
|
||||
return waitForNetworkEvents(aMonitor, 5);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing status sort again, ascending.");
|
||||
testHeaders("status", "ascending");
|
||||
return testContents([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 0);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing status sort, descending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-status-button"));
|
||||
testHeaders("status", "descending");
|
||||
return testContents([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], 9);
|
||||
})
|
||||
.then(() => {
|
||||
info("Performing more requests.");
|
||||
aDebuggee.performRequests();
|
||||
return waitForNetworkEvents(aMonitor, 5);
|
||||
})
|
||||
.then(() => {
|
||||
info("Testing status sort again, descending.");
|
||||
testHeaders("status", "descending");
|
||||
return testContents([14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], 12);
|
||||
})
|
||||
.then(() => {
|
||||
return teardown(aMonitor);
|
||||
})
|
||||
.then(finish);
|
||||
});
|
||||
|
||||
function testHeaders(aSortType, aDirection) {
|
||||
let doc = aMonitor.panelWin.document;
|
||||
let target = doc.querySelector("#requests-menu-" + aSortType + "-button");
|
||||
let headers = doc.querySelectorAll(".requests-menu-header-button");
|
||||
|
||||
for (let header of headers) {
|
||||
if (header != target) {
|
||||
is(header.hasAttribute("sorted"), false,
|
||||
"The " + header.id + " header should not have a 'sorted' attribute.");
|
||||
is(header.hasAttribute("tooltiptext"), false,
|
||||
"The " + header.id + " header should not have a 'tooltiptext' attribute.");
|
||||
} else {
|
||||
is(header.getAttribute("sorted"), aDirection,
|
||||
"The " + header.id + " header has an incorrect 'sorted' attribute.");
|
||||
is(header.getAttribute("tooltiptext"), aDirection == "ascending"
|
||||
? L10N.getStr("networkMenu.sortedAsc")
|
||||
: L10N.getStr("networkMenu.sortedDesc"),
|
||||
"The " + header.id + " has an incorrect 'tooltiptext' attribute.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testContents(aOrder, aSelection) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
isnot(RequestsMenu.selectedItem, null,
|
||||
"There should still be a selected item after sorting.");
|
||||
is(RequestsMenu.selectedIndex, aSelection,
|
||||
"The first item should be still selected after sorting.");
|
||||
is(NetMonitorView.detailsPaneHidden, false,
|
||||
"The details pane should still be visible after sorting.");
|
||||
|
||||
is(RequestsMenu.allItems.length, aOrder.length,
|
||||
"There should be a specific number of items in the requests menu.");
|
||||
is(RequestsMenu.visibleItems.length, aOrder.length,
|
||||
"There should be a specific number of visbile items in the requests menu.");
|
||||
|
||||
for (let i = 0; i < aOrder.length; i++) {
|
||||
is(RequestsMenu.getItemAtIndex(i), RequestsMenu.allItems[i],
|
||||
"The requests menu items aren't ordered correctly. Misplaced item " + i + ".");
|
||||
}
|
||||
|
||||
for (let i = 0, len = aOrder.length / 5; i < len; i++) {
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i]),
|
||||
"GET1", SORTING_SJS + "?index=1", {
|
||||
status: 101,
|
||||
statusText: "Meh",
|
||||
type: "1",
|
||||
fullMimeType: "text/1",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0),
|
||||
time: true
|
||||
});
|
||||
}
|
||||
for (let i = 0, len = aOrder.length / 5; i < len; i++) {
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len]),
|
||||
"GET2", SORTING_SJS + "?index=2", {
|
||||
status: 200,
|
||||
statusText: "Meh",
|
||||
type: "2",
|
||||
fullMimeType: "text/2",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.01),
|
||||
time: true
|
||||
});
|
||||
}
|
||||
for (let i = 0, len = aOrder.length / 5; i < len; i++) {
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 2]),
|
||||
"GET3", SORTING_SJS + "?index=3", {
|
||||
status: 300,
|
||||
statusText: "Meh",
|
||||
type: "3",
|
||||
fullMimeType: "text/3",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.02),
|
||||
time: true
|
||||
});
|
||||
}
|
||||
for (let i = 0, len = aOrder.length / 5; i < len; i++) {
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 3]),
|
||||
"GET4", SORTING_SJS + "?index=4", {
|
||||
status: 400,
|
||||
statusText: "Meh",
|
||||
type: "4",
|
||||
fullMimeType: "text/4",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.03),
|
||||
time: true
|
||||
});
|
||||
}
|
||||
for (let i = 0, len = aOrder.length / 5; i < len; i++) {
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 4]),
|
||||
"GET5", SORTING_SJS + "?index=5", {
|
||||
status: 500,
|
||||
statusText: "Meh",
|
||||
type: "5",
|
||||
fullMimeType: "text/5",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.04),
|
||||
time: true
|
||||
});
|
||||
}
|
||||
|
||||
executeSoon(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
aDebuggee.performRequests();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if timeline correctly displays interval divisions.
|
||||
*/
|
||||
|
||||
function test() {
|
||||
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, L10N, NetMonitorView } = aMonitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
is(document.querySelector(".requests-menu-empty-notice")
|
||||
.hasAttribute("hidden"), false,
|
||||
"An timeline label should be displayed when the frontend is opened.");
|
||||
ok(document.querySelectorAll(".requests-menu-timings-division").length == 0,
|
||||
"No tick labels should be displayed when the frontend is opened.");
|
||||
|
||||
ok(!RequestsMenu._canvas,
|
||||
"No canvas should be created when the frontend is opened.");
|
||||
ok(!RequestsMenu._ctx,
|
||||
"No 2d context should be created when the frontend is opened.");
|
||||
|
||||
waitForNetworkEvents(aMonitor, 1).then(() => {
|
||||
is(document.querySelector(".requests-menu-empty-notice")
|
||||
.hasAttribute("hidden"), true,
|
||||
"The timeline label should be hidden after the first request.");
|
||||
ok(document.querySelectorAll(".requests-menu-timings-division").length >= 3,
|
||||
"There should be at least 3 tick labels in the network requests header.");
|
||||
|
||||
is(document.querySelectorAll(".requests-menu-timings-division")[0]
|
||||
.getAttribute("value"), L10N.getFormatStr("networkMenu.divisionMS", 0),
|
||||
"The first tick label has an incorrect value");
|
||||
is(document.querySelectorAll(".requests-menu-timings-division")[1]
|
||||
.getAttribute("value"), L10N.getFormatStr("networkMenu.divisionMS", 80),
|
||||
"The second tick label has an incorrect value");
|
||||
is(document.querySelectorAll(".requests-menu-timings-division")[2]
|
||||
.getAttribute("value"), L10N.getFormatStr("networkMenu.divisionMS", 160),
|
||||
"The third tick label has an incorrect value");
|
||||
|
||||
is(document.querySelectorAll(".requests-menu-timings-division")[0]
|
||||
.style.transform, "translateX(0px)",
|
||||
"The first tick label has an incorrect translation");
|
||||
is(document.querySelectorAll(".requests-menu-timings-division")[1]
|
||||
.style.transform, "translateX(80px)",
|
||||
"The second tick label has an incorrect translation");
|
||||
is(document.querySelectorAll(".requests-menu-timings-division")[2]
|
||||
.style.transform, "translateX(160px)",
|
||||
"The third tick label has an incorrect translation");
|
||||
|
||||
ok(RequestsMenu._canvas,
|
||||
"A canvas should be created after the first request.");
|
||||
ok(RequestsMenu._ctx,
|
||||
"A 2d context should be created after the first request.");
|
||||
|
||||
let imageData = RequestsMenu._ctx.getImageData(0, 0, 161, 1);
|
||||
ok(imageData, "The image data should have been created.");
|
||||
|
||||
let data = imageData.data;
|
||||
ok(data, "The image data should contain a pixel array.");
|
||||
|
||||
ok( hasPixelAt(0), "The tick at 0 is should not be empty.");
|
||||
ok(!hasPixelAt(1), "The tick at 1 is should be empty.");
|
||||
ok(!hasPixelAt(19), "The tick at 19 is should be empty.");
|
||||
ok( hasPixelAt(20), "The tick at 20 is should not be empty.");
|
||||
ok(!hasPixelAt(21), "The tick at 21 is should be empty.");
|
||||
ok(!hasPixelAt(39), "The tick at 39 is should be empty.");
|
||||
ok( hasPixelAt(40), "The tick at 40 is should not be empty.");
|
||||
ok(!hasPixelAt(41), "The tick at 41 is should be empty.");
|
||||
ok(!hasPixelAt(59), "The tick at 59 is should be empty.");
|
||||
ok( hasPixelAt(60), "The tick at 60 is should not be empty.");
|
||||
ok(!hasPixelAt(61), "The tick at 61 is should be empty.");
|
||||
ok(!hasPixelAt(79), "The tick at 79 is should be empty.");
|
||||
ok( hasPixelAt(80), "The tick at 80 is should not be empty.");
|
||||
ok(!hasPixelAt(81), "The tick at 81 is should be empty.");
|
||||
ok(!hasPixelAt(159), "The tick at 159 is should be empty.");
|
||||
ok( hasPixelAt(160), "The tick at 160 is should not be empty.");
|
||||
ok(!hasPixelAt(161), "The tick at 161 is should be empty.");
|
||||
|
||||
ok(isPixelBrighterAtThan(0, 20),
|
||||
"The tick at 0 should be brighter than the one at 20");
|
||||
ok(isPixelBrighterAtThan(40, 20),
|
||||
"The tick at 40 should be brighter than the one at 20");
|
||||
ok(isPixelBrighterAtThan(40, 60),
|
||||
"The tick at 40 should be brighter than the one at 60");
|
||||
ok(isPixelBrighterAtThan(80, 60),
|
||||
"The tick at 80 should be brighter than the one at 60");
|
||||
|
||||
ok(isPixelBrighterAtThan(80, 100),
|
||||
"The tick at 80 should be brighter than the one at 100");
|
||||
ok(isPixelBrighterAtThan(120, 100),
|
||||
"The tick at 120 should be brighter than the one at 100");
|
||||
ok(isPixelBrighterAtThan(120, 140),
|
||||
"The tick at 120 should be brighter than the one at 140");
|
||||
ok(isPixelBrighterAtThan(160, 140),
|
||||
"The tick at 160 should be brighter than the one at 140");
|
||||
|
||||
ok(isPixelEquallyBright(20, 60),
|
||||
"The tick at 20 should be equally bright to the one at 60");
|
||||
ok(isPixelEquallyBright(100, 140),
|
||||
"The tick at 100 should be equally bright to the one at 140");
|
||||
|
||||
ok(isPixelEquallyBright(40, 120),
|
||||
"The tick at 40 should be equally bright to the one at 120");
|
||||
|
||||
ok(isPixelEquallyBright(0, 80),
|
||||
"The tick at 80 should be equally bright to the one at 160");
|
||||
ok(isPixelEquallyBright(80, 160),
|
||||
"The tick at 80 should be equally bright to the one at 160");
|
||||
|
||||
function hasPixelAt(x) {
|
||||
let i = (x | 0) * 4;
|
||||
return data[i] && data[i + 1] && data[i + 2] && data[i + 3];
|
||||
}
|
||||
|
||||
function isPixelBrighterAtThan(x1, x2) {
|
||||
let i = (x1 | 0) * 4;
|
||||
let j = (x2 | 0) * 4;
|
||||
return data[i + 3] > data [j + 3];
|
||||
}
|
||||
|
||||
function isPixelEquallyBright(x1, x2) {
|
||||
let i = (x1 | 0) * 4;
|
||||
let j = (x2 | 0) * 4;
|
||||
return data[i + 3] == data [j + 3];
|
||||
}
|
||||
|
||||
teardown(aMonitor).then(finish);
|
||||
});
|
||||
|
||||
aDebuggee.location.reload();
|
||||
});
|
||||
}
|
|
@ -15,14 +15,18 @@ const EXAMPLE_URL = "http://example.com/browser/browser/devtools/netmonitor/test
|
|||
const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
|
||||
const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
|
||||
const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
|
||||
const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html";
|
||||
const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
|
||||
const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
|
||||
const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
|
||||
const JSON_LONG_URL = EXAMPLE_URL + "html_json-long-test-page.html";
|
||||
const SORTING_URL = EXAMPLE_URL + "html_sorting-test-page.html";
|
||||
const INFINITE_GET_URL = EXAMPLE_URL + "html_infinite-get-page.html";
|
||||
|
||||
const SIMPLE_SJS = EXAMPLE_URL + "sjs_simple-test-server.sjs";
|
||||
const CONTENT_TYPE_SJS = EXAMPLE_URL + "sjs_content-type-test-server.sjs";
|
||||
const STATUS_CODES_SJS = EXAMPLE_URL + "sjs_status-codes-test-server.sjs";
|
||||
const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
|
||||
|
||||
const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Network Monitor test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Cyrillic type test</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
function get(aAddress, aCallback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", aAddress, true);
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (this.readyState == this.DONE) {
|
||||
aCallback();
|
||||
}
|
||||
};
|
||||
xhr.send(null);
|
||||
}
|
||||
|
||||
function performRequests() {
|
||||
get("sjs_content-type-test-server.sjs?fmt=txt", function() {
|
||||
// Done.
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,36 @@
|
|||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Network Monitor test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Infinite GETs</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
function get(aAddress, aCallback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", aAddress, true);
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (this.readyState == this.DONE) {
|
||||
aCallback();
|
||||
}
|
||||
};
|
||||
xhr.send(null);
|
||||
}
|
||||
|
||||
// Use a count parameter to defeat caching.
|
||||
var count = 0;
|
||||
|
||||
function performRequests() {
|
||||
get("request_" + (count++), function() {
|
||||
setTimeout(performRequests, 0);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,41 @@
|
|||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Network Monitor test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Sorting test</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
function get(aAddress, aIndex, aCallback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET" + aIndex, aAddress + "?index=" + aIndex, true);
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (this.readyState == this.DONE) {
|
||||
aCallback();
|
||||
}
|
||||
};
|
||||
xhr.send(null);
|
||||
}
|
||||
|
||||
function performRequests() {
|
||||
get("sjs_sorting-test-server.sjs", 1, function() {
|
||||
get("sjs_sorting-test-server.sjs", 5, function() {
|
||||
get("sjs_sorting-test-server.sjs", 2, function() {
|
||||
get("sjs_sorting-test-server.sjs", 4, function() {
|
||||
get("sjs_sorting-test-server.sjs", 3, function() {
|
||||
// Done.
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -11,6 +11,13 @@ function handleRequest(request, response) {
|
|||
|
||||
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).initWithCallback(() => {
|
||||
switch (format) {
|
||||
case "txt": {
|
||||
response.setStatusLine(request.httpVersion, 200, "DA DA DA");
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
response.write("Братан, ты вообще качаешься?");
|
||||
response.finish();
|
||||
break;
|
||||
}
|
||||
case "xml": {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "text/xml; charset=utf-8", false);
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const { classes: Cc, interfaces: Ci } = Components;
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.processAsync();
|
||||
|
||||
let params = request.queryString.split("&");
|
||||
let index = params.filter((s) => s.contains("index="))[0].split("=")[1];
|
||||
|
||||
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).initWithCallback(() => {
|
||||
response.setStatusLine(request.httpVersion, index == 1 ? 101 : index * 100, "Meh");
|
||||
response.setHeader("Content-Type", "text/" + index, false);
|
||||
response.write(new Array(index * 10).join(index)); // + 0.01 KB
|
||||
response.finish();
|
||||
}, 50, Ci.nsITimer.TYPE_ONE_SHOT); // Make sure this request takes a few ms.
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
this.EXPORTED_SYMBOLS = [];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/Require.jsm");
|
||||
|
||||
|
@ -80,7 +80,7 @@ gcli.addCommand({
|
|||
}
|
||||
|
||||
if (profile.isFinished) {
|
||||
throw gcli.lookup("profilerAlradyFinished");
|
||||
throw gcli.lookup("profilerAlreadyFinished");
|
||||
}
|
||||
|
||||
panel.switchToProfile(profile, function () profile.start());
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const URL = "data:text/html;charset=utf8,<p>JavaScript Profiler test</p>";
|
||||
|
||||
let gcli = Cu.import("resource:///modules/devtools/gcli.jsm", {}).gcli;
|
||||
let gcli = Cu.import("resource://gre/modules/devtools/gcli.jsm", {}).gcli;
|
||||
let gTarget, gPanel, gOptions;
|
||||
|
||||
function cmd(typed, expected="") {
|
||||
|
|
|
@ -11,7 +11,7 @@ const BRAND_SHORT_NAME = Cc["@mozilla.org/intl/stringbundle;1"].
|
|||
|
||||
this.EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/gcli.jsm");
|
||||
|
||||
/* Responsive Mode commands */
|
||||
gcli.addCommand({
|
||||
|
|
|
@ -21,11 +21,10 @@ this.EXPORTED_SYMBOLS = [ 'helpers' ];
|
|||
var helpers = {};
|
||||
this.helpers = helpers;
|
||||
let require = (Cu.import("resource://gre/modules/devtools/Require.jsm", {})).require;
|
||||
Components.utils.import("resource:///modules/devtools/gcli.jsm", {});
|
||||
Components.utils.import("resource://gre/modules/devtools/gcli.jsm", {});
|
||||
|
||||
let console = (Cu.import("resource://gre/modules/devtools/Console.jsm", {})).console;
|
||||
let devtools = (Cu.import("resource:///modules/devtools/gDevTools.jsm", {})).devtools;
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let TargetFactory = (Cu.import("resource:///modules/devtools/gDevTools.jsm", {})).devtools.TargetFactory;
|
||||
|
||||
let Promise = (Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {})).Promise;
|
||||
let assert = { ok: ok, is: is, log: info };
|
||||
|
@ -158,6 +157,7 @@ helpers.runTests = function(options, tests) {
|
|||
});
|
||||
|
||||
var recover = function(error) {
|
||||
ok(false, error);
|
||||
console.error(error);
|
||||
};
|
||||
|
||||
|
@ -341,7 +341,7 @@ helpers._createDebugCheck = function(options) {
|
|||
output += ' current: \'' + helpers._actual.current(options) + '\',\n';
|
||||
output += ' status: \'' + helpers._actual.status(options) + '\',\n';
|
||||
output += ' options: ' + outputArray(helpers._actual.options(options)) + ',\n';
|
||||
output += ' error: \'' + helpers._actual.message(options) + '\',\n';
|
||||
output += ' message: \'' + helpers._actual.message(options) + '\',\n';
|
||||
output += ' predictions: ' + outputArray(predictions) + ',\n';
|
||||
output += ' unassigned: ' + outputArray(requisition._unassigned) + ',\n';
|
||||
output += ' outputState: \'' + helpers._actual.outputState(options) + '\',\n';
|
||||
|
@ -378,6 +378,8 @@ helpers._createDebugCheck = function(options) {
|
|||
output += ' exec: {\n';
|
||||
output += ' output: \'\',\n';
|
||||
output += ' completed: true,\n';
|
||||
output += ' type: \'string\',\n';
|
||||
output += ' error: false\n';
|
||||
output += ' }\n';
|
||||
output += ' }\n';
|
||||
output += ']);';
|
||||
|
@ -702,7 +704,7 @@ helpers._check = function(options, name, checks) {
|
|||
*/
|
||||
helpers._exec = function(options, name, expected) {
|
||||
if (expected == null) {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
var output = options.display.requisition.exec({ hidden: true });
|
||||
|
@ -715,20 +717,32 @@ helpers._exec = function(options, name, expected) {
|
|||
|
||||
if (!options.window.document.createElement) {
|
||||
assert.log('skipping output tests (missing doc.createElement) for ' + name);
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({ output: output });
|
||||
}
|
||||
|
||||
if (!('output' in expected)) {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({ output: output });
|
||||
}
|
||||
|
||||
var deferred = Promise.defer();
|
||||
|
||||
var checkOutput = function() {
|
||||
var div = options.window.document.createElement('div');
|
||||
var nodePromise = converters.convert(output.data, output.type, 'dom',
|
||||
options.display.requisition.context);
|
||||
nodePromise.then(function(node) {
|
||||
var conversionContext = options.display.requisition.conversionContext;
|
||||
|
||||
if ('type' in expected) {
|
||||
assert.is(output.type,
|
||||
expected.type,
|
||||
'output.type for: ' + name);
|
||||
}
|
||||
|
||||
if ('error' in expected) {
|
||||
assert.is(output.error,
|
||||
expected.error,
|
||||
'output.error for: ' + name);
|
||||
}
|
||||
|
||||
var convertPromise = converters.convert(output.data, output.type, 'dom',
|
||||
conversionContext);
|
||||
return convertPromise.then(function(node) {
|
||||
div.appendChild(node);
|
||||
var actualOutput = div.textContent.trim();
|
||||
|
||||
|
@ -757,24 +771,11 @@ helpers._exec = function(options, name, expected) {
|
|||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
|
||||
deferred.resolve(actualOutput);
|
||||
return { output: output, text: actualOutput };
|
||||
});
|
||||
};
|
||||
|
||||
if (output.completed !== false) {
|
||||
checkOutput();
|
||||
}
|
||||
else {
|
||||
var changed = function() {
|
||||
if (output.completed !== false) {
|
||||
checkOutput();
|
||||
output.onChange.remove(changed);
|
||||
}
|
||||
};
|
||||
output.onChange.add(changed);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return output.promise.then(checkOutput, checkOutput);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -789,15 +790,15 @@ helpers._setup = function(options, name, action) {
|
|||
return Promise.resolve(action());
|
||||
}
|
||||
|
||||
return Promise.reject('setup must be a string or a function');
|
||||
return Promise.reject('\'setup\' property must be a string or a function. Is ' + action);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to shutdown the test
|
||||
*/
|
||||
helpers._post = function(name, action, output) {
|
||||
helpers._post = function(name, action, data) {
|
||||
if (typeof action === 'function') {
|
||||
return Promise.resolve(action(output));
|
||||
return Promise.resolve(action(data.output, data.text));
|
||||
}
|
||||
return Promise.resolve(action);
|
||||
};
|
||||
|
@ -943,6 +944,8 @@ helpers.audit = function(options, audits) {
|
|||
if (typeof chunkLen !== 'number') {
|
||||
chunkLen = 1;
|
||||
}
|
||||
|
||||
if (assert.currentTest) {
|
||||
var responseTime = (new Date().getTime() - start) / chunkLen;
|
||||
totalResponseTime += responseTime;
|
||||
if (responseTime > maxResponseTime) {
|
||||
|
@ -950,12 +953,13 @@ helpers.audit = function(options, audits) {
|
|||
maxResponseCulprit = assert.currentTest + '/' + name;
|
||||
}
|
||||
averageOver++;
|
||||
}
|
||||
|
||||
var checkDone = helpers._check(options, name, audit.check);
|
||||
return checkDone.then(function() {
|
||||
var execDone = helpers._exec(options, name, audit.exec);
|
||||
return execDone.then(function(output) {
|
||||
return helpers._post(name, audit.post, output).then(function() {
|
||||
return execDone.then(function(data) {
|
||||
return helpers._post(name, audit.post, data).then(function() {
|
||||
if (assert.testLogging) {
|
||||
log('- END \'' + name + '\' in ' + assert.currentTest);
|
||||
}
|
||||
|
@ -963,9 +967,8 @@ helpers.audit = function(options, audits) {
|
|||
});
|
||||
});
|
||||
});
|
||||
}).then(null, function(ex) {
|
||||
console.error(ex.stack);
|
||||
throw(ex);
|
||||
}).then(function() {
|
||||
return options.display.inputter.setInput('');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
this.EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Components.utils.import("resource:///modules/devtools/gcli.jsm");
|
||||
Components.utils.import("resource://gre/modules/devtools/gcli.jsm");
|
||||
|
||||
/**
|
||||
* 'scratchpad' command
|
||||
|
|
|
@ -21,7 +21,6 @@ const Cu = Components.utils;
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource:///modules/PropertyPanel.jsm");
|
||||
Cu.import("resource:///modules/source-editor.jsm");
|
||||
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
|
||||
Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
|
||||
|
@ -79,7 +78,7 @@ var Scratchpad = {
|
|||
.replace(/^\/\*/, "")
|
||||
.replace(/\*\/$/, "");
|
||||
|
||||
aLine.split(",").forEach(function (pair) {
|
||||
aLine.split(",").forEach(pair => {
|
||||
let [key, val] = pair.split(":");
|
||||
|
||||
if (key && val) {
|
||||
|
@ -621,18 +620,18 @@ var Scratchpad = {
|
|||
let encoder = new TextEncoder();
|
||||
let buffer = encoder.encode(this.getText());
|
||||
let promise = OS.File.writeAtomic(aFile.path, buffer,{tmpPath: aFile.path + ".tmp"});
|
||||
promise.then(function success(value) {
|
||||
promise.then(value => {
|
||||
if (aCallback) {
|
||||
aCallback.call(this, Components.results.NS_OK);
|
||||
}
|
||||
}.bind(this), function failure(reason) {
|
||||
}, reason => {
|
||||
if (!aSilentError) {
|
||||
window.alert(this.strings.GetStringFromName("saveFile.failed"));
|
||||
}
|
||||
if (aCallback) {
|
||||
aCallback.call(this, Components.results.NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
@ -656,8 +655,7 @@ var Scratchpad = {
|
|||
let channel = NetUtil.newChannel(aFile);
|
||||
channel.contentType = "application/javascript";
|
||||
|
||||
let self = this;
|
||||
NetUtil.asyncFetch(channel, function(aInputStream, aStatus) {
|
||||
NetUtil.asyncFetch(channel, (aInputStream, aStatus) => {
|
||||
let content = null;
|
||||
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
|
@ -670,22 +668,22 @@ var Scratchpad = {
|
|||
|
||||
// Check to see if the first line is a mode-line comment.
|
||||
let line = content.split("\n")[0];
|
||||
let modeline = self._scanModeLine(line);
|
||||
let modeline = this._scanModeLine(line);
|
||||
let chrome = Services.prefs.getBoolPref(DEVTOOLS_CHROME_ENABLED);
|
||||
|
||||
if (chrome && modeline["-sp-context"] === "browser") {
|
||||
self.setBrowserContext();
|
||||
this.setBrowserContext();
|
||||
}
|
||||
|
||||
self.setText(content);
|
||||
self.editor.resetUndo();
|
||||
this.setText(content);
|
||||
this.editor.resetUndo();
|
||||
}
|
||||
else if (!aSilentError) {
|
||||
window.alert(self.strings.GetStringFromName("openFile.failed"));
|
||||
window.alert(this.strings.GetStringFromName("openFile.failed"));
|
||||
}
|
||||
|
||||
if (aCallback) {
|
||||
aCallback.call(self, aStatus, content);
|
||||
aCallback.call(this, aStatus, content);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -698,8 +696,8 @@ var Scratchpad = {
|
|||
*/
|
||||
openFile: function SP_openFile(aIndex)
|
||||
{
|
||||
let promptCallback = function(aFile) {
|
||||
this.promptSave(function(aCloseFile, aSaved, aStatus) {
|
||||
let promptCallback = aFile => {
|
||||
this.promptSave((aCloseFile, aSaved, aStatus) => {
|
||||
let shouldOpen = aCloseFile;
|
||||
if (aSaved && !Components.isSuccessCode(aStatus)) {
|
||||
shouldOpen = false;
|
||||
|
@ -732,23 +730,21 @@ var Scratchpad = {
|
|||
this.importFromFile(file, false);
|
||||
this.setRecentFile(file);
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this);
|
||||
});
|
||||
};
|
||||
|
||||
if (aIndex > -1) {
|
||||
promptCallback();
|
||||
} else {
|
||||
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
let fpCallback = function fpCallback_done(aResult) {
|
||||
if (aResult != Ci.nsIFilePicker.returnCancel) {
|
||||
promptCallback(fp.file);
|
||||
}
|
||||
};
|
||||
|
||||
fp.init(window, this.strings.GetStringFromName("openFile.title"),
|
||||
Ci.nsIFilePicker.modeOpen);
|
||||
fp.defaultString = "";
|
||||
fp.open(fpCallback);
|
||||
fp.open(aResult => {
|
||||
if (aResult != Ci.nsIFilePicker.returnCancel) {
|
||||
promptCallback(fp.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -953,7 +949,7 @@ var Scratchpad = {
|
|||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(this.filename);
|
||||
|
||||
this.exportToFile(file, true, false, function(aStatus) {
|
||||
this.exportToFile(file, true, false, aStatus => {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
this.editor.dirty = false;
|
||||
this.setRecentFile(file);
|
||||
|
@ -973,10 +969,10 @@ var Scratchpad = {
|
|||
saveFileAs: function SP_saveFileAs(aCallback)
|
||||
{
|
||||
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
let fpCallback = function fpCallback_done(aResult) {
|
||||
let fpCallback = aResult => {
|
||||
if (aResult != Ci.nsIFilePicker.returnCancel) {
|
||||
this.setFilename(fp.file.path);
|
||||
this.exportToFile(fp.file, true, false, function(aStatus) {
|
||||
this.exportToFile(fp.file, true, false, aStatus => {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
this.editor.dirty = false;
|
||||
this.setRecentFile(fp.file);
|
||||
|
@ -986,7 +982,7 @@ var Scratchpad = {
|
|||
}
|
||||
});
|
||||
}
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
fp.init(window, this.strings.GetStringFromName("saveFileAs"),
|
||||
Ci.nsIFilePicker.modeSave);
|
||||
|
@ -1009,7 +1005,7 @@ var Scratchpad = {
|
|||
return;
|
||||
}
|
||||
|
||||
this.importFromFile(file, false, function(aStatus, aContent) {
|
||||
this.importFromFile(file, false, (aStatus, aContent) => {
|
||||
if (aCallback) {
|
||||
aCallback(aStatus);
|
||||
}
|
||||
|
@ -1045,8 +1041,8 @@ var Scratchpad = {
|
|||
return;
|
||||
}
|
||||
if (button == BUTTON_POSITION_REVERT) {
|
||||
this.revertFile(function(aStatus) {
|
||||
if(aCallback){
|
||||
this.revertFile(aStatus => {
|
||||
if (aCallback) {
|
||||
aCallback(true, aStatus);
|
||||
}
|
||||
});
|
||||
|
@ -1348,7 +1344,7 @@ var Scratchpad = {
|
|||
}
|
||||
|
||||
if (button == BUTTON_POSITION_SAVE) {
|
||||
this.saveFile(function(aStatus) {
|
||||
this.saveFile(aStatus => {
|
||||
if (aCallback) {
|
||||
aCallback(true, true, aStatus);
|
||||
}
|
||||
|
@ -1387,7 +1383,7 @@ var Scratchpad = {
|
|||
*/
|
||||
close: function SP_close(aCallback)
|
||||
{
|
||||
this.promptSave(function(aShouldClose, aSaved, aStatus) {
|
||||
this.promptSave((aShouldClose, aSaved, aStatus) => {
|
||||
let shouldClose = aShouldClose;
|
||||
if (aSaved && !Components.isSuccessCode(aStatus)) {
|
||||
shouldClose = false;
|
||||
|
@ -1399,7 +1395,7 @@ var Scratchpad = {
|
|||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
|
||||
_observers: [],
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
<command id="sp-cmd-errorConsole" oncommand="Scratchpad.openErrorConsole();" disabled="true"/>
|
||||
<command id="sp-cmd-webConsole" oncommand="Scratchpad.openWebConsole();"/>
|
||||
<command id="sp-cmd-documentationLink" oncommand="Scratchpad.openDocumentationPage();"/>
|
||||
<command id="sp-cmd-hideSidebar" oncommand="Scratchpad.sidebar.hide();"/>
|
||||
</commandset>
|
||||
|
||||
<keyset id="sourceEditorKeys"/>
|
||||
|
@ -102,6 +103,9 @@
|
|||
key="&errorConsoleCmd.commandkey;"
|
||||
command="sp-cmd-errorConsole"
|
||||
modifiers="accel,shift"/>
|
||||
<key id="sp-key-hideSidebar"
|
||||
keycode="VK_ESCAPE"
|
||||
command="sp-cmd-hideSidebar"/>
|
||||
<key id="key_openHelp"
|
||||
keycode="VK_F1"
|
||||
command="sp-cmd-documentationLink"/>
|
||||
|
|
|
@ -241,6 +241,10 @@ AppCacheUtils.prototype = {
|
|||
},
|
||||
|
||||
listEntries: function ACU_show(searchTerm) {
|
||||
if (!Services.prefs.getBoolPref("browser.cache.disk.enable")) {
|
||||
throw new Error(l10n.GetStringFromName("cacheDisabled"));
|
||||
}
|
||||
|
||||
let entries = [];
|
||||
|
||||
Services.cache.visitEntries({
|
||||
|
@ -275,6 +279,9 @@ AppCacheUtils.prototype = {
|
|||
}
|
||||
});
|
||||
|
||||
if (entries.length == 0) {
|
||||
throw new Error(l10n.GetStringFromName("noResults"));
|
||||
}
|
||||
return entries;
|
||||
},
|
||||
|
||||
|
@ -336,7 +343,7 @@ AppCacheUtils.prototype = {
|
|||
} else {
|
||||
this.errors.push({
|
||||
line: 0,
|
||||
msg: "The URI passed to AppCacheUtils is invalid."
|
||||
msg: l10n.GetStringFromName("invalidURI")
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Define various constants to match the globals provided by the browser.
|
||||
* This module helps cases where code is shared between the web and Firefox.
|
||||
* See also Console.jsm for an implementation of the Firefox console that
|
||||
* forwards to dump();
|
||||
*/
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "Node", "HTMLElement", "setTimeout", "clearTimeout" ];
|
||||
|
||||
/**
|
||||
* Expose Node/HTMLElement objects. This allows us to use the Node constants
|
||||
* without resorting to hardcoded numbers
|
||||
*/
|
||||
this.Node = Components.interfaces.nsIDOMNode;
|
||||
this.HTMLElement = Components.interfaces.nsIDOMHTMLElement;
|
||||
|
||||
/*
|
||||
* Import and re-export the timeout functions from Timer.jsm.
|
||||
*/
|
||||
let Timer = Components.utils.import("resource://gre/modules/Timer.jsm", {});
|
||||
this.setTimeout = Timer.setTimeout;
|
||||
this.clearTimeout = Timer.clearTimeout;
|
|
@ -19,7 +19,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "console",
|
|||
"resource://gre/modules/devtools/Console.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "gcli",
|
||||
"resource:///modules/devtools/gcli.jsm");
|
||||
"resource://gre/modules/devtools/gcli.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CmdCommands",
|
||||
"resource:///modules/devtools/BuiltinCommands.jsm");
|
||||
|
@ -153,7 +153,7 @@ let CommandUtils = {
|
|||
createEnvironment: function(chromeDocument, contentDocument) {
|
||||
let environment = {
|
||||
chromeDocument: chromeDocument,
|
||||
contentDocument: contentDocument, // Use of contentDocument is deprecated
|
||||
chromeWindow: chromeDocument.defaultView,
|
||||
|
||||
document: contentDocument,
|
||||
window: contentDocument.defaultView
|
||||
|
@ -181,9 +181,13 @@ this.CommandUtils = CommandUtils;
|
|||
* to using panels.
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(this, "isLinux", function () {
|
||||
return OS == "Linux";
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "OS", function () {
|
||||
let os = Components.classes["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Components.interfaces.nsIXULRuntime).OS;
|
||||
return os == "Linux";
|
||||
return os;
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -761,6 +765,7 @@ function OutputPanel(aDevToolbar, aLoadCallback)
|
|||
this.displayedOutput = undefined;
|
||||
|
||||
this._onload = this._onload.bind(this);
|
||||
this._update = this._update.bind(this);
|
||||
this._frame.addEventListener("load", this._onload, true);
|
||||
|
||||
this.loaded = false;
|
||||
|
@ -791,33 +796,6 @@ OutputPanel.prototype._onload = function OP_onload()
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine the scrollbar width in the current document.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Object.defineProperty(OutputPanel.prototype, 'scrollbarWidth', {
|
||||
get: function() {
|
||||
if (this.__scrollbarWidth) {
|
||||
return this.__scrollbarWidth;
|
||||
}
|
||||
|
||||
let hbox = this.document.createElementNS(XUL_NS, "hbox");
|
||||
hbox.setAttribute("style", "height: 0%; overflow: hidden");
|
||||
|
||||
let scrollbar = this.document.createElementNS(XUL_NS, "scrollbar");
|
||||
scrollbar.setAttribute("orient", "vertical");
|
||||
hbox.appendChild(scrollbar);
|
||||
|
||||
this.document.documentElement.appendChild(hbox);
|
||||
this.__scrollbarWidth = scrollbar.clientWidth;
|
||||
this.document.documentElement.removeChild(hbox);
|
||||
|
||||
return this.__scrollbarWidth;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
/**
|
||||
* Prevent the popup from hiding if it is not permitted via this.canHide.
|
||||
*/
|
||||
|
@ -863,13 +841,32 @@ OutputPanel.prototype._resize = function CLP_resize()
|
|||
// Set max panel width to match any content with a max of the width of the
|
||||
// browser window.
|
||||
let maxWidth = this._panel.ownerDocument.documentElement.clientWidth;
|
||||
let width = Math.min(maxWidth, this.document.documentElement.scrollWidth);
|
||||
|
||||
// Add scrollbar width to content size in case a scrollbar is needed.
|
||||
width += this.scrollbarWidth;
|
||||
// Adjust max width according to OS.
|
||||
// We'd like to put this in CSS but we can't:
|
||||
// body { width: calc(min(-5px, max-content)); }
|
||||
// #_panel { max-width: -5px; }
|
||||
switch(OS) {
|
||||
case "Linux":
|
||||
maxWidth -= 5;
|
||||
break;
|
||||
case "Darwin":
|
||||
maxWidth -= 25;
|
||||
break;
|
||||
case "WINNT":
|
||||
maxWidth -= 5;
|
||||
break;
|
||||
}
|
||||
|
||||
this.document.body.style.width = "-moz-max-content";
|
||||
let style = this._frame.contentWindow.getComputedStyle(this.document.body);
|
||||
let frameWidth = parseInt(style.width, 10);
|
||||
let width = Math.min(maxWidth, frameWidth);
|
||||
this.document.body.style.width = width + "px";
|
||||
|
||||
// Set the width of the iframe.
|
||||
this._frame.style.minWidth = width + "px";
|
||||
this._panel.style.maxWidth = maxWidth + "px";
|
||||
|
||||
// browserAdjustment is used to correct the panel height according to the
|
||||
// browsers borders etc.
|
||||
|
@ -906,18 +903,28 @@ OutputPanel.prototype._outputChanged = function OP_outputChanged(aEvent)
|
|||
this.remove();
|
||||
|
||||
this.displayedOutput = aEvent.output;
|
||||
this.update();
|
||||
|
||||
this.displayedOutput.onChange.add(this.update, this);
|
||||
this.displayedOutput.onClose.add(this.remove, this);
|
||||
|
||||
if (this.displayedOutput.completed) {
|
||||
this._update();
|
||||
}
|
||||
else {
|
||||
this.displayedOutput.promise.then(this._update, this._update)
|
||||
.then(null, console.error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when displayed Output says it's changed or from outputChanged, which
|
||||
* happens when there is a new displayed Output.
|
||||
*/
|
||||
OutputPanel.prototype.update = function OP_update()
|
||||
OutputPanel.prototype._update = function OP_update()
|
||||
{
|
||||
// destroy has been called, bail out
|
||||
if (this._div == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Empty this._div
|
||||
while (this._div.hasChildNodes()) {
|
||||
this._div.removeChild(this._div.firstChild);
|
||||
|
@ -927,7 +934,7 @@ OutputPanel.prototype.update = function OP_update()
|
|||
let requisition = this._devtoolbar.display.requisition;
|
||||
let nodePromise = converters.convert(this.displayedOutput.data,
|
||||
this.displayedOutput.type, 'dom',
|
||||
requisition.context);
|
||||
requisition.conversionContext);
|
||||
nodePromise.then(function(node) {
|
||||
while (this._div.hasChildNodes()) {
|
||||
this._div.removeChild(this._div.firstChild);
|
||||
|
@ -958,7 +965,6 @@ OutputPanel.prototype.remove = function OP_remove()
|
|||
}
|
||||
|
||||
if (this.displayedOutput) {
|
||||
this.displayedOutput.onChange.remove(this.update, this);
|
||||
this.displayedOutput.onClose.remove(this.remove, this);
|
||||
delete this.displayedOutput;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ include $(DEPTH)/config/autoconf.mk
|
|||
DISABLED_XPCSHELL_TESTS = unit
|
||||
|
||||
MOCHITEST_BROWSER_FILES = \
|
||||
browser_browser_basic.js \
|
||||
browser_require_basic.js \
|
||||
browser_templater_basic.js \
|
||||
browser_toolbar_basic.js \
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests exports from Browser.jsm
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,<p id=id>Text</p>";
|
||||
|
||||
let imported = {};
|
||||
Components.utils.import("resource:///modules/devtools/Browser.jsm", imported);
|
||||
|
||||
registerCleanupFunction(function tearDown() {
|
||||
imported = undefined;
|
||||
});
|
||||
|
||||
function test() {
|
||||
addTab(TEST_URI, function(browser, tab, document) {
|
||||
runTest(browser, tab, document);
|
||||
});
|
||||
}
|
||||
|
||||
function runTest(browser, tab, document) {
|
||||
var p = document.getElementById("id");
|
||||
|
||||
ok(p instanceof imported.Node, "Node correctly defined");
|
||||
ok(p instanceof imported.HTMLElement, "HTMLElement correctly defined");
|
||||
|
||||
finish();
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
|
||||
var Promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
|
||||
var template = Cu.import("resource:///modules/devtools/Templater.jsm", {}).template;
|
||||
var template = Cu.import("resource://gre/modules/devtools/Templater.jsm", {}).template;
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/browser_templater_basic.html";
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ this.EXPORTED_SYMBOLS = ["BreadcrumbsWidget"];
|
|||
* The element associated with the widget.
|
||||
*/
|
||||
this.BreadcrumbsWidget = function BreadcrumbsWidget(aNode) {
|
||||
this.document = aNode.ownerDocument;
|
||||
this.window = this.document.defaultView;
|
||||
this._parent = aNode;
|
||||
|
||||
// Create an internal arrowscrollbox container.
|
||||
|
@ -59,9 +61,6 @@ this.BreadcrumbsWidget = function BreadcrumbsWidget(aNode) {
|
|||
};
|
||||
|
||||
BreadcrumbsWidget.prototype = {
|
||||
get document() this._parent.ownerDocument,
|
||||
get window() this.document.defaultView,
|
||||
|
||||
/**
|
||||
* Inserts an item in this container at the specified index.
|
||||
*
|
||||
|
@ -108,13 +107,12 @@ BreadcrumbsWidget.prototype = {
|
|||
* Removes all of the child nodes from this container.
|
||||
*/
|
||||
removeAllItems: function BCW_removeAllItems() {
|
||||
let parent = this._parent;
|
||||
let list = this._list;
|
||||
let firstChild;
|
||||
|
||||
while (firstChild = list.firstChild) {
|
||||
list.removeChild(firstChild);
|
||||
while (list.hasChildNodes()) {
|
||||
list.firstChild.remove();
|
||||
}
|
||||
|
||||
this._selectedItem = null;
|
||||
},
|
||||
|
||||
|
@ -146,11 +144,11 @@ BreadcrumbsWidget.prototype = {
|
|||
// Repeated calls to ensureElementIsVisible would interfere with each other
|
||||
// and may sometimes result in incorrect scroll positions.
|
||||
this.window.clearTimeout(this._ensureVisibleTimeout);
|
||||
this._ensureVisibleTimeout = this.window.setTimeout(function() {
|
||||
this._ensureVisibleTimeout = this.window.setTimeout(() => {
|
||||
if (this._selectedItem) {
|
||||
this._list.ensureElementIsVisible(this._selectedItem);
|
||||
}
|
||||
}.bind(this), ENSURE_SELECTION_VISIBLE_DELAY);
|
||||
}, ENSURE_SELECTION_VISIBLE_DELAY);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -177,6 +175,8 @@ BreadcrumbsWidget.prototype = {
|
|||
target.setAttribute("overflows", "");
|
||||
},
|
||||
|
||||
window: null,
|
||||
document: null,
|
||||
_parent: null,
|
||||
_list: null,
|
||||
_selectedItem: null,
|
||||
|
@ -192,6 +192,8 @@ BreadcrumbsWidget.prototype = {
|
|||
* The string or node displayed in the container.
|
||||
*/
|
||||
function Breadcrumb(aWidget, aContents) {
|
||||
this.document = aWidget.document;
|
||||
this.window = aWidget.window;
|
||||
this.ownerView = aWidget;
|
||||
|
||||
this._target = this.document.createElement("hbox");
|
||||
|
@ -201,9 +203,6 @@ function Breadcrumb(aWidget, aContents) {
|
|||
}
|
||||
|
||||
Breadcrumb.prototype = {
|
||||
get document() this.ownerView.document,
|
||||
get window() this.document.defaultView,
|
||||
|
||||
/**
|
||||
* Sets the contents displayed in this item's view.
|
||||
*
|
||||
|
@ -228,6 +227,8 @@ Breadcrumb.prototype = {
|
|||
this._target.appendChild(aContents);
|
||||
},
|
||||
|
||||
window: null,
|
||||
document: null,
|
||||
ownerView: null,
|
||||
_target: null
|
||||
};
|
||||
|
|
|
@ -37,6 +37,8 @@ this.EXPORTED_SYMBOLS = ["SideMenuWidget"];
|
|||
* Specifies if items in this container should display horizontal arrows.
|
||||
*/
|
||||
this.SideMenuWidget = function SideMenuWidget(aNode, aShowArrows = true) {
|
||||
this.document = aNode.ownerDocument;
|
||||
this.window = this.document.defaultView;
|
||||
this._parent = aNode;
|
||||
this._showArrows = aShowArrows;
|
||||
|
||||
|
@ -60,8 +62,10 @@ this.SideMenuWidget = function SideMenuWidget(aNode, aShowArrows = true) {
|
|||
};
|
||||
|
||||
SideMenuWidget.prototype = {
|
||||
get document() this._parent.ownerDocument,
|
||||
get window() this.document.defaultView,
|
||||
/**
|
||||
* Specifies if groups in this container should be sorted alphabetically.
|
||||
*/
|
||||
sortedGroups: true,
|
||||
|
||||
/**
|
||||
* Specifies if this container should try to keep the selected item visible.
|
||||
|
@ -70,9 +74,12 @@ SideMenuWidget.prototype = {
|
|||
maintainSelectionVisible: true,
|
||||
|
||||
/**
|
||||
* Specifies if groups in this container should be sorted alphabetically.
|
||||
* Specifies that the container viewport should be "stuck" to the
|
||||
* bottom. That is, the container is automatically scrolled down to
|
||||
* keep appended items visible, but only when the scroll position is
|
||||
* already at the bottom.
|
||||
*/
|
||||
sortedGroups: true,
|
||||
autoscrollWithAppendedItems: false,
|
||||
|
||||
/**
|
||||
* Inserts an item in this container at the specified index, optionally
|
||||
|
@ -90,12 +97,26 @@ SideMenuWidget.prototype = {
|
|||
* The element associated with the displayed item.
|
||||
*/
|
||||
insertItemAt: function SMW_insertItemAt(aIndex, aContents, aTooltip = "", aGroup = "") {
|
||||
if (this.maintainSelectionVisible) {
|
||||
this.ensureSelectionIsVisible(true, true); // Don't worry, it's delayed.
|
||||
}
|
||||
// Invalidate any notices set on this widget.
|
||||
this.removeAttribute("notice");
|
||||
|
||||
let maintainScrollAtBottom =
|
||||
this.autoscrollWithAppendedItems &&
|
||||
(aIndex < 0 || aIndex >= this._orderedMenuElementsArray.length) &&
|
||||
(this._list.scrollTop + this._list.clientHeight >= this._list.scrollHeight);
|
||||
|
||||
let group = this._getGroupForName(aGroup);
|
||||
return group.insertItemAt(aIndex, aContents, aTooltip, this._showArrows);
|
||||
let item = this._getItemForGroup(group, aContents, aTooltip);
|
||||
let element = item.insertSelfAt(aIndex);
|
||||
|
||||
if (this.maintainSelectionVisible) {
|
||||
this.ensureSelectionIsVisible({ withGroup: true, delayed: true });
|
||||
}
|
||||
if (maintainScrollAtBottom) {
|
||||
this._list.scrollTop = this._list.scrollHeight;
|
||||
}
|
||||
|
||||
return element;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -117,9 +138,14 @@ SideMenuWidget.prototype = {
|
|||
* The element associated with the displayed item.
|
||||
*/
|
||||
removeChild: function SMW_removeChild(aChild) {
|
||||
if (aChild.className == "side-menu-widget-item-contents") {
|
||||
// Remove the item itself, not the contents.
|
||||
let item = aChild.parentNode;
|
||||
item.parentNode.removeChild(item);
|
||||
aChild.parentNode.remove();
|
||||
} else {
|
||||
// Groups with no title don't have any special internal structure.
|
||||
aChild.remove();
|
||||
}
|
||||
|
||||
this._orderedMenuElementsArray.splice(
|
||||
this._orderedMenuElementsArray.indexOf(aChild), 1);
|
||||
|
||||
|
@ -134,11 +160,11 @@ SideMenuWidget.prototype = {
|
|||
removeAllItems: function SMW_removeAllItems() {
|
||||
let parent = this._parent;
|
||||
let list = this._list;
|
||||
let firstChild;
|
||||
|
||||
while (firstChild = list.firstChild) {
|
||||
list.removeChild(firstChild);
|
||||
while (list.hasChildNodes()) {
|
||||
list.firstChild.remove();
|
||||
}
|
||||
|
||||
this._selectedItem = null;
|
||||
|
||||
this._groupsByName.clear();
|
||||
|
@ -157,12 +183,12 @@ SideMenuWidget.prototype = {
|
|||
* @param nsIDOMNode aChild
|
||||
*/
|
||||
set selectedItem(aChild) {
|
||||
let menuElementsArray = this._orderedMenuElementsArray;
|
||||
let menuArray = this._orderedMenuElementsArray;
|
||||
|
||||
if (!aChild) {
|
||||
this._selectedItem = null;
|
||||
}
|
||||
for (let node of menuElementsArray) {
|
||||
for (let node of menuArray) {
|
||||
if (node == aChild) {
|
||||
node.classList.add("selected");
|
||||
node.parentNode.classList.add("selected");
|
||||
|
@ -172,18 +198,18 @@ SideMenuWidget.prototype = {
|
|||
node.parentNode.classList.remove("selected");
|
||||
}
|
||||
}
|
||||
|
||||
// Repeated calls to ensureElementIsVisible would interfere with each other
|
||||
// and may sometimes result in incorrect scroll positions.
|
||||
this.ensureSelectionIsVisible(false, true);
|
||||
this.ensureSelectionIsVisible({ delayed: true });
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensures the selected element is visible.
|
||||
* @see SideMenuWidget.prototype.ensureElementIsVisible.
|
||||
*/
|
||||
ensureSelectionIsVisible:
|
||||
function SMW_ensureSelectionIsVisible(aGroupFlag, aDelayedFlag) {
|
||||
this.ensureElementIsVisible(this.selectedItem, aGroupFlag, aDelayedFlag);
|
||||
ensureSelectionIsVisible: function SMW_ensureSelectionIsVisible(aFlags) {
|
||||
this.ensureElementIsVisible(this.selectedItem, aFlags);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -191,28 +217,31 @@ SideMenuWidget.prototype = {
|
|||
*
|
||||
* @param nsIDOMNode aElement
|
||||
* The element to make visible.
|
||||
* @param boolean aGroupFlag
|
||||
* True if the group header should also be made visible, if possible.
|
||||
* @param boolean aDelayedFlag
|
||||
* True to wait a few cycles before ensuring the selection is visible.
|
||||
* @param object aFlags [optional]
|
||||
* An object containing some of the following flags:
|
||||
* - withGroup: true if the group header should also be made visible, if possible
|
||||
* - delayed: wait a few cycles before ensuring the selection is visible
|
||||
*/
|
||||
ensureElementIsVisible:
|
||||
function SMW_ensureElementIsVisible(aElement, aGroupFlag, aDelayedFlag) {
|
||||
ensureElementIsVisible: function SMW_ensureElementIsVisible(aElement, aFlags = {}) {
|
||||
if (!aElement) {
|
||||
return;
|
||||
}
|
||||
if (aDelayedFlag) {
|
||||
|
||||
if (aFlags.delayed) {
|
||||
delete aFlags.delayed;
|
||||
this.window.clearTimeout(this._ensureVisibleTimeout);
|
||||
this._ensureVisibleTimeout = this.window.setTimeout(function() {
|
||||
this.ensureElementIsVisible(aElement, aGroupFlag, false);
|
||||
}.bind(this), ENSURE_SELECTION_VISIBLE_DELAY);
|
||||
this._ensureVisibleTimeout = this.window.setTimeout(() => {
|
||||
this.ensureElementIsVisible(aElement, aFlags);
|
||||
}, ENSURE_SELECTION_VISIBLE_DELAY);
|
||||
return;
|
||||
}
|
||||
if (aGroupFlag) {
|
||||
|
||||
if (aFlags.withGroup) {
|
||||
let groupList = aElement.parentNode;
|
||||
let groupContainer = groupList.parentNode;
|
||||
groupContainer.scrollIntoView(true); // Align with the top.
|
||||
}
|
||||
|
||||
this._boxObject.ensureElementIsVisible(aElement);
|
||||
},
|
||||
|
||||
|
@ -349,6 +378,24 @@ SideMenuWidget.prototype = {
|
|||
return group;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a menu item to be displayed inside a group.
|
||||
* @see SideMenuWidget.prototype._getGroupForName
|
||||
*
|
||||
* @param SideMenuGroup aGroup
|
||||
* The group to contain the menu item.
|
||||
* @param string | nsIDOMNode aContents
|
||||
* The string or node displayed in the container.
|
||||
* @param string aTooltip [optional]
|
||||
* A tooltip attribute for the displayed item.
|
||||
*/
|
||||
_getItemForGroup: function SMW__getItemForGroup(aGroup, aContents, aTooltip) {
|
||||
return new SideMenuItem(aGroup, aContents, aTooltip, this._showArrows);
|
||||
},
|
||||
|
||||
window: null,
|
||||
document: null,
|
||||
_showArrows: false,
|
||||
_parent: null,
|
||||
_list: null,
|
||||
_boxObject: null,
|
||||
|
@ -372,70 +419,44 @@ SideMenuWidget.prototype = {
|
|||
* The string displayed in the container.
|
||||
*/
|
||||
function SideMenuGroup(aWidget, aName) {
|
||||
this.document = aWidget.document;
|
||||
this.window = aWidget.window;
|
||||
this.ownerView = aWidget;
|
||||
this.identifier = aName;
|
||||
|
||||
let document = this.document;
|
||||
let title = this._title = document.createElement("hbox");
|
||||
// Create an internal title and list container.
|
||||
if (aName) {
|
||||
let target = this._target = this.document.createElement("vbox");
|
||||
target.className = "side-menu-widget-group";
|
||||
target.setAttribute("name", aName);
|
||||
target.setAttribute("tooltiptext", aName);
|
||||
|
||||
let list = this._list = this.document.createElement("vbox");
|
||||
list.className = "side-menu-widget-group-list";
|
||||
|
||||
let title = this._title = this.document.createElement("hbox");
|
||||
title.className = "side-menu-widget-group-title";
|
||||
|
||||
let name = this._name = document.createElement("label");
|
||||
let name = this._name = this.document.createElement("label");
|
||||
name.className = "plain name";
|
||||
name.setAttribute("value", aName);
|
||||
name.setAttribute("crop", "end");
|
||||
name.setAttribute("flex", "1");
|
||||
|
||||
let list = this._list = document.createElement("vbox");
|
||||
list.className = "side-menu-widget-group-list";
|
||||
|
||||
let target = this._target = document.createElement("vbox");
|
||||
target.className = "side-menu-widget-group side-menu-widget-item-or-group";
|
||||
target.setAttribute("name", aName);
|
||||
target.setAttribute("tooltiptext", aName);
|
||||
|
||||
title.appendChild(name);
|
||||
target.appendChild(title);
|
||||
target.appendChild(list);
|
||||
}
|
||||
// Skip a few redundant nodes when no title is shown.
|
||||
else {
|
||||
let target = this._target = this._list = this.document.createElement("vbox");
|
||||
target.className = "side-menu-widget-group side-menu-widget-group-list";
|
||||
}
|
||||
}
|
||||
|
||||
SideMenuGroup.prototype = {
|
||||
get document() this.ownerView.document,
|
||||
get window() this.document.defaultView,
|
||||
get _groupElementsArray() this.ownerView._orderedGroupElementsArray,
|
||||
get _menuElementsArray() this.ownerView._orderedMenuElementsArray,
|
||||
|
||||
/**
|
||||
* Inserts an item in this group at the specified index.
|
||||
*
|
||||
* @param number aIndex
|
||||
* The position in the container intended for this item.
|
||||
* @param string | nsIDOMNode aContents
|
||||
* The string or node displayed in the container.
|
||||
* @param string aTooltip [optional]
|
||||
* A tooltip attribute for the displayed item.
|
||||
* @param boolean aArrowFlag
|
||||
* True if a horizontal arrow should be shown.
|
||||
* @return nsIDOMNode
|
||||
* The element associated with the displayed item.
|
||||
*/
|
||||
insertItemAt: function SMG_insertItemAt(aIndex, aContents, aTooltip, aArrowFlag) {
|
||||
let list = this._list;
|
||||
let menuArray = this._menuElementsArray;
|
||||
let item = new SideMenuItem(this, aContents, aTooltip, aArrowFlag);
|
||||
|
||||
// Invalidate any notices set on the owner widget.
|
||||
this.ownerView.removeAttribute("notice");
|
||||
|
||||
if (aIndex >= 0) {
|
||||
list.insertBefore(item._container, list.childNodes[aIndex]);
|
||||
menuArray.splice(aIndex, 0, item._target);
|
||||
} else {
|
||||
list.appendChild(item._container);
|
||||
menuArray.push(item._target);
|
||||
}
|
||||
|
||||
return item._target;
|
||||
},
|
||||
get _orderedGroupElementsArray() this.ownerView._orderedGroupElementsArray,
|
||||
get _orderedMenuElementsArray() this.ownerView._orderedMenuElementsArray,
|
||||
|
||||
/**
|
||||
* Inserts this group in the parent container at the specified index.
|
||||
|
@ -445,7 +466,7 @@ SideMenuGroup.prototype = {
|
|||
*/
|
||||
insertSelfAt: function SMG_insertSelfAt(aIndex) {
|
||||
let ownerList = this.ownerView._list;
|
||||
let groupsArray = this._groupElementsArray;
|
||||
let groupsArray = this._orderedGroupElementsArray;
|
||||
|
||||
if (aIndex >= 0) {
|
||||
ownerList.insertBefore(this._target, groupsArray[aIndex]);
|
||||
|
@ -464,7 +485,7 @@ SideMenuGroup.prototype = {
|
|||
*/
|
||||
findExpectedIndexForSelf: function SMG_findExpectedIndexForSelf() {
|
||||
let identifier = this.identifier;
|
||||
let groupsArray = this._groupElementsArray;
|
||||
let groupsArray = this._orderedGroupElementsArray;
|
||||
|
||||
for (let group of groupsArray) {
|
||||
let name = group.getAttribute("name");
|
||||
|
@ -476,6 +497,8 @@ SideMenuGroup.prototype = {
|
|||
return -1;
|
||||
},
|
||||
|
||||
window: null,
|
||||
document: null,
|
||||
ownerView: null,
|
||||
identifier: "",
|
||||
_target: null,
|
||||
|
@ -497,31 +520,29 @@ SideMenuGroup.prototype = {
|
|||
* True if a horizontal arrow should be shown.
|
||||
*/
|
||||
function SideMenuItem(aGroup, aContents, aTooltip, aArrowFlag) {
|
||||
this.document = aGroup.document;
|
||||
this.window = aGroup.window;
|
||||
this.ownerView = aGroup;
|
||||
|
||||
let document = this.document;
|
||||
|
||||
// Show a horizontal arrow towards the content.
|
||||
if (aArrowFlag) {
|
||||
let target = this._target = document.createElement("vbox");
|
||||
let container = this._container = this.document.createElement("hbox");
|
||||
container.className = "side-menu-widget-item";
|
||||
container.setAttribute("tooltiptext", aTooltip);
|
||||
|
||||
let target = this._target = this.document.createElement("vbox");
|
||||
target.className = "side-menu-widget-item-contents";
|
||||
|
||||
let arrow = this._arrow = document.createElement("hbox");
|
||||
let arrow = this._arrow = this.document.createElement("hbox");
|
||||
arrow.className = "side-menu-widget-item-arrow";
|
||||
|
||||
let container = this._container = document.createElement("hbox");
|
||||
container.className = "side-menu-widget-item side-menu-widget-item-or-group";
|
||||
container.setAttribute("tooltiptext", aTooltip);
|
||||
container.appendChild(target);
|
||||
container.appendChild(arrow);
|
||||
}
|
||||
// Skip a few redundant nodes when no horizontal arrow is shown.
|
||||
else {
|
||||
let target = this._target = this._container = document.createElement("hbox");
|
||||
target.className =
|
||||
"side-menu-widget-item " +
|
||||
"side-menu-widget-item-or-group " +
|
||||
"side-menu-widget-item-contents";
|
||||
let target = this._target = this._container = this.document.createElement("hbox");
|
||||
target.className = "side-menu-widget-item side-menu-widget-item-contents";
|
||||
}
|
||||
|
||||
this._target.setAttribute("flex", "1");
|
||||
|
@ -529,8 +550,31 @@ function SideMenuItem(aGroup, aContents, aTooltip, aArrowFlag) {
|
|||
}
|
||||
|
||||
SideMenuItem.prototype = {
|
||||
get document() this.ownerView.document,
|
||||
get window() this.document.defaultView,
|
||||
get _orderedGroupElementsArray() this.ownerView._orderedGroupElementsArray,
|
||||
get _orderedMenuElementsArray() this.ownerView._orderedMenuElementsArray,
|
||||
|
||||
/**
|
||||
* Inserts this item in the parent group at the specified index.
|
||||
*
|
||||
* @param number aIndex
|
||||
* The position in the container intended for this item.
|
||||
* @return nsIDOMNode
|
||||
* The element associated with the displayed item.
|
||||
*/
|
||||
insertSelfAt: function SMI_insertSelfAt(aIndex) {
|
||||
let ownerList = this.ownerView._list;
|
||||
let menuArray = this._orderedMenuElementsArray;
|
||||
|
||||
if (aIndex >= 0) {
|
||||
ownerList.insertBefore(this._container, ownerList.childNodes[aIndex]);
|
||||
menuArray.splice(aIndex, 0, this._target);
|
||||
} else {
|
||||
ownerList.appendChild(this._container);
|
||||
menuArray.push(this._target);
|
||||
}
|
||||
|
||||
return this._target;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the contents displayed in this item's view.
|
||||
|
@ -559,6 +603,8 @@ SideMenuItem.prototype = {
|
|||
this._target.appendChild(aContents);
|
||||
},
|
||||
|
||||
window: null,
|
||||
document: null,
|
||||
ownerView: null,
|
||||
_target: null,
|
||||
_container: null,
|
||||
|
|
|
@ -128,10 +128,9 @@ VariablesView.prototype = {
|
|||
}
|
||||
|
||||
let list = this._list;
|
||||
let firstChild;
|
||||
|
||||
while (firstChild = list.firstChild) {
|
||||
list.removeChild(firstChild);
|
||||
while (list.hasChildNodes()) {
|
||||
list.firstChild.remove();
|
||||
}
|
||||
|
||||
this._store.length = 0;
|
||||
|
@ -163,7 +162,7 @@ VariablesView.prototype = {
|
|||
this._store.length = 0;
|
||||
this._itemsByElement.clear();
|
||||
|
||||
this._emptyTimeout = this.window.setTimeout(function() {
|
||||
this._emptyTimeout = this.window.setTimeout(() => {
|
||||
this._emptyTimeout = null;
|
||||
|
||||
prevList.removeEventListener("keypress", this._onViewKeyPress, false);
|
||||
|
@ -178,7 +177,7 @@ VariablesView.prototype = {
|
|||
this._appendEmptyNotice();
|
||||
this._toggleSearchVisibility(false);
|
||||
}
|
||||
}.bind(this), aTimeout);
|
||||
}, aTimeout);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -198,6 +197,12 @@ VariablesView.prototype = {
|
|||
*/
|
||||
lazyAppend: true,
|
||||
|
||||
/**
|
||||
* Specifies if nodes in this view may be expanded lazily.
|
||||
* @see Scope.prototype.expand
|
||||
*/
|
||||
lazyExpand: true,
|
||||
|
||||
/**
|
||||
* Function called each time a variable or property's value is changed via
|
||||
* user interaction. If null, then value changes are disabled.
|
||||
|
@ -403,7 +408,7 @@ VariablesView.prototype = {
|
|||
if (!this._searchboxContainer) {
|
||||
return;
|
||||
}
|
||||
this._searchboxContainer.parentNode.removeChild(this._searchboxContainer);
|
||||
this._searchboxContainer.remove();
|
||||
this._searchboxNode.removeEventListener("input", this._onSearchboxInput, false);
|
||||
this._searchboxNode.removeEventListener("keypress", this._onSearchboxKeyPress, false);
|
||||
|
||||
|
@ -642,15 +647,17 @@ VariablesView.prototype = {
|
|||
* Focuses the next scope, variable or property in this view.
|
||||
* @see VariablesView.prototype._focusChange
|
||||
*/
|
||||
focusNextItem: function VV_focusNextItem(aMaintainViewFocusedFlag)
|
||||
this._focusChange("advanceFocus", aMaintainViewFocusedFlag),
|
||||
focusNextItem: function VV_focusNextItem(aMaintainViewFocusedFlag) {
|
||||
this._focusChange("advanceFocus", aMaintainViewFocusedFlag)
|
||||
},
|
||||
|
||||
/**
|
||||
* Focuses the previous scope, variable or property in this view.
|
||||
* @see VariablesView.prototype._focusChange
|
||||
*/
|
||||
focusPrevItem: function VV_focusPrevItem(aMaintainViewFocusedFlag)
|
||||
this._focusChange("rewindFocus", aMaintainViewFocusedFlag),
|
||||
focusPrevItem: function VV_focusPrevItem(aMaintainViewFocusedFlag) {
|
||||
this._focusChange("rewindFocus", aMaintainViewFocusedFlag)
|
||||
},
|
||||
|
||||
/**
|
||||
* Focuses the next or previous scope, variable or property in this view.
|
||||
|
@ -761,7 +768,6 @@ VariablesView.prototype = {
|
|||
if (!item._isArrowVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Expand scopes, variables and properties before advancing focus.
|
||||
if (!item._isExpanded) {
|
||||
item.expand();
|
||||
|
@ -1051,7 +1057,8 @@ VariablesView.getterOrSetterEvalMacro = function(aItem, aCurrentString) {
|
|||
VariablesView.getterOrSetterDeleteCallback = function(aItem) {
|
||||
aItem._disable();
|
||||
|
||||
// Make sure the right getter/setter to value override macro is applied to the target object.
|
||||
// Make sure the right getter/setter to value override macro is applied
|
||||
// to the target object.
|
||||
aItem.ownerView.eval(aItem.evaluationMacro(aItem, ""));
|
||||
|
||||
return true; // Don't hide the element.
|
||||
|
@ -1237,7 +1244,7 @@ Scope.prototype = {
|
|||
// even if they were already displayed before. In this case, show a throbber
|
||||
// to suggest that this scope is expanding.
|
||||
if (!this._isExpanding &&
|
||||
this._variablesView.lazyAppend &&
|
||||
this._variablesView.lazyExpand &&
|
||||
this._store.size > LAZY_APPEND_BATCH) {
|
||||
this._isExpanding = true;
|
||||
|
||||
|
@ -1971,6 +1978,13 @@ function Variable(aScope, aName, aDescriptor) {
|
|||
this._activateNameInput = this._activateNameInput.bind(this);
|
||||
this._activateValueInput = this._activateValueInput.bind(this);
|
||||
|
||||
// Treat safe getter descriptors as descriptors with a value.
|
||||
if ("getterValue" in aDescriptor) {
|
||||
aDescriptor.value = aDescriptor.getterValue;
|
||||
delete aDescriptor.get;
|
||||
delete aDescriptor.set;
|
||||
}
|
||||
|
||||
Scope.call(this, aScope, aName, this._initialDescriptor = aDescriptor);
|
||||
this.setGrip(aDescriptor.value);
|
||||
this._symbolicName = aName;
|
||||
|
@ -1995,6 +2009,8 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
|
|||
* - { value: { type: "object", class: "Object" } }
|
||||
* - { get: { type: "object", class: "Function" },
|
||||
* set: { type: "undefined" } }
|
||||
* - { get: { type "object", class: "Function" },
|
||||
* getterValue: "foo", getterPrototypeLevel: 2 }
|
||||
* @param boolean aRelaxed
|
||||
* True if name duplicates should be allowed.
|
||||
* @return Property
|
||||
|
@ -2374,14 +2390,17 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
|
|||
let configurableLabel = document.createElement("label");
|
||||
let enumerableLabel = document.createElement("label");
|
||||
let writableLabel = document.createElement("label");
|
||||
let safeGetterLabel = document.createElement("label");
|
||||
configurableLabel.setAttribute("value", "configurable");
|
||||
enumerableLabel.setAttribute("value", "enumerable");
|
||||
writableLabel.setAttribute("value", "writable");
|
||||
safeGetterLabel.setAttribute("value", "native-getter");
|
||||
|
||||
tooltip.setAttribute("orient", "horizontal");
|
||||
tooltip.appendChild(configurableLabel);
|
||||
tooltip.appendChild(enumerableLabel);
|
||||
tooltip.appendChild(writableLabel);
|
||||
tooltip.appendChild(safeGetterLabel);
|
||||
|
||||
this._target.appendChild(tooltip);
|
||||
this._target.setAttribute("tooltip", tooltip.id);
|
||||
|
@ -2420,6 +2439,9 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
|
|||
if (!descriptor.null && !descriptor.writable && !this.ownerView.getter && !this.ownerView.setter) {
|
||||
this._target.setAttribute("non-writable", "");
|
||||
}
|
||||
if (descriptor && "getterValue" in descriptor) {
|
||||
this._target.setAttribute("safe-getter", "");
|
||||
}
|
||||
if (name == "this") {
|
||||
this._target.setAttribute("self", "");
|
||||
}
|
||||
|
|
|
@ -305,43 +305,39 @@ ViewHelpers.Prefs.prototype = {
|
|||
*
|
||||
* @param any aAttachment
|
||||
* Some attached primitive/object.
|
||||
* @param string aLabel
|
||||
* The label displayed in the container.
|
||||
* @param string aValue
|
||||
* The actual internal value of the item.
|
||||
* @param string aDescription [optional]
|
||||
* An optional description of the item.
|
||||
* @param nsIDOMNode | nsIDOMDocumentFragment | array aContents [optional]
|
||||
* A prebuilt node, or an array containing the following properties:
|
||||
* - aLabel: the label displayed in the container
|
||||
* - aValue: the actual internal value of the item
|
||||
* - aDescription: an optional description of the item
|
||||
*/
|
||||
this.MenuItem = function MenuItem(aAttachment, aLabel, aValue, aDescription) {
|
||||
this.MenuItem = function MenuItem(aAttachment, aContents = []) {
|
||||
this.attachment = aAttachment;
|
||||
|
||||
// Allow the insertion of prebuilt nodes.
|
||||
if (aContents instanceof Ci.nsIDOMNode ||
|
||||
aContents instanceof Ci.nsIDOMDocumentFragment) {
|
||||
this._prebuiltTarget = aContents;
|
||||
}
|
||||
// Delegate the item view creation to a container widget.
|
||||
else {
|
||||
let [aLabel, aValue, aDescription] = aContents;
|
||||
this._label = aLabel + "";
|
||||
this._value = aValue + "";
|
||||
this._description = (aDescription || "") + "";
|
||||
}
|
||||
};
|
||||
|
||||
MenuItem.prototype = {
|
||||
/**
|
||||
* Gets the label set for this item.
|
||||
* @return string
|
||||
*/
|
||||
get label() this._label,
|
||||
|
||||
/**
|
||||
* Gets the value set for this item.
|
||||
* @return string
|
||||
*/
|
||||
get value() this._value,
|
||||
|
||||
/**
|
||||
* Gets the description set for this item.
|
||||
* @return string
|
||||
*/
|
||||
get description() this._description,
|
||||
get target() this._target,
|
||||
|
||||
/**
|
||||
* Immediately appends a child item to this menu item.
|
||||
*
|
||||
* @param nsIDOMNode
|
||||
* @param nsIDOMNode aElement
|
||||
* An nsIDOMNode representing the child element to append.
|
||||
* @param object aOptions [optional]
|
||||
* Additional options or flags supported by this operation:
|
||||
|
@ -363,7 +359,7 @@ MenuItem.prototype = {
|
|||
}
|
||||
|
||||
// Entangle the item with the newly inserted child node.
|
||||
this._entangleItem(item, this.target.appendChild(aElement));
|
||||
this._entangleItem(item, this._target.appendChild(aElement));
|
||||
|
||||
// Return the item associated with the displayed element.
|
||||
return item;
|
||||
|
@ -379,7 +375,7 @@ MenuItem.prototype = {
|
|||
if (!aItem) {
|
||||
return;
|
||||
}
|
||||
this.target.removeChild(aItem.target);
|
||||
this._target.removeChild(aItem._target);
|
||||
this._untangleItem(aItem);
|
||||
},
|
||||
|
||||
|
@ -387,20 +383,20 @@ MenuItem.prototype = {
|
|||
* Visually marks this menu item as selected.
|
||||
*/
|
||||
markSelected: function MI_markSelected() {
|
||||
if (!this.target) {
|
||||
if (!this._target) {
|
||||
return;
|
||||
}
|
||||
this.target.classList.add("selected");
|
||||
this._target.classList.add("selected");
|
||||
},
|
||||
|
||||
/**
|
||||
* Visually marks this menu item as deselected.
|
||||
*/
|
||||
markDeselected: function MI_markDeselected() {
|
||||
if (!this.target) {
|
||||
if (!this._target) {
|
||||
return;
|
||||
}
|
||||
this.target.classList.remove("selected");
|
||||
this._target.classList.remove("selected");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -411,7 +407,7 @@ MenuItem.prototype = {
|
|||
* @param nsIDOMNode aElement [optional]
|
||||
* A custom element to set the attributes to.
|
||||
*/
|
||||
setAttributes: function MI_setAttributes(aAttributes, aElement = this.target) {
|
||||
setAttributes: function MI_setAttributes(aAttributes, aElement = this._target) {
|
||||
for (let [name, value] of aAttributes) {
|
||||
aElement.setAttribute(name, value);
|
||||
}
|
||||
|
@ -431,7 +427,7 @@ MenuItem.prototype = {
|
|||
}
|
||||
|
||||
this._itemsByElement.set(aElement, aItem);
|
||||
aItem.target = aElement;
|
||||
aItem._target = aElement;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -448,8 +444,19 @@ MenuItem.prototype = {
|
|||
aItem.remove(childItem);
|
||||
}
|
||||
|
||||
this._itemsByElement.delete(aItem.target);
|
||||
aItem.target = null;
|
||||
this._unlinkItem(aItem);
|
||||
aItem._prebuiltTarget = null;
|
||||
aItem._target = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes an item from the its parent's storage maps.
|
||||
*
|
||||
* @param MenuItem aItem
|
||||
* The item to forget.
|
||||
*/
|
||||
_unlinkItem: function MC__unlinkItem(aItem) {
|
||||
this._itemsByElement.delete(aItem._target);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -469,7 +476,8 @@ MenuItem.prototype = {
|
|||
_label: "",
|
||||
_value: "",
|
||||
_description: "",
|
||||
target: null,
|
||||
_prebuiltTarget: null,
|
||||
_target: null,
|
||||
finalize: null,
|
||||
attachment: null
|
||||
};
|
||||
|
@ -537,8 +545,8 @@ MenuContainer.prototype = {
|
|||
* (items with "undefined" or "null" labels/values). This can, as well, be
|
||||
* overridden via the "relaxed" flag.
|
||||
*
|
||||
* @param nsIDOMNode | object aContents
|
||||
* An nsIDOMNode, or an array containing the following properties:
|
||||
* @param nsIDOMNode | nsIDOMDocumentFragment array aContents
|
||||
* A prebuilt node, or an array containing the following properties:
|
||||
* - label: the label displayed in the container
|
||||
* - value: the actual internal value of the item
|
||||
* - description: an optional description of the item
|
||||
|
@ -555,23 +563,17 @@ MenuContainer.prototype = {
|
|||
* undefined if the item was staged for a later commit.
|
||||
*/
|
||||
push: function MC_push(aContents, aOptions = {}) {
|
||||
if (aContents instanceof Ci.nsIDOMNode ||
|
||||
aContents instanceof Ci.nsIDOMElement) {
|
||||
// Allow the insertion of prebuilt nodes.
|
||||
aOptions.node = aContents;
|
||||
aContents = ["", "", ""];
|
||||
}
|
||||
|
||||
let [label, value, description] = aContents;
|
||||
let item = new MenuItem(aOptions.attachment, label, value, description);
|
||||
let item = new MenuItem(aOptions.attachment, aContents);
|
||||
|
||||
// Batch the item to be added later.
|
||||
if (aOptions.staged) {
|
||||
// Commit operations will ignore any specified index.
|
||||
delete aOptions.index;
|
||||
return void this._stagedItems.push({ item: item, options: aOptions });
|
||||
}
|
||||
// Find the target position in this container and insert the item there.
|
||||
if (!("index" in aOptions)) {
|
||||
return this._insertItemAt(this._findExpectedIndex(label), item, aOptions);
|
||||
return this._insertItemAt(this._findExpectedIndex(item), item, aOptions);
|
||||
}
|
||||
// Insert the item at the specified index. If negative or out of bounds,
|
||||
// the item will be simply appended.
|
||||
|
@ -580,6 +582,7 @@ MenuContainer.prototype = {
|
|||
|
||||
/**
|
||||
* Flushes all the prepared items into this container.
|
||||
* Any specified index on the items will be ignored. Everything is appended.
|
||||
*
|
||||
* @param object aOptions [optional]
|
||||
* Additional options or flags supported by this operation:
|
||||
|
@ -590,8 +593,7 @@ MenuContainer.prototype = {
|
|||
|
||||
// Sort the items before adding them to this container, if preferred.
|
||||
if (aOptions.sorted) {
|
||||
stagedItems.sort(function(a, b) a.item._label.toLowerCase() >
|
||||
b.item._label.toLowerCase());
|
||||
stagedItems.sort((a, b) => this._sortPredicate(a.item, b.item));
|
||||
}
|
||||
// Append the prepared items to this container.
|
||||
for (let { item, options } of stagedItems) {
|
||||
|
@ -630,7 +632,7 @@ MenuContainer.prototype = {
|
|||
if (!aItem) {
|
||||
return;
|
||||
}
|
||||
this._container.removeChild(aItem.target);
|
||||
this._container.removeChild(aItem._target);
|
||||
this._untangleItem(aItem);
|
||||
},
|
||||
|
||||
|
@ -684,10 +686,97 @@ MenuContainer.prototype = {
|
|||
*/
|
||||
toggleContents: function MC_toggleContents(aVisibleFlag) {
|
||||
for (let [, item] of this._itemsByElement) {
|
||||
item.target.hidden = !aVisibleFlag;
|
||||
item._target.hidden = !aVisibleFlag;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sorts all the items in this container based on a predicate.
|
||||
*
|
||||
* @param function aPredicate [optional]
|
||||
* Items are sorted according to the return value of the function, which
|
||||
* will become the new default sorting predicate in this container.
|
||||
* If unspecified, all items will be sorted by their label.
|
||||
*/
|
||||
sortContents: function MC_sortContents(aPredicate = this._sortPredicate) {
|
||||
let sortedItems = this.allItems.sort(this._sortPredicate = aPredicate);
|
||||
|
||||
for (let i = 0, len = sortedItems.length; i < len; i++) {
|
||||
this.swapItems(this.getItemAtIndex(i), sortedItems[i]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Visually swaps two items in this container.
|
||||
*
|
||||
* @param MenuItem aFirst
|
||||
* The first menu item to be swapped.
|
||||
* @param MenuItem aSecond
|
||||
* The second menu item to be swapped.
|
||||
*/
|
||||
swapItems: function MC_swapItems(aFirst, aSecond) {
|
||||
if (aFirst == aSecond) { // We're just dandy, thank you.
|
||||
return;
|
||||
}
|
||||
let { _prebuiltTarget: firstPrebuiltTarget, target: firstTarget } = aFirst;
|
||||
let { _prebuiltTarget: secondPrebuiltTarget, target: secondTarget } = aSecond;
|
||||
|
||||
// If the two items were constructed with prebuilt nodes as DocumentFragments,
|
||||
// then those DocumentFragments are now empty and need to be reassembled.
|
||||
if (firstPrebuiltTarget instanceof Ci.nsIDOMDocumentFragment) {
|
||||
for (let node of firstTarget.childNodes) {
|
||||
firstPrebuiltTarget.appendChild(node.cloneNode(true));
|
||||
}
|
||||
}
|
||||
if (secondPrebuiltTarget instanceof Ci.nsIDOMDocumentFragment) {
|
||||
for (let node of secondTarget.childNodes) {
|
||||
secondPrebuiltTarget.appendChild(node.cloneNode(true));
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Get the indices of the two items to swap.
|
||||
let i = this._indexOfElement(firstTarget);
|
||||
let j = this._indexOfElement(secondTarget);
|
||||
|
||||
// 2. Remeber the selection index, to reselect an item, if necessary.
|
||||
let selectedTarget = this._container.selectedItem;
|
||||
let selectedIndex = -1;
|
||||
if (selectedTarget == firstTarget) {
|
||||
selectedIndex = i;
|
||||
} else if (selectedTarget == secondTarget) {
|
||||
selectedIndex = j;
|
||||
}
|
||||
|
||||
// 3. Silently nuke both items, nobody needs to know about this.
|
||||
this._container.removeChild(firstTarget);
|
||||
this._container.removeChild(secondTarget);
|
||||
this._unlinkItem(aFirst);
|
||||
this._unlinkItem(aSecond);
|
||||
|
||||
// 4. Add the items again, but reversing their indices.
|
||||
this._insertItemAt.apply(this, i < j ? [i, aSecond] : [j, aFirst]);
|
||||
this._insertItemAt.apply(this, i < j ? [j, aFirst] : [i, aSecond]);
|
||||
|
||||
// 5. Restore the previous selection, if necessary.
|
||||
if (selectedIndex == i) {
|
||||
this._container.selectedItem = aFirst._target;
|
||||
} else if (selectedIndex == j) {
|
||||
this._container.selectedItem = aSecond._target;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Visually swaps two items in this container at specific indices.
|
||||
*
|
||||
* @param number aFirst
|
||||
* The index of the first menu item to be swapped.
|
||||
* @param number aSecond
|
||||
* The index of the second menu item to be swapped.
|
||||
*/
|
||||
swapItemsAtIndices: function MC_swapItemsAtIndices(aFirst, aSecond) {
|
||||
this.swapItems(this.getItemAtIndex(aFirst), this.getItemAtIndex(aSecond));
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether an item with the specified label is among the elements
|
||||
* shown in this container.
|
||||
|
@ -776,14 +865,15 @@ MenuContainer.prototype = {
|
|||
*/
|
||||
set selectedItem(aItem) {
|
||||
// A falsy item is allowed to invalidate the current selection.
|
||||
let targetNode = aItem ? aItem.target : null;
|
||||
let targetElement = aItem ? aItem._target : null;
|
||||
|
||||
// Prevent selecting the same item again, so return early.
|
||||
if (this._container.selectedItem == targetNode) {
|
||||
if (this._container.selectedItem == targetElement) {
|
||||
return;
|
||||
}
|
||||
this._container.selectedItem = targetNode;
|
||||
ViewHelpers.dispatchEvent(targetNode, "select", aItem);
|
||||
|
||||
this._container.selectedItem = targetElement;
|
||||
ViewHelpers.dispatchEvent(targetElement, "select", aItem);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -877,7 +967,7 @@ MenuContainer.prototype = {
|
|||
* The index of the matched item, or -1 if nothing is found.
|
||||
*/
|
||||
indexOfItem: function MC_indexOfItem(aItem) {
|
||||
return this._indexOfElement(aItem.target);
|
||||
return this._indexOfElement(aItem._target);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -931,7 +1021,20 @@ MenuContainer.prototype = {
|
|||
get itemCount() this._itemsByElement.size,
|
||||
|
||||
/**
|
||||
* Returns a list of all the visible (non-hidden) items in this container.
|
||||
* Returns a list of all items in this container, in the displayed order.
|
||||
* @return array
|
||||
*/
|
||||
get allItems() {
|
||||
let items = [];
|
||||
for (let i = 0; i < this.itemCount; i++) {
|
||||
items.push(this.getItemAtIndex(i));
|
||||
}
|
||||
return items;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a list of all the visible (non-hidden) items in this container,
|
||||
* in no particular order.
|
||||
* @return array
|
||||
*/
|
||||
get visibleItems() {
|
||||
|
@ -987,25 +1090,26 @@ MenuContainer.prototype = {
|
|||
* True if the element is eligible, false otherwise.
|
||||
*/
|
||||
isEligible: function MC_isEligible(aItem) {
|
||||
return this.isUnique(aItem) &&
|
||||
return aItem._prebuiltTarget || (this.isUnique(aItem) &&
|
||||
aItem._label != "undefined" && aItem._label != "null" &&
|
||||
aItem._value != "undefined" && aItem._value != "null";
|
||||
aItem._value != "undefined" && aItem._value != "null");
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds the expected item index in this container based on its label.
|
||||
* Finds the expected item index in this container based on the default
|
||||
* sort predicate.
|
||||
*
|
||||
* @param string aLabel
|
||||
* The label used to identify the element.
|
||||
* @param MenuItem aItem
|
||||
* The item to get the expected index for.
|
||||
* @return number
|
||||
* The expected item index.
|
||||
*/
|
||||
_findExpectedIndex: function MC__findExpectedIndex(aLabel) {
|
||||
_findExpectedIndex: function MC__findExpectedIndex(aItem) {
|
||||
let container = this._container;
|
||||
let itemCount = this.itemCount;
|
||||
|
||||
for (let i = 0; i < itemCount; i++) {
|
||||
if (this.getItemAtIndex(i)._label > aLabel) {
|
||||
if (this._sortPredicate(this.getItemAtIndex(i), aItem) > 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -1028,7 +1132,7 @@ MenuContainer.prototype = {
|
|||
* @return MenuItem
|
||||
* The item associated with the displayed element, null if rejected.
|
||||
*/
|
||||
_insertItemAt: function MC__insertItemAt(aIndex, aItem, aOptions) {
|
||||
_insertItemAt: function MC__insertItemAt(aIndex, aItem, aOptions = {}) {
|
||||
// Relaxed nodes may be appended without verifying their eligibility.
|
||||
if (!aOptions.relaxed && !this.isEligible(aItem)) {
|
||||
return null;
|
||||
|
@ -1036,14 +1140,14 @@ MenuContainer.prototype = {
|
|||
|
||||
// Entangle the item with the newly inserted node.
|
||||
this._entangleItem(aItem, this._container.insertItemAt(aIndex,
|
||||
aOptions.node || aItem._label,
|
||||
aItem._prebuiltTarget || aItem._label, // Allow the insertion of prebuilt nodes.
|
||||
aItem._value,
|
||||
aItem._description,
|
||||
aOptions.attachment));
|
||||
aItem.attachment));
|
||||
|
||||
// Handle any additional options after entangling the item.
|
||||
if (aOptions.attributes) {
|
||||
aItem.setAttributes(aOptions.attributes, aItem.target);
|
||||
aItem.setAttributes(aOptions.attributes, aItem._target);
|
||||
}
|
||||
if (aOptions.finalize) {
|
||||
aItem.finalize = aOptions.finalize;
|
||||
|
@ -1065,7 +1169,7 @@ MenuContainer.prototype = {
|
|||
this._itemsByLabel.set(aItem._label, aItem);
|
||||
this._itemsByValue.set(aItem._value, aItem);
|
||||
this._itemsByElement.set(aElement, aItem);
|
||||
aItem.target = aElement;
|
||||
aItem._target = aElement;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1082,10 +1186,38 @@ MenuContainer.prototype = {
|
|||
aItem.remove(childItem);
|
||||
}
|
||||
|
||||
this._unlinkItem(aItem);
|
||||
aItem._prebuiltTarget = null;
|
||||
aItem._target = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes an item from the its parent's storage maps.
|
||||
*
|
||||
* @param MenuItem aItem
|
||||
* The item to forget.
|
||||
*/
|
||||
_unlinkItem: function MI__unlinkItem(aItem) {
|
||||
this._itemsByLabel.delete(aItem._label);
|
||||
this._itemsByValue.delete(aItem._value);
|
||||
this._itemsByElement.delete(aItem.target);
|
||||
aItem.target = null;
|
||||
this._itemsByElement.delete(aItem._target);
|
||||
},
|
||||
|
||||
/**
|
||||
* The predicate used when sorting items. By default, items in this view
|
||||
* are sorted by their label.
|
||||
*
|
||||
* @param MenuItem aFirst
|
||||
* The first menu item used in the comparison.
|
||||
* @param MenuItem aSecond
|
||||
* The second menu item used in the comparison.
|
||||
* @return number
|
||||
* -1 to sort aFirst to a lower index than aSecond
|
||||
* 0 to leave aFirst and aSecond unchanged with respect to each other
|
||||
* 1 to sort aSecond to a lower index than aFirst
|
||||
*/
|
||||
_sortPredicate: function MC__sortPredicate(aFirst, aSecond) {
|
||||
return +(aFirst._label.toLowerCase() > aSecond._label.toLowerCase());
|
||||
},
|
||||
|
||||
_container: null,
|
||||
|
|
|
@ -16,10 +16,6 @@
|
|||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.side-menu-widget-group[name=""] > .side-menu-widget-group-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* VariablesView */
|
||||
|
||||
.variables-view-container {
|
||||
|
|
|
@ -7,7 +7,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
|||
this.EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/gcli.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
|
||||
"resource:///modules/devtools/gDevTools.jsm");
|
||||
|
|
|
@ -23,7 +23,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
|||
* the target's document. It wraps remote debugging protocol comunications.
|
||||
*
|
||||
* It emits these events:
|
||||
* 'stylesheet-added': A stylesheet has been added to the debuggee's document
|
||||
* 'document-load': debuggee's document is loaded, style sheets are argument
|
||||
* 'stylesheets-cleared': The debuggee's stylesheets have been reset (e.g. the
|
||||
* page navigated)
|
||||
*
|
||||
|
@ -37,12 +37,12 @@ let StyleEditorDebuggee = function(target) {
|
|||
|
||||
this.clear = this.clear.bind(this);
|
||||
this._onNewDocument = this._onNewDocument.bind(this);
|
||||
this._onStyleSheetsAdded = this._onStyleSheetsAdded.bind(this);
|
||||
this._onDocumentLoad = this._onDocumentLoad.bind(this);
|
||||
|
||||
this._target = target;
|
||||
this._actor = this.target.form.styleEditorActor;
|
||||
|
||||
this.client.addListener("styleSheetsAdded", this._onStyleSheetsAdded);
|
||||
this.client.addListener("documentLoad", this._onDocumentLoad);
|
||||
this._target.on("navigate", this._onNewDocument);
|
||||
|
||||
this._onNewDocument();
|
||||
|
@ -128,18 +128,21 @@ StyleEditorDebuggee.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Handle stylesheet-added event from the target
|
||||
* Handler for document load, forward event with
|
||||
* all the stylesheets available on load.
|
||||
*
|
||||
* @param {string} type
|
||||
* Type of event
|
||||
* Event type
|
||||
* @param {object} request
|
||||
* Event details
|
||||
* Object with 'styleSheets' array of actor forms
|
||||
*/
|
||||
_onStyleSheetsAdded: function(type, request) {
|
||||
_onDocumentLoad: function(type, request) {
|
||||
let sheets = [];
|
||||
for (let form of request.styleSheets) {
|
||||
let sheet = this._addStyleSheet(form);
|
||||
this.emit("stylesheet-added", sheet);
|
||||
sheets.push(sheet);
|
||||
}
|
||||
this.emit("document-load", sheets);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -191,7 +194,6 @@ StyleEditorDebuggee.prototype = {
|
|||
destroy: function() {
|
||||
this.clear();
|
||||
|
||||
this._target.off("will-navigate", this.clear);
|
||||
this._target.off("navigate", this._onNewDocument);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,7 +110,6 @@ StyleEditorPanel.prototype = {
|
|||
if (!this._destroyed) {
|
||||
this._destroyed = true;
|
||||
|
||||
this._target.off("will-navigate", this.beforeNavigate);
|
||||
this._target.off("close", this.destroy);
|
||||
this._target = null;
|
||||
this._toolbox = null;
|
||||
|
|
|
@ -49,12 +49,12 @@ function StyleEditorUI(debuggee, panelDoc) {
|
|||
this.editors = [];
|
||||
this.selectedStyleSheetIndex = -1;
|
||||
|
||||
this._onStyleSheetAdded = this._onStyleSheetAdded.bind(this);
|
||||
this._onStyleSheetCreated = this._onStyleSheetCreated.bind(this);
|
||||
this._onStyleSheetsCleared = this._onStyleSheetsCleared.bind(this);
|
||||
this._onDocumentLoad = this._onDocumentLoad.bind(this);
|
||||
this._onError = this._onError.bind(this);
|
||||
|
||||
debuggee.on("stylesheet-added", this._onStyleSheetAdded);
|
||||
debuggee.on("document-load", this._onDocumentLoad);
|
||||
debuggee.on("stylesheets-cleared", this._onStyleSheetsCleared);
|
||||
|
||||
this.createUI();
|
||||
|
@ -156,17 +156,21 @@ StyleEditorUI.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Handler for debuggee's 'stylesheet-added' event. Add an editor.
|
||||
* Handler for debuggee's 'document-load' event. Add editors
|
||||
* for all style sheets in the document
|
||||
*
|
||||
* @param {string} event
|
||||
* Event name
|
||||
* @param {StyleSheet} styleSheet
|
||||
* StyleSheet object for new sheet
|
||||
*/
|
||||
_onStyleSheetAdded: function(event, styleSheet) {
|
||||
_onDocumentLoad: function(event, styleSheets) {
|
||||
for (let sheet of styleSheets) {
|
||||
this._addStyleSheetEditor(sheet);
|
||||
}
|
||||
// this might be the first stylesheet, so remove loading indicator
|
||||
this._root.classList.remove("loading");
|
||||
this._addStyleSheetEditor(styleSheet);
|
||||
this.emit("document-load");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -421,7 +425,7 @@ StyleEditorUI.prototype = {
|
|||
destroy: function() {
|
||||
this._clearStyleSheetEditors();
|
||||
|
||||
this._debuggee.off("stylesheet-added", this._onStyleSheetAdded);
|
||||
this._debuggee.off("document-load", this._onDocumentLoad);
|
||||
this._debuggee.off("stylesheets-cleared", this._onStyleSheetsCleared);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ _BROWSER_TEST_FILES = \
|
|||
browser_styleeditor_sv_resize.js \
|
||||
browser_styleeditor_bug_740541_iframes.js \
|
||||
browser_styleeditor_bug_851132_middle_click.js \
|
||||
browser_styleeditor_nostyle.js \
|
||||
head.js \
|
||||
helpers.js \
|
||||
four.html \
|
||||
|
@ -39,6 +40,7 @@ _BROWSER_TEST_FILES = \
|
|||
media.html \
|
||||
media-small.css \
|
||||
minified.html \
|
||||
nostyle.html \
|
||||
resources_inpage.jsi \
|
||||
resources_inpage1.css \
|
||||
resources_inpage2.css \
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TESTCASE_URI = TEST_BASE + "nostyle.html";
|
||||
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
// launch Style Editor right when the tab is created (before load)
|
||||
// this checks that the Style Editor still launches correctly when it is opened
|
||||
// *while* the page is still loading. The Style Editor should not signal that
|
||||
// it is loaded until the accompanying content page is loaded.
|
||||
|
||||
addTabAndOpenStyleEditor(function(panel) {
|
||||
panel.UI.once("document-load", testDocumentLoad);
|
||||
|
||||
content.location = TESTCASE_URI;
|
||||
});
|
||||
}
|
||||
|
||||
function testDocumentLoad(event)
|
||||
{
|
||||
let root = gPanelWindow.document.querySelector(".splitview-root");
|
||||
ok(!root.classList.contains("loading"),
|
||||
"style editor root element does not have 'loading' class name anymore");
|
||||
|
||||
ok(root.querySelector(".empty.placeholder"), "showing 'no style' indicator");
|
||||
|
||||
let button = gPanelWindow.document.querySelector(".style-editor-newButton");
|
||||
ok(!button.hasAttribute("disabled"),
|
||||
"new style sheet button is enabled");
|
||||
|
||||
button = gPanelWindow.document.querySelector(".style-editor-importButton");
|
||||
ok(!button.hasAttribute("disabled"),
|
||||
"import button is enabled");
|
||||
|
||||
finish();
|
||||
}
|
|
@ -21,11 +21,10 @@ this.EXPORTED_SYMBOLS = [ 'helpers' ];
|
|||
var helpers = {};
|
||||
this.helpers = helpers;
|
||||
let require = (Cu.import("resource://gre/modules/devtools/Require.jsm", {})).require;
|
||||
Components.utils.import("resource:///modules/devtools/gcli.jsm", {});
|
||||
Components.utils.import("resource://gre/modules/devtools/gcli.jsm", {});
|
||||
|
||||
let console = (Cu.import("resource://gre/modules/devtools/Console.jsm", {})).console;
|
||||
let devtools = (Cu.import("resource:///modules/devtools/gDevTools.jsm", {})).devtools;
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let TargetFactory = (Cu.import("resource:///modules/devtools/gDevTools.jsm", {})).devtools.TargetFactory;
|
||||
|
||||
let Promise = (Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {})).Promise;
|
||||
let assert = { ok: ok, is: is, log: info };
|
||||
|
@ -158,6 +157,7 @@ helpers.runTests = function(options, tests) {
|
|||
});
|
||||
|
||||
var recover = function(error) {
|
||||
ok(false, error);
|
||||
console.error(error);
|
||||
};
|
||||
|
||||
|
@ -341,7 +341,7 @@ helpers._createDebugCheck = function(options) {
|
|||
output += ' current: \'' + helpers._actual.current(options) + '\',\n';
|
||||
output += ' status: \'' + helpers._actual.status(options) + '\',\n';
|
||||
output += ' options: ' + outputArray(helpers._actual.options(options)) + ',\n';
|
||||
output += ' error: \'' + helpers._actual.message(options) + '\',\n';
|
||||
output += ' message: \'' + helpers._actual.message(options) + '\',\n';
|
||||
output += ' predictions: ' + outputArray(predictions) + ',\n';
|
||||
output += ' unassigned: ' + outputArray(requisition._unassigned) + ',\n';
|
||||
output += ' outputState: \'' + helpers._actual.outputState(options) + '\',\n';
|
||||
|
@ -378,6 +378,8 @@ helpers._createDebugCheck = function(options) {
|
|||
output += ' exec: {\n';
|
||||
output += ' output: \'\',\n';
|
||||
output += ' completed: true,\n';
|
||||
output += ' type: \'string\',\n';
|
||||
output += ' error: false\n';
|
||||
output += ' }\n';
|
||||
output += ' }\n';
|
||||
output += ']);';
|
||||
|
@ -702,7 +704,7 @@ helpers._check = function(options, name, checks) {
|
|||
*/
|
||||
helpers._exec = function(options, name, expected) {
|
||||
if (expected == null) {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
var output = options.display.requisition.exec({ hidden: true });
|
||||
|
@ -715,20 +717,32 @@ helpers._exec = function(options, name, expected) {
|
|||
|
||||
if (!options.window.document.createElement) {
|
||||
assert.log('skipping output tests (missing doc.createElement) for ' + name);
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({ output: output });
|
||||
}
|
||||
|
||||
if (!('output' in expected)) {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({ output: output });
|
||||
}
|
||||
|
||||
var deferred = Promise.defer();
|
||||
|
||||
var checkOutput = function() {
|
||||
var div = options.window.document.createElement('div');
|
||||
var nodePromise = converters.convert(output.data, output.type, 'dom',
|
||||
options.display.requisition.context);
|
||||
nodePromise.then(function(node) {
|
||||
var conversionContext = options.display.requisition.conversionContext;
|
||||
|
||||
if ('type' in expected) {
|
||||
assert.is(output.type,
|
||||
expected.type,
|
||||
'output.type for: ' + name);
|
||||
}
|
||||
|
||||
if ('error' in expected) {
|
||||
assert.is(output.error,
|
||||
expected.error,
|
||||
'output.error for: ' + name);
|
||||
}
|
||||
|
||||
var convertPromise = converters.convert(output.data, output.type, 'dom',
|
||||
conversionContext);
|
||||
return convertPromise.then(function(node) {
|
||||
div.appendChild(node);
|
||||
var actualOutput = div.textContent.trim();
|
||||
|
||||
|
@ -757,24 +771,11 @@ helpers._exec = function(options, name, expected) {
|
|||
doTest(expected.output, actualOutput);
|
||||
}
|
||||
|
||||
deferred.resolve(actualOutput);
|
||||
return { output: output, text: actualOutput };
|
||||
});
|
||||
};
|
||||
|
||||
if (output.completed !== false) {
|
||||
checkOutput();
|
||||
}
|
||||
else {
|
||||
var changed = function() {
|
||||
if (output.completed !== false) {
|
||||
checkOutput();
|
||||
output.onChange.remove(changed);
|
||||
}
|
||||
};
|
||||
output.onChange.add(changed);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return output.promise.then(checkOutput, checkOutput);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -789,15 +790,15 @@ helpers._setup = function(options, name, action) {
|
|||
return Promise.resolve(action());
|
||||
}
|
||||
|
||||
return Promise.reject('setup must be a string or a function');
|
||||
return Promise.reject('\'setup\' property must be a string or a function. Is ' + action);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to shutdown the test
|
||||
*/
|
||||
helpers._post = function(name, action, output) {
|
||||
helpers._post = function(name, action, data) {
|
||||
if (typeof action === 'function') {
|
||||
return Promise.resolve(action(output));
|
||||
return Promise.resolve(action(data.output, data.text));
|
||||
}
|
||||
return Promise.resolve(action);
|
||||
};
|
||||
|
@ -943,6 +944,8 @@ helpers.audit = function(options, audits) {
|
|||
if (typeof chunkLen !== 'number') {
|
||||
chunkLen = 1;
|
||||
}
|
||||
|
||||
if (assert.currentTest) {
|
||||
var responseTime = (new Date().getTime() - start) / chunkLen;
|
||||
totalResponseTime += responseTime;
|
||||
if (responseTime > maxResponseTime) {
|
||||
|
@ -950,12 +953,13 @@ helpers.audit = function(options, audits) {
|
|||
maxResponseCulprit = assert.currentTest + '/' + name;
|
||||
}
|
||||
averageOver++;
|
||||
}
|
||||
|
||||
var checkDone = helpers._check(options, name, audit.check);
|
||||
return checkDone.then(function() {
|
||||
var execDone = helpers._exec(options, name, audit.exec);
|
||||
return execDone.then(function(output) {
|
||||
return helpers._post(name, audit.post, output).then(function() {
|
||||
return execDone.then(function(data) {
|
||||
return helpers._post(name, audit.post, data).then(function() {
|
||||
if (assert.testLogging) {
|
||||
log('- END \'' + name + '\' in ' + assert.currentTest);
|
||||
}
|
||||
|
@ -963,9 +967,8 @@ helpers.audit = function(options, audits) {
|
|||
});
|
||||
});
|
||||
});
|
||||
}).then(null, function(ex) {
|
||||
console.error(ex.stack);
|
||||
throw(ex);
|
||||
}).then(function() {
|
||||
return options.display.inputter.setInput('');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<html>
|
||||
<div>
|
||||
Page with no stylesheets
|
||||
</div>
|
||||
</html>
|
|
@ -12,7 +12,7 @@ let {CssLogic} = require("devtools/styleinspector/css-logic");
|
|||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/PluralForm.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/devtools/Templater.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/Templater.jsm");
|
||||
|
||||
Cu.import("resource:///modules/devtools/gDevTools.jsm");
|
||||
|
||||
|
|
|
@ -941,8 +941,8 @@ CssRuleView.prototype = {
|
|||
*/
|
||||
nodeChanged: function CssRuleView_nodeChanged()
|
||||
{
|
||||
// Ignore refreshes during editing.
|
||||
if (this.isEditing) {
|
||||
// Ignore refreshes during editing or when no element is selected.
|
||||
if (this.isEditing || !this._elementStyle) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1324,6 +1324,7 @@ function TextPropertyEditor(aRuleEditor, aProperty)
|
|||
this.doc = aRuleEditor.doc;
|
||||
this.prop = aProperty;
|
||||
this.prop.editor = this;
|
||||
this.browserWindow = this.doc.defaultView.top;
|
||||
|
||||
let sheet = this.prop.rule.sheet;
|
||||
let href = sheet ? CssLogic.href(sheet) : null;
|
||||
|
@ -1520,9 +1521,14 @@ TextPropertyEditor.prototype = {
|
|||
href: this.resolveURI(resourceURI)
|
||||
});
|
||||
|
||||
a.addEventListener("click", function(aEvent) {
|
||||
a.addEventListener("click", (aEvent) => {
|
||||
|
||||
// Clicks within the link shouldn't trigger editing.
|
||||
aEvent.stopPropagation();
|
||||
aEvent.preventDefault();
|
||||
|
||||
this.browserWindow.openUILinkIn(aEvent.target.href, "tab");
|
||||
|
||||
}, false);
|
||||
|
||||
appendText(this.valueSpan, val.split(resourceURI)[1]);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
this.EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Components.utils.import("resource:///modules/devtools/gcli.jsm");
|
||||
Components.utils.import("resource://gre/modules/devtools/gcli.jsm");
|
||||
Components.utils.import("resource:///modules/devtools/gDevTools.jsm");
|
||||
|
||||
// Fetch TiltManager using the current loader, but don't save a
|
||||
|
|
|
@ -11,7 +11,6 @@ include $(DEPTH)/config/autoconf.mk
|
|||
|
||||
EXTRA_JS_MODULES = \
|
||||
HUDService.jsm \
|
||||
PropertyPanel.jsm \
|
||||
NetworkPanel.jsm \
|
||||
WebConsolePanel.jsm \
|
||||
$(NULL)
|
||||
|
|
|
@ -1,501 +0,0 @@
|
|||
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
|
||||
/* vim: set ft=javascript 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
|
||||
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["PropertyPanel", "PropertyTreeView"];
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// PropertyTreeView.
|
||||
|
||||
/**
|
||||
* This is an implementation of the nsITreeView interface. For comments on the
|
||||
* interface properties, see the documentation:
|
||||
* https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsITreeView
|
||||
*/
|
||||
this.PropertyTreeView = function() {
|
||||
this._rows = [];
|
||||
this._objectActors = [];
|
||||
};
|
||||
|
||||
PropertyTreeView.prototype = {
|
||||
/**
|
||||
* Stores the visible rows of the tree.
|
||||
* @private
|
||||
*/
|
||||
_rows: null,
|
||||
|
||||
/**
|
||||
* Stores the nsITreeBoxObject for this tree.
|
||||
* @private
|
||||
*/
|
||||
_treeBox: null,
|
||||
|
||||
/**
|
||||
* Track known object actor IDs. We clean these when the panel is
|
||||
* destroyed/cleaned up.
|
||||
*
|
||||
* @private
|
||||
* @type array
|
||||
*/
|
||||
_objectActors: null,
|
||||
|
||||
/**
|
||||
* Map fake object actors to their IDs. This is used when we inspect local
|
||||
* objects.
|
||||
* @private
|
||||
* @type Object
|
||||
*/
|
||||
_localObjectActors: null,
|
||||
|
||||
_releaseObject: null,
|
||||
_objectPropertiesProvider: null,
|
||||
|
||||
/**
|
||||
* Use this setter to update the content of the tree.
|
||||
*
|
||||
* @param object aData
|
||||
* A meta object that holds information about the object you want to
|
||||
* display in the property panel. Object properties:
|
||||
* - object:
|
||||
* This is the raw object you want to display. You can only provide
|
||||
* this object if you want the property panel to work in sync mode.
|
||||
* - objectProperties:
|
||||
* An array that holds information on the remote object being
|
||||
* inspected. Each element in this array describes each property in the
|
||||
* remote object. See WebConsoleUtils.inspectObject() for details.
|
||||
* - objectPropertiesProvider:
|
||||
* A function that is invoked when a new object is needed. This is
|
||||
* called when the user tries to expand an inspectable property. The
|
||||
* callback must take four arguments:
|
||||
* - actorID:
|
||||
* The object actor ID from which we request the properties.
|
||||
* - callback:
|
||||
* The callback function to be invoked when the remote object is
|
||||
* received. This function takes one argument: the array of
|
||||
* descriptors for each property in the object represented by the
|
||||
* actor.
|
||||
* - releaseObject:
|
||||
* Function to invoke when an object actor should be released. The
|
||||
* function must take one argument: the object actor ID.
|
||||
*/
|
||||
set data(aData) {
|
||||
let oldLen = this._rows.length;
|
||||
|
||||
this.cleanup();
|
||||
|
||||
if (!aData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aData.objectPropertiesProvider) {
|
||||
this._objectPropertiesProvider = aData.objectPropertiesProvider;
|
||||
this._releaseObject = aData.releaseObject;
|
||||
this._propertiesToRows(aData.objectProperties, 0);
|
||||
this._rows = aData.objectProperties;
|
||||
}
|
||||
else if (aData.object) {
|
||||
this._localObjectActors = Object.create(null);
|
||||
this._rows = this._inspectObject(aData.object);
|
||||
}
|
||||
else {
|
||||
throw new Error("First argument must have an objectActor or an " +
|
||||
"object property!");
|
||||
}
|
||||
|
||||
if (this._treeBox) {
|
||||
this._treeBox.beginUpdateBatch();
|
||||
if (oldLen) {
|
||||
this._treeBox.rowCountChanged(0, -oldLen);
|
||||
}
|
||||
this._treeBox.rowCountChanged(0, this._rows.length);
|
||||
this._treeBox.endUpdateBatch();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update a remote object so it can be used with the tree view. This method
|
||||
* adds properties to each array element.
|
||||
*
|
||||
* @private
|
||||
* @param array aObject
|
||||
* The remote object you want prepared for use with the tree view.
|
||||
* @param number aLevel
|
||||
* The level you want to give to each property in the remote object.
|
||||
*/
|
||||
_propertiesToRows: function PTV__propertiesToRows(aObject, aLevel)
|
||||
{
|
||||
aObject.forEach(function(aItem) {
|
||||
aItem._level = aLevel;
|
||||
aItem._open = false;
|
||||
aItem._children = null;
|
||||
|
||||
if (this._releaseObject) {
|
||||
["value", "get", "set"].forEach(function(aProp) {
|
||||
let val = aItem[aProp];
|
||||
if (val && val.actor) {
|
||||
this._objectActors.push(val.actor);
|
||||
if (typeof val.displayString == "object" &&
|
||||
val.displayString.type == "longString") {
|
||||
this._objectActors.push(val.displayString.actor);
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Inspect a local object.
|
||||
*
|
||||
* @private
|
||||
* @param object aObject
|
||||
* The object you want to inspect.
|
||||
* @return array
|
||||
* The array of properties, each being described in a way that is
|
||||
* usable by the tree view.
|
||||
*/
|
||||
_inspectObject: function PTV__inspectObject(aObject)
|
||||
{
|
||||
this._objectPropertiesProvider = this._localPropertiesProvider.bind(this);
|
||||
let children =
|
||||
WebConsoleUtils.inspectObject(aObject, this._localObjectGrip.bind(this));
|
||||
this._propertiesToRows(children, 0);
|
||||
return children;
|
||||
},
|
||||
|
||||
/**
|
||||
* Make a local fake object actor for the given object.
|
||||
*
|
||||
* @private
|
||||
* @param object aObject
|
||||
* The object to make an actor for.
|
||||
* @return object
|
||||
* The fake actor grip that represents the given object.
|
||||
*/
|
||||
_localObjectGrip: function PTV__localObjectGrip(aObject)
|
||||
{
|
||||
let grip = WebConsoleUtils.getObjectGrip(aObject);
|
||||
grip.actor = "obj" + gSequenceId();
|
||||
this._localObjectActors[grip.actor] = aObject;
|
||||
return grip;
|
||||
},
|
||||
|
||||
/**
|
||||
* A properties provider for when the user inspects local objects (not remote
|
||||
* ones).
|
||||
*
|
||||
* @private
|
||||
* @param string aActor
|
||||
* The ID of the object actor you want.
|
||||
* @param function aCallback
|
||||
* The function you want to receive the list of properties.
|
||||
*/
|
||||
_localPropertiesProvider:
|
||||
function PTV__localPropertiesProvider(aActor, aCallback)
|
||||
{
|
||||
let object = this._localObjectActors[aActor];
|
||||
let properties =
|
||||
WebConsoleUtils.inspectObject(object, this._localObjectGrip.bind(this));
|
||||
aCallback(properties);
|
||||
},
|
||||
|
||||
/** nsITreeView interface implementation **/
|
||||
|
||||
selection: null,
|
||||
|
||||
get rowCount() { return this._rows.length; },
|
||||
setTree: function(treeBox) { this._treeBox = treeBox; },
|
||||
getCellText: function PTV_getCellText(idx, column)
|
||||
{
|
||||
let row = this._rows[idx];
|
||||
return row.name + ": " + WebConsoleUtils.getPropertyPanelValue(row);
|
||||
},
|
||||
getLevel: function(idx) {
|
||||
return this._rows[idx]._level;
|
||||
},
|
||||
isContainer: function(idx) {
|
||||
return typeof this._rows[idx].value == "object" && this._rows[idx].value &&
|
||||
this._rows[idx].value.inspectable;
|
||||
},
|
||||
isContainerOpen: function(idx) {
|
||||
return this._rows[idx]._open;
|
||||
},
|
||||
isContainerEmpty: function(idx) { return false; },
|
||||
isSeparator: function(idx) { return false; },
|
||||
isSorted: function() { return false; },
|
||||
isEditable: function(idx, column) { return false; },
|
||||
isSelectable: function(row, col) { return true; },
|
||||
|
||||
getParentIndex: function(idx)
|
||||
{
|
||||
if (this.getLevel(idx) == 0) {
|
||||
return -1;
|
||||
}
|
||||
for (var t = idx - 1; t >= 0; t--) {
|
||||
if (this.isContainer(t)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
|
||||
hasNextSibling: function(idx, after)
|
||||
{
|
||||
let thisLevel = this.getLevel(idx);
|
||||
return this._rows.slice(after + 1).some(function (r) r._level == thisLevel);
|
||||
},
|
||||
|
||||
toggleOpenState: function(idx)
|
||||
{
|
||||
let item = this._rows[idx];
|
||||
if (!this.isContainer(idx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item._open) {
|
||||
this._treeBox.beginUpdateBatch();
|
||||
item._open = false;
|
||||
|
||||
var thisLevel = item._level;
|
||||
var t = idx + 1, deleteCount = 0;
|
||||
while (t < this._rows.length && this.getLevel(t++) > thisLevel) {
|
||||
deleteCount++;
|
||||
}
|
||||
|
||||
if (deleteCount) {
|
||||
this._rows.splice(idx + 1, deleteCount);
|
||||
this._treeBox.rowCountChanged(idx + 1, -deleteCount);
|
||||
}
|
||||
this._treeBox.invalidateRow(idx);
|
||||
this._treeBox.endUpdateBatch();
|
||||
}
|
||||
else {
|
||||
let levelUpdate = true;
|
||||
let callback = function _onRemoteResponse(aProperties) {
|
||||
this._treeBox.beginUpdateBatch();
|
||||
if (levelUpdate) {
|
||||
this._propertiesToRows(aProperties, item._level + 1);
|
||||
item._children = aProperties;
|
||||
}
|
||||
|
||||
this._rows.splice.apply(this._rows, [idx + 1, 0].concat(item._children));
|
||||
|
||||
this._treeBox.rowCountChanged(idx + 1, item._children.length);
|
||||
this._treeBox.invalidateRow(idx);
|
||||
this._treeBox.endUpdateBatch();
|
||||
item._open = true;
|
||||
}.bind(this);
|
||||
|
||||
if (!item._children) {
|
||||
this._objectPropertiesProvider(item.value.actor, callback);
|
||||
}
|
||||
else {
|
||||
levelUpdate = false;
|
||||
callback(item._children);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getImageSrc: function(idx, column) { },
|
||||
getProgressMode : function(idx,column) { },
|
||||
getCellValue: function(idx, column) { },
|
||||
cycleHeader: function(col, elem) { },
|
||||
selectionChanged: function() { },
|
||||
cycleCell: function(idx, column) { },
|
||||
performAction: function(action) { },
|
||||
performActionOnCell: function(action, index, column) { },
|
||||
performActionOnRow: function(action, row) { },
|
||||
getRowProperties: function(idx) { return ""; },
|
||||
getCellProperties: function(idx, column) { return ""; },
|
||||
getColumnProperties: function(column, element) { return ""; },
|
||||
|
||||
setCellValue: function(row, col, value) { },
|
||||
setCellText: function(row, col, value) { },
|
||||
drop: function(index, orientation, dataTransfer) { },
|
||||
canDrop: function(index, orientation, dataTransfer) { return false; },
|
||||
|
||||
/**
|
||||
* Cleanup the property tree view.
|
||||
*/
|
||||
cleanup: function PTV_cleanup()
|
||||
{
|
||||
if (this._releaseObject) {
|
||||
this._objectActors.forEach(this._releaseObject);
|
||||
delete this._objectPropertiesProvider;
|
||||
delete this._releaseObject;
|
||||
}
|
||||
if (this._localObjectActors) {
|
||||
delete this._localObjectActors;
|
||||
delete this._objectPropertiesProvider;
|
||||
}
|
||||
|
||||
this._rows = [];
|
||||
this._objectActors = [];
|
||||
},
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// Helper for creating the panel.
|
||||
|
||||
/**
|
||||
* Creates a DOMNode and sets all the attributes of aAttributes on the created
|
||||
* element.
|
||||
*
|
||||
* @param nsIDOMDocument aDocument
|
||||
* Document to create the new DOMNode.
|
||||
* @param string aTag
|
||||
* Name of the tag for the DOMNode.
|
||||
* @param object aAttributes
|
||||
* Attributes set on the created DOMNode.
|
||||
* @returns nsIDOMNode
|
||||
*/
|
||||
function createElement(aDocument, aTag, aAttributes)
|
||||
{
|
||||
let node = aDocument.createElement(aTag);
|
||||
for (var attr in aAttributes) {
|
||||
node.setAttribute(attr, aAttributes[attr]);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DOMNode and appends it to aParent.
|
||||
*
|
||||
* @param nsIDOMDocument aDocument
|
||||
* Document to create the new DOMNode.
|
||||
* @param nsIDOMNode aParent
|
||||
* A parent node to append the created element.
|
||||
* @param string aTag
|
||||
* Name of the tag for the DOMNode.
|
||||
* @param object aAttributes
|
||||
* Attributes set on the created DOMNode.
|
||||
* @returns nsIDOMNode
|
||||
*/
|
||||
function appendChild(aDocument, aParent, aTag, aAttributes)
|
||||
{
|
||||
let node = createElement(aDocument, aTag, aAttributes);
|
||||
aParent.appendChild(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// PropertyPanel
|
||||
|
||||
/**
|
||||
* Creates a new PropertyPanel.
|
||||
*
|
||||
* @see PropertyTreeView
|
||||
* @param nsIDOMNode aParent
|
||||
* Parent node to append the created panel to.
|
||||
* @param string aTitle
|
||||
* Title for the panel.
|
||||
* @param string aObject
|
||||
* Object to display in the tree. For details about this object please
|
||||
* see the PropertyTreeView constructor in this file.
|
||||
* @param array of objects aButtons
|
||||
* Array with buttons to display at the bottom of the panel.
|
||||
*/
|
||||
this.PropertyPanel = function PropertyPanel(aParent, aTitle, aObject, aButtons)
|
||||
{
|
||||
let document = aParent.ownerDocument;
|
||||
|
||||
// Create the underlying panel
|
||||
this.panel = createElement(document, "panel", {
|
||||
label: aTitle,
|
||||
titlebar: "normal",
|
||||
noautofocus: "true",
|
||||
noautohide: "true",
|
||||
close: "true",
|
||||
});
|
||||
|
||||
// Create the tree.
|
||||
let tree = this.tree = createElement(document, "tree", {
|
||||
flex: 1,
|
||||
hidecolumnpicker: "true"
|
||||
});
|
||||
|
||||
let treecols = document.createElement("treecols");
|
||||
appendChild(document, treecols, "treecol", {
|
||||
primary: "true",
|
||||
flex: 1,
|
||||
hideheader: "true",
|
||||
ignoreincolumnpicker: "true"
|
||||
});
|
||||
tree.appendChild(treecols);
|
||||
|
||||
tree.appendChild(document.createElement("treechildren"));
|
||||
this.panel.appendChild(tree);
|
||||
|
||||
// Create the footer.
|
||||
let footer = createElement(document, "hbox", { align: "end" });
|
||||
appendChild(document, footer, "spacer", { flex: 1 });
|
||||
|
||||
// The footer can have butttons.
|
||||
let self = this;
|
||||
if (aButtons) {
|
||||
aButtons.forEach(function(button) {
|
||||
let buttonNode = appendChild(document, footer, "button", {
|
||||
label: button.label,
|
||||
accesskey: button.accesskey || "",
|
||||
class: button.class || "",
|
||||
});
|
||||
buttonNode.addEventListener("command", button.oncommand, false);
|
||||
});
|
||||
}
|
||||
|
||||
appendChild(document, footer, "resizer", { dir: "bottomend" });
|
||||
this.panel.appendChild(footer);
|
||||
|
||||
aParent.appendChild(this.panel);
|
||||
|
||||
// Create the treeView object.
|
||||
this.treeView = new PropertyTreeView();
|
||||
this.treeView.data = aObject;
|
||||
|
||||
// Set the treeView object on the tree view. This has to be done *after* the
|
||||
// panel is shown. This is because the tree binding must be attached first.
|
||||
this.panel.addEventListener("popupshown", function onPopupShow()
|
||||
{
|
||||
self.panel.removeEventListener("popupshown", onPopupShow, false);
|
||||
self.tree.view = self.treeView;
|
||||
}, false);
|
||||
|
||||
this.panel.addEventListener("popuphidden", function onPopupHide()
|
||||
{
|
||||
self.panel.removeEventListener("popuphidden", onPopupHide, false);
|
||||
self.destroy();
|
||||
}, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the PropertyPanel. This closes the panel and removes it from the
|
||||
* browser DOM.
|
||||
*/
|
||||
PropertyPanel.prototype.destroy = function PP_destroy()
|
||||
{
|
||||
this.treeView.data = null;
|
||||
this.panel.parentNode.removeChild(this.panel);
|
||||
this.treeView = null;
|
||||
this.panel = null;
|
||||
this.tree = null;
|
||||
}
|
||||
|
||||
|
||||
function gSequenceId()
|
||||
{
|
||||
return gSequenceId.n++;
|
||||
}
|
||||
gSequenceId.n = 0;
|
|
@ -125,6 +125,10 @@ MOCHITEST_BROWSER_FILES = \
|
|||
browser_webconsole_bug_837351_securityerrors.js \
|
||||
browser_bug_865871_variables_view_close_on_esc_key.js \
|
||||
browser_bug_865288_repeat_different_objects.js \
|
||||
browser_jsterm_inspect.js \
|
||||
browser_bug_869003_inspect_cross_domain_object.js \
|
||||
browser_bug_862916_console_dir_and_filter_off.js \
|
||||
browser_console_native_getters.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
|
@ -228,6 +232,8 @@ MOCHITEST_BROWSER_FILES += \
|
|||
test-eval-in-stackframe.html \
|
||||
test-bug-859170-longstring-hang.html \
|
||||
test-bug-837351-security-errors.html \
|
||||
test-bug-869003-top-window.html \
|
||||
test-bug-869003-iframe.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Check that the output for console.dir() works even if Logging filter is off.
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8,<p>test for bug 862916";
|
||||
|
||||
function test()
|
||||
{
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
openConsole(null, consoleOpened);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function consoleOpened(hud)
|
||||
{
|
||||
ok(hud, "web console opened");
|
||||
|
||||
hud.setFilterState("log", false);
|
||||
registerCleanupFunction(() => hud.setFilterState("log", true));
|
||||
|
||||
content.wrappedJSObject.fooBarz = "bug862916";
|
||||
hud.jsterm.execute("console.dir(window)");
|
||||
hud.jsterm.once("variablesview-fetched", (aEvent, aVar) => {
|
||||
ok(aVar, "variables view object");
|
||||
findVariableViewProperties(aVar, [
|
||||
{ name: "fooBarz", value: "bug862916" },
|
||||
], { webconsole: hud }).then(finishTest);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Check that users can inspect objects logged from cross-domain iframes -
|
||||
// bug 869003.
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-869003-top-window.html";
|
||||
|
||||
let gWebConsole, gJSTerm, gVariablesView;
|
||||
|
||||
function test()
|
||||
{
|
||||
addTab("data:text/html;charset=utf8,<p>hello");
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
openConsole(null, consoleOpened);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function consoleOpened(hud)
|
||||
{
|
||||
gWebConsole = hud;
|
||||
gJSTerm = hud.jsterm;
|
||||
content.location = TEST_URI;
|
||||
|
||||
waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
name: "console.log message",
|
||||
text: "foobar",
|
||||
category: CATEGORY_WEBDEV,
|
||||
severity: SEVERITY_LOG,
|
||||
objects: true,
|
||||
}],
|
||||
}).then(onConsoleMessage);
|
||||
}
|
||||
|
||||
function onConsoleMessage(aResults)
|
||||
{
|
||||
let clickable = aResults[0].clickableElements[0];
|
||||
ok(clickable, "clickable object found");
|
||||
isnot(clickable.textContent.indexOf("[object Object]"), -1,
|
||||
"message text check");
|
||||
|
||||
gJSTerm.once("variablesview-fetched", onObjFetch);
|
||||
|
||||
EventUtils.synthesizeMouse(clickable, 2, 2, {}, gWebConsole.iframeWindow)
|
||||
}
|
||||
|
||||
function onObjFetch(aEvent, aVar)
|
||||
{
|
||||
gVariablesView = aVar._variablesView;
|
||||
ok(gVariablesView, "variables view object");
|
||||
|
||||
findVariableViewProperties(aVar, [
|
||||
{ name: "hello", value: "world!" },
|
||||
{ name: "bug", value: 869003 },
|
||||
], { webconsole: gWebConsole }).then(onPropFound);
|
||||
}
|
||||
|
||||
function onPropFound(aResults)
|
||||
{
|
||||
let prop = aResults[0].matchedProp;
|
||||
ok(prop, "matched the |hello| property in the variables view");
|
||||
|
||||
// Check that property value updates work.
|
||||
updateVariablesViewProperty({
|
||||
property: prop,
|
||||
field: "value",
|
||||
string: "'omgtest'",
|
||||
webconsole: gWebConsole,
|
||||
callback: onFetchAfterUpdate,
|
||||
});
|
||||
}
|
||||
|
||||
function onFetchAfterUpdate(aEvent, aVar)
|
||||
{
|
||||
info("onFetchAfterUpdate");
|
||||
|
||||
findVariableViewProperties(aVar, [
|
||||
{ name: "hello", value: "omgtest" },
|
||||
{ name: "bug", value: 869003 },
|
||||
], { webconsole: gWebConsole }).then(() => {
|
||||
gWebConsole = gJSTerm = gVariablesView = null;
|
||||
finishTest();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Check that native getters and setters for DOM elements work as expected in
|
||||
// variables view - bug 870220.
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8,<title>bug870220</title>\n" +
|
||||
"<p>hello world\n<p>native getters!";
|
||||
|
||||
let gWebConsole, gJSTerm, gVariablesView;
|
||||
|
||||
function test()
|
||||
{
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
openConsole(null, consoleOpened);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function consoleOpened(hud)
|
||||
{
|
||||
gWebConsole = hud;
|
||||
gJSTerm = hud.jsterm;
|
||||
|
||||
gJSTerm.execute("document");
|
||||
|
||||
waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
text: "[object HTMLDocument]",
|
||||
category: CATEGORY_OUTPUT,
|
||||
objects: true,
|
||||
}],
|
||||
}).then(onEvalResult);
|
||||
}
|
||||
|
||||
function onEvalResult(aResults)
|
||||
{
|
||||
let clickable = aResults[0].clickableElements[0];
|
||||
ok(clickable, "clickable object found");
|
||||
|
||||
gJSTerm.once("variablesview-fetched", onDocumentFetch);
|
||||
EventUtils.synthesizeMouse(clickable, 2, 2, {}, gWebConsole.iframeWindow)
|
||||
}
|
||||
|
||||
function onDocumentFetch(aEvent, aVar)
|
||||
{
|
||||
gVariablesView = aVar._variablesView;
|
||||
ok(gVariablesView, "variables view object");
|
||||
|
||||
findVariableViewProperties(aVar, [
|
||||
{ name: "title", value: "bug870220" },
|
||||
{ name: "bgColor" },
|
||||
], { webconsole: gWebConsole }).then(onDocumentPropsFound);
|
||||
}
|
||||
|
||||
function onDocumentPropsFound(aResults)
|
||||
{
|
||||
let prop = aResults[1].matchedProp;
|
||||
ok(prop, "matched the |bgColor| property in the variables view");
|
||||
|
||||
// Check that property value updates work.
|
||||
updateVariablesViewProperty({
|
||||
property: prop,
|
||||
field: "value",
|
||||
string: "'red'",
|
||||
webconsole: gWebConsole,
|
||||
callback: onFetchAfterBackgroundUpdate,
|
||||
});
|
||||
}
|
||||
|
||||
function onFetchAfterBackgroundUpdate(aEvent, aVar)
|
||||
{
|
||||
info("onFetchAfterBackgroundUpdate");
|
||||
|
||||
is(content.document.bgColor, "red", "document background color changed");
|
||||
|
||||
findVariableViewProperties(aVar, [
|
||||
{ name: "bgColor", value: "red" },
|
||||
], { webconsole: gWebConsole }).then(testParagraphs);
|
||||
}
|
||||
|
||||
function testParagraphs()
|
||||
{
|
||||
gJSTerm.execute("$$('p')");
|
||||
|
||||
waitForMessages({
|
||||
webconsole: gWebConsole,
|
||||
messages: [{
|
||||
text: "[object NodeList]",
|
||||
category: CATEGORY_OUTPUT,
|
||||
objects: true,
|
||||
}],
|
||||
}).then(onEvalNodeList);
|
||||
}
|
||||
|
||||
function onEvalNodeList(aResults)
|
||||
{
|
||||
let clickable = aResults[0].clickableElements[0];
|
||||
ok(clickable, "clickable object found");
|
||||
|
||||
gJSTerm.once("variablesview-fetched", onNodeListFetch);
|
||||
EventUtils.synthesizeMouse(clickable, 2, 2, {}, gWebConsole.iframeWindow)
|
||||
}
|
||||
|
||||
function onNodeListFetch(aEvent, aVar)
|
||||
{
|
||||
gVariablesView = aVar._variablesView;
|
||||
ok(gVariablesView, "variables view object");
|
||||
|
||||
findVariableViewProperties(aVar, [
|
||||
{ name: "0.textContent", value: /hello world/ },
|
||||
{ name: "1.textContent", value: /native getters/ },
|
||||
], { webconsole: gWebConsole }).then(() => {
|
||||
gWebConsole = gJSTerm = gVariablesView = null;
|
||||
finishTest();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Check that the inspect() jsterm helper function works.
|
||||
|
||||
function test()
|
||||
{
|
||||
const TEST_URI = "data:text/html;charset=utf8,<p>hello bug 869981";
|
||||
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
openConsole(null, consoleOpened);
|
||||
}, true);
|
||||
|
||||
function consoleOpened(hud)
|
||||
{
|
||||
content.wrappedJSObject.testProp = "testValue";
|
||||
|
||||
hud.jsterm.once("variablesview-fetched", onObjFetch);
|
||||
hud.jsterm.execute("inspect(window)");
|
||||
}
|
||||
|
||||
function onObjFetch(aEvent, aVar)
|
||||
{
|
||||
ok(aVar._variablesView, "variables view object");
|
||||
|
||||
findVariableViewProperties(aVar, [
|
||||
{ name: "testProp", value: "testValue" },
|
||||
{ name: "document", value: "[object HTMLDocument]" },
|
||||
], { webconsole: hud }).then(finishTest);
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ let initialString = longString.substring(0,
|
|||
tempScope.DebuggerServer.LONG_STRING_INITIAL_LENGTH);
|
||||
|
||||
let inputValues = [
|
||||
// [showsPropertyPanel?, input value, expected output format,
|
||||
// [showsVariablesView?, input value, expected output format,
|
||||
// print() output, console API output, optional console API test]
|
||||
|
||||
// 0
|
||||
|
@ -132,7 +132,7 @@ function testNext() {
|
|||
function testGen() {
|
||||
let cpos = pos;
|
||||
|
||||
let showsPropertyPanel = inputValues[cpos][0];
|
||||
let showsVariablesView = inputValues[cpos][0];
|
||||
let inputValue = inputValues[cpos][1];
|
||||
let expectedOutput = inputValues[cpos][2];
|
||||
|
||||
|
@ -224,35 +224,35 @@ function testGen() {
|
|||
// Test click on output.
|
||||
let eventHandlerID = eventHandlers.length + 1;
|
||||
|
||||
let propertyPanelShown = function(aEvent, aView, aOptions) {
|
||||
let variablesViewShown = function(aEvent, aView, aOptions) {
|
||||
if (aOptions.label.indexOf(expectedOutput) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
HUD.jsterm.off("variablesview-open", propertyPanelShown);
|
||||
HUD.jsterm.off("variablesview-open", variablesViewShown);
|
||||
|
||||
eventHandlers[eventHandlerID] = null;
|
||||
|
||||
ok(showsPropertyPanel,
|
||||
"the property panel shown for inputValues[" + cpos + "]");
|
||||
ok(showsVariablesView,
|
||||
"the variables view shown for inputValues[" + cpos + "]");
|
||||
|
||||
popupShown[cpos] = true;
|
||||
|
||||
if (showsPropertyPanel) {
|
||||
if (showsVariablesView) {
|
||||
executeSoon(subtestNext);
|
||||
}
|
||||
};
|
||||
|
||||
HUD.jsterm.on("variablesview-open", propertyPanelShown);
|
||||
HUD.jsterm.on("variablesview-open", variablesViewShown);
|
||||
|
||||
eventHandlers.push(propertyPanelShown);
|
||||
eventHandlers.push(variablesViewShown);
|
||||
|
||||
// Send the mousedown, mouseup and click events to check if the property
|
||||
// panel opens.
|
||||
// Send the mousedown, mouseup and click events to check if the variables
|
||||
// view opens.
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, messageBody, window);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, messageBody, window);
|
||||
|
||||
if (showsPropertyPanel) {
|
||||
if (showsVariablesView) {
|
||||
yield; // wait for the panel to open if we need to.
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,7 @@ function testEnd() {
|
|||
|
||||
for (let i = 0; i < inputValues.length; i++) {
|
||||
if (inputValues[i][0] && !popupShown[i]) {
|
||||
ok(false, "the property panel failed to show for inputValues[" + i + "]");
|
||||
ok(false, "the variables view failed to show for inputValues[" + i + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче