mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge fx-team to m-c
This commit is contained in:
commit
e3f37996ee
@ -1013,8 +1013,9 @@ pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
|
||||
// Disable the error console
|
||||
pref("devtools.errorconsole.enabled", false);
|
||||
|
||||
// Enable the developer toolbar
|
||||
// Developer toolbar and GCLI preferences
|
||||
pref("devtools.toolbar.enabled", false);
|
||||
pref("devtools.gcli.allowSet", false);
|
||||
|
||||
// Enable the Inspector
|
||||
pref("devtools.inspector.enabled", true);
|
||||
|
@ -292,7 +292,7 @@ let TabView = {
|
||||
// if group has title, it's not hidden and there is no active group or
|
||||
// the active group id doesn't match the group id, a group menu item
|
||||
// would be added.
|
||||
if (groupItem.getTitle().length > 0 && !groupItem.hidden &&
|
||||
if (!groupItem.hidden && groupItem.getChildren().length &&
|
||||
(!activeGroup || activeGroup.id != groupItem.id)) {
|
||||
let menuItem = self._createGroupMenuItem(groupItem);
|
||||
popup.insertBefore(menuItem, separator);
|
||||
@ -305,10 +305,27 @@ let TabView = {
|
||||
|
||||
// ----------
|
||||
_createGroupMenuItem: function TabView__createGroupMenuItem(groupItem) {
|
||||
let menuItem = document.createElement("menuitem")
|
||||
menuItem.setAttribute("label", groupItem.getTitle());
|
||||
let menuItem = document.createElement("menuitem");
|
||||
let title = groupItem.getTitle();
|
||||
|
||||
if (!title.trim()) {
|
||||
let topChildLabel = groupItem.getTopChild().tab.label;
|
||||
|
||||
if (groupItem.getChildren().length > 1) {
|
||||
title =
|
||||
gNavigatorBundle.getFormattedString("tabview2.moveToUnnamedGroup.label",
|
||||
[topChildLabel, groupItem.getChildren().length - 1]);
|
||||
} else {
|
||||
title = topChildLabel;
|
||||
}
|
||||
}
|
||||
|
||||
menuItem.setAttribute("label", title);
|
||||
menuItem.setAttribute("tooltiptext", title);
|
||||
menuItem.setAttribute("crop", "center");
|
||||
menuItem.setAttribute("class", "tabview-menuitem");
|
||||
menuItem.setAttribute(
|
||||
"oncommand",
|
||||
"oncommand",
|
||||
"TabView.moveTabTo(TabContextMenu.contextTab,'" + groupItem.id + "')");
|
||||
|
||||
return menuItem;
|
||||
|
@ -545,5 +545,10 @@ statuspanel[inactive][previoustype=overLink] {
|
||||
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#promobox");
|
||||
}
|
||||
|
||||
/* tabview menus */
|
||||
.tabview-menuitem {
|
||||
max-width: 32em;
|
||||
}
|
||||
|
||||
/* highlighter */
|
||||
%include highlighter.css
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
let EXPORTED_SYMBOLS = [ "GcliCommands" ];
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Components.utils.import("resource:///modules/devtools/gcli.jsm");
|
||||
Components.utils.import("resource:///modules/HUDService.jsm");
|
||||
|
@ -65,7 +65,7 @@ var mozl10n = {};
|
||||
|
||||
})(mozl10n);
|
||||
|
||||
define('gcli/index', ['require', 'exports', 'module' , 'gcli/types/basic', 'gcli/types/command', 'gcli/types/javascript', 'gcli/types/node', 'gcli/types/resource', 'gcli/types/setting', 'gcli/types/selection', 'gcli/settings', 'gcli/ui/intro', 'gcli/ui/focus', 'gcli/ui/fields/basic', 'gcli/ui/fields/javascript', 'gcli/ui/fields/selection', 'gcli/commands/help', 'gcli/canon', 'gcli/ui/ffdisplay'], function(require, exports, module) {
|
||||
define('gcli/index', ['require', 'exports', 'module' , 'gcli/types/basic', 'gcli/types/command', 'gcli/types/javascript', 'gcli/types/node', 'gcli/types/resource', 'gcli/types/setting', 'gcli/types/selection', 'gcli/settings', 'gcli/ui/intro', 'gcli/ui/focus', 'gcli/ui/fields/basic', 'gcli/ui/fields/javascript', 'gcli/ui/fields/selection', 'gcli/commands/help', 'gcli/commands/pref', 'gcli/canon', 'gcli/ui/ffdisplay'], function(require, exports, module) {
|
||||
|
||||
// Internal startup process. Not exported
|
||||
require('gcli/types/basic').startup();
|
||||
@ -84,6 +84,7 @@ define('gcli/index', ['require', 'exports', 'module' , 'gcli/types/basic', 'gcli
|
||||
require('gcli/ui/fields/selection').startup();
|
||||
|
||||
require('gcli/commands/help').startup();
|
||||
require('gcli/commands/pref').startup();
|
||||
|
||||
// The API for use by command authors
|
||||
exports.addCommand = require('gcli/canon').addCommand;
|
||||
@ -1674,7 +1675,7 @@ exports.Speller = Speller;
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gcli/types/selection', ['require', 'exports', 'module' , 'gcli/l10n', 'gcli/types', 'gcli/types/spell', 'gcli/argument'], function(require, exports, module) {
|
||||
define('gcli/types/selection', ['require', 'exports', 'module' , 'gcli/l10n', 'gcli/types', 'gcli/types/spell'], function(require, exports, module) {
|
||||
|
||||
|
||||
var l10n = require('gcli/l10n');
|
||||
@ -1683,7 +1684,6 @@ var Type = require('gcli/types').Type;
|
||||
var Status = require('gcli/types').Status;
|
||||
var Conversion = require('gcli/types').Conversion;
|
||||
var Speller = require('gcli/types/spell').Speller;
|
||||
var Argument = require('gcli/argument').Argument;
|
||||
|
||||
|
||||
/**
|
||||
@ -1714,6 +1714,9 @@ exports.shutdown = function() {
|
||||
* the associated name. However the name maybe available directly from the
|
||||
* value using a property lookup. Setting 'stringifyProperty' allows
|
||||
* SelectionType to take this shortcut.
|
||||
* - cacheable : If lookup is a function, then we normally assume that
|
||||
* the values fetched can change. Setting 'cacheable' enables internal
|
||||
* caching.
|
||||
*/
|
||||
function SelectionType(typeSpec) {
|
||||
if (typeSpec) {
|
||||
@ -1743,14 +1746,30 @@ SelectionType.prototype.stringify = function(value) {
|
||||
return name;
|
||||
};
|
||||
|
||||
/**
|
||||
* If typeSpec contained cacheable:true then calls to parse() work on cached
|
||||
* data. clearCache() enables the cache to be cleared.
|
||||
*/
|
||||
SelectionType.prototype.clearCache = function() {
|
||||
delete this._cachedLookup;
|
||||
};
|
||||
|
||||
/**
|
||||
* There are several ways to get selection data. This unifies them into one
|
||||
* single function.
|
||||
* @return An array of objects with name and value properties.
|
||||
*/
|
||||
SelectionType.prototype.getLookup = function() {
|
||||
if (this._cachedLookup) {
|
||||
return this._cachedLookup;
|
||||
}
|
||||
|
||||
if (this.lookup) {
|
||||
if (typeof this.lookup === 'function') {
|
||||
if (this.cacheable) {
|
||||
this._cachedLookup = this.lookup();
|
||||
return this._cachedLookup;
|
||||
}
|
||||
return this.lookup();
|
||||
}
|
||||
return this.lookup;
|
||||
@ -2257,8 +2276,6 @@ Parameter.prototype.isKnownAs = function(name) {
|
||||
* parseString on an empty string
|
||||
*/
|
||||
Parameter.prototype.getBlank = function() {
|
||||
var conversion;
|
||||
|
||||
if (this.type.getBlank) {
|
||||
return this.type.getBlank();
|
||||
}
|
||||
@ -2357,13 +2374,19 @@ canon.addCommand = function addCommand(commandSpec) {
|
||||
|
||||
/**
|
||||
* Remove an individual command. The opposite of #addCommand().
|
||||
* Removing a non-existent command is a no-op.
|
||||
* @param commandOrName Either a command name or the command itself.
|
||||
* @return true if a command was removed, false otherwise.
|
||||
*/
|
||||
canon.removeCommand = function removeCommand(commandOrName) {
|
||||
var name = typeof commandOrName === 'string' ?
|
||||
commandOrName :
|
||||
commandOrName.name;
|
||||
|
||||
if (!commands[name]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// See start of canon.addCommand if changing this code
|
||||
delete commands[name];
|
||||
delete commandSpecs[name];
|
||||
@ -2372,6 +2395,7 @@ canon.removeCommand = function removeCommand(commandOrName) {
|
||||
});
|
||||
|
||||
canon.onCanonChange();
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2941,6 +2965,56 @@ exports.createUrlLookup = function(callingModule) {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to find the 'data-command' attribute and call some action on it.
|
||||
* @see |updateCommand()| and |executeCommand()|
|
||||
*/
|
||||
function withCommand(element, action) {
|
||||
var command = element.getAttribute('data-command');
|
||||
if (!command) {
|
||||
command = element.querySelector('*[data-command]')
|
||||
.getAttribute('data-command');
|
||||
}
|
||||
|
||||
if (command) {
|
||||
action(command);
|
||||
}
|
||||
else {
|
||||
console.warn('Missing data-command for ' + util.findCssSelector(element));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the requisition to contain the text of the clicked element
|
||||
* @param element The clicked element, containing either a data-command
|
||||
* attribute directly or in a nested element, from which we get the command
|
||||
* to be executed.
|
||||
* @param context Either a Requisition or an ExecutionContext or another object
|
||||
* that contains an |update()| function that follows a similar contract.
|
||||
*/
|
||||
exports.updateCommand = function(element, context) {
|
||||
withCommand(element, function(command) {
|
||||
context.update(command);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute the text contained in the element that was clicked
|
||||
* @param element The clicked element, containing either a data-command
|
||||
* attribute directly or in a nested element, from which we get the command
|
||||
* to be executed.
|
||||
* @param context Either a Requisition or an ExecutionContext or another object
|
||||
* that contains an |update()| function that follows a similar contract.
|
||||
*/
|
||||
exports.executeCommand = function(element, context) {
|
||||
withCommand(element, function(command) {
|
||||
context.exec({
|
||||
visible: true,
|
||||
typed: command
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@ -4136,9 +4210,13 @@ function SettingType(typeSpec) {
|
||||
if (Object.keys(typeSpec).length > 0) {
|
||||
throw new Error('SettingType can not be customized');
|
||||
}
|
||||
|
||||
settings.onChange.add(function(ev) {
|
||||
this.clearCache();
|
||||
}, this);
|
||||
}
|
||||
|
||||
SettingType.prototype = Object.create(SelectionType.prototype);
|
||||
SettingType.prototype = new SelectionType({ cacheable: true });
|
||||
|
||||
SettingType.prototype.lookup = function() {
|
||||
return settings.getAll().map(function(setting) {
|
||||
@ -4219,8 +4297,7 @@ var types = require('gcli/types');
|
||||
var allSettings = [];
|
||||
|
||||
/**
|
||||
* No setup required because settings are pre-loaded with Mozilla,
|
||||
* but match API with main settings.js
|
||||
* Cache existing settings on startup
|
||||
*/
|
||||
exports.startup = function() {
|
||||
imports.prefBranch.getChildList('').forEach(function(name) {
|
||||
@ -4304,9 +4381,8 @@ Object.defineProperty(Setting.prototype, 'value', {
|
||||
case imports.prefBranch.PREF_STRING:
|
||||
var value = imports.prefBranch.getComplexValue(this.name,
|
||||
Components.interfaces.nsISupportsString).data;
|
||||
// Try in case it's a localized string (will throw an exception if not)
|
||||
var isL10n = /^chrome:\/\/.+\/locale\/.+\.properties/.test(value);
|
||||
if (!this.changed && isL10n) {
|
||||
// In case of a localized string
|
||||
if (/^chrome:\/\/.+\/locale\/.+\.properties/.test(value)) {
|
||||
value = imports.prefBranch.getComplexValue(this.name,
|
||||
Components.interfaces.nsIPrefLocalizedString).data;
|
||||
}
|
||||
@ -4348,6 +4424,13 @@ Object.defineProperty(Setting.prototype, 'value', {
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
/**
|
||||
* Reset this setting to it's initial default value
|
||||
*/
|
||||
Setting.prototype.setDefault = function() {
|
||||
imports.prefBranch.clearUserPref(this.name);
|
||||
Services.prefs.savePrefFile(null);
|
||||
};
|
||||
|
||||
/**
|
||||
* 'static' function to get an array containing all known Settings
|
||||
@ -4371,9 +4454,36 @@ exports.addSetting = function(prefSpec) {
|
||||
allSettings[i] = setting;
|
||||
}
|
||||
}
|
||||
exports.onChange({ added: setting.name });
|
||||
return setting;
|
||||
};
|
||||
|
||||
/**
|
||||
* Getter for an existing setting. Generally use of this function should be
|
||||
* avoided. Systems that define a setting should export it if they wish it to
|
||||
* be available to the outside, or not otherwise. Use of this function breaks
|
||||
* that boundary and also hides dependencies. Acceptable uses include testing
|
||||
* and embedded uses of GCLI that pre-define all settings (e.g. Firefox)
|
||||
* @param name The name of the setting to fetch
|
||||
* @return The found Setting object, or undefined if the setting was not found
|
||||
*/
|
||||
exports.getSetting = function(name) {
|
||||
var found = undefined;
|
||||
allSettings.some(function(setting) {
|
||||
if (setting.name === name) {
|
||||
found = setting;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return found;
|
||||
};
|
||||
|
||||
/**
|
||||
* Event for use to detect when the list of settings changes
|
||||
*/
|
||||
exports.onChange = util.createEvent('Settings.onChange');
|
||||
|
||||
/**
|
||||
* Remove a setting. A no-op in this case
|
||||
*/
|
||||
@ -4388,10 +4498,11 @@ exports.removeSetting = function(nameOrSpec) {
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gcli/ui/intro', ['require', 'exports', 'module' , 'gcli/settings', 'gcli/l10n', 'gcli/ui/view', 'gcli/cli', 'text!gcli/ui/intro.html'], function(require, exports, module) {
|
||||
define('gcli/ui/intro', ['require', 'exports', 'module' , 'gcli/settings', 'gcli/l10n', 'gcli/util', 'gcli/ui/view', 'gcli/cli', 'text!gcli/ui/intro.html'], function(require, exports, module) {
|
||||
|
||||
var settings = require('gcli/settings');
|
||||
var l10n = require('gcli/l10n');
|
||||
var util = require('gcli/util');
|
||||
var view = require('gcli/ui/view');
|
||||
var Output = require('gcli/cli').Output;
|
||||
|
||||
@ -4421,7 +4532,7 @@ define('gcli/ui/intro', ['require', 'exports', 'module' , 'gcli/settings', 'gcli
|
||||
/**
|
||||
* Called when the UI is ready to add a welcome message to the output
|
||||
*/
|
||||
exports.maybeShowIntro = function(commandOutputManager) {
|
||||
exports.maybeShowIntro = function(commandOutputManager, context) {
|
||||
if (hideIntro.value) {
|
||||
return;
|
||||
}
|
||||
@ -4429,18 +4540,33 @@ define('gcli/ui/intro', ['require', 'exports', 'module' , 'gcli/settings', 'gcli
|
||||
var output = new Output();
|
||||
commandOutputManager.onOutput({ output: output });
|
||||
|
||||
var viewData = view.createView({
|
||||
var viewData = this.createView(context, output);
|
||||
|
||||
output.complete(viewData);
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the UI is ready to add a welcome message to the output
|
||||
*/
|
||||
exports.createView = function(context, output) {
|
||||
return view.createView({
|
||||
html: require('text!gcli/ui/intro.html'),
|
||||
options: { stack: 'intro.html' },
|
||||
data: {
|
||||
showHideButton: true,
|
||||
l10n: l10n.propertyLookup,
|
||||
onclick: function(ev) {
|
||||
util.updateCommand(ev.currentTarget, context);
|
||||
},
|
||||
ondblclick: function(ev) {
|
||||
util.executeCommand(ev.currentTarget, context);
|
||||
},
|
||||
showHideButton: (output != null),
|
||||
onGotIt: function(ev) {
|
||||
hideIntro.value = true;
|
||||
output.onClose();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
output.complete(viewData);
|
||||
};
|
||||
});
|
||||
/*
|
||||
@ -6097,6 +6223,12 @@ Output.prototype.toDom = function(element) {
|
||||
util.setContents(node, output.toString());
|
||||
}
|
||||
|
||||
// Make sure that links open in a new window.
|
||||
var links = node.querySelectorAll('*[href]');
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
links[i].setAttribute('target', '_blank');
|
||||
}
|
||||
|
||||
element.appendChild(node);
|
||||
};
|
||||
|
||||
@ -6155,17 +6287,16 @@ define('gcli/promise', ['require', 'exports', 'module' ], function(require, expo
|
||||
});
|
||||
define("text!gcli/ui/intro.html", [], "\n" +
|
||||
"<div>\n" +
|
||||
" <p>${l10n.introTextOpening}</p>\n" +
|
||||
"\n" +
|
||||
" <p>\n" +
|
||||
" GCLI is an experiment to create a highly usable <strong>graphical command\n" +
|
||||
" line</strong> for developers. It's not a JavaScript\n" +
|
||||
" <a href=\"https://en.wikipedia.org/wiki/Read<61>eval<61>print_loop\">REPL</a>, so\n" +
|
||||
" it focuses on speed of input over JavaScript syntax and a rich display over\n" +
|
||||
" monospace output.</p>\n" +
|
||||
" ${l10n.introTextCommands}\n" +
|
||||
" <span class=\"gcli-out-shortcut\" onclick=\"${onclick}\"\n" +
|
||||
" ondblclick=\"${ondblclick}\" data-command=\"help\">help</span>,\n" +
|
||||
" ${l10n.introTextKeys} <code>${l10n.introTextF1Escape}</code>.\n" +
|
||||
" </p>\n" +
|
||||
"\n" +
|
||||
" <p>Type <span class=\"gcli-out-shortcut\">help</span> for a list of commands,\n" +
|
||||
" or press <code>F1/Escape</code> to show/hide command hints.</p>\n" +
|
||||
"\n" +
|
||||
" <button onclick=\"${onGotIt}\" if=\"${showHideButton}\">Got it!</button>\n" +
|
||||
" <button onclick=\"${onGotIt}\" if=\"${showHideButton}\">${l10n.introTextGo}</button>\n" +
|
||||
"</div>\n" +
|
||||
"");
|
||||
|
||||
@ -7729,12 +7860,13 @@ SelectionTooltipField.DEFAULT_VALUE = '__SelectionTooltipField.DEFAULT_VALUE';
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gcli/commands/help', ['require', 'exports', 'module' , 'gcli/canon', 'gcli/l10n', 'gcli/ui/view', 'text!gcli/commands/help_man.html', 'text!gcli/commands/help_list.html', 'text!gcli/commands/help.css'], function(require, exports, module) {
|
||||
define('gcli/commands/help', ['require', 'exports', 'module' , 'gcli/canon', 'gcli/l10n', 'gcli/util', 'gcli/ui/view', 'text!gcli/commands/help_man.html', 'text!gcli/commands/help_list.html', 'text!gcli/commands/help.css'], function(require, exports, module) {
|
||||
var help = exports;
|
||||
|
||||
|
||||
var canon = require('gcli/canon');
|
||||
var l10n = require('gcli/l10n');
|
||||
var util = require('gcli/util');
|
||||
var view = require('gcli/ui/view');
|
||||
|
||||
// Storing the HTML on exports allows other builds to alter the help template
|
||||
@ -7794,26 +7926,6 @@ help.shutdown = function() {
|
||||
canon.removeCommand(helpCommandSpec);
|
||||
};
|
||||
|
||||
/**
|
||||
* Find an element within the passed element with the class gcli-help-command
|
||||
* and update the requisition to contain this text.
|
||||
*/
|
||||
function updateCommand(element, context) {
|
||||
var typed = element.querySelector('.gcli-help-command').textContent;
|
||||
context.update(typed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an element within the passed element with the class gcli-help-command
|
||||
* and execute this text.
|
||||
*/
|
||||
function executeCommand(element, context) {
|
||||
context.exec({
|
||||
visible: true,
|
||||
typed: element.querySelector('.gcli-help-command').textContent
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a block of data suitable to be passed to the help_list.html template
|
||||
*/
|
||||
@ -7823,11 +7935,11 @@ function getListTemplateData(args, context) {
|
||||
includeIntro: args.search == null,
|
||||
|
||||
onclick: function(ev) {
|
||||
updateCommand(ev.currentTarget, context);
|
||||
util.updateCommand(ev.currentTarget, context);
|
||||
},
|
||||
|
||||
ondblclick: function(ev) {
|
||||
executeCommand(ev.currentTarget, context);
|
||||
util.executeCommand(ev.currentTarget, context);
|
||||
},
|
||||
|
||||
getHeading: function() {
|
||||
@ -7867,11 +7979,18 @@ function getManTemplateData(command, context) {
|
||||
command: command,
|
||||
|
||||
onclick: function(ev) {
|
||||
updateCommand(ev.currentTarget, context);
|
||||
util.updateCommand(ev.currentTarget, context);
|
||||
},
|
||||
|
||||
ondblclick: function(ev) {
|
||||
executeCommand(ev.currentTarget, context);
|
||||
util.executeCommand(ev.currentTarget, context);
|
||||
},
|
||||
|
||||
describe: function(item, element) {
|
||||
var text = item.manual || item.description;
|
||||
var parent = element.ownerDocument.createElement('div');
|
||||
util.setContents(parent, text);
|
||||
return parent.childNodes;
|
||||
},
|
||||
|
||||
getTypeDescription: function(param) {
|
||||
@ -7911,8 +8030,8 @@ define("text!gcli/commands/help_man.html", [], "\n" +
|
||||
"\n" +
|
||||
" <h4 class=\"gcli-help-header\">\n" +
|
||||
" ${l10n.helpManSynopsis}:\n" +
|
||||
" <span class=\"gcli-help-synopsis\" onclick=\"${onclick}\">\n" +
|
||||
" <span class=\"gcli-help-command\">${command.name}</span>\n" +
|
||||
" <span class=\"gcli-out-shortcut\" onclick=\"${onclick}\" data-command=\"${command.name}\">\n" +
|
||||
" ${command.name}\n" +
|
||||
" <span foreach=\"param in ${command.params}\">\n" +
|
||||
" ${param.defaultValue !== undefined ? '[' + param.name + ']' : param.name}\n" +
|
||||
" </span>\n" +
|
||||
@ -7921,9 +8040,7 @@ define("text!gcli/commands/help_man.html", [], "\n" +
|
||||
"\n" +
|
||||
" <h4 class=\"gcli-help-header\">${l10n.helpManDescription}:</h4>\n" +
|
||||
"\n" +
|
||||
" <p class=\"gcli-help-description\">\n" +
|
||||
" ${command.manual || command.description}\n" +
|
||||
" </p>\n" +
|
||||
" <p class=\"gcli-help-description\">${describe(command, __element)}</p>\n" +
|
||||
"\n" +
|
||||
" <div if=\"${command.exec}\">\n" +
|
||||
" <h4 class=\"gcli-help-header\">${l10n.helpManParameters}:</h4>\n" +
|
||||
@ -7931,9 +8048,9 @@ define("text!gcli/commands/help_man.html", [], "\n" +
|
||||
" <ul class=\"gcli-help-parameter\">\n" +
|
||||
" <li if=\"${command.params.length === 0}\">${l10n.helpManNone}</li>\n" +
|
||||
" <li foreach=\"param in ${command.params}\">\n" +
|
||||
" <tt>${param.name}</tt> ${getTypeDescription(param)}\n" +
|
||||
" ${param.name} <em>${getTypeDescription(param)}</em>\n" +
|
||||
" <br/>\n" +
|
||||
" ${param.manual || param.description}\n" +
|
||||
" ${describe(param, __element)}\n" +
|
||||
" </li>\n" +
|
||||
" </ul>\n" +
|
||||
" </div>\n" +
|
||||
@ -7946,8 +8063,9 @@ define("text!gcli/commands/help_man.html", [], "\n" +
|
||||
" <li foreach=\"subcommand in ${subcommands}\">\n" +
|
||||
" <strong>${subcommand.name}</strong>:\n" +
|
||||
" ${subcommand.description}\n" +
|
||||
" <span class=\"gcli-help-synopsis\" onclick=\"${onclick}\" ondblclick=\"${ondblclick}\">\n" +
|
||||
" <span class=\"gcli-help-command\">help ${subcommand.name}</span>\n" +
|
||||
" <span class=\"gcli-out-shortcut\" data-command=\"help ${subcommand.name}\"\n" +
|
||||
" onclick=\"${onclick}\" ondblclick=\"${ondblclick}\">\n" +
|
||||
" help ${subcommand.name}\n" +
|
||||
" </span>\n" +
|
||||
" </li>\n" +
|
||||
" </ul>\n" +
|
||||
@ -7967,7 +8085,7 @@ define("text!gcli/commands/help_list.html", [], "\n" +
|
||||
" <td class=\"gcli-help-arrow\">→</td>\n" +
|
||||
" <td>\n" +
|
||||
" ${command.description}\n" +
|
||||
" <span class=\"gcli-out-shortcut gcli-help-command\">help ${command.name}</span>\n" +
|
||||
" <span class=\"gcli-out-shortcut\" data-command=\"help ${command.name}\">help ${command.name}</span>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" </table>\n" +
|
||||
@ -7976,6 +8094,151 @@ define("text!gcli/commands/help_list.html", [], "\n" +
|
||||
|
||||
define("text!gcli/commands/help.css", [], "");
|
||||
|
||||
/*
|
||||
* 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('gcli/commands/pref', ['require', 'exports', 'module' , 'gcli/canon', 'gcli/l10n', 'gcli/settings', 'text!gcli/commands/pref_set_check.html'], function(require, exports, module) {
|
||||
|
||||
|
||||
var canon = require('gcli/canon');
|
||||
var l10n = require('gcli/l10n');
|
||||
var settings = require('gcli/settings');
|
||||
|
||||
/**
|
||||
* Record if the user has clicked on 'Got It!'
|
||||
*/
|
||||
var allowSetSettingSpec = {
|
||||
name: 'allowSet',
|
||||
type: 'boolean',
|
||||
description: l10n.lookup('allowSetDesc'),
|
||||
defaultValue: false
|
||||
};
|
||||
exports.allowSet = undefined;
|
||||
|
||||
/**
|
||||
* 'pref' command
|
||||
*/
|
||||
var prefCmdSpec = {
|
||||
name: 'pref',
|
||||
description: l10n.lookup('prefDesc'),
|
||||
manual: l10n.lookup('prefManual')
|
||||
};
|
||||
|
||||
/**
|
||||
* 'pref show' command
|
||||
*/
|
||||
var prefShowCmdSpec = {
|
||||
name: 'pref show',
|
||||
description: l10n.lookup('prefShowDesc'),
|
||||
manual: l10n.lookup('prefShowManual'),
|
||||
params: [
|
||||
{
|
||||
name: 'setting',
|
||||
type: 'setting',
|
||||
description: l10n.lookup('prefShowSettingDesc'),
|
||||
manual: l10n.lookup('prefShowSettingManual')
|
||||
}
|
||||
],
|
||||
exec: function Command_prefShow(args, context) {
|
||||
return args.setting.value;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 'pref set' command
|
||||
*/
|
||||
var prefSetCmdSpec = {
|
||||
name: 'pref set',
|
||||
description: l10n.lookup('prefSetDesc'),
|
||||
manual: l10n.lookup('prefSetManual'),
|
||||
params: [
|
||||
{
|
||||
name: 'setting',
|
||||
type: 'setting',
|
||||
description: l10n.lookup('prefSetSettingDesc'),
|
||||
manual: l10n.lookup('prefSetSettingManual')
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
type: 'settingValue',
|
||||
description: l10n.lookup('prefSetValueDesc'),
|
||||
manual: l10n.lookup('prefSetValueManual')
|
||||
}
|
||||
],
|
||||
exec: function Command_prefSet(args, context) {
|
||||
if (!exports.allowSet.value &&
|
||||
args.setting.name !== exports.allowSet.name) {
|
||||
return context.createView({
|
||||
html: require('text!gcli/commands/pref_set_check.html'),
|
||||
options: { allowEval: true, stack: 'pref_set_check.html' },
|
||||
data: {
|
||||
l10n: l10n.propertyLookup,
|
||||
activate: function() {
|
||||
context.exec('pref set ' + exports.allowSet.name + ' true');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
args.setting.value = args.value;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 'pref reset' command
|
||||
*/
|
||||
var prefResetCmdSpec = {
|
||||
name: 'pref reset',
|
||||
description: l10n.lookup('prefResetDesc'),
|
||||
manual: l10n.lookup('prefResetManual'),
|
||||
params: [
|
||||
{
|
||||
name: 'setting',
|
||||
type: 'setting',
|
||||
description: l10n.lookup('prefResetSettingDesc'),
|
||||
manual: l10n.lookup('prefResetSettingManual')
|
||||
}
|
||||
],
|
||||
exec: function Command_prefReset(args, context) {
|
||||
args.setting.setDefault();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Registration and de-registration.
|
||||
*/
|
||||
exports.startup = function() {
|
||||
exports.allowSet = settings.addSetting(allowSetSettingSpec);
|
||||
|
||||
canon.addCommand(prefCmdSpec);
|
||||
canon.addCommand(prefShowCmdSpec);
|
||||
canon.addCommand(prefSetCmdSpec);
|
||||
canon.addCommand(prefResetCmdSpec);
|
||||
};
|
||||
|
||||
exports.shutdown = function() {
|
||||
canon.removeCommand(prefCmdSpec);
|
||||
canon.removeCommand(prefShowCmdSpec);
|
||||
canon.removeCommand(prefSetCmdSpec);
|
||||
canon.removeCommand(prefResetCmdSpec);
|
||||
|
||||
settings.removeSetting(allowSetSettingSpec);
|
||||
exports.allowSet = undefined;
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
define("text!gcli/commands/pref_set_check.html", [], "<div>\n" +
|
||||
" <p><strong>${l10n.prefSetCheckHeading}</strong></p>\n" +
|
||||
" <p>${l10n.prefSetCheckBody}</p>\n" +
|
||||
" <button onclick=\"${activate}\">${l10n.prefSetCheckGo}</button>\n" +
|
||||
"</div>\n" +
|
||||
"");
|
||||
|
||||
/*
|
||||
* Copyright 2009-2011 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE.txt or:
|
||||
|
@ -1,18 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
|
||||
[
|
||||
<!ENTITY % webConsoleDTD SYSTEM "chrome://browser/locale/devtools/webConsole.dtd">
|
||||
%webConsoleDTD;
|
||||
]
|
||||
>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
|
||||
|
@ -1,18 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
|
||||
[
|
||||
<!ENTITY % webConsoleDTD SYSTEM "chrome://browser/locale/devtools/webConsole.dtd">
|
||||
%webConsoleDTD;
|
||||
]
|
||||
>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
|
||||
|
@ -17,6 +17,8 @@ _BROWSER_TEST_FILES = \
|
||||
browser_gcli_commands.js \
|
||||
browser_gcli_inspect.js \
|
||||
browser_gcli_integrate.js \
|
||||
browser_gcli_pref.js \
|
||||
browser_gcli_settings.js \
|
||||
browser_gcli_web.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
414
browser/devtools/commandline/test/browser_gcli_pref.js
Executable file
414
browser/devtools/commandline/test/browser_gcli_pref.js
Executable file
@ -0,0 +1,414 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the pref commands work
|
||||
|
||||
let imports = {};
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm", imports);
|
||||
|
||||
imports.XPCOMUtils.defineLazyGetter(imports, "prefBranch", function() {
|
||||
let prefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefService);
|
||||
return prefService.getBranch(null)
|
||||
.QueryInterface(Components.interfaces.nsIPrefBranch2);
|
||||
});
|
||||
|
||||
imports.XPCOMUtils.defineLazyGetter(imports, "supportsString", function() {
|
||||
return Components.classes["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Components.interfaces.nsISupportsString);
|
||||
});
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,gcli-pref";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
setup();
|
||||
|
||||
testPrefSetEnable();
|
||||
testPrefStatus();
|
||||
testPrefBoolExec();
|
||||
testPrefNumberExec();
|
||||
testPrefStringExec();
|
||||
testPrefSetDisable();
|
||||
|
||||
shutdown();
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
let tiltEnabledOrig = undefined;
|
||||
let tabSizeOrig = undefined;
|
||||
let remoteHostOrig = undefined;
|
||||
|
||||
function setup() {
|
||||
Components.utils.import("resource:///modules/devtools/Require.jsm", imports);
|
||||
imports.settings = imports.require("gcli/settings");
|
||||
|
||||
tiltEnabledOrig = imports.prefBranch.getBoolPref("devtools.tilt.enabled");
|
||||
tabSizeOrig = imports.prefBranch.getIntPref("devtools.editor.tabsize");
|
||||
remoteHostOrig = imports.prefBranch.getComplexValue(
|
||||
"devtools.debugger.remote-host",
|
||||
Components.interfaces.nsISupportsString).data;
|
||||
|
||||
info("originally: devtools.tilt.enabled = " + tiltEnabledOrig);
|
||||
info("originally: devtools.editor.tabsize = " + tabSizeOrig);
|
||||
info("originally: devtools.debugger.remote-host = " + remoteHostOrig);
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
imports.prefBranch.setBoolPref("devtools.tilt.enabled", tiltEnabledOrig);
|
||||
imports.prefBranch.setIntPref("devtools.editor.tabsize", tabSizeOrig);
|
||||
imports.supportsString.data = remoteHostOrig;
|
||||
imports.prefBranch.setComplexValue("devtools.debugger.remote-host",
|
||||
Components.interfaces.nsISupportsString,
|
||||
imports.supportsString);
|
||||
|
||||
tiltEnabledOrig = undefined;
|
||||
tabSizeOrig = undefined;
|
||||
remoteHostOrig = undefined;
|
||||
|
||||
imports = undefined;
|
||||
}
|
||||
|
||||
function testPrefStatus() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref s",
|
||||
markup: "IIIIVI",
|
||||
status: "ERROR",
|
||||
directTabText: "et"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show",
|
||||
markup: "VVVVVVVVV",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ " <setting>" ]
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show tempTBo",
|
||||
markup: "VVVVVVVVVVEEEEEEE",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show devtools.toolbar.ena",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
|
||||
directTabText: "bled",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show hideIntro",
|
||||
markup: "VVVVVVVVVVVVVVVVVVV",
|
||||
directTabText: "",
|
||||
arrowTabText: "devtools.gcli.hideIntro",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show devtools.toolbar.enabled",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
|
||||
status: "VALID",
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show devtools.tilt.enabled 4",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE",
|
||||
directTabText: "",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show devtools.tilt.enabled",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
|
||||
status: "VALID",
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref reset devtools.tilt.enabled",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
|
||||
status: "VALID",
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref set devtools.tilt.enabled 4",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref set devtools.editor.tabsize 4",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
|
||||
status: "VALID",
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref list",
|
||||
markup: "EEEEVEEEE",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
}
|
||||
|
||||
function testPrefSetEnable() {
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref set devtools.editor.tabsize 9",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.editor.tabsize"),
|
||||
value: 9
|
||||
},
|
||||
completed: true,
|
||||
outputMatch: [ /void your warranty/, /I promise/ ],
|
||||
});
|
||||
|
||||
is(imports.prefBranch.getIntPref("devtools.editor.tabsize"),
|
||||
tabSizeOrig,
|
||||
"devtools.editor.tabsize is unchanged");
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref set devtools.gcli.allowSet true",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.gcli.allowSet"),
|
||||
value: true
|
||||
},
|
||||
completed: true,
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
is(imports.prefBranch.getBoolPref("devtools.gcli.allowSet"), true,
|
||||
"devtools.gcli.allowSet is true");
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref set devtools.editor.tabsize 10",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.editor.tabsize"),
|
||||
value: 10
|
||||
},
|
||||
completed: true,
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
is(imports.prefBranch.getIntPref("devtools.editor.tabsize"),
|
||||
10,
|
||||
"devtools.editor.tabsize is 10");
|
||||
}
|
||||
|
||||
function testPrefBoolExec() {
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref show devtools.tilt.enabled",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.tilt.enabled")
|
||||
},
|
||||
completed: true,
|
||||
outputMatch: new RegExp("^" + tiltEnabledOrig + "$"),
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref set devtools.tilt.enabled true",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.tilt.enabled"),
|
||||
value: true
|
||||
},
|
||||
completed: true,
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
is(imports.prefBranch.getBoolPref("devtools.tilt.enabled"), true,
|
||||
"devtools.tilt.enabled is true");
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref show devtools.tilt.enabled",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.tilt.enabled")
|
||||
},
|
||||
completed: true,
|
||||
outputMatch: new RegExp("^true$"),
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref set devtools.tilt.enabled false",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.tilt.enabled"),
|
||||
value: false
|
||||
},
|
||||
completed: true,
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref show devtools.tilt.enabled",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.tilt.enabled")
|
||||
},
|
||||
completed: true,
|
||||
outputMatch: new RegExp("^false$"),
|
||||
});
|
||||
|
||||
is(imports.prefBranch.getBoolPref("devtools.tilt.enabled"), false,
|
||||
"devtools.tilt.enabled is false");
|
||||
}
|
||||
|
||||
function testPrefNumberExec() {
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref show devtools.editor.tabsize",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.editor.tabsize")
|
||||
},
|
||||
completed: true,
|
||||
outputMatch: new RegExp("^10$"),
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref set devtools.editor.tabsize 20",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.editor.tabsize"),
|
||||
value: 20
|
||||
},
|
||||
completed: true,
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref show devtools.editor.tabsize",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.editor.tabsize")
|
||||
},
|
||||
completed: true,
|
||||
outputMatch: new RegExp("^20$"),
|
||||
});
|
||||
|
||||
is(imports.prefBranch.getIntPref("devtools.editor.tabsize"), 20,
|
||||
"devtools.editor.tabsize is 20");
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref set devtools.editor.tabsize 1",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.editor.tabsize"),
|
||||
value: true
|
||||
},
|
||||
completed: true,
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref show devtools.editor.tabsize",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.editor.tabsize")
|
||||
},
|
||||
completed: true,
|
||||
outputMatch: new RegExp("^1$"),
|
||||
});
|
||||
|
||||
is(imports.prefBranch.getIntPref("devtools.editor.tabsize"), 1,
|
||||
"devtools.editor.tabsize is 1");
|
||||
}
|
||||
|
||||
function testPrefStringExec() {
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref show devtools.debugger.remote-host",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.debugger.remote-host")
|
||||
},
|
||||
completed: true,
|
||||
outputMatch: new RegExp("^" + remoteHostOrig + "$"),
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref set devtools.debugger.remote-host e.com",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.debugger.remote-host"),
|
||||
value: "e.com"
|
||||
},
|
||||
completed: true,
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref show devtools.debugger.remote-host",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.debugger.remote-host")
|
||||
},
|
||||
completed: true,
|
||||
outputMatch: new RegExp("^e.com$"),
|
||||
});
|
||||
|
||||
var ecom = imports.prefBranch.getComplexValue(
|
||||
"devtools.debugger.remote-host",
|
||||
Components.interfaces.nsISupportsString).data;
|
||||
is(ecom, "e.com", "devtools.debugger.remote-host is e.com");
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref set devtools.debugger.remote-host moz.foo",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.debugger.remote-host"),
|
||||
value: "moz.foo"
|
||||
},
|
||||
completed: true,
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref show devtools.debugger.remote-host",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.debugger.remote-host")
|
||||
},
|
||||
completed: true,
|
||||
outputMatch: new RegExp("^moz.foo$"),
|
||||
});
|
||||
|
||||
var mozfoo = imports.prefBranch.getComplexValue(
|
||||
"devtools.debugger.remote-host",
|
||||
Components.interfaces.nsISupportsString).data;
|
||||
is(mozfoo, "moz.foo", "devtools.debugger.remote-host is moz.foo");
|
||||
}
|
||||
|
||||
function testPrefSetDisable() {
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref set devtools.editor.tabsize 32",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.editor.tabsize"),
|
||||
value: 32
|
||||
},
|
||||
completed: true,
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
is(imports.prefBranch.getIntPref("devtools.editor.tabsize"), 32,
|
||||
"devtools.editor.tabsize is 32");
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref reset devtools.gcli.allowSet",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.gcli.allowSet")
|
||||
},
|
||||
completed: true,
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
is(imports.prefBranch.getBoolPref("devtools.gcli.allowSet"), false,
|
||||
"devtools.gcli.allowSet is false");
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "pref set devtools.editor.tabsize 33",
|
||||
args: {
|
||||
setting: imports.settings.getSetting("devtools.editor.tabsize"),
|
||||
value: 33
|
||||
},
|
||||
completed: true,
|
||||
outputMatch: [ /void your warranty/, /I promise/ ],
|
||||
});
|
||||
|
||||
is(imports.prefBranch.getIntPref("devtools.editor.tabsize"), 32,
|
||||
"devtools.editor.tabsize is still 32");
|
||||
}
|
149
browser/devtools/commandline/test/browser_gcli_settings.js
Executable file
149
browser/devtools/commandline/test/browser_gcli_settings.js
Executable file
@ -0,0 +1,149 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the pref commands work
|
||||
|
||||
let imports = {};
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm", imports);
|
||||
|
||||
imports.XPCOMUtils.defineLazyGetter(imports, "prefBranch", function() {
|
||||
let prefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefService);
|
||||
return prefService.getBranch(null)
|
||||
.QueryInterface(Components.interfaces.nsIPrefBranch2);
|
||||
});
|
||||
|
||||
imports.XPCOMUtils.defineLazyGetter(imports, "supportsString", function() {
|
||||
return Components.classes["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Components.interfaces.nsISupportsString);
|
||||
});
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,gcli-settings";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
setup();
|
||||
|
||||
testSettings();
|
||||
|
||||
shutdown();
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
let tiltEnabled = undefined;
|
||||
let tabSize = undefined;
|
||||
let remoteHost = undefined;
|
||||
|
||||
let tiltEnabledOrig = undefined;
|
||||
let tabSizeOrig = undefined;
|
||||
let remoteHostOrig = undefined;
|
||||
|
||||
function setup() {
|
||||
Components.utils.import("resource:///modules/devtools/Require.jsm", imports);
|
||||
imports.settings = imports.require("gcli/settings");
|
||||
|
||||
tiltEnabled = imports.settings.getSetting("devtools.tilt.enabled");
|
||||
tabSize = imports.settings.getSetting("devtools.editor.tabsize");
|
||||
remoteHost = imports.settings.getSetting("devtools.debugger.remote-host");
|
||||
|
||||
tiltEnabledOrig = imports.prefBranch.getBoolPref("devtools.tilt.enabled");
|
||||
tabSizeOrig = imports.prefBranch.getIntPref("devtools.editor.tabsize");
|
||||
remoteHostOrig = imports.prefBranch.getComplexValue(
|
||||
"devtools.debugger.remote-host",
|
||||
Components.interfaces.nsISupportsString).data;
|
||||
|
||||
info("originally: devtools.tilt.enabled = " + tiltEnabledOrig);
|
||||
info("originally: devtools.editor.tabsize = " + tabSizeOrig);
|
||||
info("originally: devtools.debugger.remote-host = " + remoteHostOrig);
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
imports.prefBranch.setBoolPref("devtools.tilt.enabled", tiltEnabledOrig);
|
||||
imports.prefBranch.setIntPref("devtools.editor.tabsize", tabSizeOrig);
|
||||
imports.supportsString.data = remoteHostOrig;
|
||||
imports.prefBranch.setComplexValue("devtools.debugger.remote-host",
|
||||
Components.interfaces.nsISupportsString,
|
||||
imports.supportsString);
|
||||
|
||||
tiltEnabled = undefined;
|
||||
tabSize = undefined;
|
||||
remoteHost = undefined;
|
||||
|
||||
tiltEnabledOrig = undefined;
|
||||
tabSizeOrig = undefined;
|
||||
remoteHostOrig = undefined;
|
||||
|
||||
imports = undefined;
|
||||
}
|
||||
|
||||
function testSettings() {
|
||||
is(tiltEnabled.value, tiltEnabledOrig, "tiltEnabled default");
|
||||
is(tabSize.value, tabSizeOrig, "tabSize default");
|
||||
is(remoteHost.value, remoteHostOrig, "remoteHost default");
|
||||
|
||||
tiltEnabled.setDefault();
|
||||
tabSize.setDefault();
|
||||
remoteHost.setDefault();
|
||||
|
||||
let tiltEnabledDefault = tiltEnabled.value;
|
||||
let tabSizeDefault = tabSize.value;
|
||||
let remoteHostDefault = remoteHost.value;
|
||||
|
||||
tiltEnabled.value = false;
|
||||
tabSize.value = 42;
|
||||
remoteHost.value = "example.com"
|
||||
|
||||
is(tiltEnabled.value, false, "tiltEnabled basic");
|
||||
is(tabSize.value, 42, "tabSize basic");
|
||||
is(remoteHost.value, "example.com", "remoteHost basic");
|
||||
|
||||
function tiltEnabledCheck(ev) {
|
||||
is(ev.setting, tiltEnabled, "tiltEnabled event setting");
|
||||
is(ev.value, true, "tiltEnabled event value");
|
||||
is(ev.setting.value, true, "tiltEnabled event setting value");
|
||||
}
|
||||
tiltEnabled.onChange.add(tiltEnabledCheck);
|
||||
tiltEnabled.value = true;
|
||||
is(tiltEnabled.value, true, "tiltEnabled change");
|
||||
|
||||
function tabSizeCheck(ev) {
|
||||
is(ev.setting, tabSize, "tabSize event setting");
|
||||
is(ev.value, 1, "tabSize event value");
|
||||
is(ev.setting.value, 1, "tabSize event setting value");
|
||||
}
|
||||
tabSize.onChange.add(tabSizeCheck);
|
||||
tabSize.value = 1;
|
||||
is(tabSize.value, 1, "tabSize change");
|
||||
|
||||
function remoteHostCheck(ev) {
|
||||
is(ev.setting, remoteHost, "remoteHost event setting");
|
||||
is(ev.value, "y.com", "remoteHost event value");
|
||||
is(ev.setting.value, "y.com", "remoteHost event setting value");
|
||||
}
|
||||
remoteHost.onChange.add(remoteHostCheck);
|
||||
remoteHost.value = "y.com";
|
||||
is(remoteHost.value, "y.com", "remoteHost change");
|
||||
|
||||
tiltEnabled.onChange.remove(tiltEnabledCheck);
|
||||
tabSize.onChange.remove(tabSizeCheck);
|
||||
remoteHost.onChange.remove(remoteHostCheck);
|
||||
|
||||
function remoteHostReCheck(ev) {
|
||||
is(ev.setting, remoteHost, "remoteHost event reset");
|
||||
is(ev.value, null, "remoteHost event revalue");
|
||||
is(ev.setting.value, null, "remoteHost event setting revalue");
|
||||
}
|
||||
remoteHost.onChange.add(remoteHostReCheck);
|
||||
|
||||
tiltEnabled.setDefault();
|
||||
tabSize.setDefault();
|
||||
remoteHost.setDefault();
|
||||
|
||||
remoteHost.onChange.remove(remoteHostReCheck);
|
||||
|
||||
is(tiltEnabled.value, tiltEnabledDefault, "tiltEnabled reset");
|
||||
is(tabSize.value, tabSizeDefault, "tabSize reset");
|
||||
is(remoteHost.value, remoteHostDefault, "remoteHost reset");
|
||||
}
|
@ -156,10 +156,11 @@ define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/e
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('test/examiner', ['require', 'exports', 'module' , 'test/assert'], function(require, exports, module) {
|
||||
define('test/examiner', ['require', 'exports', 'module' , 'test/assert', 'test/status'], function(require, exports, module) {
|
||||
var examiner = exports;
|
||||
|
||||
var assert = require('test/assert');
|
||||
var stati = require('test/status').stati;
|
||||
|
||||
/**
|
||||
* Test harness data
|
||||
@ -171,14 +172,6 @@ examiner.suites = {};
|
||||
*/
|
||||
var delay = 10;
|
||||
|
||||
var stati = {
|
||||
notrun: { index: 0, name: 'Skipped' },
|
||||
executing: { index: 1, name: 'Executing' },
|
||||
asynchronous: { index: 2, name: 'Waiting' },
|
||||
pass: { index: 3, name: 'Pass' },
|
||||
fail: { index: 4, name: 'Fail' }
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a test suite. Generally used like:
|
||||
* test.addSuite('foo', require('path/to/foo'));
|
||||
@ -580,6 +573,28 @@ define('test/assert', ['require', 'exports', 'module' ], function(require, expor
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('test/status', ['require', 'exports', 'module' ], function(require, exports, module) {
|
||||
|
||||
/**
|
||||
* This should really be inside assert.js, however that is over-ridden by
|
||||
* a custom assert.js for mozilla, so we keep it separate to avoid
|
||||
* duplicating it in 2 places.
|
||||
*/
|
||||
exports.stati = {
|
||||
notrun: { index: 0, name: 'Skipped' },
|
||||
executing: { index: 1, name: 'Executing' },
|
||||
asynchronous: { index: 2, name: 'Waiting' },
|
||||
pass: { index: 3, name: 'Pass' },
|
||||
fail: { index: 4, name: 'Fail' }
|
||||
};
|
||||
|
||||
});
|
||||
/*
|
||||
* 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('gclitest/testCanon', ['require', 'exports', 'module' , 'gclitest/helpers', 'gcli/canon', 'test/assert'], function(require, exports, module) {
|
||||
|
||||
var helpers = require('gclitest/helpers');
|
||||
@ -657,6 +672,14 @@ define('gclitest/testCanon', ['require', 'exports', 'module' , 'gclitest/helpers
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
canon.removeCommand({ name: 'nonexistant' });
|
||||
test.is(canon.getCommands().length, startCount, 'nonexistant1 command success');
|
||||
test.is(events, 5, 'nonexistant1 event');
|
||||
|
||||
canon.removeCommand('nonexistant');
|
||||
test.is(canon.getCommands().length, startCount, 'nonexistant2 command success');
|
||||
test.is(events, 5, 'nonexistant2 event');
|
||||
|
||||
canon.onCanonChange.remove(canonChange);
|
||||
};
|
||||
|
||||
@ -2215,8 +2238,7 @@ define('gclitest/testIntro', ['require', 'exports', 'module' , 'gclitest/helpers
|
||||
typed: 'intro',
|
||||
args: { },
|
||||
outputMatch: [
|
||||
/graphical\s*command\s*line/,
|
||||
/GCLI/,
|
||||
/command\s*line/,
|
||||
/help/,
|
||||
/F1/,
|
||||
/Escape/
|
||||
@ -2610,9 +2632,69 @@ exports.shutdown = function(options) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.testPrefShowStatus = function(options) {
|
||||
if (options.isFirefox) {
|
||||
test.log('Skipping testPrefShowStatus in Firefox.');
|
||||
return;
|
||||
}
|
||||
|
||||
helpers.status(options, {
|
||||
typed: 'pref s',
|
||||
markup: 'IIIIVI',
|
||||
status: 'ERROR',
|
||||
directTabText: 'et'
|
||||
});
|
||||
|
||||
helpers.status(options, {
|
||||
typed: 'pref show',
|
||||
markup: 'VVVVVVVVV',
|
||||
status: 'ERROR',
|
||||
emptyParameters: [ ' <setting>' ]
|
||||
});
|
||||
|
||||
helpers.status(options, {
|
||||
typed: 'pref show ',
|
||||
markup: 'VVVVVVVVVV',
|
||||
status: 'ERROR',
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
helpers.status(options, {
|
||||
typed: 'pref show tempTBo',
|
||||
markup: 'VVVVVVVVVVIIIIIII',
|
||||
directTabText: 'ol',
|
||||
status: 'ERROR',
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
helpers.status(options, {
|
||||
typed: 'pref show tempTBool',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVV',
|
||||
directTabText: '',
|
||||
status: 'VALID',
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
helpers.status(options, {
|
||||
typed: 'pref show tempTBool 4',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVE',
|
||||
directTabText: '',
|
||||
status: 'ERROR',
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
helpers.status(options, {
|
||||
typed: 'pref show tempNumber 4',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVE',
|
||||
directTabText: '',
|
||||
status: 'ERROR',
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
};
|
||||
|
||||
exports.testPrefSetStatus = function(options) {
|
||||
if (options.isFirefox) {
|
||||
test.log('Skipping testPref in Firefox.');
|
||||
test.log('Skipping testPrefSetStatus in Firefox.');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2643,13 +2725,6 @@ exports.testPrefSetStatus = function(options) {
|
||||
emptyParameters: [ ' <value>' ]
|
||||
});
|
||||
|
||||
helpers.status(options, {
|
||||
typed: 'pref set ',
|
||||
markup: 'VVVVVVVVV',
|
||||
status: 'ERROR',
|
||||
emptyParameters: [ ' <value>' ]
|
||||
});
|
||||
|
||||
helpers.status(options, {
|
||||
typed: 'pref set tempTBo',
|
||||
markup: 'VVVVVVVVVIIIIIII',
|
||||
@ -2677,7 +2752,7 @@ exports.testPrefSetStatus = function(options) {
|
||||
|
||||
exports.testPrefExec = function(options) {
|
||||
if (options.isFirefox) {
|
||||
test.log('Skipping testPref in Firefox.');
|
||||
test.log('Skipping testPrefExec in Firefox.');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2738,313 +2813,6 @@ exports.testPrefExec = function(options) {
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gcli/commands/pref', ['require', 'exports', 'module' , 'gcli/index', 'gcli/l10n', 'gcli/util', 'gcli/settings', 'gcli/promise', 'text!gcli/commands/pref_list_outer.html', 'text!gcli/commands/pref_list.css', 'text!gcli/commands/pref_set_check.html', 'text!gcli/commands/pref_list_inner.html'], function(require, exports, module) {
|
||||
|
||||
|
||||
var gcli = require('gcli/index');
|
||||
var l10n = require('gcli/l10n');
|
||||
var util = require('gcli/util');
|
||||
var settings = require('gcli/settings');
|
||||
var Promise = require('gcli/promise').Promise;
|
||||
|
||||
/**
|
||||
* Record if the user has clicked on 'Got It!'
|
||||
*/
|
||||
var allowSetSettingSpec = {
|
||||
name: 'allowSet',
|
||||
type: 'boolean',
|
||||
description: l10n.lookup('allowSetDesc'),
|
||||
defaultValue: false
|
||||
};
|
||||
exports.allowSet = undefined;
|
||||
|
||||
/**
|
||||
* 'pref' command
|
||||
*/
|
||||
var prefCmdSpec = {
|
||||
name: 'pref',
|
||||
description: l10n.lookup('prefDesc'),
|
||||
manual: l10n.lookup('prefManual')
|
||||
};
|
||||
|
||||
/**
|
||||
* 'pref list' command
|
||||
*/
|
||||
var prefListCmdSpec = {
|
||||
name: 'pref list',
|
||||
description: l10n.lookup('prefListDesc'),
|
||||
manual: l10n.lookup('prefListManual'),
|
||||
params: [
|
||||
{
|
||||
name: 'search',
|
||||
type: 'string',
|
||||
defaultValue: null,
|
||||
description: l10n.lookup('prefListSearchDesc'),
|
||||
manual: l10n.lookup('prefListSearchManual')
|
||||
}
|
||||
],
|
||||
exec: function Command_prefList(args, context) {
|
||||
return context.createView({
|
||||
html: require('text!gcli/commands/pref_list_outer.html'),
|
||||
data: new PrefList(args, context),
|
||||
options: {
|
||||
blankNullUndefined: true,
|
||||
allowEval: true,
|
||||
stack: 'pref_list_outer.html'
|
||||
},
|
||||
css: require('text!gcli/commands/pref_list.css'),
|
||||
cssId: 'gcli-pref-list'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 'pref set' command
|
||||
*/
|
||||
var prefSetCmdSpec = {
|
||||
name: 'pref set',
|
||||
description: l10n.lookup('prefSetDesc'),
|
||||
manual: l10n.lookup('prefSetManual'),
|
||||
params: [
|
||||
{
|
||||
name: 'setting',
|
||||
type: 'setting',
|
||||
description: l10n.lookup('prefSetSettingDesc'),
|
||||
manual: l10n.lookup('prefSetSettingManual')
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
type: 'settingValue',
|
||||
description: l10n.lookup('prefSetValueDesc'),
|
||||
manual: l10n.lookup('prefSetValueManual')
|
||||
}
|
||||
],
|
||||
exec: function Command_prefSet(args, context) {
|
||||
if (!exports.allowSet.value &&
|
||||
args.setting.name !== exports.allowSet.name) {
|
||||
return context.createView({
|
||||
html: require('text!gcli/commands/pref_set_check.html'),
|
||||
options: { allowEval: true, stack: 'pref_set_check.html' },
|
||||
data: {
|
||||
l10n: l10n.propertyLookup,
|
||||
activate: function() {
|
||||
context.exec('pref set allowSet true');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
args.setting.value = args.value;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 'pref reset' command
|
||||
*/
|
||||
var prefResetCmdSpec = {
|
||||
name: 'pref reset',
|
||||
description: l10n.lookup('prefResetDesc'),
|
||||
manual: l10n.lookup('prefResetManual'),
|
||||
params: [
|
||||
{
|
||||
name: 'setting',
|
||||
type: 'setting',
|
||||
description: l10n.lookup('prefResetSettingDesc'),
|
||||
manual: l10n.lookup('prefResetSettingManual')
|
||||
}
|
||||
],
|
||||
exec: function Command_prefReset(args, context) {
|
||||
args.setting.setDefault();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Registration and de-registration.
|
||||
*/
|
||||
exports.startup = function() {
|
||||
exports.allowSet = settings.addSetting(allowSetSettingSpec);
|
||||
|
||||
gcli.addCommand(prefCmdSpec);
|
||||
gcli.addCommand(prefListCmdSpec);
|
||||
gcli.addCommand(prefSetCmdSpec);
|
||||
gcli.addCommand(prefResetCmdSpec);
|
||||
};
|
||||
|
||||
exports.shutdown = function() {
|
||||
gcli.removeCommand(prefCmdSpec);
|
||||
gcli.removeCommand(prefListCmdSpec);
|
||||
gcli.removeCommand(prefSetCmdSpec);
|
||||
gcli.removeCommand(prefResetCmdSpec);
|
||||
|
||||
settings.removeSetting(allowSetSettingSpec);
|
||||
exports.allowSet = undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A manager for our version of about:config
|
||||
*/
|
||||
function PrefList(args, context) {
|
||||
this.search = args.search;
|
||||
this.context = context;
|
||||
this.url = util.createUrlLookup(module);
|
||||
this.edit = this.url('pref_list_edit.png');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PrefList.prototype.onLoad = function(element) {
|
||||
var table = element.querySelector('.gcli-pref-list-table');
|
||||
this.updateTable(table);
|
||||
return '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Forward localization lookups
|
||||
*/
|
||||
PrefList.prototype.l10n = l10n.propertyLookup;
|
||||
|
||||
/**
|
||||
* Called from the template onkeyup for the filter element
|
||||
*/
|
||||
PrefList.prototype.updateTable = function(table) {
|
||||
util.clearElement(table);
|
||||
var view = this.context.createView({
|
||||
html: require('text!gcli/commands/pref_list_inner.html'),
|
||||
options: { blankNullUndefined: true, stack: 'pref_list_inner.html' },
|
||||
data: this
|
||||
});
|
||||
var child = view.toDom(table.ownerDocument);
|
||||
util.setContents(table, child);
|
||||
};
|
||||
|
||||
/**
|
||||
* Which preferences match the filter?
|
||||
*/
|
||||
Object.defineProperty(PrefList.prototype, 'preferences', {
|
||||
get: function() {
|
||||
return settings.getAll(this.search);
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
/**
|
||||
* Which preferences match the filter?
|
||||
*/
|
||||
Object.defineProperty(PrefList.prototype, 'promisePreferences', {
|
||||
get: function() {
|
||||
var promise = new Promise();
|
||||
setTimeout(function() {
|
||||
promise.resolve(settings.getAll(this.search));
|
||||
}.bind(this), 10);
|
||||
return promise;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
PrefList.prototype.onFilterChange = function(ev) {
|
||||
if (ev.target.value !== this.search) {
|
||||
this.search = ev.target.value;
|
||||
|
||||
var root = ev.target.parentNode.parentNode;
|
||||
var table = root.querySelector('.gcli-pref-list-table');
|
||||
this.updateTable(table);
|
||||
}
|
||||
};
|
||||
|
||||
PrefList.prototype.onSetClick = function(ev) {
|
||||
var typed = ev.currentTarget.getAttribute('data-command');
|
||||
this.context.update(typed);
|
||||
};
|
||||
|
||||
});
|
||||
define("text!gcli/commands/pref_list_outer.html", [], "<div ignore=\"${onLoad(__element)}\">\n" +
|
||||
" <div class=\"gcli-pref-list-filter\">\n" +
|
||||
" ${l10n.prefOutputFilter}:\n" +
|
||||
" <input onKeyUp=\"${onFilterChange}\" value=\"${search}\"/>\n" +
|
||||
" </div>\n" +
|
||||
" <table class=\"gcli-pref-list-table\">\n" +
|
||||
" <colgroup>\n" +
|
||||
" <col class=\"gcli-pref-list-name\"/>\n" +
|
||||
" <col class=\"gcli-pref-list-value\"/>\n" +
|
||||
" </colgroup>\n" +
|
||||
" <tr>\n" +
|
||||
" <th>${l10n.prefOutputName}</th>\n" +
|
||||
" <th>${l10n.prefOutputValue}</th>\n" +
|
||||
" </tr>\n" +
|
||||
" </table>\n" +
|
||||
" <div class=\"gcli-pref-list-scroller\">\n" +
|
||||
" <table class=\"gcli-pref-list-table\" save=\"${table}\">\n" +
|
||||
" </table>\n" +
|
||||
" </div>\n" +
|
||||
"</div>\n" +
|
||||
"");
|
||||
|
||||
define("text!gcli/commands/pref_list.css", [], "\n" +
|
||||
".gcli-pref-list-scroller {\n" +
|
||||
" max-height: 200px;\n" +
|
||||
" overflow-y: auto;\n" +
|
||||
" overflow-x: hidden;\n" +
|
||||
" display: inline-block;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".gcli-pref-list-table {\n" +
|
||||
" width: 500px;\n" +
|
||||
" table-layout: fixed;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".gcli-pref-list-table tr > th {\n" +
|
||||
" text-align: left;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".gcli-pref-list-table tr > td {\n" +
|
||||
" text-overflow: elipsis;\n" +
|
||||
" word-wrap: break-word;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".gcli-pref-list-name {\n" +
|
||||
" width: 70%;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".gcli-pref-list-command {\n" +
|
||||
" display: none;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".gcli-pref-list-row:hover .gcli-pref-list-command {\n" +
|
||||
" display: inline-block;\n" +
|
||||
"}\n" +
|
||||
"");
|
||||
|
||||
define("text!gcli/commands/pref_set_check.html", [], "<div>\n" +
|
||||
" <p><strong>${l10n.prefSetCheckHeading}</strong></p>\n" +
|
||||
" <p>${l10n.prefSetCheckBody}</p>\n" +
|
||||
" <button onclick=\"${activate}\">${l10n.prefSetCheckGo}</button>\n" +
|
||||
"</div>\n" +
|
||||
"");
|
||||
|
||||
define("text!gcli/commands/pref_list_inner.html", [], "<table>\n" +
|
||||
" <colgroup>\n" +
|
||||
" <col class=\"gcli-pref-list-name\"/>\n" +
|
||||
" <col class=\"gcli-pref-list-value\"/>\n" +
|
||||
" </colgroup>\n" +
|
||||
" <tr class=\"gcli-pref-list-row\" foreach=\"preference in ${promisePreferences}\">\n" +
|
||||
" <td>${preference.name}</td>\n" +
|
||||
" <td onclick=\"${onSetClick}\" data-command=\"pref set ${preference.name} \">\n" +
|
||||
" ${preference.value}\n" +
|
||||
" <img class=\"gcli-pref-list-command\" _src=\"${edit}\"/>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
"</table>\n" +
|
||||
"");
|
||||
|
||||
/*
|
||||
* 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('gclitest/mockSettings', ['require', 'exports', 'module' , 'gcli/settings'], function(require, exports, module) {
|
||||
|
||||
|
||||
@ -4109,6 +3877,7 @@ let testModuleNames = [
|
||||
'gclitest/suite',
|
||||
'test/examiner',
|
||||
'test/assert',
|
||||
'test/status',
|
||||
'gclitest/testCanon',
|
||||
'gclitest/helpers',
|
||||
'gclitest/testCli',
|
||||
@ -4122,11 +3891,6 @@ let testModuleNames = [
|
||||
'gclitest/testJs',
|
||||
'gclitest/testKeyboard',
|
||||
'gclitest/testPref',
|
||||
'gcli/commands/pref',
|
||||
'text!gcli/commands/pref_list_outer.html',
|
||||
'text!gcli/commands/pref_list.css',
|
||||
'text!gcli/commands/pref_set_check.html',
|
||||
'text!gcli/commands/pref_list_inner.html',
|
||||
'gclitest/mockSettings',
|
||||
'gclitest/testRequire',
|
||||
'gclitest/requirable',
|
||||
|
@ -146,7 +146,8 @@ let DeveloperToolbarTest = {
|
||||
*
|
||||
* // Thing to check
|
||||
* args: { message: "hi" }, // Check that the args were understood properly
|
||||
* outputMatch: /^hi$/, // Regex to test against textContent of output
|
||||
* outputMatch: /^hi$/, // RegExp to test against textContent of output
|
||||
* // (can also be array of RegExps)
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
@ -201,10 +202,21 @@ let DeveloperToolbarTest = {
|
||||
let displayed = DeveloperToolbar.outputPanel._div.textContent;
|
||||
|
||||
if (test.outputMatch) {
|
||||
if (!test.outputMatch.test(displayed)) {
|
||||
ok(false, "html output for " + typed + " (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(displayed);
|
||||
function doTest(match, against) {
|
||||
if (!match.test(against)) {
|
||||
ok(false, "html output for " + typed + " against " + match.source +
|
||||
" (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(against);
|
||||
}
|
||||
}
|
||||
if (Array.isArray(test.outputMatch)) {
|
||||
test.outputMatch.forEach(function(match) {
|
||||
doTest(match, displayed);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(test.outputMatch, displayed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,9 +418,11 @@ StackFrames.prototype = {
|
||||
_onFrames: function SF__onFrames() {
|
||||
if (!this.activeThread.cachedFrames.length) {
|
||||
DebuggerView.StackFrames.emptyText();
|
||||
DebuggerView.Properties.emptyText();
|
||||
return;
|
||||
}
|
||||
DebuggerView.StackFrames.empty();
|
||||
DebuggerView.Properties.empty();
|
||||
|
||||
for each (let frame in this.activeThread.cachedFrames) {
|
||||
this._addFrame(frame);
|
||||
@ -451,8 +453,7 @@ StackFrames.prototype = {
|
||||
_afterFramesCleared: function SF__afterFramesCleared() {
|
||||
if (!this.activeThread.cachedFrames.length) {
|
||||
DebuggerView.StackFrames.emptyText();
|
||||
DebuggerView.Properties.localScope.empty();
|
||||
DebuggerView.Properties.globalScope.empty();
|
||||
DebuggerView.Properties.emptyText();
|
||||
DebuggerController.dispatchEvent("Debugger:AfterFramesCleared");
|
||||
}
|
||||
},
|
||||
@ -521,39 +522,77 @@ StackFrames.prototype = {
|
||||
// Start recording any added variables or properties in any scope.
|
||||
DebuggerView.Properties.createHierarchyStore();
|
||||
|
||||
// Display the local variables.
|
||||
let localScope = DebuggerView.Properties.localScope;
|
||||
localScope.empty();
|
||||
|
||||
// Add "this".
|
||||
if (frame.this) {
|
||||
let thisVar = localScope.addVar("this");
|
||||
thisVar.setGrip({
|
||||
type: frame.this.type,
|
||||
class: frame.this.class
|
||||
});
|
||||
this._addExpander(thisVar, frame.this);
|
||||
}
|
||||
// Clear existing scopes and create each one dynamically.
|
||||
DebuggerView.Properties.empty();
|
||||
|
||||
if (frame.environment) {
|
||||
// Add nodes for every argument.
|
||||
let variables = frame.environment.bindings.arguments;
|
||||
for each (let variable in variables) {
|
||||
let name = Object.getOwnPropertyNames(variable)[0];
|
||||
let paramVar = localScope.addVar(name);
|
||||
let paramVal = variable[name].value;
|
||||
paramVar.setGrip(paramVal);
|
||||
this._addExpander(paramVar, paramVal);
|
||||
}
|
||||
let env = frame.environment;
|
||||
do {
|
||||
// Construct the scope name.
|
||||
let name = env.type.charAt(0).toUpperCase() + env.type.slice(1);
|
||||
// Call the outermost scope Global.
|
||||
if (!env.parent) {
|
||||
name = L10N.getStr("globalScopeLabel");
|
||||
}
|
||||
let label = L10N.getFormatStr("scopeLabel", [name]);
|
||||
switch (env.type) {
|
||||
case "with":
|
||||
case "object":
|
||||
label += " [" + env.object.class + "]";
|
||||
break;
|
||||
case "function":
|
||||
if (env.functionName) {
|
||||
label += " [" + env.functionName + "]";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Add nodes for every other variable in scope.
|
||||
variables = frame.environment.bindings.variables;
|
||||
for (let variable in variables) {
|
||||
let paramVar = localScope.addVar(variable);
|
||||
let paramVal = variables[variable].value;
|
||||
paramVar.setGrip(paramVal);
|
||||
this._addExpander(paramVar, paramVal);
|
||||
}
|
||||
let scope = DebuggerView.Properties.addScope(label);
|
||||
|
||||
// Add "this" to the innermost scope.
|
||||
if (frame.this && env == frame.environment) {
|
||||
let thisVar = scope.addVar("this");
|
||||
thisVar.setGrip({
|
||||
type: frame.this.type,
|
||||
class: frame.this.class
|
||||
});
|
||||
this._addExpander(thisVar, frame.this);
|
||||
// Expand the innermost scope by default.
|
||||
scope.expand(true);
|
||||
scope.addToHierarchy();
|
||||
}
|
||||
|
||||
switch (env.type) {
|
||||
case "with":
|
||||
case "object":
|
||||
let objClient = this.activeThread.pauseGrip(env.object);
|
||||
objClient.getPrototypeAndProperties(function SF_getProps(aResponse) {
|
||||
this._addScopeVariables(aResponse.ownProperties, scope);
|
||||
// Signal that variables have been fetched.
|
||||
DebuggerController.dispatchEvent("Debugger:FetchedVariables");
|
||||
}.bind(this));
|
||||
break;
|
||||
case "block":
|
||||
case "function":
|
||||
// Add nodes for every argument.
|
||||
let variables = env.bindings.arguments;
|
||||
for each (let variable in variables) {
|
||||
let name = Object.getOwnPropertyNames(variable)[0];
|
||||
let paramVar = scope.addVar(name);
|
||||
let paramVal = variable[name].value;
|
||||
paramVar.setGrip(paramVal);
|
||||
this._addExpander(paramVar, paramVal);
|
||||
}
|
||||
// Add nodes for every other variable in scope.
|
||||
this._addScopeVariables(env.bindings.variables, scope);
|
||||
break;
|
||||
default:
|
||||
Cu.reportError("Unknown Debugger.Environment type: " + env.type);
|
||||
break;
|
||||
}
|
||||
} while (env = env.parent);
|
||||
}
|
||||
|
||||
// Signal that variables have been fetched.
|
||||
@ -567,6 +606,31 @@ StackFrames.prototype = {
|
||||
DebuggerView.Properties.commitHierarchy();
|
||||
},
|
||||
|
||||
/**
|
||||
* Add nodes for every variable in scope.
|
||||
*
|
||||
* @param object aVariables
|
||||
* The map of names to variables, as specified in the Remote
|
||||
* Debugging Protocol.
|
||||
* @param object aScope
|
||||
* The scope where the nodes will be placed into.
|
||||
*/
|
||||
_addScopeVariables: function SF_addScopeVariables(aVariables, aScope) {
|
||||
// Sort all of the variables before adding them, for better UX.
|
||||
let variables = {};
|
||||
for each (let prop in Object.keys(aVariables).sort()) {
|
||||
variables[prop] = aVariables[prop];
|
||||
}
|
||||
|
||||
// Add the sorted variables to the specified scope.
|
||||
for (let variable in variables) {
|
||||
let paramVar = aScope.addVar(variable);
|
||||
let paramVal = variables[variable].value;
|
||||
paramVar.setGrip(paramVal);
|
||||
this._addExpander(paramVar, paramVal);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an 'onexpand' callback for a variable, lazily handling the addition of
|
||||
* new properties.
|
||||
|
@ -760,12 +760,17 @@ StackFramesView.prototype = {
|
||||
* Functions handling the properties view.
|
||||
*/
|
||||
function PropertiesView() {
|
||||
this._addScope = this._addScope.bind(this);
|
||||
this.addScope = this._addScope.bind(this);
|
||||
this._addVar = this._addVar.bind(this);
|
||||
this._addProperties = this._addProperties.bind(this);
|
||||
}
|
||||
|
||||
PropertiesView.prototype = {
|
||||
/**
|
||||
* A monotonically-increasing counter, that guarantees the uniqueness of scope
|
||||
* IDs.
|
||||
*/
|
||||
_idCount: 1,
|
||||
|
||||
/**
|
||||
* Adds a scope to contain any inspected variables.
|
||||
@ -786,8 +791,8 @@ PropertiesView.prototype = {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Compute the id of the element if not specified.
|
||||
aId = aId || (aName.toLowerCase().trim().replace(" ", "-") + "-scope");
|
||||
// Generate a unique id for the element, if not specified.
|
||||
aId = aId || aName.toLowerCase().trim().replace(/\s+/g, "-") + this._idCount++;
|
||||
|
||||
// Contains generic nodes and functionality.
|
||||
let element = this._createPropertyElement(aName, aId, "scope", this._vars);
|
||||
@ -796,16 +801,48 @@ PropertiesView.prototype = {
|
||||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
element._identifier = aName;
|
||||
|
||||
/**
|
||||
* @see DebuggerView.Properties._addVar
|
||||
*/
|
||||
element.addVar = this._addVar.bind(this, element);
|
||||
|
||||
/**
|
||||
* @see DebuggerView.Properties.addScopeToHierarchy
|
||||
*/
|
||||
element.addToHierarchy = this.addScopeToHierarchy.bind(this, element);
|
||||
|
||||
// Return the element for later use if necessary.
|
||||
return element;
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all added scopes in the property container tree.
|
||||
*/
|
||||
empty: function DVP_empty() {
|
||||
while (this._vars.firstChild) {
|
||||
this._vars.removeChild(this._vars.firstChild);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all elements from the variables container, and adds a child node
|
||||
* with an empty text note attached.
|
||||
*/
|
||||
emptyText: function DVP_emptyText() {
|
||||
// Make sure the container is empty first.
|
||||
this.empty();
|
||||
|
||||
let item = document.createElement("label");
|
||||
|
||||
// The empty node should look grayed out to avoid confusion.
|
||||
item.className = "list-item empty";
|
||||
item.setAttribute("value", L10N.getStr("emptyVariablesText"));
|
||||
|
||||
this._vars.appendChild(item);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a variable to a specified scope.
|
||||
* If the optional id is not specified, the variable html node will have a
|
||||
@ -837,6 +874,7 @@ PropertiesView.prototype = {
|
||||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
element._identifier = aName;
|
||||
|
||||
/**
|
||||
* @see DebuggerView.Properties._setGrip
|
||||
@ -1050,6 +1088,7 @@ PropertiesView.prototype = {
|
||||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
element._identifier = aName;
|
||||
|
||||
/**
|
||||
* @see DebuggerView.Properties._setGrip
|
||||
@ -1382,16 +1421,22 @@ PropertiesView.prototype = {
|
||||
|
||||
/**
|
||||
* Expands the element, showing all the added details.
|
||||
*
|
||||
* @param boolean aSkipAnimationFlag
|
||||
* Pass true to not show an opening animation.
|
||||
* @return object
|
||||
* The same element.
|
||||
*/
|
||||
element.expand = function DVP_element_expand() {
|
||||
element.expand = function DVP_element_expand(aSkipAnimationFlag) {
|
||||
if (element._preventExpand) {
|
||||
return;
|
||||
}
|
||||
arrow.setAttribute("open", "");
|
||||
details.setAttribute("open", "");
|
||||
|
||||
if (!aSkipAnimationFlag) {
|
||||
details.setAttribute("animated", "");
|
||||
}
|
||||
if ("function" === typeof element.onexpand) {
|
||||
element.onexpand(element);
|
||||
}
|
||||
@ -1409,6 +1454,7 @@ PropertiesView.prototype = {
|
||||
}
|
||||
arrow.removeAttribute("open");
|
||||
details.removeAttribute("open");
|
||||
details.removeAttribute("animated");
|
||||
|
||||
if ("function" === typeof element.oncollapse) {
|
||||
element.oncollapse(element);
|
||||
@ -1621,7 +1667,7 @@ PropertiesView.prototype = {
|
||||
children: {}
|
||||
};
|
||||
|
||||
store[element.id] = relation;
|
||||
store[element._identifier] = relation;
|
||||
element._root = relation.root;
|
||||
element._children = relation.children;
|
||||
},
|
||||
@ -1633,11 +1679,16 @@ PropertiesView.prototype = {
|
||||
createHierarchyStore: function DVP_createHierarchyStore() {
|
||||
this._prevHierarchy = this._currHierarchy;
|
||||
this._currHierarchy = {};
|
||||
},
|
||||
|
||||
this._saveHierarchy({ element: this._globalScope, store: this._currHierarchy });
|
||||
this._saveHierarchy({ element: this._localScope, store: this._currHierarchy });
|
||||
this._saveHierarchy({ element: this._withScope, store: this._currHierarchy });
|
||||
this._saveHierarchy({ element: this._closureScope, store: this._currHierarchy });
|
||||
/**
|
||||
* Creates a hierarchy holder for a scope.
|
||||
*
|
||||
* @param object aScope
|
||||
* The designated scope to track.
|
||||
*/
|
||||
addScopeToHierarchy: function DVP_addScopeToHierarchy(aScope) {
|
||||
this._saveHierarchy({ element: aScope, store: this._currHierarchy });
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1648,6 +1699,10 @@ PropertiesView.prototype = {
|
||||
let currScope = this._currHierarchy[i];
|
||||
let prevScope = this._prevHierarchy[i];
|
||||
|
||||
if (!prevScope) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let v in currScope.children) {
|
||||
let currVar = currScope.children[v];
|
||||
let prevVar = prevScope.children[v];
|
||||
@ -1672,7 +1727,7 @@ PropertiesView.prototype = {
|
||||
|
||||
window.setTimeout(function() {
|
||||
currVar.element.removeAttribute(action);
|
||||
}, PROPERTY_VIEW_FLASH_DURATION);
|
||||
}, PROPERTY_VIEW_FLASH_DURATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1685,103 +1740,11 @@ PropertiesView.prototype = {
|
||||
_currHierarchy: null,
|
||||
_prevHierarchy: null,
|
||||
|
||||
/**
|
||||
* Returns the global scope container.
|
||||
*/
|
||||
get globalScope() {
|
||||
return this._globalScope;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the display mode for the global scope container.
|
||||
*
|
||||
* @param boolean aFlag
|
||||
* False to hide the container, true to show.
|
||||
*/
|
||||
set globalScope(aFlag) {
|
||||
if (aFlag) {
|
||||
this._globalScope.show();
|
||||
} else {
|
||||
this._globalScope.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the local scope container.
|
||||
*/
|
||||
get localScope() {
|
||||
return this._localScope;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the display mode for the local scope container.
|
||||
*
|
||||
* @param boolean aFlag
|
||||
* False to hide the container, true to show.
|
||||
*/
|
||||
set localScope(aFlag) {
|
||||
if (aFlag) {
|
||||
this._localScope.show();
|
||||
} else {
|
||||
this._localScope.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the with block scope container.
|
||||
*/
|
||||
get withScope() {
|
||||
return this._withScope;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the display mode for the with block scope container.
|
||||
*
|
||||
* @param boolean aFlag
|
||||
* False to hide the container, true to show.
|
||||
*/
|
||||
set withScope(aFlag) {
|
||||
if (aFlag) {
|
||||
this._withScope.show();
|
||||
} else {
|
||||
this._withScope.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the closure scope container.
|
||||
*/
|
||||
get closureScope() {
|
||||
return this._closureScope;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the display mode for the with block scope container.
|
||||
*
|
||||
* @param boolean aFlag
|
||||
* False to hide the container, true to show.
|
||||
*/
|
||||
set closureScope(aFlag) {
|
||||
if (aFlag) {
|
||||
this._closureScope.show();
|
||||
} else {
|
||||
this._closureScope.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The cached variable properties container.
|
||||
*/
|
||||
_vars: null,
|
||||
|
||||
/**
|
||||
* Auto-created global, local, with block and closure scopes containing vars.
|
||||
*/
|
||||
_globalScope: null,
|
||||
_localScope: null,
|
||||
_withScope: null,
|
||||
_closureScope: null,
|
||||
|
||||
/**
|
||||
* Initialization function, called when the debugger is initialized.
|
||||
*/
|
||||
@ -1789,10 +1752,6 @@ PropertiesView.prototype = {
|
||||
this.createHierarchyStore();
|
||||
|
||||
this._vars = document.getElementById("variables");
|
||||
this._localScope = this._addScope(L10N.getStr("localScope")).expand();
|
||||
this._withScope = this._addScope(L10N.getStr("withScope")).hide();
|
||||
this._closureScope = this._addScope(L10N.getStr("closureScope")).hide();
|
||||
this._globalScope = this._addScope(L10N.getStr("globalScope"));
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1802,10 +1761,6 @@ PropertiesView.prototype = {
|
||||
this._currHierarchy = null;
|
||||
this._prevHierarchy = null;
|
||||
this._vars = null;
|
||||
this._globalScope = null;
|
||||
this._localScope = null;
|
||||
this._withScope = null;
|
||||
this._closureScope = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -30,6 +30,8 @@ _BROWSER_TEST_FILES = \
|
||||
browser_dbg_propertyview-06.js \
|
||||
browser_dbg_propertyview-07.js \
|
||||
browser_dbg_propertyview-08.js \
|
||||
browser_dbg_propertyview-09.js \
|
||||
browser_dbg_propertyview-10.js \
|
||||
browser_dbg_propertyview-edit.js \
|
||||
browser_dbg_panesize.js \
|
||||
browser_dbg_stack-01.js \
|
||||
@ -66,6 +68,7 @@ _BROWSER_TEST_PAGES = \
|
||||
test-editor-mode \
|
||||
browser_dbg_displayName.html \
|
||||
browser_dbg_iframes.html \
|
||||
browser_dbg_with-frame.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_TEST_FILES)
|
||||
|
@ -23,65 +23,14 @@ function testSimpleCall() {
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let globalScope = gDebugger.DebuggerView.Properties._globalScope;
|
||||
let localScope = gDebugger.DebuggerView.Properties._localScope;
|
||||
let withScope = gDebugger.DebuggerView.Properties._withScope;
|
||||
let closureScope = gDebugger.DebuggerView.Properties._closureScope;
|
||||
|
||||
ok(globalScope,
|
||||
"Should have a globalScope container for the variables property view.");
|
||||
|
||||
ok(localScope,
|
||||
"Should have a localScope container for the variables property view.");
|
||||
|
||||
ok(withScope,
|
||||
"Should have a withScope container for the variables property view.");
|
||||
|
||||
ok(closureScope,
|
||||
"Should have a closureScope container for the variables property view.");
|
||||
|
||||
is(globalScope, gDebugger.DebuggerView.Properties.globalScope,
|
||||
"The globalScope object should be equal to the corresponding getter.");
|
||||
|
||||
is(localScope, gDebugger.DebuggerView.Properties.localScope,
|
||||
"The localScope object should be equal to the corresponding getter.");
|
||||
|
||||
is(withScope, gDebugger.DebuggerView.Properties.withScope,
|
||||
"The withScope object should be equal to the corresponding getter.");
|
||||
|
||||
is(closureScope, gDebugger.DebuggerView.Properties.closureScope,
|
||||
"The closureScope object should be equal to the corresponding getter.");
|
||||
|
||||
|
||||
ok(!globalScope.expanded,
|
||||
"The globalScope should be initially collapsed.");
|
||||
|
||||
ok(localScope.expanded,
|
||||
"The localScope should be initially expanded.");
|
||||
|
||||
ok(!withScope.expanded,
|
||||
"The withScope should be initially collapsed.");
|
||||
|
||||
ok(!withScope.visible,
|
||||
"The withScope should be initially hidden.");
|
||||
|
||||
ok(!closureScope.expanded,
|
||||
"The closureScope should be initially collapsed.");
|
||||
|
||||
ok(!closureScope.visible,
|
||||
"The closureScope should be initially hidden.");
|
||||
|
||||
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 4,
|
||||
"Should have only 4 scopes created: global, local, with and scope.");
|
||||
|
||||
resumeAndFinish();
|
||||
testScriptLabelShortening();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
function testScriptLabelShortening() {
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
let vs = gDebugger.DebuggerView.Scripts;
|
||||
let ss = gDebugger.DebuggerController.SourceScripts;
|
||||
|
@ -28,7 +28,7 @@ function testSimpleCall() {
|
||||
ok(testScope,
|
||||
"Should have created a scope.");
|
||||
|
||||
is(testScope.id, "test-scope",
|
||||
is(testScope.id.substring(0, 4), "test",
|
||||
"The newly created scope should have the default id set.");
|
||||
|
||||
is(testScope.querySelector(".name").getAttribute("value"), "test",
|
||||
@ -37,8 +37,8 @@ function testSimpleCall() {
|
||||
is(testScope.querySelector(".details").childNodes.length, 0,
|
||||
"Any new scope should have a container with no child nodes.");
|
||||
|
||||
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 5,
|
||||
"Should have 5 scopes created: global, local, with, closure and test.");
|
||||
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 3,
|
||||
"Should have 3 scopes created.");
|
||||
|
||||
|
||||
ok(!testScope.expanded,
|
||||
|
@ -23,7 +23,7 @@ function testSimpleCall() {
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let testScope = gDebugger.DebuggerView.Properties._addScope("test");
|
||||
let testScope = gDebugger.DebuggerView.Properties._addScope("test-scope");
|
||||
let testVar = testScope.addVar("something");
|
||||
let duplVar = testScope.addVar("something");
|
||||
|
||||
@ -33,9 +33,6 @@ function testSimpleCall() {
|
||||
is(duplVar, null,
|
||||
"Shouldn't be able to duplicate variables in the same scope.");
|
||||
|
||||
is(testVar.id, "test-scope->something-variable",
|
||||
"The newly created scope should have the default id set.");
|
||||
|
||||
is(testVar.querySelector(".name").getAttribute("value"), "something",
|
||||
"Any new variable should have the designated title.");
|
||||
|
||||
@ -188,7 +185,7 @@ function testSimpleCall() {
|
||||
is(removeCallbackSender, testScope,
|
||||
"The removeCallback wasn't called as it should.");
|
||||
|
||||
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 4,
|
||||
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 2,
|
||||
"The scope should have been removed from the parent container tree.");
|
||||
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
|
@ -23,8 +23,8 @@ function testSimpleCall() {
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let globalScope = gDebugger.DebuggerView.Properties.globalScope;
|
||||
let localScope = gDebugger.DebuggerView.Properties.localScope;
|
||||
let globalScope = gDebugger.DebuggerView.Properties.addScope("Global");
|
||||
let localScope = gDebugger.DebuggerView.Properties.addScope("Local");
|
||||
globalScope.empty();
|
||||
localScope.empty();
|
||||
|
||||
|
@ -37,7 +37,7 @@ function testFrameParameters()
|
||||
|
||||
var frames = gDebugger.DebuggerView.StackFrames._frames,
|
||||
childNodes = frames.childNodes,
|
||||
localScope = gDebugger.DebuggerView.Properties.localScope,
|
||||
localScope = gDebugger.DebuggerView.Properties._vars.firstChild,
|
||||
localNodes = localScope.querySelector(".details").childNodes;
|
||||
|
||||
dump("Got our variables:\n");
|
||||
@ -79,14 +79,14 @@ function testFrameParameters()
|
||||
is(localNodes[7].querySelector(".value").getAttribute("value"), "1",
|
||||
"Should have the right property value for 'a'.");
|
||||
|
||||
is(localNodes[8].querySelector(".value").getAttribute("value"), "[object Object]",
|
||||
"Should have the right property value for 'b'.");
|
||||
is(localNodes[8].querySelector(".value").getAttribute("value"), "[object Arguments]",
|
||||
"Should have the right property value for 'arguments'.");
|
||||
|
||||
is(localNodes[9].querySelector(".value").getAttribute("value"), "[object Object]",
|
||||
"Should have the right property value for 'c'.");
|
||||
"Should have the right property value for 'b'.");
|
||||
|
||||
is(localNodes[10].querySelector(".value").getAttribute("value"), "[object Arguments]",
|
||||
"Should have the right property value for 'arguments'.");
|
||||
is(localNodes[10].querySelector(".value").getAttribute("value"), "[object Object]",
|
||||
"Should have the right property value for 'c'.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
|
@ -36,7 +36,7 @@ function testFrameParameters()
|
||||
dump("After currentThread.dispatch!\n");
|
||||
|
||||
var frames = gDebugger.DebuggerView.StackFrames._frames,
|
||||
localScope = gDebugger.DebuggerView.Properties.localScope,
|
||||
localScope = gDebugger.DebuggerView.Properties._vars.firstChild,
|
||||
localNodes = localScope.querySelector(".details").childNodes;
|
||||
|
||||
dump("Got our variables:\n");
|
||||
@ -59,7 +59,7 @@ function testFrameParameters()
|
||||
// Expand the 'this', 'arguments' and 'c' tree nodes. This causes
|
||||
// their properties to be retrieved and displayed.
|
||||
localNodes[0].expand();
|
||||
localNodes[9].expand();
|
||||
localNodes[8].expand();
|
||||
localNodes[10].expand();
|
||||
|
||||
// Poll every few milliseconds until the properties are retrieved.
|
||||
@ -73,7 +73,7 @@ function testFrameParameters()
|
||||
resumeAndFinish();
|
||||
}
|
||||
if (!localNodes[0].fetched ||
|
||||
!localNodes[9].fetched ||
|
||||
!localNodes[8].fetched ||
|
||||
!localNodes[10].fetched) {
|
||||
return;
|
||||
}
|
||||
@ -86,29 +86,29 @@ function testFrameParameters()
|
||||
.getAttribute("value").search(/object/) != -1,
|
||||
"__proto__ should be an object.");
|
||||
|
||||
is(localNodes[9].querySelector(".value").getAttribute("value"), "[object Object]",
|
||||
"Should have the right property value for 'c'.");
|
||||
|
||||
is(localNodes[9].querySelectorAll(".property > .title > .key")[1]
|
||||
.getAttribute("value"), "a",
|
||||
"Should have the right property name for 'a'.");
|
||||
|
||||
is(localNodes[9].querySelectorAll(".property > .title > .value")[1]
|
||||
.getAttribute("value"), 1,
|
||||
"Should have the right value for 'c.a'.");
|
||||
|
||||
is(localNodes[10].querySelector(".value").getAttribute("value"),
|
||||
is(localNodes[8].querySelector(".value").getAttribute("value"),
|
||||
"[object Arguments]",
|
||||
"Should have the right property value for 'arguments'.");
|
||||
|
||||
is(localNodes[10].querySelectorAll(".property > .title > .key")[7]
|
||||
is(localNodes[8].querySelectorAll(".property > .title > .key")[7]
|
||||
.getAttribute("value"), "length",
|
||||
"Should have the right property name for 'length'.");
|
||||
|
||||
is(localNodes[10].querySelectorAll(".property > .title > .value")[7]
|
||||
is(localNodes[8].querySelectorAll(".property > .title > .value")[7]
|
||||
.getAttribute("value"), 5,
|
||||
"Should have the right argument length.");
|
||||
|
||||
is(localNodes[10].querySelector(".value").getAttribute("value"), "[object Object]",
|
||||
"Should have the right property value for 'c'.");
|
||||
|
||||
is(localNodes[10].querySelectorAll(".property > .title > .key")[1]
|
||||
.getAttribute("value"), "a",
|
||||
"Should have the right property name for 'a'.");
|
||||
|
||||
is(localNodes[10].querySelectorAll(".property > .title > .value")[1]
|
||||
.getAttribute("value"), 1,
|
||||
"Should have the right value for 'c.a'.");
|
||||
|
||||
resumeAndFinish();
|
||||
}, 100);
|
||||
}}, 0);
|
||||
|
@ -0,0 +1,94 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure that the property view populates the global scope pane.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_frame-parameters.html";
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.contentWindow;
|
||||
|
||||
testFrameParameters();
|
||||
});
|
||||
}
|
||||
|
||||
function testFrameParameters()
|
||||
{
|
||||
let count = 0;
|
||||
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
|
||||
// We expect 2 Debugger:FetchedVariables events, one from the global object
|
||||
// scope and the regular one.
|
||||
if (++count <2) {
|
||||
info("Number of received Debugger:FetchedVariables events: " + count);
|
||||
return;
|
||||
}
|
||||
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
var frames = gDebugger.DebuggerView.StackFrames._frames,
|
||||
globalScope = gDebugger.DebuggerView.Properties._vars.lastChild,
|
||||
globalNodes = globalScope.querySelector(".details").childNodes;
|
||||
|
||||
globalScope.expand();
|
||||
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 3,
|
||||
"Should have three frames.");
|
||||
|
||||
is(globalNodes[0].querySelector(".name").getAttribute("value"), "Array",
|
||||
"Should have the right property name for |Array|.");
|
||||
|
||||
is(globalNodes[0].querySelector(".value").getAttribute("value"), "[object Function]",
|
||||
"Should have the right property value for |Array|.");
|
||||
|
||||
let len = globalNodes.length - 1;
|
||||
is(globalNodes[len].querySelector(".name").getAttribute("value"), "window",
|
||||
"Should have the right property name for |window|.");
|
||||
|
||||
is(globalNodes[len].querySelector(".value").getAttribute("value"), "[object Proxy]",
|
||||
"Should have the right property value for |window|.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
}, false);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
content.document.querySelector("button"),
|
||||
content.window);
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.addEventListener("Debugger:AfterFramesCleared", function listener() {
|
||||
gDebugger.removeEventListener("Debugger:AfterFramesCleared", listener, true);
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
var frames = gDebugger.DebuggerView.StackFrames._frames;
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
|
||||
"Should have no frames.");
|
||||
|
||||
closeDebuggerAndFinish(gTab);
|
||||
}}, 0);
|
||||
}, true);
|
||||
|
||||
gDebugger.DebuggerController.activeThread.resume();
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebugger = null;
|
||||
});
|
105
browser/devtools/debugger/test/browser_dbg_propertyview-10.js
Normal file
105
browser/devtools/debugger/test/browser_dbg_propertyview-10.js
Normal file
@ -0,0 +1,105 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure that the property view is correctly populated in |with| frames.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_with-frame.html";
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.contentWindow;
|
||||
|
||||
testWithFrame();
|
||||
});
|
||||
}
|
||||
|
||||
function testWithFrame()
|
||||
{
|
||||
let count = 0;
|
||||
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
|
||||
// We expect 4 Debugger:FetchedVariables events, one from the global object
|
||||
// scope, two from the |with| scopes and the regular one.
|
||||
if (++count <3) {
|
||||
info("Number of received Debugger:FetchedVariables events: " + count);
|
||||
return;
|
||||
}
|
||||
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
var frames = gDebugger.DebuggerView.StackFrames._frames,
|
||||
scopes = gDebugger.DebuggerView.Properties._vars,
|
||||
globalScope = scopes.lastChild,
|
||||
innerScope = scopes.firstChild,
|
||||
globalNodes = globalScope.querySelector(".details").childNodes,
|
||||
innerNodes = innerScope.querySelector(".details").childNodes;
|
||||
|
||||
globalScope.expand();
|
||||
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 2,
|
||||
"Should have three frames.");
|
||||
|
||||
is(scopes.children.length, 5, "Should have 5 variable scopes.");
|
||||
|
||||
is(innerNodes[1].querySelector(".name").getAttribute("value"), "one",
|
||||
"Should have the right property name for |one|.");
|
||||
|
||||
is(innerNodes[1].querySelector(".value").getAttribute("value"), "1",
|
||||
"Should have the right property value for |one|.");
|
||||
|
||||
is(globalNodes[0].querySelector(".name").getAttribute("value"), "Array",
|
||||
"Should have the right property name for |Array|.");
|
||||
|
||||
is(globalNodes[0].querySelector(".value").getAttribute("value"), "[object Function]",
|
||||
"Should have the right property value for |Array|.");
|
||||
|
||||
let len = globalNodes.length - 1;
|
||||
is(globalNodes[len].querySelector(".name").getAttribute("value"), "window",
|
||||
"Should have the right property name for |window|.");
|
||||
|
||||
is(globalNodes[len].querySelector(".value").getAttribute("value"), "[object Proxy]",
|
||||
"Should have the right property value for |window|.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
}, false);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
content.document.querySelector("button"),
|
||||
content.window);
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.addEventListener("Debugger:AfterFramesCleared", function listener() {
|
||||
gDebugger.removeEventListener("Debugger:AfterFramesCleared", listener, true);
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
var frames = gDebugger.DebuggerView.StackFrames._frames;
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
|
||||
"Should have no frames.");
|
||||
|
||||
closeDebuggerAndFinish(gTab);
|
||||
}}, 0);
|
||||
}, true);
|
||||
|
||||
gDebugger.DebuggerController.activeThread.resume();
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebugger = null;
|
||||
});
|
@ -29,7 +29,7 @@ function testFrameEval() {
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
var localScope = gDebugger.DebuggerView.Properties.localScope,
|
||||
var localScope = gDebugger.DebuggerView.Properties._vars.firstChild,
|
||||
localNodes = localScope.querySelector(".details").childNodes,
|
||||
varA = localNodes[7];
|
||||
|
||||
@ -68,11 +68,18 @@ function testModification(aVar, aCallback, aNewValue, aNewResult) {
|
||||
ok(aVar.querySelector(".element-input"),
|
||||
"There should be an input element created.");
|
||||
|
||||
let count = 0;
|
||||
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
|
||||
// We expect 2 Debugger:FetchedVariables events, one from the global
|
||||
// object scope and the regular one.
|
||||
if (++count <2) {
|
||||
info("Number of received Debugger:FetchedVariables events: " + count);
|
||||
return;
|
||||
}
|
||||
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
|
||||
// Get the variable reference anew, since the old ones were discarded when
|
||||
// we resumed.
|
||||
var localScope = gDebugger.DebuggerView.Properties.localScope,
|
||||
var localScope = gDebugger.DebuggerView.Properties._vars.firstChild,
|
||||
localNodes = localScope.querySelector(".details").childNodes,
|
||||
varA = localNodes[7];
|
||||
|
||||
|
33
browser/devtools/debugger/test/browser_dbg_with-frame.html
Normal file
33
browser/devtools/debugger/test/browser_dbg_with-frame.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<title>Debugger Function Call Parameter Test</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript">
|
||||
window.addEventListener("load", function() {
|
||||
function test(aNumber) {
|
||||
var a, obj = { one: 1, two: 2 };
|
||||
var r = aNumber;
|
||||
with (Math) {
|
||||
a = PI * r * r;
|
||||
with (obj) {
|
||||
var foo = two * PI;
|
||||
debugger;
|
||||
}
|
||||
}
|
||||
};
|
||||
function load() {
|
||||
test(10);
|
||||
}
|
||||
var button = document.querySelector("button");
|
||||
button.addEventListener("click", load, false);
|
||||
});
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<button>Click me!</button>
|
||||
</body>
|
||||
</html>
|
@ -31,9 +31,7 @@ const console = (function() {
|
||||
*/
|
||||
function define(moduleName, deps, payload) {
|
||||
if (typeof moduleName != "string") {
|
||||
console.error(this.depth + " Error: Module name is not a string.");
|
||||
console.trace();
|
||||
return;
|
||||
throw new Error("Error: Module name is not a string");
|
||||
}
|
||||
|
||||
if (arguments.length == 2) {
|
||||
@ -49,8 +47,11 @@ function define(moduleName, deps, payload) {
|
||||
}
|
||||
|
||||
if (moduleName in define.modules) {
|
||||
console.error(this.depth + " Error: Redefining module: " + moduleName);
|
||||
throw new Error("Error: Redefining module: " + moduleName);
|
||||
}
|
||||
|
||||
// Mark the payload so we know we need to call it to get the real module
|
||||
payload.__uncompiled = true;
|
||||
define.modules[moduleName] = payload;
|
||||
}
|
||||
|
||||
@ -65,14 +66,6 @@ define.modules = {};
|
||||
define.debugDependencies = false;
|
||||
|
||||
|
||||
/**
|
||||
* Self executing function in which Domain is defined, and attached to define
|
||||
*/
|
||||
var Syntax = {
|
||||
COMMON_JS: 'commonjs',
|
||||
AMD: 'amd'
|
||||
};
|
||||
|
||||
/**
|
||||
* We invoke require() in the context of a Domain so we can have multiple
|
||||
* sets of modules running separate from each other.
|
||||
@ -83,7 +76,6 @@ var Syntax = {
|
||||
*/
|
||||
function Domain() {
|
||||
this.modules = {};
|
||||
this.syntax = Syntax.COMMON_JS;
|
||||
|
||||
if (define.debugDependencies) {
|
||||
this.depth = "";
|
||||
@ -111,7 +103,6 @@ Domain.prototype.require = function(config, deps, callback) {
|
||||
}
|
||||
|
||||
if (Array.isArray(deps)) {
|
||||
this.syntax = Syntax.AMD;
|
||||
var params = deps.map(function(dep) {
|
||||
return this.lookup(dep);
|
||||
}, this);
|
||||
@ -141,8 +132,7 @@ Domain.prototype.lookup = function(moduleName) {
|
||||
}
|
||||
|
||||
if (!(moduleName in define.modules)) {
|
||||
console.error(this.depth + " Missing module: " + moduleName);
|
||||
return null;
|
||||
throw new Error("Missing module: " + moduleName);
|
||||
}
|
||||
|
||||
var module = define.modules[moduleName];
|
||||
@ -151,29 +141,33 @@ Domain.prototype.lookup = function(moduleName) {
|
||||
console.log(this.depth + " Compiling module: " + moduleName);
|
||||
}
|
||||
|
||||
if (typeof module == "function") {
|
||||
if (module.__uncompiled) {
|
||||
if (define.debugDependencies) {
|
||||
this.depth += ".";
|
||||
}
|
||||
|
||||
var exports;
|
||||
var exports = {};
|
||||
try {
|
||||
if (this.syntax === Syntax.COMMON_JS) {
|
||||
exports = {};
|
||||
module(this.require.bind(this), exports, { id: moduleName, uri: "" });
|
||||
}
|
||||
else {
|
||||
var modules = module.deps.map(function(dep) {
|
||||
return this.lookup(dep);
|
||||
}.bind(this));
|
||||
exports = module.apply(null, modules);
|
||||
}
|
||||
var params = module.deps.map(function(dep) {
|
||||
if (dep === "require") {
|
||||
return this.require.bind(this);
|
||||
}
|
||||
if (dep === "exports") {
|
||||
return exports;
|
||||
}
|
||||
if (dep === "module") {
|
||||
return { id: moduleName, uri: "" };
|
||||
}
|
||||
return this.lookup(dep);
|
||||
}.bind(this));
|
||||
|
||||
var reply = module.apply(null, params);
|
||||
module = (reply !== undefined) ? reply : exports;
|
||||
}
|
||||
catch (ex) {
|
||||
console.error("Error using module: " + moduleName, ex);
|
||||
dump("Error using module '" + moduleName + "' - " + ex + "\n");
|
||||
throw ex;
|
||||
}
|
||||
module = exports;
|
||||
|
||||
if (define.debugDependencies) {
|
||||
this.depth = this.depth.slice(0, -1);
|
||||
|
@ -56,6 +56,7 @@ function Templater(options) {
|
||||
else {
|
||||
this.stack = [];
|
||||
}
|
||||
this.nodes = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,6 +94,7 @@ Templater.prototype.processNode = function(node, data) {
|
||||
data = {};
|
||||
}
|
||||
this.stack.push(node.nodeName + (node.id ? '#' + node.id : ''));
|
||||
var pushedNode = false;
|
||||
try {
|
||||
// Process attributes
|
||||
if (node.attributes && node.attributes.length) {
|
||||
@ -109,7 +111,9 @@ Templater.prototype.processNode = function(node, data) {
|
||||
}
|
||||
}
|
||||
// Only make the node available once we know it's not going away
|
||||
this.nodes.push(data.__element);
|
||||
data.__element = node;
|
||||
pushedNode = true;
|
||||
// It's good to clean up the attributes when we've processed them,
|
||||
// but if we do it straight away, we mess up the array index
|
||||
var attrs = Array.prototype.slice.call(node.attributes);
|
||||
@ -172,7 +176,9 @@ Templater.prototype.processNode = function(node, data) {
|
||||
this._processTextNode(node, data);
|
||||
}
|
||||
} finally {
|
||||
delete data.__element;
|
||||
if (pushedNode) {
|
||||
data.__element = this.nodes.pop();
|
||||
}
|
||||
this.stack.pop();
|
||||
}
|
||||
};
|
||||
@ -347,11 +353,14 @@ Templater.prototype._processTextNode = function(node, data) {
|
||||
reply = this._maybeImportNode(reply, doc);
|
||||
siblingNode.parentNode.insertBefore(reply, siblingNode);
|
||||
} else if (typeof reply.item === 'function' && reply.length) {
|
||||
// if thing is a NodeList, then import the children
|
||||
for (var i = 0; i < reply.length; i++) {
|
||||
var child = this._maybeImportNode(reply.item(i), doc);
|
||||
siblingNode.parentNode.insertBefore(child, siblingNode);
|
||||
}
|
||||
// NodeLists can be live, in which case _maybeImportNode can
|
||||
// remove them from the document, and thus the NodeList, which in
|
||||
// turn breaks iteration. So first we clone the list
|
||||
var list = Array.prototype.slice.call(reply, 0);
|
||||
list.forEach(function(child) {
|
||||
var imported = this._maybeImportNode(child, doc);
|
||||
siblingNode.parentNode.insertBefore(imported, siblingNode);
|
||||
}.bind(this));
|
||||
}
|
||||
else {
|
||||
// if thing isn't a DOM element then wrap its string value in one
|
||||
|
@ -21,13 +21,14 @@ function test() {
|
||||
testMultiImport();
|
||||
testRecursive();
|
||||
testUncompilable();
|
||||
testFirebug();
|
||||
|
||||
shutdown();
|
||||
});
|
||||
}
|
||||
|
||||
function setup() {
|
||||
define('gclitest/requirable', [], function(require, exports, module) {
|
||||
define('gclitest/requirable', [ 'require', 'exports', 'module' ], function(require, exports, module) {
|
||||
exports.thing1 = 'thing1';
|
||||
exports.thing2 = 2;
|
||||
|
||||
@ -36,13 +37,17 @@ function setup() {
|
||||
exports.getStatus = function() { return status; };
|
||||
});
|
||||
|
||||
define('gclitest/unrequirable', [], function(require, exports, module) {
|
||||
define('gclitest/unrequirable', [ 'require', 'exports', 'module' ], function(require, exports, module) {
|
||||
null.throwNPE();
|
||||
});
|
||||
|
||||
define('gclitest/recurse', [], function(require, exports, module) {
|
||||
define('gclitest/recurse', [ 'require', 'exports', 'module', 'gclitest/recurse' ], function(require, exports, module) {
|
||||
require('gclitest/recurse');
|
||||
});
|
||||
|
||||
define('gclitest/firebug', [ 'gclitest/requirable' ], function(requirable) {
|
||||
return { requirable: requirable, fb: true };
|
||||
});
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
@ -52,6 +57,8 @@ function shutdown() {
|
||||
delete define.globalDomain.modules['gclitest/unrequirable'];
|
||||
delete define.modules['gclitest/recurse'];
|
||||
delete define.globalDomain.modules['gclitest/recurse'];
|
||||
delete define.modules['gclitest/firebug'];
|
||||
delete define.globalDomain.modules['gclitest/firebug'];
|
||||
|
||||
define = undefined;
|
||||
require = undefined;
|
||||
@ -124,3 +131,10 @@ function testRecursive() {
|
||||
// require('gclitest/recurse');
|
||||
// Also see the comments in the testRecursive() function
|
||||
}
|
||||
|
||||
function testFirebug() {
|
||||
let requirable = require('gclitest/requirable');
|
||||
let firebug = require('gclitest/firebug');
|
||||
ok(firebug.fb, 'firebug.fb is true');
|
||||
is(requirable, firebug.requirable, 'requirable pass-through');
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||
EXTRA_JS_MODULES = \
|
||||
PropertyPanel.jsm \
|
||||
NetworkHelper.jsm \
|
||||
NetworkPanel.jsm \
|
||||
AutocompletePopup.jsm \
|
||||
WebConsoleUtils.jsm \
|
||||
$(NULL)
|
||||
|
@ -49,6 +49,7 @@
|
||||
* Austin Andrews
|
||||
* Christoph Dorn
|
||||
* Steven Roussey (AppCenter Inc, Network54)
|
||||
* Mihai Sucan (Mozilla Corp.)
|
||||
*/
|
||||
|
||||
const Cc = Components.classes;
|
||||
@ -68,7 +69,7 @@ var EXPORTED_SYMBOLS = ["NetworkHelper"];
|
||||
/**
|
||||
* Helper object for networking stuff.
|
||||
*
|
||||
* All of the following functions have been taken from the Firebug source. They
|
||||
* Most of the following functions have been taken from the Firebug source. They
|
||||
* have been modified to match the Firefox coding rules.
|
||||
*/
|
||||
|
||||
@ -128,12 +129,13 @@ var NetworkHelper =
|
||||
* Reads the posted text from aRequest.
|
||||
*
|
||||
* @param nsIHttpChannel aRequest
|
||||
* @param nsIDOMNode aBrowser
|
||||
* @param string aCharset
|
||||
* The content document charset, used when reading the POSTed data.
|
||||
* @returns string or null
|
||||
* Returns the posted string if it was possible to read from aRequest
|
||||
* otherwise null.
|
||||
*/
|
||||
readPostTextFromRequest: function NH_readPostTextFromRequest(aRequest, aBrowser)
|
||||
readPostTextFromRequest: function NH_readPostTextFromRequest(aRequest, aCharset)
|
||||
{
|
||||
if (aRequest instanceof Ci.nsIUploadChannel) {
|
||||
let iStream = aRequest.uploadStream;
|
||||
@ -150,8 +152,7 @@ var NetworkHelper =
|
||||
}
|
||||
|
||||
// Read data from the stream.
|
||||
let charset = aBrowser.contentWindow.document.characterSet;
|
||||
let text = this.readAndConvertFromStream(iStream, charset);
|
||||
let text = this.readAndConvertFromStream(iStream, aCharset);
|
||||
|
||||
// Seek locks the file, so seek to the beginning only if necko hasn't
|
||||
// read it yet, since necko doesn't seek to 0 before reading (at lest
|
||||
@ -167,14 +168,15 @@ var NetworkHelper =
|
||||
/**
|
||||
* Reads the posted text from the page's cache.
|
||||
*
|
||||
* @param nsIDOMNode aBrowser
|
||||
* @param nsIDocShell aDocShell
|
||||
* @param string aCharset
|
||||
* @returns string or null
|
||||
* Returns the posted string if it was possible to read from aBrowser
|
||||
* otherwise null.
|
||||
* Returns the posted string if it was possible to read from
|
||||
* aDocShell otherwise null.
|
||||
*/
|
||||
readPostTextFromPage: function NH_readPostTextFromPage(aBrowser)
|
||||
readPostTextFromPage: function NH_readPostTextFromPage(aDocShell, aCharset)
|
||||
{
|
||||
let webNav = aBrowser.webNavigation;
|
||||
let webNav = aDocShell.QueryInterface(Ci.nsIWebNavigation);
|
||||
if (webNav instanceof Ci.nsIWebPageDescriptor) {
|
||||
let descriptor = webNav.currentDescriptor;
|
||||
|
||||
@ -182,8 +184,7 @@ var NetworkHelper =
|
||||
descriptor instanceof Ci.nsISeekableStream) {
|
||||
descriptor.seek(NS_SEEK_SET, 0);
|
||||
|
||||
let charset = browser.contentWindow.document.characterSet;
|
||||
return this.readAndConvertFromStream(descriptor, charset);
|
||||
return this.readAndConvertFromStream(descriptor, aCharset);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -266,6 +267,81 @@ var NetworkHelper =
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse a raw Cookie header value.
|
||||
*
|
||||
* @param string aHeader
|
||||
* The raw Cookie header value.
|
||||
* @return array
|
||||
* Array holding an object for each cookie. Each object holds the
|
||||
* following properties: name and value.
|
||||
*/
|
||||
parseCookieHeader: function NH_parseCookieHeader(aHeader)
|
||||
{
|
||||
let cookies = aHeader.split(";");
|
||||
let result = [];
|
||||
|
||||
cookies.forEach(function(aCookie) {
|
||||
let [name, value] = aCookie.split("=");
|
||||
result.push({name: unescape(name.trim()),
|
||||
value: unescape(value.trim())});
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse a raw Set-Cookie header value.
|
||||
*
|
||||
* @param string aHeader
|
||||
* The raw Set-Cookie header value.
|
||||
* @return array
|
||||
* Array holding an object for each cookie. Each object holds the
|
||||
* following properties: name, value, secure (boolean), httpOnly
|
||||
* (boolean), path, domain and expires (ISO date string).
|
||||
*/
|
||||
parseSetCookieHeader: function NH_parseSetCookieHeader(aHeader)
|
||||
{
|
||||
let rawCookies = aHeader.split(/\r\n|\n|\r/);
|
||||
let cookies = [];
|
||||
|
||||
rawCookies.forEach(function(aCookie) {
|
||||
let name = unescape(aCookie.substr(0, aCookie.indexOf("=")).trim());
|
||||
let parts = aCookie.substr(aCookie.indexOf("=") + 1).split(";");
|
||||
let value = unescape(parts.shift().trim());
|
||||
|
||||
let cookie = {name: name, value: value};
|
||||
|
||||
parts.forEach(function(aPart) {
|
||||
let part = aPart.trim();
|
||||
if (part.toLowerCase() == "secure") {
|
||||
cookie.secure = true;
|
||||
}
|
||||
else if (part.toLowerCase() == "httponly") {
|
||||
cookie.httpOnly = true;
|
||||
}
|
||||
else if (part.indexOf("=") > -1) {
|
||||
let pair = part.split("=");
|
||||
pair[0] = pair[0].toLowerCase();
|
||||
if (pair[0] == "path" || pair[0] == "domain") {
|
||||
cookie[pair[0]] = pair[1];
|
||||
}
|
||||
else if (pair[0] == "expires") {
|
||||
try {
|
||||
pair[1] = pair[1].replace(/-/g, ' ');
|
||||
cookie.expires = new Date(pair[1]).toISOString();
|
||||
}
|
||||
catch (ex) { }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cookies.push(cookie);
|
||||
});
|
||||
|
||||
return cookies;
|
||||
},
|
||||
|
||||
// This is a list of all the mime category maps jviereck could find in the
|
||||
// firebug code base.
|
||||
mimeCategoryMap: {
|
||||
@ -333,6 +409,7 @@ var NetworkHelper =
|
||||
"audio/x-wav": "media",
|
||||
"text/json": "json",
|
||||
"application/x-json": "json",
|
||||
"application/json-rpc": "json"
|
||||
"application/json-rpc": "json",
|
||||
"application/x-web-app-manifest+json": "json",
|
||||
}
|
||||
}
|
||||
|
668
browser/devtools/webconsole/NetworkPanel.jsm
Normal file
668
browser/devtools/webconsole/NetworkPanel.jsm
Normal file
@ -0,0 +1,668 @@
|
||||
/* -*- 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.defineLazyServiceGetter(this, "mimeService", "@mozilla.org/mime;1",
|
||||
"nsIMIMEService");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
|
||||
"resource:///modules/NetworkHelper.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
|
||||
"resource:///modules/WebConsoleUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "l10n", function() {
|
||||
return WebConsoleUtils.l10n;
|
||||
});
|
||||
|
||||
var EXPORTED_SYMBOLS = ["NetworkPanel"];
|
||||
|
||||
/**
|
||||
* Creates a new NetworkPanel.
|
||||
*
|
||||
* @param nsIDOMNode aParent
|
||||
* Parent node to append the created panel to.
|
||||
* @param object aHttpActivity
|
||||
* HttpActivity to display in the panel.
|
||||
*/
|
||||
function NetworkPanel(aParent, aHttpActivity)
|
||||
{
|
||||
let doc = aParent.ownerDocument;
|
||||
this.httpActivity = aHttpActivity;
|
||||
|
||||
// Create the underlaying panel
|
||||
this.panel = createElement(doc, "panel", {
|
||||
label: l10n.getStr("NetworkPanel.label"),
|
||||
titlebar: "normal",
|
||||
noautofocus: "true",
|
||||
noautohide: "true",
|
||||
close: "true"
|
||||
});
|
||||
|
||||
// Create the iframe that displays the NetworkPanel XHTML.
|
||||
this.iframe = createAndAppendElement(this.panel, "iframe", {
|
||||
src: "chrome://browser/content/NetworkPanel.xhtml",
|
||||
type: "content",
|
||||
flex: "1"
|
||||
});
|
||||
|
||||
let self = this;
|
||||
|
||||
// Destroy the panel when it's closed.
|
||||
this.panel.addEventListener("popuphidden", function onPopupHide() {
|
||||
self.panel.removeEventListener("popuphidden", onPopupHide, false);
|
||||
self.panel.parentNode.removeChild(self.panel);
|
||||
self.panel = null;
|
||||
self.iframe = null;
|
||||
self.document = null;
|
||||
self.httpActivity = null;
|
||||
|
||||
if (self.linkNode) {
|
||||
self.linkNode._panelOpen = false;
|
||||
self.linkNode = null;
|
||||
}
|
||||
}, false);
|
||||
|
||||
// Set the document object and update the content once the panel is loaded.
|
||||
this.panel.addEventListener("load", function onLoad() {
|
||||
self.panel.removeEventListener("load", onLoad, true);
|
||||
self.document = self.iframe.contentWindow.document;
|
||||
self.update();
|
||||
}, true);
|
||||
|
||||
// Create the footer.
|
||||
let footer = createElement(doc, "hbox", { align: "end" });
|
||||
createAndAppendElement(footer, "spacer", { flex: 1 });
|
||||
|
||||
createAndAppendElement(footer, "resizer", { dir: "bottomend" });
|
||||
this.panel.appendChild(footer);
|
||||
|
||||
aParent.appendChild(this.panel);
|
||||
}
|
||||
|
||||
NetworkPanel.prototype =
|
||||
{
|
||||
/**
|
||||
* Callback is called once the NetworkPanel is processed completely. Used by
|
||||
* unit tests.
|
||||
*/
|
||||
isDoneCallback: null,
|
||||
|
||||
/**
|
||||
* The current state of the output.
|
||||
*/
|
||||
_state: 0,
|
||||
|
||||
/**
|
||||
* State variables.
|
||||
*/
|
||||
_INIT: 0,
|
||||
_DISPLAYED_REQUEST_HEADER: 1,
|
||||
_DISPLAYED_REQUEST_BODY: 2,
|
||||
_DISPLAYED_RESPONSE_HEADER: 3,
|
||||
_TRANSITION_CLOSED: 4,
|
||||
|
||||
_fromDataRegExp: /Content-Type\:\s*application\/x-www-form-urlencoded/,
|
||||
|
||||
_contentType: null,
|
||||
|
||||
/**
|
||||
* Small helper function that is nearly equal to l10n.getFormatStr
|
||||
* except that it prefixes aName with "NetworkPanel.".
|
||||
*
|
||||
* @param string aName
|
||||
* The name of an i10n string to format. This string is prefixed with
|
||||
* "NetworkPanel." before calling the HUDService.getFormatStr function.
|
||||
* @param array aArray
|
||||
* Values used as placeholder for the i10n string.
|
||||
* @returns string
|
||||
* The i10n formated string.
|
||||
*/
|
||||
_format: function NP_format(aName, aArray)
|
||||
{
|
||||
return l10n.getFormatStr("NetworkPanel." + aName, aArray);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the content type of the response body. This is based on the
|
||||
* response.content.mimeType property. If this value is not available, then
|
||||
* the content type is guessed by the file extension of the request URL.
|
||||
*
|
||||
* @return string
|
||||
* Content type or empty string if no content type could be figured
|
||||
* out.
|
||||
*/
|
||||
get contentType()
|
||||
{
|
||||
if (this._contentType) {
|
||||
return this._contentType;
|
||||
}
|
||||
|
||||
let entry = this.httpActivity.log.entries[0];
|
||||
let request = entry.request;
|
||||
let response = entry.response;
|
||||
|
||||
let contentType = "";
|
||||
let types = response.content ?
|
||||
(response.content.mimeType || "").split(/,|;/) : [];
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
if (types[i] in NetworkHelper.mimeCategoryMap) {
|
||||
contentType = types[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (contentType) {
|
||||
this._contentType = contentType;
|
||||
return contentType;
|
||||
}
|
||||
|
||||
// Try to get the content type from the request file extension.
|
||||
let uri = NetUtil.newURI(request.url);
|
||||
if ((uri instanceof Ci.nsIURL) && uri.fileExtension) {
|
||||
try {
|
||||
contentType = mimeService.getTypeFromExtension(uri.fileExtension);
|
||||
}
|
||||
catch(ex) {
|
||||
// Added to prevent failures on OS X 64. No Flash?
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
this._contentType = contentType;
|
||||
return contentType;
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns boolean
|
||||
* True if the response is an image, false otherwise.
|
||||
*/
|
||||
get _responseIsImage()
|
||||
{
|
||||
return this.contentType &&
|
||||
NetworkHelper.mimeCategoryMap[this.contentType] == "image";
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns boolean
|
||||
* True if the response body contains text, false otherwise.
|
||||
*/
|
||||
get _isResponseBodyTextData()
|
||||
{
|
||||
let contentType = this.contentType;
|
||||
|
||||
if (!contentType)
|
||||
return false;
|
||||
|
||||
if (contentType.indexOf("text/") == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (NetworkHelper.mimeCategoryMap[contentType]) {
|
||||
case "txt":
|
||||
case "js":
|
||||
case "json":
|
||||
case "css":
|
||||
case "html":
|
||||
case "svg":
|
||||
case "xml":
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Tells if the server response is cached.
|
||||
*
|
||||
* @returns boolean
|
||||
* Returns true if the server responded that the request is already
|
||||
* in the browser's cache, false otherwise.
|
||||
*/
|
||||
get _isResponseCached()
|
||||
{
|
||||
return this.httpActivity.log.entries[0].response.status == 304;
|
||||
},
|
||||
|
||||
/**
|
||||
* Tells if the request body includes form data.
|
||||
*
|
||||
* @returns boolean
|
||||
* Returns true if the posted body contains form data.
|
||||
*/
|
||||
get _isRequestBodyFormData()
|
||||
{
|
||||
let requestBody = this.httpActivity.log.entries[0].request.postData.text;
|
||||
return this._fromDataRegExp.test(requestBody);
|
||||
},
|
||||
|
||||
/**
|
||||
* Appends the node with id=aId by the text aValue.
|
||||
*
|
||||
* @param string aId
|
||||
* @param string aValue
|
||||
* @returns void
|
||||
*/
|
||||
_appendTextNode: function NP_appendTextNode(aId, aValue)
|
||||
{
|
||||
let textNode = this.document.createTextNode(aValue);
|
||||
this.document.getElementById(aId).appendChild(textNode);
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates some HTML to display the key-value pair of the aList data. The
|
||||
* generated HTML is added to node with id=aParentId.
|
||||
*
|
||||
* @param string aParentId
|
||||
* Id of the parent node to append the list to.
|
||||
* @oaram array aList
|
||||
* Array that holds the objects you want to display. Each object must
|
||||
* have two properties: name and value.
|
||||
* @param boolean aIgnoreCookie
|
||||
* If true, the key-value named "Cookie" is not added to the list.
|
||||
* @returns void
|
||||
*/
|
||||
_appendList: function NP_appendList(aParentId, aList, aIgnoreCookie)
|
||||
{
|
||||
let parent = this.document.getElementById(aParentId);
|
||||
let doc = this.document;
|
||||
|
||||
aList.sort(function(a, b) {
|
||||
return a.name.toLowerCase() < b.name.toLowerCase();
|
||||
});
|
||||
|
||||
aList.forEach(function(aItem) {
|
||||
let name = aItem.name;
|
||||
let value = aItem.value;
|
||||
if (aIgnoreCookie && name == "Cookie") {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The following code creates the HTML:
|
||||
* <tr>
|
||||
* <th scope="row" class="property-name">${line}:</th>
|
||||
* <td class="property-value">${aList[line]}</td>
|
||||
* </tr>
|
||||
* and adds it to parent.
|
||||
*/
|
||||
let row = doc.createElement("tr");
|
||||
let textNode = doc.createTextNode(name + ":");
|
||||
let th = doc.createElement("th");
|
||||
th.setAttribute("scope", "row");
|
||||
th.setAttribute("class", "property-name");
|
||||
th.appendChild(textNode);
|
||||
row.appendChild(th);
|
||||
|
||||
textNode = doc.createTextNode(value);
|
||||
let td = doc.createElement("td");
|
||||
td.setAttribute("class", "property-value");
|
||||
td.appendChild(textNode);
|
||||
row.appendChild(td);
|
||||
|
||||
parent.appendChild(row);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the node with id=aId.
|
||||
*
|
||||
* @param string aId
|
||||
* @returns void
|
||||
*/
|
||||
_displayNode: function NP_displayNode(aId)
|
||||
{
|
||||
this.document.getElementById(aId).style.display = "block";
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the request URL, request method, the timing information when the
|
||||
* request started and the request header content on the NetworkPanel.
|
||||
* If the request header contains cookie data, a list of sent cookies is
|
||||
* generated and a special sent cookie section is displayed + the cookie list
|
||||
* added to it.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
_displayRequestHeader: function NP__displayRequestHeader()
|
||||
{
|
||||
let entry = this.httpActivity.log.entries[0];
|
||||
let request = entry.request;
|
||||
let requestTime = new Date(entry.startedDateTime);
|
||||
|
||||
this._appendTextNode("headUrl", request.url);
|
||||
this._appendTextNode("headMethod", request.method);
|
||||
this._appendTextNode("requestHeadersInfo",
|
||||
l10n.timestampString(requestTime));
|
||||
|
||||
this._appendList("requestHeadersContent", request.headers, true);
|
||||
|
||||
if (request.cookies.length > 0) {
|
||||
this._displayNode("requestCookie");
|
||||
this._appendList("requestCookieContent", request.cookies);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the request body section of the NetworkPanel and set the request
|
||||
* body content on the NetworkPanel.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
_displayRequestBody: function NP__displayRequestBody() {
|
||||
let postData = this.httpActivity.log.entries[0].request.postData;
|
||||
this._displayNode("requestBody");
|
||||
this._appendTextNode("requestBodyContent", postData.text);
|
||||
},
|
||||
|
||||
/*
|
||||
* Displays the `sent form data` section. Parses the request header for the
|
||||
* submitted form data displays it inside of the `sent form data` section.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
_displayRequestForm: function NP__processRequestForm() {
|
||||
let postData = this.httpActivity.log.entries[0].request.postData.text;
|
||||
let requestBodyLines = postData.split("\n");
|
||||
let formData = requestBodyLines[requestBodyLines.length - 1].
|
||||
replace(/\+/g, " ").split("&");
|
||||
|
||||
function unescapeText(aText)
|
||||
{
|
||||
try {
|
||||
return decodeURIComponent(aText);
|
||||
}
|
||||
catch (ex) {
|
||||
return decodeURIComponent(unescape(aText));
|
||||
}
|
||||
}
|
||||
|
||||
let formDataArray = [];
|
||||
for (let i = 0; i < formData.length; i++) {
|
||||
let data = formData[i];
|
||||
let idx = data.indexOf("=");
|
||||
let key = data.substring(0, idx);
|
||||
let value = data.substring(idx + 1);
|
||||
formDataArray.push({
|
||||
name: unescapeText(key),
|
||||
value: unescapeText(value)
|
||||
});
|
||||
}
|
||||
|
||||
this._appendList("requestFormDataContent", formDataArray);
|
||||
this._displayNode("requestFormData");
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the response section of the NetworkPanel, sets the response status,
|
||||
* the duration between the start of the request and the receiving of the
|
||||
* response header as well as the response header content on the the NetworkPanel.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
_displayResponseHeader: function NP__displayResponseHeader()
|
||||
{
|
||||
let entry = this.httpActivity.log.entries[0];
|
||||
let timing = entry.timings;
|
||||
let response = entry.response;
|
||||
|
||||
this._appendTextNode("headStatus",
|
||||
[response.httpVersion, response.status,
|
||||
response.statusText].join(" "));
|
||||
|
||||
// Calculate how much time it took from the request start, until the
|
||||
// response started to be received.
|
||||
let deltaDuration = 0;
|
||||
["dns", "connect", "send", "wait"].forEach(function (aValue) {
|
||||
let ms = timing[aValue];
|
||||
if (ms > -1) {
|
||||
deltaDuration += ms;
|
||||
}
|
||||
});
|
||||
|
||||
this._appendTextNode("responseHeadersInfo",
|
||||
this._format("durationMS", [deltaDuration]));
|
||||
|
||||
this._displayNode("responseContainer");
|
||||
this._appendList("responseHeadersContent", response.headers);
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the respones image section, sets the source of the image displayed
|
||||
* in the image response section to the request URL and the duration between
|
||||
* the receiving of the response header and the end of the request. Once the
|
||||
* image is loaded, the size of the requested image is set.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
_displayResponseImage: function NP__displayResponseImage()
|
||||
{
|
||||
let self = this;
|
||||
let entry = this.httpActivity.log.entries[0];
|
||||
let timing = entry.timings;
|
||||
let request = entry.request;
|
||||
let cached = "";
|
||||
|
||||
if (this._isResponseCached) {
|
||||
cached = "Cached";
|
||||
}
|
||||
|
||||
let imageNode = this.document.getElementById("responseImage" + cached +"Node");
|
||||
imageNode.setAttribute("src", request.url);
|
||||
|
||||
// This function is called to set the imageInfo.
|
||||
function setImageInfo() {
|
||||
self._appendTextNode("responseImage" + cached + "Info",
|
||||
self._format("imageSizeDeltaDurationMS",
|
||||
[ imageNode.width, imageNode.height, timing.receive ]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Check if the image is already loaded.
|
||||
if (imageNode.width != 0) {
|
||||
setImageInfo();
|
||||
}
|
||||
else {
|
||||
// Image is not loaded yet therefore add a load event.
|
||||
imageNode.addEventListener("load", function imageNodeLoad() {
|
||||
imageNode.removeEventListener("load", imageNodeLoad, false);
|
||||
setImageInfo();
|
||||
}, false);
|
||||
}
|
||||
|
||||
this._displayNode("responseImage" + cached);
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the response body section, sets the the duration between
|
||||
* the receiving of the response header and the end of the request as well as
|
||||
* the content of the response body on the NetworkPanel.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
_displayResponseBody: function NP__displayResponseBody()
|
||||
{
|
||||
let entry = this.httpActivity.log.entries[0];
|
||||
let timing = entry.timings;
|
||||
let response = entry.response;
|
||||
let cached = this._isResponseCached ? "Cached" : "";
|
||||
|
||||
this._appendTextNode("responseBody" + cached + "Info",
|
||||
this._format("durationMS", [timing.receive]));
|
||||
|
||||
this._displayNode("responseBody" + cached);
|
||||
this._appendTextNode("responseBody" + cached + "Content",
|
||||
response.content.text);
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the `Unknown Content-Type hint` and sets the duration between the
|
||||
* receiving of the response header on the NetworkPanel.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
_displayResponseBodyUnknownType: function NP__displayResponseBodyUnknownType()
|
||||
{
|
||||
let timing = this.httpActivity.log.entries[0].timings;
|
||||
|
||||
this._displayNode("responseBodyUnknownType");
|
||||
this._appendTextNode("responseBodyUnknownTypeInfo",
|
||||
this._format("durationMS", [timing.receive]));
|
||||
|
||||
this._appendTextNode("responseBodyUnknownTypeContent",
|
||||
this._format("responseBodyUnableToDisplay.content", [this.contentType]));
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the `no response body` section and sets the the duration between
|
||||
* the receiving of the response header and the end of the request.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
_displayNoResponseBody: function NP_displayNoResponseBody()
|
||||
{
|
||||
let timing = this.httpActivity.log.entries[0].timings;
|
||||
|
||||
this._displayNode("responseNoBody");
|
||||
this._appendTextNode("responseNoBodyInfo",
|
||||
this._format("durationMS", [timing.receive]));
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the content of the NetworkPanel's iframe.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
update: function NP_update()
|
||||
{
|
||||
// After the iframe's contentWindow is ready, the document object is set.
|
||||
// If the document object is not available yet nothing needs to be updated.
|
||||
if (!this.document) {
|
||||
return;
|
||||
}
|
||||
|
||||
let stages = this.httpActivity.meta.stages;
|
||||
let entry = this.httpActivity.log.entries[0];
|
||||
let timing = entry.timings;
|
||||
let request = entry.request;
|
||||
let response = entry.response;
|
||||
|
||||
switch (this._state) {
|
||||
case this._INIT:
|
||||
this._displayRequestHeader();
|
||||
this._state = this._DISPLAYED_REQUEST_HEADER;
|
||||
// FALL THROUGH
|
||||
|
||||
case this._DISPLAYED_REQUEST_HEADER:
|
||||
// Process the request body if there is one.
|
||||
if (!this.httpActivity.meta.discardRequestBody && request.postData) {
|
||||
// Check if we send some form data. If so, display the form data special.
|
||||
if (this._isRequestBodyFormData) {
|
||||
this._displayRequestForm();
|
||||
}
|
||||
else {
|
||||
this._displayRequestBody();
|
||||
}
|
||||
this._state = this._DISPLAYED_REQUEST_BODY;
|
||||
}
|
||||
// FALL THROUGH
|
||||
|
||||
case this._DISPLAYED_REQUEST_BODY:
|
||||
// There is always a response header. Therefore we can skip here if
|
||||
// we don't have a response header yet and don't have to try updating
|
||||
// anything else in the NetworkPanel.
|
||||
if (!response.headers.length || !Object.keys(timing).length) {
|
||||
break;
|
||||
}
|
||||
this._displayResponseHeader();
|
||||
this._state = this._DISPLAYED_RESPONSE_HEADER;
|
||||
// FALL THROUGH
|
||||
|
||||
case this._DISPLAYED_RESPONSE_HEADER:
|
||||
if (stages.indexOf("REQUEST_STOP") == -1 ||
|
||||
stages.indexOf("TRANSACTION_CLOSE") == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
this._state = this._TRANSITION_CLOSED;
|
||||
if (this.httpActivity.meta.discardResponseBody) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!response.content || !response.content.text) {
|
||||
this._displayNoResponseBody();
|
||||
}
|
||||
else if (this._responseIsImage) {
|
||||
this._displayResponseImage();
|
||||
}
|
||||
else if (!this._isResponseBodyTextData) {
|
||||
this._displayResponseBodyUnknownType();
|
||||
}
|
||||
else if (response.content.text) {
|
||||
this._displayResponseBody();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
if (aAttributes) {
|
||||
for (let attr in aAttributes) {
|
||||
node.setAttribute(attr, aAttributes[attr]);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DOMNode and appends it to aParent.
|
||||
*
|
||||
* @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 createAndAppendElement(aParent, aTag, aAttributes)
|
||||
{
|
||||
let node = createElement(aParent.ownerDocument, aTag, aAttributes);
|
||||
aParent.appendChild(node);
|
||||
return node;
|
||||
}
|
@ -11,17 +11,12 @@ const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "WebConsoleUtils", function () {
|
||||
let obj = {};
|
||||
Cu.import("resource:///modules/WebConsoleUtils.jsm", obj);
|
||||
return obj.WebConsoleUtils;
|
||||
});
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
|
||||
"resource:///modules/WebConsoleUtils.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["PropertyPanel", "PropertyTreeView"];
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// PropertyTreeView.
|
||||
|
||||
|
@ -11,7 +11,9 @@ const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["WebConsoleUtils", "JSPropertyProvider"];
|
||||
|
||||
|
@ -5,31 +5,17 @@
|
||||
|
||||
const TEST_FILE = "test-network.html";
|
||||
|
||||
function tabLoad(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, arguments.callee, true);
|
||||
|
||||
openConsole();
|
||||
|
||||
let hudId = HUDService.getHudIdByWindow(content);
|
||||
hud = HUDService.hudReferences[hudId];
|
||||
|
||||
browser.addEventListener("load", tabReload, true);
|
||||
|
||||
content.location.reload();
|
||||
}
|
||||
|
||||
function tabReload(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, arguments.callee, true);
|
||||
browser.removeEventListener(aEvent.type, tabReload, true);
|
||||
|
||||
let textContent = hud.outputNode.textContent;
|
||||
isnot(textContent.indexOf("test-network.html"), -1,
|
||||
"found test-network.html");
|
||||
isnot(textContent.indexOf("test-image.png"), -1, "found test-image.png");
|
||||
isnot(textContent.indexOf("testscript.js"), -1, "found testscript.js");
|
||||
isnot(textContent.indexOf("running network console logging tests"), -1,
|
||||
outputNode = hud.outputNode;
|
||||
findLogEntry("test-network.html");
|
||||
findLogEntry("test-image.png");
|
||||
findLogEntry("testscript.js");
|
||||
isnot(outputNode.textContent.indexOf("running network console logging tests"), -1,
|
||||
"found the console.log() message from testscript.js");
|
||||
|
||||
finishTest();
|
||||
executeSoon(finishTest);
|
||||
}
|
||||
|
||||
function test() {
|
||||
@ -42,5 +28,12 @@ function test() {
|
||||
let uri = Services.io.newFileURI(dir);
|
||||
|
||||
addTab(uri.spec);
|
||||
browser.addEventListener("load", tabLoad, true);
|
||||
browser.addEventListener("load", function tabLoad() {
|
||||
browser.removeEventListener("load", tabLoad, true);
|
||||
openConsole(null, function(aHud) {
|
||||
hud = aHud;
|
||||
browser.addEventListener("load", tabReload, true);
|
||||
content.location.reload();
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
@ -10,25 +10,27 @@
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-599725-response-headers.sjs";
|
||||
|
||||
let lastFinishedRequest = null;
|
||||
|
||||
function requestDoneCallback(aHttpRequest)
|
||||
{
|
||||
lastFinishedRequest = aHttpRequest;
|
||||
}
|
||||
|
||||
function performTest()
|
||||
function performTest(lastFinishedRequest)
|
||||
{
|
||||
ok(lastFinishedRequest, "page load was logged");
|
||||
|
||||
let headers = lastFinishedRequest.response.header;
|
||||
ok(headers, "we have the response headers");
|
||||
ok(!headers["Content-Type"], "we do not have the Content-Type header");
|
||||
ok(headers["Content-Length"] != 60, "Content-Length != 60");
|
||||
function readHeader(aName)
|
||||
{
|
||||
for (let header of headers) {
|
||||
if (header.name == aName) {
|
||||
return header.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
let headers = lastFinishedRequest.log.entries[0].response.headers;
|
||||
ok(headers, "we have the response headers");
|
||||
ok(!readHeader("Content-Type"), "we do not have the Content-Type header");
|
||||
isnot(readHeader("Content-Length"), 60, "Content-Length != 60");
|
||||
|
||||
lastFinishedRequest = null;
|
||||
HUDService.lastFinishedRequestCallback = null;
|
||||
finishTest();
|
||||
executeSoon(finishTest);
|
||||
}
|
||||
|
||||
function test()
|
||||
@ -37,15 +39,15 @@ function test()
|
||||
|
||||
let initialLoad = true;
|
||||
|
||||
browser.addEventListener("load", function () {
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
if (initialLoad) {
|
||||
openConsole();
|
||||
HUDService.lastFinishedRequestCallback = requestDoneCallback;
|
||||
content.location.reload();
|
||||
openConsole(null, function() {
|
||||
HUDService.lastFinishedRequestCallback = performTest;
|
||||
content.location.reload();
|
||||
});
|
||||
initialLoad = false;
|
||||
} else {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
performTest();
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
@ -10,28 +10,19 @@
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-600183-charset.html";
|
||||
|
||||
let lastFinishedRequest = null;
|
||||
|
||||
function requestDoneCallback(aHttpRequest)
|
||||
{
|
||||
lastFinishedRequest = aHttpRequest;
|
||||
}
|
||||
|
||||
function performTest()
|
||||
function performTest(lastFinishedRequest)
|
||||
{
|
||||
ok(lastFinishedRequest, "charset test page was loaded and logged");
|
||||
|
||||
let body = lastFinishedRequest.response.body;
|
||||
let body = lastFinishedRequest.log.entries[0].response.content.text;
|
||||
ok(body, "we have the response body");
|
||||
|
||||
let chars = "\u7684\u95ee\u5019!"; // 的问候!
|
||||
isnot(body.indexOf("<p>" + chars + "</p>"), -1,
|
||||
"found the chinese simplified string");
|
||||
|
||||
lastFinishedRequest = null;
|
||||
HUDService.saveRequestAndResponseBodies = false;
|
||||
HUDService.lastFinishedRequestCallback = null;
|
||||
finishTest();
|
||||
executeSoon(finishTest);
|
||||
}
|
||||
|
||||
function test()
|
||||
@ -40,20 +31,18 @@ function test()
|
||||
|
||||
let initialLoad = true;
|
||||
|
||||
browser.addEventListener("load", function () {
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
if (initialLoad) {
|
||||
waitForFocus(function() {
|
||||
openConsole();
|
||||
openConsole(null, function(hud) {
|
||||
|
||||
HUDService.saveRequestAndResponseBodies = true;
|
||||
HUDService.lastFinishedRequestCallback = requestDoneCallback;
|
||||
hud.saveRequestAndResponseBodies = true;
|
||||
HUDService.lastFinishedRequestCallback = performTest;
|
||||
|
||||
content.location = TEST_URI;
|
||||
}, content);
|
||||
});
|
||||
initialLoad = false;
|
||||
} else {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
performTest();
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
@ -57,10 +57,10 @@ function onpopupshown2(aEvent)
|
||||
isnot(menuitems[1].getAttribute("checked"), "true",
|
||||
"menuitems[1] is not checked");
|
||||
|
||||
ok(!HUDService.saveRequestAndResponseBodies, "bodies are not logged");
|
||||
ok(!huds[1].saveRequestAndResponseBodies, "bodies are not logged");
|
||||
|
||||
// Enable body logging.
|
||||
HUDService.saveRequestAndResponseBodies = true;
|
||||
huds[1].saveRequestAndResponseBodies = true;
|
||||
|
||||
menupopups[1].addEventListener("popuphidden", function _onhidden(aEvent) {
|
||||
menupopups[1].removeEventListener(aEvent.type, _onhidden, false);
|
||||
@ -103,11 +103,12 @@ function onpopupshown1(aEvent)
|
||||
{
|
||||
menupopups[0].removeEventListener(aEvent.type, onpopupshown1, false);
|
||||
|
||||
// The menuitem checkbox must be in sync with the other tabs.
|
||||
is(menuitems[0].getAttribute("checked"), "true", "menuitems[0] is checked");
|
||||
// The menuitem checkbox must not be in sync with the other tabs.
|
||||
isnot(menuitems[0].getAttribute("checked"), "true",
|
||||
"menuitems[0] is not checked");
|
||||
|
||||
// Disable body logging.
|
||||
HUDService.saveRequestAndResponseBodies = false;
|
||||
// Enable body logging for tab 1 as well.
|
||||
huds[0].saveRequestAndResponseBodies = true;
|
||||
|
||||
// Close the menu, and switch back to tab 2.
|
||||
menupopups[0].addEventListener("popuphidden", function _onhidden(aEvent) {
|
||||
@ -127,8 +128,7 @@ function onpopupshown2c(aEvent)
|
||||
{
|
||||
menupopups[1].removeEventListener(aEvent.type, onpopupshown2c, false);
|
||||
|
||||
isnot(menuitems[1].getAttribute("checked"), "true",
|
||||
"menuitems[1] is not checked");
|
||||
is(menuitems[1].getAttribute("checked"), "true", "menuitems[1] is checked");
|
||||
|
||||
menupopups[1].addEventListener("popuphidden", function _onhidden(aEvent) {
|
||||
menupopups[1].removeEventListener(aEvent.type, _onhidden, false);
|
||||
|
@ -41,14 +41,11 @@ let TestObserver = {
|
||||
function tabLoad(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, tabLoad, true);
|
||||
|
||||
openConsole();
|
||||
|
||||
let hudId = HUDService.getHudIdByWindow(content);
|
||||
hud = HUDService.hudReferences[hudId];
|
||||
|
||||
Services.console.registerListener(TestObserver);
|
||||
|
||||
content.location = TEST_URI;
|
||||
openConsole(null, function(aHud) {
|
||||
hud = aHud;
|
||||
Services.console.registerListener(TestObserver);
|
||||
content.location = TEST_URI;
|
||||
});
|
||||
}
|
||||
|
||||
function performTest() {
|
||||
|
@ -92,8 +92,8 @@ function tabLoaded() {
|
||||
successFn: function()
|
||||
{
|
||||
let jstermMessage = HUD.outputNode.querySelector(".webconsole-msg-output");
|
||||
EventUtils.synthesizeMouse(networkLink, 2, 2, {});
|
||||
EventUtils.synthesizeMouse(jstermMessage, 2, 2, {});
|
||||
EventUtils.synthesizeMouse(networkLink, 2, 2, {});
|
||||
},
|
||||
failureFn: finishTest,
|
||||
});
|
||||
|
@ -118,8 +118,8 @@ function tabLoaded() {
|
||||
successFn: function()
|
||||
{
|
||||
let jstermMessage = HUD.outputNode.querySelector(".webconsole-msg-output");
|
||||
EventUtils.synthesizeMouse(networkLink, 2, 2, {});
|
||||
EventUtils.synthesizeMouse(jstermMessage, 2, 2, {});
|
||||
EventUtils.synthesizeMouse(networkLink, 2, 2, {});
|
||||
},
|
||||
failureFn: finishTest,
|
||||
});
|
||||
|
@ -13,57 +13,63 @@ let lastFinishedRequests = {};
|
||||
|
||||
function requestDoneCallback(aHttpRequest)
|
||||
{
|
||||
let status = aHttpRequest.response.status.
|
||||
replace(/^HTTP\/\d\.\d (\d+).+$/, "$1");
|
||||
let status = aHttpRequest.log.entries[0].response.status;
|
||||
lastFinishedRequests[status] = aHttpRequest;
|
||||
}
|
||||
|
||||
function performTest(aEvent)
|
||||
{
|
||||
HUDService.saveRequestAndResponseBodies = false;
|
||||
HUDService.lastFinishedRequestCallback = null;
|
||||
|
||||
ok("301" in lastFinishedRequests, "request 1: 301 Moved Permanently");
|
||||
ok("404" in lastFinishedRequests, "request 2: 404 Not found");
|
||||
|
||||
let headers0 = lastFinishedRequests["301"].response.header;
|
||||
is(headers0["Content-Type"], "text/html",
|
||||
function readHeader(aName)
|
||||
{
|
||||
for (let header of headers) {
|
||||
if (header.name == aName) {
|
||||
return header.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
let headers = lastFinishedRequests["301"].log.entries[0].response.headers;
|
||||
is(readHeader("Content-Type"), "text/html",
|
||||
"we do have the Content-Type header");
|
||||
is(headers0["Content-Length"], 71, "Content-Length is correct");
|
||||
is(headers0["Location"], "/redirect-from-bug-630733",
|
||||
is(readHeader("Content-Length"), 71, "Content-Length is correct");
|
||||
is(readHeader("Location"), "/redirect-from-bug-630733",
|
||||
"Content-Length is correct");
|
||||
is(headers0["x-foobar-bug630733"], "bazbaz",
|
||||
is(readHeader("x-foobar-bug630733"), "bazbaz",
|
||||
"X-Foobar-bug630733 is correct");
|
||||
let body = lastFinishedRequests["301"].response.body;
|
||||
ok(!body, "body discarded for request 1");
|
||||
let body = lastFinishedRequests["301"].log.entries[0].response.content;
|
||||
ok(!body.text, "body discarded for request 1");
|
||||
|
||||
let headers1 = lastFinishedRequests["404"].response.header;
|
||||
ok(!headers1["Location"], "no Location header");
|
||||
ok(!headers1["x-foobar-bug630733"], "no X-Foobar-bug630733 header");
|
||||
headers = lastFinishedRequests["404"].log.entries[0].response.headers;
|
||||
ok(!readHeader("Location"), "no Location header");
|
||||
ok(!readHeader("x-foobar-bug630733"), "no X-Foobar-bug630733 header");
|
||||
|
||||
body = lastFinishedRequests["404"].response.body;
|
||||
body = lastFinishedRequests["404"].log.entries[0].response.content.text;
|
||||
isnot(body.indexOf("404"), -1,
|
||||
"body is correct for request 2");
|
||||
|
||||
lastFinishedRequests = null;
|
||||
finishTest();
|
||||
executeSoon(finishTest);
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
addTab("data:text/html;charset=utf-8,<p>Web Console test for bug 630733");
|
||||
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, arguments.callee, true);
|
||||
browser.addEventListener("load", function onLoad1(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, onLoad1, true);
|
||||
|
||||
executeSoon(function() {
|
||||
openConsole();
|
||||
|
||||
HUDService.saveRequestAndResponseBodies = true;
|
||||
openConsole(null, function(hud) {
|
||||
hud.saveRequestAndResponseBodies = true;
|
||||
HUDService.lastFinishedRequestCallback = requestDoneCallback;
|
||||
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, arguments.callee, true);
|
||||
browser.addEventListener("load", function onLoad2(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, onLoad2, true);
|
||||
executeSoon(performTest);
|
||||
}, true);
|
||||
|
||||
|
@ -18,38 +18,36 @@ function test()
|
||||
{
|
||||
addTab("data:text/html;charset=utf-8,Web Console network logging tests");
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
|
||||
openConsole();
|
||||
openConsole(null, function(aHud) {
|
||||
hud = aHud;
|
||||
|
||||
hud = HUDService.getHudByWindow(content);
|
||||
ok(hud, "Web Console is now open");
|
||||
HUDService.lastFinishedRequestCallback = function(aRequest) {
|
||||
lastRequest = aRequest.log.entries[0];
|
||||
if (requestCallback) {
|
||||
requestCallback();
|
||||
}
|
||||
};
|
||||
|
||||
HUDService.lastFinishedRequestCallback = function(aRequest) {
|
||||
lastRequest = aRequest;
|
||||
if (requestCallback) {
|
||||
requestCallback();
|
||||
}
|
||||
};
|
||||
|
||||
executeSoon(testPageLoad);
|
||||
executeSoon(testPageLoad);
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
function testPageLoad()
|
||||
{
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, arguments.callee, true);
|
||||
|
||||
requestCallback = function() {
|
||||
// Check if page load was logged correctly.
|
||||
ok(lastRequest, "Page load was logged");
|
||||
is(lastRequest.url, TEST_NETWORK_REQUEST_URI,
|
||||
is(lastRequest.request.url, TEST_NETWORK_REQUEST_URI,
|
||||
"Logged network entry is page load");
|
||||
is(lastRequest.method, "GET", "Method is correct");
|
||||
is(lastRequest.request.method, "GET", "Method is correct");
|
||||
lastRequest = null;
|
||||
requestCallback = null;
|
||||
executeSoon(testPageLoadBody);
|
||||
}, true);
|
||||
};
|
||||
|
||||
content.location = TEST_NETWORK_REQUEST_URI;
|
||||
}
|
||||
@ -57,12 +55,12 @@ function testPageLoad()
|
||||
function testPageLoadBody()
|
||||
{
|
||||
// Turn off logging of request bodies and check again.
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, arguments.callee, true);
|
||||
requestCallback = function() {
|
||||
ok(lastRequest, "Page load was logged again");
|
||||
lastRequest = null;
|
||||
requestCallback = null;
|
||||
executeSoon(testXhrGet);
|
||||
}, true);
|
||||
};
|
||||
|
||||
content.location.reload();
|
||||
}
|
||||
@ -71,7 +69,7 @@ function testXhrGet()
|
||||
{
|
||||
requestCallback = function() {
|
||||
ok(lastRequest, "testXhrGet() was logged");
|
||||
is(lastRequest.method, "GET", "Method is correct");
|
||||
is(lastRequest.request.method, "GET", "Method is correct");
|
||||
lastRequest = null;
|
||||
requestCallback = null;
|
||||
executeSoon(testXhrPost);
|
||||
@ -85,7 +83,7 @@ function testXhrPost()
|
||||
{
|
||||
requestCallback = function() {
|
||||
ok(lastRequest, "testXhrPost() was logged");
|
||||
is(lastRequest.method, "POST", "Method is correct");
|
||||
is(lastRequest.request.method, "POST", "Method is correct");
|
||||
lastRequest = null;
|
||||
requestCallback = null;
|
||||
executeSoon(testFormSubmission);
|
||||
@ -99,12 +97,11 @@ function testFormSubmission()
|
||||
{
|
||||
// Start the form submission test. As the form is submitted, the page is
|
||||
// loaded again. Bind to the load event to catch when this is done.
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, arguments.callee, true);
|
||||
requestCallback = function() {
|
||||
ok(lastRequest, "testFormSubmission() was logged");
|
||||
is(lastRequest.method, "POST", "Method is correct");
|
||||
is(lastRequest.request.method, "POST", "Method is correct");
|
||||
executeSoon(testLiveFilteringOnSearchStrings);
|
||||
}, true);
|
||||
};
|
||||
|
||||
let form = content.document.querySelector("form");
|
||||
ok(form, "we have the HTML form");
|
||||
@ -112,9 +109,6 @@ function testFormSubmission()
|
||||
}
|
||||
|
||||
function testLiveFilteringOnSearchStrings() {
|
||||
browser.removeEventListener("DOMContentLoaded",
|
||||
testLiveFilteringOnSearchStrings, false);
|
||||
|
||||
setStringFilter("http");
|
||||
isnot(countMessageNodes(), 0, "the log nodes are not hidden when the " +
|
||||
"search string is set to \"http\"");
|
||||
@ -146,6 +140,9 @@ function testLiveFilteringOnSearchStrings() {
|
||||
is(countMessageNodes(), 0, "the log nodes are hidden when searching for " +
|
||||
"the string \"foo\"bar'baz\"boo'\"");
|
||||
|
||||
HUDService.lastFinishedRequestCallback = null;
|
||||
lastRequest = null;
|
||||
requestCallback = null;
|
||||
finishTest();
|
||||
}
|
||||
|
||||
|
@ -21,47 +21,47 @@ const TEST_DATA_JSON_CONTENT =
|
||||
|
||||
let lastRequest = null;
|
||||
let requestCallback = null;
|
||||
let lastActivity = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
addTab("data:text/html;charset=utf-8,Web Console network logging tests");
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
|
||||
openConsole();
|
||||
openConsole(null, function(aHud) {
|
||||
hud = aHud;
|
||||
|
||||
hud = HUDService.getHudByWindow(content);
|
||||
ok(hud, "Web Console is now open");
|
||||
HUDService.lastFinishedRequestCallback = function(aRequest) {
|
||||
lastRequest = aRequest.log.entries[0];
|
||||
lastActivity = aRequest;
|
||||
if (requestCallback) {
|
||||
requestCallback();
|
||||
}
|
||||
};
|
||||
|
||||
HUDService.lastFinishedRequestCallback = function(aRequest) {
|
||||
lastRequest = aRequest;
|
||||
if (requestCallback) {
|
||||
requestCallback();
|
||||
}
|
||||
};
|
||||
|
||||
executeSoon(testPageLoad);
|
||||
executeSoon(testPageLoad);
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
function testPageLoad()
|
||||
{
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, arguments.callee, true);
|
||||
|
||||
requestCallback = function() {
|
||||
// Check if page load was logged correctly.
|
||||
ok(lastRequest, "Page load was logged");
|
||||
is(lastRequest.url, TEST_NETWORK_REQUEST_URI,
|
||||
|
||||
is(lastRequest.request.url, TEST_NETWORK_REQUEST_URI,
|
||||
"Logged network entry is page load");
|
||||
is(lastRequest.method, "GET", "Method is correct");
|
||||
ok(!("body" in lastRequest.request), "No request body was stored");
|
||||
ok(!("body" in lastRequest.response), "No response body was stored");
|
||||
ok(!lastRequest.response.listener, "No response listener is stored");
|
||||
is(lastRequest.request.method, "GET", "Method is correct");
|
||||
ok(!lastRequest.request.postData, "No request body was stored");
|
||||
ok(!lastRequest.response.content.text, "No response body was stored");
|
||||
|
||||
lastRequest = null;
|
||||
requestCallback = null;
|
||||
executeSoon(testPageLoadBody);
|
||||
}, true);
|
||||
};
|
||||
|
||||
content.location = TEST_NETWORK_REQUEST_URI;
|
||||
}
|
||||
@ -69,17 +69,16 @@ function testPageLoad()
|
||||
function testPageLoadBody()
|
||||
{
|
||||
// Turn on logging of request bodies and check again.
|
||||
HUDService.saveRequestAndResponseBodies = true;
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, arguments.callee, true);
|
||||
|
||||
hud.saveRequestAndResponseBodies = true;
|
||||
requestCallback = function() {
|
||||
ok(lastRequest, "Page load was logged again");
|
||||
is(lastRequest.response.body.indexOf("<!DOCTYPE HTML>"), 0,
|
||||
is(lastRequest.response.content.text.indexOf("<!DOCTYPE HTML>"), 0,
|
||||
"Response body's beginning is okay");
|
||||
|
||||
lastRequest = null;
|
||||
requestCallback = null;
|
||||
executeSoon(testXhrGet);
|
||||
}, true);
|
||||
};
|
||||
|
||||
content.location.reload();
|
||||
}
|
||||
@ -88,9 +87,9 @@ function testXhrGet()
|
||||
{
|
||||
requestCallback = function() {
|
||||
ok(lastRequest, "testXhrGet() was logged");
|
||||
is(lastRequest.method, "GET", "Method is correct");
|
||||
is(lastRequest.request.body, null, "No request body was sent");
|
||||
is(lastRequest.response.body, TEST_DATA_JSON_CONTENT,
|
||||
is(lastRequest.request.method, "GET", "Method is correct");
|
||||
ok(!lastRequest.request.postData, "No request body was sent");
|
||||
is(lastRequest.response.content.text, TEST_DATA_JSON_CONTENT,
|
||||
"Response is correct");
|
||||
|
||||
lastRequest = null;
|
||||
@ -106,10 +105,10 @@ function testXhrPost()
|
||||
{
|
||||
requestCallback = function() {
|
||||
ok(lastRequest, "testXhrPost() was logged");
|
||||
is(lastRequest.method, "POST", "Method is correct");
|
||||
is(lastRequest.request.body, "Hello world!",
|
||||
is(lastRequest.request.method, "POST", "Method is correct");
|
||||
is(lastRequest.request.postData.text, "Hello world!",
|
||||
"Request body was logged");
|
||||
is(lastRequest.response.body, TEST_DATA_JSON_CONTENT,
|
||||
is(lastRequest.response.content.text, TEST_DATA_JSON_CONTENT,
|
||||
"Response is correct");
|
||||
|
||||
lastRequest = null;
|
||||
@ -125,23 +124,21 @@ function testFormSubmission()
|
||||
{
|
||||
// Start the form submission test. As the form is submitted, the page is
|
||||
// loaded again. Bind to the load event to catch when this is done.
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, arguments.callee, true);
|
||||
|
||||
requestCallback = function() {
|
||||
ok(lastRequest, "testFormSubmission() was logged");
|
||||
is(lastRequest.method, "POST", "Method is correct");
|
||||
isnot(lastRequest.request.body.
|
||||
is(lastRequest.request.method, "POST", "Method is correct");
|
||||
isnot(lastRequest.request.postData.text.
|
||||
indexOf("Content-Type: application/x-www-form-urlencoded"), -1,
|
||||
"Content-Type is correct");
|
||||
isnot(lastRequest.request.body.
|
||||
isnot(lastRequest.request.postData.text.
|
||||
indexOf("Content-Length: 20"), -1, "Content-length is correct");
|
||||
isnot(lastRequest.request.body.
|
||||
isnot(lastRequest.request.postData.text.
|
||||
indexOf("name=foo+bar&age=144"), -1, "Form data is correct");
|
||||
ok(lastRequest.response.body.indexOf("<!DOCTYPE HTML>") == 0,
|
||||
is(lastRequest.response.content.text.indexOf("<!DOCTYPE HTML>"), 0,
|
||||
"Response body's beginning is okay");
|
||||
|
||||
executeSoon(testNetworkPanel);
|
||||
}, true);
|
||||
};
|
||||
|
||||
let form = content.document.querySelector("form");
|
||||
ok(form, "we have the HTML form");
|
||||
@ -152,19 +149,19 @@ function testNetworkPanel()
|
||||
{
|
||||
// Open the NetworkPanel. The functionality of the NetworkPanel is tested
|
||||
// within separate test files.
|
||||
let networkPanel = HUDService.openNetworkPanel(hud.filterBox, lastRequest);
|
||||
is(networkPanel, lastRequest.panels[0].get(),
|
||||
"Network panel stored on lastRequest object");
|
||||
let networkPanel = HUDService.openNetworkPanel(hud.filterBox, lastActivity);
|
||||
is(networkPanel, hud.filterBox._netPanel,
|
||||
"Network panel stored on anchor node");
|
||||
|
||||
networkPanel.panel.addEventListener("load", function(aEvent) {
|
||||
networkPanel.panel.removeEventListener(aEvent.type, arguments.callee,
|
||||
true);
|
||||
networkPanel.panel.addEventListener("load", function onLoad(aEvent) {
|
||||
networkPanel.panel.removeEventListener(aEvent.type, onLoad, true);
|
||||
|
||||
ok(true, "NetworkPanel was opened");
|
||||
|
||||
// All tests are done. Shutdown.
|
||||
networkPanel.panel.hidePopup();
|
||||
lastRequest = null;
|
||||
lastActivity = null;
|
||||
HUDService.lastFinishedRequestCallback = null;
|
||||
executeSoon(finishTest);
|
||||
}, true);
|
||||
|
@ -68,25 +68,39 @@ function testGen() {
|
||||
let l10n = tempScope.WebConsoleUtils.l10n;
|
||||
tempScope = null;
|
||||
|
||||
var httpActivity = {
|
||||
url: "http://www.testpage.com",
|
||||
method: "GET",
|
||||
|
||||
panels: [],
|
||||
request: {
|
||||
header: {
|
||||
foo: "bar"
|
||||
}
|
||||
let httpActivity = {
|
||||
meta: {
|
||||
stages: [],
|
||||
discardRequestBody: true,
|
||||
discardResponseBody: true,
|
||||
},
|
||||
log: {
|
||||
entries: [{
|
||||
startedDateTime: (new Date()).toISOString(),
|
||||
request: {
|
||||
url: "http://www.testpage.com",
|
||||
method: "GET",
|
||||
cookies: [],
|
||||
headers: [
|
||||
{ name: "foo", value: "bar" },
|
||||
],
|
||||
},
|
||||
response: {
|
||||
headers: [],
|
||||
content: {},
|
||||
},
|
||||
timings: {},
|
||||
}],
|
||||
},
|
||||
response: { },
|
||||
timing: {
|
||||
"REQUEST_HEADER": 0
|
||||
}
|
||||
};
|
||||
|
||||
let entry = httpActivity.log.entries[0];
|
||||
|
||||
let networkPanel = HUDService.openNetworkPanel(filterBox, httpActivity);
|
||||
|
||||
is (networkPanel, httpActivity.panels[0].get(), "Network panel stored on httpActivity object");
|
||||
is(filterBox._netPanel, networkPanel,
|
||||
"Network panel stored on the anchor object");
|
||||
|
||||
networkPanel.panel.addEventListener("load", function onLoad() {
|
||||
networkPanel.panel.removeEventListener("load", onLoad, true);
|
||||
testDriver.next();
|
||||
@ -94,6 +108,8 @@ function testGen() {
|
||||
|
||||
yield;
|
||||
|
||||
info("test 1");
|
||||
|
||||
checkIsVisible(networkPanel, {
|
||||
requestCookie: false,
|
||||
requestFormData: false,
|
||||
@ -110,8 +126,11 @@ function testGen() {
|
||||
checkNodeKeyValue(networkPanel, "requestHeadersContent", "foo", "bar");
|
||||
|
||||
// Test request body.
|
||||
httpActivity.request.body = "hello world";
|
||||
info("test 2: request body");
|
||||
httpActivity.meta.discardRequestBody = false;
|
||||
entry.request.postData = { text: "hello world" };
|
||||
networkPanel.update();
|
||||
|
||||
checkIsVisible(networkPanel, {
|
||||
requestBody: true,
|
||||
requestFormData: false,
|
||||
@ -125,13 +144,19 @@ function testGen() {
|
||||
checkNodeContent(networkPanel, "requestBodyContent", "hello world");
|
||||
|
||||
// Test response header.
|
||||
httpActivity.timing.RESPONSE_HEADER = 1000;
|
||||
httpActivity.response.status = "999 earthquake win";
|
||||
httpActivity.response.header = {
|
||||
"Content-Type": "text/html",
|
||||
leaveHouses: "true"
|
||||
}
|
||||
info("test 3: response header");
|
||||
entry.timings.wait = 10;
|
||||
entry.response.httpVersion = "HTTP/3.14";
|
||||
entry.response.status = 999;
|
||||
entry.response.statusText = "earthquake win";
|
||||
entry.response.content.mimeType = "text/html";
|
||||
entry.response.headers.push(
|
||||
{ name: "Content-Type", value: "text/html" },
|
||||
{ name: "leaveHouses", value: "true" }
|
||||
);
|
||||
|
||||
networkPanel.update();
|
||||
|
||||
checkIsVisible(networkPanel, {
|
||||
requestBody: true,
|
||||
requestFormData: false,
|
||||
@ -143,13 +168,14 @@ function testGen() {
|
||||
responseImageCached: false
|
||||
});
|
||||
|
||||
checkNodeContent(networkPanel, "header", "999 earthquake win");
|
||||
checkNodeContent(networkPanel, "header", "HTTP/3.14 999 earthquake win");
|
||||
checkNodeKeyValue(networkPanel, "responseHeadersContent", "leaveHouses", "true");
|
||||
checkNodeContent(networkPanel, "responseHeadersInfo", "1ms");
|
||||
checkNodeContent(networkPanel, "responseHeadersInfo", "10ms");
|
||||
|
||||
httpActivity.timing.RESPONSE_COMPLETE = 2500;
|
||||
// This is necessary to show that the request is done.
|
||||
httpActivity.timing.TRANSACTION_CLOSE = 2500;
|
||||
info("test 4");
|
||||
|
||||
httpActivity.meta.discardResponseBody = false;
|
||||
entry.timings.receive = 2;
|
||||
networkPanel.update();
|
||||
|
||||
checkIsVisible(networkPanel, {
|
||||
@ -163,7 +189,9 @@ function testGen() {
|
||||
responseImageCached: false
|
||||
});
|
||||
|
||||
httpActivity.response.isDone = true;
|
||||
info("test 5");
|
||||
|
||||
httpActivity.meta.stages.push("REQUEST_STOP", "TRANSACTION_CLOSE");
|
||||
networkPanel.update();
|
||||
|
||||
checkNodeContent(networkPanel, "responseNoBodyInfo", "2ms");
|
||||
@ -180,11 +208,17 @@ function testGen() {
|
||||
networkPanel.panel.hidePopup();
|
||||
|
||||
// Second run: Test for cookies and response body.
|
||||
httpActivity.request.header.Cookie = "foo=bar; hello=world";
|
||||
httpActivity.response.body = "get out here";
|
||||
info("test 6: cookies and response body");
|
||||
entry.request.cookies.push(
|
||||
{ name: "foo", value: "bar" },
|
||||
{ name: "hello", value: "world" }
|
||||
);
|
||||
entry.response.content.text = "get out here";
|
||||
|
||||
networkPanel = HUDService.openNetworkPanel(filterBox, httpActivity);
|
||||
is (networkPanel, httpActivity.panels[1].get(), "Network panel stored on httpActivity object");
|
||||
is(filterBox._netPanel, networkPanel,
|
||||
"Network panel stored on httpActivity object");
|
||||
|
||||
networkPanel.panel.addEventListener("load", function onLoad() {
|
||||
networkPanel.panel.removeEventListener("load", onLoad, true);
|
||||
testDriver.next();
|
||||
@ -192,7 +226,6 @@ function testGen() {
|
||||
|
||||
yield;
|
||||
|
||||
|
||||
checkIsVisible(networkPanel, {
|
||||
requestBody: true,
|
||||
requestFormData: false,
|
||||
@ -212,8 +245,10 @@ function testGen() {
|
||||
networkPanel.panel.hidePopup();
|
||||
|
||||
// Check image request.
|
||||
httpActivity.response.header["Content-Type"] = "image/png";
|
||||
httpActivity.url = TEST_IMG;
|
||||
info("test 7: image request");
|
||||
entry.response.headers[1].value = "image/png";
|
||||
entry.response.content.mimeType = "image/png";
|
||||
entry.request.url = TEST_IMG;
|
||||
|
||||
networkPanel = HUDService.openNetworkPanel(filterBox, httpActivity);
|
||||
networkPanel.panel.addEventListener("load", function onLoad() {
|
||||
@ -259,7 +294,10 @@ function testGen() {
|
||||
}
|
||||
|
||||
// Check cached image request.
|
||||
httpActivity.response.status = "HTTP/1.1 304 Not Modified";
|
||||
info("test 8: cached image request");
|
||||
entry.response.httpVersion = "HTTP/1.1";
|
||||
entry.response.status = 304;
|
||||
entry.response.statusText = "Not Modified";
|
||||
|
||||
networkPanel = HUDService.openNetworkPanel(filterBox, httpActivity);
|
||||
networkPanel.panel.addEventListener("load", function onLoad() {
|
||||
@ -286,11 +324,12 @@ function testGen() {
|
||||
networkPanel.panel.hidePopup();
|
||||
|
||||
// Test sent form data.
|
||||
httpActivity.request.body = [
|
||||
"Content-Type: application/x-www-form-urlencoded\n" +
|
||||
"Content-Length: 59\n" +
|
||||
info("test 9: sent form data");
|
||||
entry.request.postData.text = [
|
||||
"Content-Type: application/x-www-form-urlencoded",
|
||||
"Content-Length: 59",
|
||||
"name=rob&age=20"
|
||||
].join("");
|
||||
].join("\n");
|
||||
|
||||
networkPanel = HUDService.openNetworkPanel(filterBox, httpActivity);
|
||||
networkPanel.panel.addEventListener("load", function onLoad() {
|
||||
@ -316,7 +355,8 @@ function testGen() {
|
||||
networkPanel.panel.hidePopup();
|
||||
|
||||
// Test no space after Content-Type:
|
||||
httpActivity.request.body = "Content-Type:application/x-www-form-urlencoded\n";
|
||||
info("test 10: no space after Content-Type header in post data");
|
||||
entry.request.postData.text = "Content-Type:application/x-www-form-urlencoded\n";
|
||||
|
||||
networkPanel = HUDService.openNetworkPanel(filterBox, httpActivity);
|
||||
networkPanel.panel.addEventListener("load", function onLoad() {
|
||||
@ -341,25 +381,18 @@ function testGen() {
|
||||
|
||||
// Test cached data.
|
||||
|
||||
// Load a Latin-1 encoded page.
|
||||
browser.addEventListener("load", function onLoad () {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
httpActivity.charset = content.document.characterSet;
|
||||
testDriver.next();
|
||||
}, true);
|
||||
browser.contentWindow.wrappedJSObject.document.location = TEST_ENCODING_ISO_8859_1;
|
||||
info("test 11: cached data");
|
||||
|
||||
yield;
|
||||
|
||||
httpActivity.url = TEST_ENCODING_ISO_8859_1;
|
||||
httpActivity.response.header["Content-Type"] = "application/json";
|
||||
httpActivity.response.body = "";
|
||||
entry.request.url = TEST_ENCODING_ISO_8859_1;
|
||||
entry.response.headers[1].value = "application/json";
|
||||
entry.response.content.mimeType = "application/json";
|
||||
entry.response.content.text = "my cached data is here!";
|
||||
|
||||
networkPanel = HUDService.openNetworkPanel(filterBox, httpActivity);
|
||||
networkPanel.isDoneCallback = function NP_doneCallback() {
|
||||
networkPanel.isDoneCallback = null;
|
||||
networkPanel.panel.addEventListener("load", function onLoad() {
|
||||
networkPanel.panel.removeEventListener("load", onLoad, true);
|
||||
testDriver.next();
|
||||
}
|
||||
}, true);
|
||||
|
||||
yield;
|
||||
|
||||
@ -375,21 +408,22 @@ function testGen() {
|
||||
responseImageCached: false
|
||||
});
|
||||
|
||||
checkNodeContent(networkPanel, "responseBodyCachedContent", "<body>\u00fc\u00f6\u00E4</body>");
|
||||
checkNodeContent(networkPanel, "responseBodyCachedContent",
|
||||
"my cached data is here!");
|
||||
|
||||
networkPanel.panel.hidePopup();
|
||||
|
||||
// Test a response with a content type that can't be displayed in the
|
||||
// NetworkPanel.
|
||||
httpActivity.response.header["Content-Type"] = "application/x-shockwave-flash";
|
||||
info("test 12: unknown content type");
|
||||
entry.response.headers[1].value = "application/x-shockwave-flash";
|
||||
entry.response.content.mimeType = "application/x-shockwave-flash";
|
||||
|
||||
networkPanel = HUDService.openNetworkPanel(filterBox, httpActivity);
|
||||
networkPanel.isDoneCallback = function NP_doneCallback() {
|
||||
networkPanel.isDoneCallback = null;
|
||||
try {
|
||||
testDriver.next();
|
||||
} catch (e if e instanceof StopIteration) {
|
||||
}
|
||||
}
|
||||
networkPanel.panel.addEventListener("load", function onLoad() {
|
||||
networkPanel.panel.removeEventListener("load", onLoad, true);
|
||||
testDriver.next();
|
||||
}, true);
|
||||
|
||||
yield;
|
||||
|
||||
@ -453,4 +487,6 @@ function testGen() {
|
||||
// All done!
|
||||
testDriver = null;
|
||||
executeSoon(finishTest);
|
||||
|
||||
yield;
|
||||
}
|
||||
|
@ -306,6 +306,7 @@ addKeywordTitleAutoFill=Search %S
|
||||
|
||||
# TabView
|
||||
tabView2.title=%S - Group Your Tabs
|
||||
tabview2.moveToUnnamedGroup.label=%S and %S more
|
||||
|
||||
extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name=Default
|
||||
extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description=The default theme.
|
||||
|
@ -42,22 +42,6 @@ pauseTooltip=Click to pause
|
||||
# button when the debugger is in a paused state.
|
||||
resumeTooltip=Click to resume
|
||||
|
||||
# LOCALIZATION NOTE (localScope): The label that is displayed in the variables
|
||||
# pane as a header on the local scope container.
|
||||
localScope=Local
|
||||
|
||||
# LOCALIZATION NOTE (globalScope): The label that is displayed in the variables
|
||||
# pane as a header on the globel scope container.
|
||||
globalScope=Global
|
||||
|
||||
# LOCALIZATION NOTE (withScope): The label that is displayed in the variables
|
||||
# pane as a header on the container for identifiers in a with block.
|
||||
withScope=With block
|
||||
|
||||
# LOCALIZATION NOTE (closureScope): The label that is displayed in the variables
|
||||
# pane as a header on container for identifiers in a closure scope.
|
||||
closureScope=Closure
|
||||
|
||||
# LOCALIZATION NOTE (emptyStackText): The text that is displayed in the stack
|
||||
# frames list when there are no frames to display.
|
||||
emptyStackText=No stacks to display.
|
||||
@ -72,3 +56,17 @@ loadingText=Loading\u2026
|
||||
# external resource file.
|
||||
# %1$S=URL, %2$S=status code
|
||||
loadingError=Error loading %1$S: %2$S
|
||||
|
||||
# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the
|
||||
# variables pane when there are no variables to display.
|
||||
emptyVariablesText=No variables to display.
|
||||
|
||||
# LOCALIZATION NOTE (scopeLabel): The text that is displayed in the variables
|
||||
# pane as a header for each variable scope (e.g. "Global scope, "With scope",
|
||||
# etc.).
|
||||
scopeLabel=%S scope
|
||||
|
||||
# LOCALIZATION NOTE (globalScopeLabel): The name of the global scope. This text
|
||||
# is added to scopeLabel and displayed in the variables pane as a header for
|
||||
# the global scope.
|
||||
globalScopeLabel=Global
|
||||
|
@ -178,6 +178,28 @@ prefListSearchDesc=Filter the list of settings displayed
|
||||
# for help on what it does.
|
||||
prefListSearchManual=Search for the given string in the list of available preferences
|
||||
|
||||
# LOCALIZATION NOTE (prefShowDesc): A very short description of the 'pref
|
||||
# show' command. This string is designed to be shown in a menu alongside the
|
||||
# command name, which is why it should be as short as possible. See
|
||||
# prefShowManual for a fuller description of what it does.
|
||||
prefShowDesc=Display setting value
|
||||
|
||||
# LOCALIZATION NOTE (prefShowManual): A fuller description of the 'pref show'
|
||||
# command. Displayed when the user asks for help on what it does.
|
||||
prefShowManual=Display the value of a given preference
|
||||
|
||||
# LOCALIZATION NOTE (prefShowSettingDesc): A short description of the
|
||||
# 'setting' parameter to the 'pref show' command. See prefShowSettingManual
|
||||
# for a fuller description of what it does. This string is designed to be
|
||||
# shown in a dialog with restricted space, which is why it should be as short
|
||||
# as possible.
|
||||
prefShowSettingDesc=Setting to display
|
||||
|
||||
# LOCALIZATION NOTE (prefShowSettingManual): A fuller description of the
|
||||
# 'setting' parameter to the 'pref show' command. Displayed when the user asks
|
||||
# for help on what it does.
|
||||
prefShowSettingManual=The name of the setting to display
|
||||
|
||||
# LOCALIZATION NOTE (prefSetDesc): A very short description of the 'pref set'
|
||||
# command. This string is designed to be shown in a menu alongside the command
|
||||
# name, which is why it should be as short as possible. See prefSetManual for
|
||||
@ -272,6 +294,31 @@ introDesc=Show the opening message
|
||||
# command. Displayed when the user asks for help on what it does.
|
||||
introManual=Redisplay the message that is shown to new users until they click the 'Got it!' button
|
||||
|
||||
# LOCALIZATION NOTE (introTextOpening): The 'intro text' opens when the user
|
||||
# first opens the developer toolbar to explain the command line, and is shown
|
||||
# each time it is opened until the user clicks the 'Got it!' button. This
|
||||
# string is the opening paragraph of the intro text.
|
||||
introTextOpening=The Firefox command line is designed for developers. It focuses on speed of input over JavaScript syntax and a rich display over monospace output.
|
||||
|
||||
# LOCALIZATION NOTE (introTextCommands): For information about the 'intro
|
||||
# text' see introTextOpening. The second paragraph is in 2 sections, the first
|
||||
# section points the user to the 'help' command.
|
||||
introTextCommands=For a list of commands type
|
||||
|
||||
# LOCALIZATION NOTE (introTextKeys): For information about the 'intro text'
|
||||
# see introTextOpening. The second section in the second paragraph points the
|
||||
# user to the F1/Escape keys which show and hide hints.
|
||||
introTextKeys=or to show/hide command hints press
|
||||
|
||||
# LOCALIZATION NOTE (introTextF1Escape): For information about the 'intro
|
||||
# text' see introTextOpening. This string is used with introTextKeys, and
|
||||
# contains the keys that are pressed to open and close hints.
|
||||
introTextF1Escape=F1/Escape
|
||||
|
||||
# LOCALIZATION NOTE (introTextGo): For information about the 'intro text' see
|
||||
# introTextOpening. The text on the button that dismisses the intro text.
|
||||
introTextGo=Got it!
|
||||
|
||||
# LOCALIZATION NOTE (hideIntroDesc): Short description of the 'hideIntro'
|
||||
# setting. Displayed when the user asks for help on the settings.
|
||||
hideIntroDesc=Show the initial welcome message
|
||||
|
@ -195,7 +195,7 @@
|
||||
* Animations
|
||||
*/
|
||||
|
||||
.details[open] {
|
||||
.details[open][animated] {
|
||||
-moz-animation-duration: 0.25s;
|
||||
-moz-animation-name: showblock;
|
||||
}
|
||||
|
@ -194,7 +194,7 @@
|
||||
* Animations
|
||||
*/
|
||||
|
||||
.details[open] {
|
||||
.details[open][animated] {
|
||||
-moz-animation-duration: 0.25s;
|
||||
-moz-animation-name: showblock;
|
||||
}
|
||||
|
@ -198,7 +198,7 @@
|
||||
* Animations
|
||||
*/
|
||||
|
||||
.details[open] {
|
||||
.details[open][animated] {
|
||||
-moz-animation-duration: 0.25s;
|
||||
-moz-animation-name: showblock;
|
||||
}
|
||||
|
@ -1078,6 +1078,10 @@ ObjectActor.prototype = {
|
||||
message: "cannot access the environment of this function." };
|
||||
}
|
||||
|
||||
// XXX: the following call of env.form() won't work until bug 747514 lands.
|
||||
// We can't get to the frame that defined this function's environment,
|
||||
// neither here, nor during ObjectActor's construction. Luckily, we don't
|
||||
// use the 'scope' request in the debugger frontend.
|
||||
return { name: this.obj.name || null,
|
||||
scope: envActor.form(this.obj) };
|
||||
},
|
||||
@ -1197,14 +1201,7 @@ FrameActor.prototype = {
|
||||
type: this.frame.type };
|
||||
if (this.frame.type === "call") {
|
||||
form.callee = this.threadActor.createValueGrip(this.frame.callee);
|
||||
if (this.frame.callee.name) {
|
||||
form.calleeName = this.frame.callee.name;
|
||||
} else {
|
||||
let desc = this.frame.callee.getOwnPropertyDescriptor("displayName");
|
||||
if (desc && desc.value && typeof desc.value == "string") {
|
||||
form.calleeName = desc.value;
|
||||
}
|
||||
}
|
||||
form.calleeName = getFunctionName(this.frame.callee);
|
||||
}
|
||||
|
||||
let envActor = this.threadActor
|
||||
@ -1335,13 +1332,13 @@ EnvironmentActor.prototype = {
|
||||
|
||||
/**
|
||||
* Returns an environment form for use in a protocol message. Note that the
|
||||
* requirement of passing the frame or function as a parameter is only
|
||||
* temporary, since when bug 747514 lands, the environment will have a callee
|
||||
* property that will contain it.
|
||||
* requirement of passing the frame as a parameter is only temporary, since
|
||||
* when bug 747514 lands, the environment will have a callee property that
|
||||
* will contain it.
|
||||
*
|
||||
* @param object aObject
|
||||
* The stack frame or function object whose environment bindings are
|
||||
* being generated.
|
||||
* @param Debugger.Frame aObject
|
||||
* The stack frame object whose environment bindings are being
|
||||
* generated.
|
||||
*/
|
||||
form: function EA_form(aObject) {
|
||||
// Debugger.Frame might be dead by the time we get here, which will cause
|
||||
@ -1353,24 +1350,29 @@ EnvironmentActor.prototype = {
|
||||
let parent;
|
||||
if (this.obj.parent) {
|
||||
let thread = this.threadActor;
|
||||
parent = thread.createEnvironmentActor(this.obj.parent.environment,
|
||||
parent = thread.createEnvironmentActor(this.obj.parent,
|
||||
this.registeredPool);
|
||||
}
|
||||
// Deduce the frame that created the parent scope in order to pass it to
|
||||
// parent.form(). TODO: this can be removed after bug 747514 is done.
|
||||
let parentFrame = aObject;
|
||||
if (this.obj.type == "declarative" && aObject.older) {
|
||||
parentFrame = aObject.older;
|
||||
}
|
||||
let form = { actor: this.actorID,
|
||||
parent: parent ? parent.form(this.obj.parent) : parent };
|
||||
parent: parent ? parent.form(parentFrame) : parent };
|
||||
|
||||
if (aObject.type == "object") {
|
||||
if (this.obj.parent) {
|
||||
form.type = "with";
|
||||
} else {
|
||||
form.type = "object";
|
||||
}
|
||||
form.object = this.threadActor.createValueGrip(aObject.object);
|
||||
} else {
|
||||
if (aObject.class == "Function") {
|
||||
if (this.obj.type == "with") {
|
||||
form.type = "with";
|
||||
form.object = this.threadActor.createValueGrip(this.obj.object);
|
||||
} else if (this.obj.type == "object") {
|
||||
form.type = "object";
|
||||
form.object = this.threadActor.createValueGrip(this.obj.object);
|
||||
} else { // this.obj.type == "declarative"
|
||||
if (aObject.callee) {
|
||||
form.type = "function";
|
||||
form.function = this.threadActor.createValueGrip(aObject);
|
||||
form.functionName = aObject.name;
|
||||
form.function = this.threadActor.createValueGrip(aObject.callee);
|
||||
form.functionName = getFunctionName(aObject.callee);
|
||||
} else {
|
||||
form.type = "block";
|
||||
}
|
||||
@ -1382,14 +1384,14 @@ EnvironmentActor.prototype = {
|
||||
|
||||
/**
|
||||
* Return the identifier bindings object as required by the remote protocol
|
||||
* specification. Note that the requirement of passing the frame or function
|
||||
* as a parameter is only temporary, since when bug 747514 lands, the
|
||||
* environment will have a callee property that will contain it.
|
||||
* specification. Note that the requirement of passing the frame as a
|
||||
* parameter is only temporary, since when bug 747514 lands, the environment
|
||||
* will have a callee property that will contain it.
|
||||
*
|
||||
* @param object aObject [optional]
|
||||
* The stack frame or function object whose environment bindings are
|
||||
* being generated. When left unspecified, the bindings do not contain
|
||||
* an 'arguments' property.
|
||||
* @param Debugger.Frame aObject [optional]
|
||||
* The stack frame whose environment bindings are being generated. When
|
||||
* left unspecified, the bindings do not contain an 'arguments'
|
||||
* property.
|
||||
*/
|
||||
_bindings: function EA_bindings(aObject) {
|
||||
let bindings = { arguments: [], variables: {} };
|
||||
@ -1514,3 +1516,22 @@ EnvironmentActor.prototype.requestTypes = {
|
||||
"assign": EnvironmentActor.prototype.onAssign,
|
||||
"bindings": EnvironmentActor.prototype.onBindings
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to deduce the name of the provided function.
|
||||
*
|
||||
* @param Debugger.Object aFunction
|
||||
* The function whose name will be returned.
|
||||
*/
|
||||
function getFunctionName(aFunction) {
|
||||
let name;
|
||||
if (aFunction.name) {
|
||||
name = aFunction.name;
|
||||
} else {
|
||||
let desc = aFunction.getOwnPropertyDescriptor("displayName");
|
||||
if (desc && desc.value && typeof desc.value == "string") {
|
||||
name = desc.value;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check a frame actor's parent bindings.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-stack");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_pause_frame();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_pause_frame()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let parentEnv = aPacket.frame.environment.parent;
|
||||
let bindings = parentEnv.bindings;
|
||||
let args = bindings.arguments;
|
||||
let vars = bindings.variables;
|
||||
do_check_neq(parentEnv, undefined);
|
||||
do_check_eq(args.length, 0);
|
||||
do_check_eq(vars.stopMe.value.type, "object");
|
||||
do_check_eq(vars.stopMe.value.class, "Function");
|
||||
do_check_true(!!vars.stopMe.value.actor);
|
||||
|
||||
parentEnv = parentEnv.parent;
|
||||
do_check_neq(parentEnv, undefined);
|
||||
let objClient = gThreadClient.pauseGrip(parentEnv.object);
|
||||
objClient.getPrototypeAndProperties(function(aResponse) {
|
||||
do_check_eq(aResponse.ownProperties.Object.value.type, "object");
|
||||
do_check_eq(aResponse.ownProperties.Object.value.class, "Function");
|
||||
do_check_true(!!aResponse.ownProperties.Object.value.actor);
|
||||
|
||||
gThreadClient.resume(function() {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function() {
|
||||
function stopMe(aNumber, aBool, aString, aNull, aUndefined, aObject) {
|
||||
var a = 1;
|
||||
var b = true;
|
||||
var c = { a: "a" };
|
||||
debugger;
|
||||
};
|
||||
stopMe(42, true, "nasu", null, undefined, { foo: "bar" });
|
||||
} + ")()");
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check a |with| frame actor's bindings.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-stack");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_pause_frame();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_pause_frame()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let env = aPacket.frame.environment;
|
||||
do_check_neq(env, undefined);
|
||||
|
||||
let parentEnv = env.parent;
|
||||
do_check_neq(parentEnv, undefined);
|
||||
|
||||
let bindings = parentEnv.bindings;
|
||||
let args = bindings.arguments;
|
||||
let vars = bindings.variables;
|
||||
do_check_eq(args.length, 1);
|
||||
do_check_eq(args[0].aNumber.value, 10);
|
||||
do_check_eq(vars.r.value, 10);
|
||||
do_check_eq(vars.a.value, Math.PI * 100);
|
||||
do_check_eq(vars.arguments.value.class, "Arguments");
|
||||
do_check_true(!!vars.arguments.value.actor);
|
||||
|
||||
let objClient = gThreadClient.pauseGrip(env.object);
|
||||
objClient.getPrototypeAndProperties(function(aResponse) {
|
||||
do_check_eq(aResponse.ownProperties.PI.value, Math.PI);
|
||||
do_check_eq(aResponse.ownProperties.cos.value.type, "object");
|
||||
do_check_eq(aResponse.ownProperties.cos.value.class, "Function");
|
||||
do_check_true(!!aResponse.ownProperties.cos.value.actor);
|
||||
|
||||
gThreadClient.resume(function() {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function() {
|
||||
function stopMe(aNumber) {
|
||||
var a;
|
||||
var r = aNumber;
|
||||
with (Math) {
|
||||
a = PI * r * r;
|
||||
debugger;
|
||||
}
|
||||
};
|
||||
stopMe(10);
|
||||
} + ")()");
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check the environment bindongs of a |with| within a |with|.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-stack");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_pause_frame();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_pause_frame()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let env = aPacket.frame.environment;
|
||||
do_check_neq(env, undefined);
|
||||
|
||||
let objClient = gThreadClient.pauseGrip(env.object);
|
||||
objClient.getPrototypeAndProperties(function(aResponse) {
|
||||
do_check_eq(aResponse.ownProperties.one.value, 1);
|
||||
do_check_eq(aResponse.ownProperties.two.value, 2);
|
||||
do_check_eq(aResponse.ownProperties.foo, undefined);
|
||||
|
||||
let parentEnv = env.parent;
|
||||
do_check_neq(parentEnv, undefined);
|
||||
|
||||
let parentClient = gThreadClient.pauseGrip(parentEnv.object);
|
||||
parentClient.getPrototypeAndProperties(function(aResponse) {
|
||||
do_check_eq(aResponse.ownProperties.PI.value, Math.PI);
|
||||
do_check_eq(aResponse.ownProperties.cos.value.type, "object");
|
||||
do_check_eq(aResponse.ownProperties.cos.value.class, "Function");
|
||||
do_check_true(!!aResponse.ownProperties.cos.value.actor);
|
||||
|
||||
parentEnv = parentEnv.parent;
|
||||
do_check_neq(parentEnv, undefined);
|
||||
|
||||
let bindings = parentEnv.bindings;
|
||||
let args = bindings.arguments;
|
||||
let vars = bindings.variables;
|
||||
do_check_eq(args.length, 1);
|
||||
do_check_eq(args[0].aNumber.value, 10);
|
||||
do_check_eq(vars.r.value, 10);
|
||||
do_check_eq(vars.a.value, Math.PI * 100);
|
||||
do_check_eq(vars.arguments.value.class, "Arguments");
|
||||
do_check_true(!!vars.arguments.value.actor);
|
||||
do_check_eq(vars.foo.value, 2 * Math.PI);
|
||||
|
||||
gThreadClient.resume(function() {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function() {
|
||||
function stopMe(aNumber) {
|
||||
var a, obj = { one: 1, two: 2 };
|
||||
var r = aNumber;
|
||||
with (Math) {
|
||||
a = PI * r * r;
|
||||
with (obj) {
|
||||
var foo = two * PI;
|
||||
debugger;
|
||||
}
|
||||
}
|
||||
};
|
||||
stopMe(10);
|
||||
} + ")()");
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check the environment bindings of a |with| in global scope.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-stack");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_pause_frame();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_pause_frame()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let env = aPacket.frame.environment;
|
||||
do_check_neq(env, undefined);
|
||||
|
||||
let objClient = gThreadClient.pauseGrip(env.object);
|
||||
objClient.getPrototypeAndProperties(function(aResponse) {
|
||||
do_check_eq(aResponse.ownProperties.PI.value, Math.PI);
|
||||
do_check_eq(aResponse.ownProperties.cos.value.type, "object");
|
||||
do_check_eq(aResponse.ownProperties.cos.value.class, "Function");
|
||||
do_check_true(!!aResponse.ownProperties.cos.value.actor);
|
||||
|
||||
let parentEnv = env.parent;
|
||||
do_check_neq(parentEnv, undefined);
|
||||
|
||||
let parentClient = gThreadClient.pauseGrip(parentEnv.object);
|
||||
parentClient.getPrototypeAndProperties(function(aResponse) {
|
||||
do_check_eq(aResponse.ownProperties.a.value, Math.PI * 100);
|
||||
do_check_eq(aResponse.ownProperties.r.value, 10);
|
||||
do_check_eq(aResponse.ownProperties.Object.value.type, "object");
|
||||
do_check_eq(aResponse.ownProperties.Object.value.class, "Function");
|
||||
do_check_true(!!aResponse.ownProperties.Object.value.actor);
|
||||
|
||||
gThreadClient.resume(function() {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("var a, r = 10;\n" +
|
||||
"with (Math) {\n" +
|
||||
" a = PI * r * r;\n" +
|
||||
" debugger;\n" +
|
||||
"}");
|
||||
}
|
@ -54,3 +54,7 @@ tail =
|
||||
[test_stepping-03.js]
|
||||
[test_stepping-04.js]
|
||||
[test_framebindings-01.js]
|
||||
[test_framebindings-02.js]
|
||||
[test_framebindings-03.js]
|
||||
[test_framebindings-04.js]
|
||||
[test_framebindings-05.js]
|
||||
|
@ -322,7 +322,7 @@ AddonCompatibilityOverride.prototype = {
|
||||
* A type of add-on, used by the UI to determine how to display different types
|
||||
* of add-ons.
|
||||
*
|
||||
* @param aId
|
||||
* @param aID
|
||||
* The add-on type ID
|
||||
* @param aLocaleURI
|
||||
* The URI of a localized properties file to get the displayable name
|
||||
@ -340,15 +340,15 @@ AddonCompatibilityOverride.prototype = {
|
||||
* An option set of flags that customize the display of the add-on in
|
||||
* the UI.
|
||||
*/
|
||||
function AddonType(aId, aLocaleURI, aLocaleKey, aViewType, aUIPriority, aFlags) {
|
||||
if (!aId)
|
||||
function AddonType(aID, aLocaleURI, aLocaleKey, aViewType, aUIPriority, aFlags) {
|
||||
if (!aID)
|
||||
throw new Error("An AddonType must have an ID");
|
||||
if (aViewType && aUIPriority === undefined)
|
||||
throw new Error("An AddonType with a defined view must have a set UI priority");
|
||||
if (!aLocaleKey)
|
||||
throw new Error("An AddonType must have a displayable name");
|
||||
|
||||
this.id = aId;
|
||||
this.id = aID;
|
||||
this.uiPriority = aUIPriority;
|
||||
this.viewType = aViewType;
|
||||
this.flags = aFlags;
|
||||
@ -357,7 +357,7 @@ function AddonType(aId, aLocaleURI, aLocaleKey, aViewType, aUIPriority, aFlags)
|
||||
this.__defineGetter__("name", function() {
|
||||
delete this.name;
|
||||
let bundle = Services.strings.createBundle(aLocaleURI);
|
||||
this.name = bundle.GetStringFromName(aLocaleKey.replace("%ID%", aId));
|
||||
this.name = bundle.GetStringFromName(aLocaleKey.replace("%ID%", aID));
|
||||
return this.name;
|
||||
});
|
||||
}
|
||||
@ -555,9 +555,17 @@ var AddonManagerInternal = {
|
||||
* @param aProvider
|
||||
* The provider to register
|
||||
* @param aTypes
|
||||
* An array of add-on types
|
||||
* An optional array of add-on types
|
||||
*/
|
||||
registerProvider: function AMI_registerProvider(aProvider, aTypes) {
|
||||
if (!aProvider || typeof aProvider != "object")
|
||||
throw Components.Exception("aProvider must be specified",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aTypes && !Array.isArray(aTypes))
|
||||
throw Components.Exception("aTypes must be an array or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
this.providers.push(aProvider);
|
||||
|
||||
if (aTypes) {
|
||||
@ -597,6 +605,10 @@ var AddonManagerInternal = {
|
||||
* The provider to unregister
|
||||
*/
|
||||
unregisterProvider: function AMI_unregisterProvider(aProvider) {
|
||||
if (!aProvider || typeof aProvider != "object")
|
||||
throw Components.Exception("aProvider must be specified",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let pos = 0;
|
||||
while (pos < this.providers.length) {
|
||||
if (this.providers[pos] == aProvider)
|
||||
@ -739,15 +751,27 @@ var AddonManagerInternal = {
|
||||
* appropriate values.
|
||||
*
|
||||
* @param aAddon
|
||||
* The AddonInternal representing the add-on
|
||||
* The Addon representing the add-on
|
||||
* @param aUri
|
||||
* The uri to escape
|
||||
* The string representation of the URI to escape
|
||||
* @param aAppVersion
|
||||
* The optional application version to use for %APP_VERSION%
|
||||
* @return the appropriately escaped uri.
|
||||
* @return The appropriately escaped URI.
|
||||
*/
|
||||
escapeAddonURI: function AMI_escapeAddonURI(aAddon, aUri, aAppVersion)
|
||||
{
|
||||
if (!aAddon || typeof aAddon != "object")
|
||||
throw Components.Exception("aAddon must be an Addon object",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!aUri || typeof aUri != "string")
|
||||
throw Components.Exception("aUri must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aAppVersion && typeof aAppVersion != "string")
|
||||
throw Components.Exception("aAppVersion must be a string or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
var addonStatus = aAddon.userDisabled || aAddon.softDisabled ? "userDisabled"
|
||||
: "userEnabled";
|
||||
|
||||
@ -977,6 +1001,14 @@ var AddonManagerInternal = {
|
||||
* The ID of the add-on
|
||||
*/
|
||||
addStartupChange: function AMI_addStartupChange(aType, aID) {
|
||||
if (!aType || typeof aType != "string")
|
||||
throw Components.Exception("aType must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!aID || typeof aID != "string")
|
||||
throw Components.Exception("aID must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (gStarted)
|
||||
return;
|
||||
|
||||
@ -998,6 +1030,14 @@ var AddonManagerInternal = {
|
||||
* The ID of the add-on
|
||||
*/
|
||||
removeStartupChange: function AMI_removeStartupChange(aType, aID) {
|
||||
if (!aType || typeof aType != "string")
|
||||
throw Components.Exception("aType must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!aID || typeof aID != "string")
|
||||
throw Components.Exception("aID must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (gStarted)
|
||||
return;
|
||||
|
||||
@ -1015,6 +1055,10 @@ var AddonManagerInternal = {
|
||||
* The method on the listeners to call
|
||||
*/
|
||||
callManagerListeners: function AMI_callManagerListeners(aMethod) {
|
||||
if (!aMethod || typeof aMethod != "string")
|
||||
throw Components.Exception("aMethod must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
var args = Array.slice(arguments, 1);
|
||||
this.managerListeners.forEach(function(listener) {
|
||||
try {
|
||||
@ -1034,10 +1078,18 @@ var AddonManagerInternal = {
|
||||
* @param aMethod
|
||||
* The method on the listeners to call
|
||||
* @param aExtraListeners
|
||||
* An array of extra InstallListeners to also call
|
||||
* An optional array of extra InstallListeners to also call
|
||||
* @return false if any of the listeners returned false, true otherwise
|
||||
*/
|
||||
callInstallListeners: function AMI_callInstallListeners(aMethod, aExtraListeners) {
|
||||
if (!aMethod || typeof aMethod != "string")
|
||||
throw Components.Exception("aMethod must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aExtraListeners && !Array.isArray(aExtraListeners))
|
||||
throw Components.Exception("aExtraListeners must be an array or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let result = true;
|
||||
let listeners = this.installListeners;
|
||||
if (aExtraListeners)
|
||||
@ -1066,6 +1118,10 @@ var AddonManagerInternal = {
|
||||
* The method on the listeners to call
|
||||
*/
|
||||
callAddonListeners: function AMI_callAddonListeners(aMethod) {
|
||||
if (!aMethod || typeof aMethod != "string")
|
||||
throw Components.Exception("aMethod must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
var args = Array.slice(arguments, 1);
|
||||
this.addonListeners.forEach(function(listener) {
|
||||
try {
|
||||
@ -1083,17 +1139,25 @@ var AddonManagerInternal = {
|
||||
* add-on only supports a single add-on being enabled at a time. This allows
|
||||
* the providers to disable theirs if necessary.
|
||||
*
|
||||
* @param aId
|
||||
* The id of the enabled add-on
|
||||
* @param aID
|
||||
* The ID of the enabled add-on
|
||||
* @param aType
|
||||
* The type of the enabled add-on
|
||||
* @param aPendingRestart
|
||||
* A boolean indicating if the change will only take place the next
|
||||
* time the application is restarted
|
||||
*/
|
||||
notifyAddonChanged: function AMI_notifyAddonChanged(aId, aType, aPendingRestart) {
|
||||
notifyAddonChanged: function AMI_notifyAddonChanged(aID, aType, aPendingRestart) {
|
||||
if (aID && typeof aID != "string")
|
||||
throw Components.Exception("aID must be a string or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!aType || typeof aType != "string")
|
||||
throw Components.Exception("aType must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
this.providers.forEach(function(provider) {
|
||||
callProvider(provider, "addonChanged", null, aId, aType, aPendingRestart);
|
||||
callProvider(provider, "addonChanged", null, aID, aType, aPendingRestart);
|
||||
});
|
||||
},
|
||||
|
||||
@ -1116,8 +1180,8 @@ var AddonManagerInternal = {
|
||||
* Function to call when operation is complete.
|
||||
*/
|
||||
updateAddonRepositoryData: function AMI_updateAddonRepositoryData(aCallback) {
|
||||
if (!aCallback)
|
||||
throw Components.Exception("Must specify aCallback",
|
||||
if (typeof aCallback != "function")
|
||||
throw Components.Exception("aCallback must be a function",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
new AsyncObjectCaller(this.providers, "updateAddonRepositoryData", {
|
||||
@ -1132,11 +1196,12 @@ var AddonManagerInternal = {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Asynchronously gets an AddonInstall for a URL.
|
||||
*
|
||||
* @param aUrl
|
||||
* The url the add-on is located at
|
||||
* The string represenation of the URL the add-on is located at
|
||||
* @param aCallback
|
||||
* A callback to pass the AddonInstall to
|
||||
* @param aMimetype
|
||||
@ -1156,8 +1221,37 @@ var AddonManagerInternal = {
|
||||
getInstallForURL: function AMI_getInstallForURL(aUrl, aCallback, aMimetype,
|
||||
aHash, aName, aIconURL,
|
||||
aVersion, aLoadGroup) {
|
||||
if (!aUrl || !aMimetype || !aCallback)
|
||||
throw new TypeError("Invalid arguments");
|
||||
if (!aUrl || typeof aUrl != "string")
|
||||
throw Components.Exception("aURL must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (typeof aCallback != "function")
|
||||
throw Components.Exception("aCallback must be a function",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!aMimetype || typeof aMimetype != "string")
|
||||
throw Components.Exception("aMimetype must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aHash && typeof aHash != "string")
|
||||
throw Components.Exception("aHash must be a string or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aName && typeof aName != "string")
|
||||
throw Components.Exception("aName must be a string or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aIconURL && typeof aIconURL != "string")
|
||||
throw Components.Exception("aIconURL must be a string or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aVersion && typeof aVersion != "string")
|
||||
throw Components.Exception("aVersion must be a string or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aLoadGroup && (!(aLoadGroup instanceof Ci.nsILoadGroup)))
|
||||
throw Components.Exception("aLoadGroup must be a nsILoadGroup or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
for (let provider of this.providers) {
|
||||
if (callProvider(provider, "supportsMimetype", false, aMimetype)) {
|
||||
@ -1176,7 +1270,7 @@ var AddonManagerInternal = {
|
||||
* Asynchronously gets an AddonInstall for an nsIFile.
|
||||
*
|
||||
* @param aFile
|
||||
* the nsIFile where the add-on is located
|
||||
* The nsIFile where the add-on is located
|
||||
* @param aCallback
|
||||
* A callback to pass the AddonInstall to
|
||||
* @param aMimetype
|
||||
@ -1184,8 +1278,17 @@ var AddonManagerInternal = {
|
||||
* @throws if the aFile or aCallback arguments are not specified
|
||||
*/
|
||||
getInstallForFile: function AMI_getInstallForFile(aFile, aCallback, aMimetype) {
|
||||
if (!aFile || !aCallback)
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
if (!(aFile instanceof Ci.nsIFile))
|
||||
throw Components.Exception("aFile must be a nsIFile",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (typeof aCallback != "function")
|
||||
throw Components.Exception("aCallback must be a function",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aMimetype && typeof aMimetype != "string")
|
||||
throw Components.Exception("aMimetype must be a string or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
new AsyncObjectCaller(this.providers, "getInstallForFile", {
|
||||
nextObject: function(aCaller, aProvider) {
|
||||
@ -1212,11 +1315,16 @@ var AddonManagerInternal = {
|
||||
* An optional array of types to retrieve. Each type is a string name
|
||||
* @param aCallback
|
||||
* A callback which will be passed an array of AddonInstalls
|
||||
* @throws if the aCallback argument is not specified
|
||||
* @throws If the aCallback argument is not specified
|
||||
*/
|
||||
getInstallsByTypes: function AMI_getInstallsByTypes(aTypes, aCallback) {
|
||||
if (!aCallback)
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
if (aTypes && !Array.isArray(aTypes))
|
||||
throw Components.Exception("aTypes must be an array or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (typeof aCallback != "function")
|
||||
throw Components.Exception("aCallback must be a function",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let installs = [];
|
||||
|
||||
@ -1253,6 +1361,10 @@ var AddonManagerInternal = {
|
||||
* @return true if installation is enabled for the mimetype
|
||||
*/
|
||||
isInstallEnabled: function AMI_isInstallEnabled(aMimetype) {
|
||||
if (!aMimetype || typeof aMimetype != "string")
|
||||
throw Components.Exception("aMimetype must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
for (let provider of this.providers) {
|
||||
if (callProvider(provider, "supportsMimetype", false, aMimetype) &&
|
||||
callProvider(provider, "isInstallEnabled"))
|
||||
@ -1268,10 +1380,18 @@ var AddonManagerInternal = {
|
||||
* @param aMimetype
|
||||
* The mimetype of the add-on
|
||||
* @param aURI
|
||||
* The uri of the source, may be null
|
||||
* The optional nsIURI of the source
|
||||
* @return true if the source is allowed to install this mimetype
|
||||
*/
|
||||
isInstallAllowed: function AMI_isInstallAllowed(aMimetype, aURI) {
|
||||
if (!aMimetype || typeof aMimetype != "string")
|
||||
throw Components.Exception("aMimetype must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aURI && !(aURI instanceof Ci.nsIURI))
|
||||
throw Components.Exception("aURI must be a nsIURI or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
for (let provider of this.providers) {
|
||||
if (callProvider(provider, "supportsMimetype", false, aMimetype) &&
|
||||
callProvider(provider, "isInstallAllowed", null, aURI))
|
||||
@ -1287,9 +1407,9 @@ var AddonManagerInternal = {
|
||||
* @param aMimetype
|
||||
* The mimetype of add-ons being installed
|
||||
* @param aSource
|
||||
* The nsIDOMWindow that started the installs
|
||||
* The optional nsIDOMWindow that started the installs
|
||||
* @param aURI
|
||||
* the nsIURI that started the installs
|
||||
* The optional nsIURI that started the installs
|
||||
* @param aInstalls
|
||||
* The array of AddonInstalls to be installed
|
||||
*/
|
||||
@ -1297,6 +1417,22 @@ var AddonManagerInternal = {
|
||||
aSource,
|
||||
aURI,
|
||||
aInstalls) {
|
||||
if (!aMimetype || typeof aMimetype != "string")
|
||||
throw Components.Exception("aMimetype must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aSource && !(aSource instanceof Ci.nsIDOMWindow))
|
||||
throw Components.Exception("aSource must be a nsIDOMWindow or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (aURI && !(aURI instanceof Ci.nsIURI))
|
||||
throw Components.Exception("aURI must be a nsIURI or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!Array.isArray(aInstalls))
|
||||
throw Components.Exception("aInstalls must be an array",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!("@mozilla.org/addons/web-install-listener;1" in Cc)) {
|
||||
WARN("No web installer available, cancelling all installs");
|
||||
aInstalls.forEach(function(aInstall) {
|
||||
@ -1346,6 +1482,10 @@ var AddonManagerInternal = {
|
||||
* The InstallListener to add
|
||||
*/
|
||||
addInstallListener: function AMI_addInstallListener(aListener) {
|
||||
if (!aListener || typeof aListener != "object")
|
||||
throw Components.Exception("aListener must be a InstallListener object",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!this.installListeners.some(function(i) { return i == aListener; }))
|
||||
this.installListeners.push(aListener);
|
||||
},
|
||||
@ -1357,6 +1497,10 @@ var AddonManagerInternal = {
|
||||
* The InstallListener to remove
|
||||
*/
|
||||
removeInstallListener: function AMI_removeInstallListener(aListener) {
|
||||
if (!aListener || typeof aListener != "object")
|
||||
throw Components.Exception("aListener must be a InstallListener object",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let pos = 0;
|
||||
while (pos < this.installListeners.length) {
|
||||
if (this.installListeners[pos] == aListener)
|
||||
@ -1369,19 +1513,24 @@ var AddonManagerInternal = {
|
||||
/**
|
||||
* Asynchronously gets an add-on with a specific ID.
|
||||
*
|
||||
* @param aId
|
||||
* @param aID
|
||||
* The ID of the add-on to retrieve
|
||||
* @param aCallback
|
||||
* The callback to pass the retrieved add-on to
|
||||
* @throws if the aId or aCallback arguments are not specified
|
||||
* @throws if the aID or aCallback arguments are not specified
|
||||
*/
|
||||
getAddonByID: function AMI_getAddonByID(aId, aCallback) {
|
||||
if (!aId || !aCallback)
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
getAddonByID: function AMI_getAddonByID(aID, aCallback) {
|
||||
if (!aID || typeof aID != "string")
|
||||
throw Components.Exception("aID must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (typeof aCallback != "function")
|
||||
throw Components.Exception("aCallback must be a function",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
new AsyncObjectCaller(this.providers, "getAddonByID", {
|
||||
nextObject: function(aCaller, aProvider) {
|
||||
callProvider(aProvider, "getAddonByID", null, aId, function(aAddon) {
|
||||
callProvider(aProvider, "getAddonByID", null, aID, function(aAddon) {
|
||||
if (aAddon)
|
||||
safeCall(aCallback, aAddon);
|
||||
else
|
||||
@ -1405,9 +1554,13 @@ var AddonManagerInternal = {
|
||||
* @throws if the aGUID or aCallback arguments are not specified
|
||||
*/
|
||||
getAddonBySyncGUID: function AMI_getAddonBySyncGUID(aGUID, aCallback) {
|
||||
if (!aGUID || !aCallback) {
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
if (!aGUID || typeof aGUID != "string")
|
||||
throw Components.Exception("aGUID must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (typeof aCallback != "function")
|
||||
throw Components.Exception("aCallback must be a function",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
new AsyncObjectCaller(this.providers, "getAddonBySyncGUID", {
|
||||
nextObject: function(aCaller, aProvider) {
|
||||
@ -1429,21 +1582,26 @@ var AddonManagerInternal = {
|
||||
/**
|
||||
* Asynchronously gets an array of add-ons.
|
||||
*
|
||||
* @param aIds
|
||||
* @param aIDs
|
||||
* The array of IDs to retrieve
|
||||
* @param aCallback
|
||||
* The callback to pass an array of Addons to
|
||||
* @throws if the aId or aCallback arguments are not specified
|
||||
* @throws if the aID or aCallback arguments are not specified
|
||||
*/
|
||||
getAddonsByIDs: function AMI_getAddonsByIDs(aIds, aCallback) {
|
||||
if (!aIds || !aCallback)
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
getAddonsByIDs: function AMI_getAddonsByIDs(aIDs, aCallback) {
|
||||
if (!Array.isArray(aIDs))
|
||||
throw Components.Exception("aIDs must be an array",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (typeof aCallback != "function")
|
||||
throw Components.Exception("aCallback must be a function",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let addons = [];
|
||||
|
||||
new AsyncObjectCaller(aIds, null, {
|
||||
nextObject: function(aCaller, aId) {
|
||||
AddonManagerInternal.getAddonByID(aId, function(aAddon) {
|
||||
new AsyncObjectCaller(aIDs, null, {
|
||||
nextObject: function(aCaller, aID) {
|
||||
AddonManagerInternal.getAddonByID(aID, function(aAddon) {
|
||||
addons.push(aAddon);
|
||||
aCaller.callNext();
|
||||
});
|
||||
@ -1465,8 +1623,13 @@ var AddonManagerInternal = {
|
||||
* @throws if the aCallback argument is not specified
|
||||
*/
|
||||
getAddonsByTypes: function AMI_getAddonsByTypes(aTypes, aCallback) {
|
||||
if (!aCallback)
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
if (aTypes && !Array.isArray(aTypes))
|
||||
throw Components.Exception("aTypes must be an array or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (typeof aCallback != "function")
|
||||
throw Components.Exception("aCallback must be a function",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let addons = [];
|
||||
|
||||
@ -1507,8 +1670,13 @@ var AddonManagerInternal = {
|
||||
*/
|
||||
getAddonsWithOperationsByTypes:
|
||||
function AMI_getAddonsWithOperationsByTypes(aTypes, aCallback) {
|
||||
if (!aCallback)
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
if (aTypes && !Array.isArray(aTypes))
|
||||
throw Components.Exception("aTypes must be an array or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (typeof aCallback != "function")
|
||||
throw Components.Exception("aCallback must be a function",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let addons = [];
|
||||
|
||||
@ -1534,6 +1702,10 @@ var AddonManagerInternal = {
|
||||
* The listener to add
|
||||
*/
|
||||
addManagerListener: function AMI_addManagerListener(aListener) {
|
||||
if (!aListener || typeof aListener != "object")
|
||||
throw Components.Exception("aListener must be an AddonManagerListener object",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!this.managerListeners.some(function(i) { return i == aListener; }))
|
||||
this.managerListeners.push(aListener);
|
||||
},
|
||||
@ -1545,6 +1717,10 @@ var AddonManagerInternal = {
|
||||
* The listener to remove
|
||||
*/
|
||||
removeManagerListener: function AMI_removeManagerListener(aListener) {
|
||||
if (!aListener || typeof aListener != "object")
|
||||
throw Components.Exception("aListener must be an AddonManagerListener object",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let pos = 0;
|
||||
while (pos < this.managerListeners.length) {
|
||||
if (this.managerListeners[pos] == aListener)
|
||||
@ -1558,9 +1734,13 @@ var AddonManagerInternal = {
|
||||
* Adds a new AddonListener if the listener is not already registered.
|
||||
*
|
||||
* @param aListener
|
||||
* The listener to add
|
||||
* The AddonListener to add
|
||||
*/
|
||||
addAddonListener: function AMI_addAddonListener(aListener) {
|
||||
if (!aListener || typeof aListener != "object")
|
||||
throw Components.Exception("aListener must be an AddonListener object",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!this.addonListeners.some(function(i) { return i == aListener; }))
|
||||
this.addonListeners.push(aListener);
|
||||
},
|
||||
@ -1569,9 +1749,14 @@ var AddonManagerInternal = {
|
||||
* Removes an AddonListener if the listener is registered.
|
||||
*
|
||||
* @param aListener
|
||||
* The listener to remove
|
||||
* The AddonListener to remove
|
||||
*/
|
||||
removeAddonListener: function AMI_removeAddonListener(aListener) {
|
||||
if (!aListener || typeof aListener != "object")
|
||||
throw Components.Exception("aListener must be an AddonListener object",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
|
||||
let pos = 0;
|
||||
while (pos < this.addonListeners.length) {
|
||||
if (this.addonListeners[pos] == aListener)
|
||||
@ -1581,12 +1766,32 @@ var AddonManagerInternal = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a new TypeListener if the listener is not already registered.
|
||||
*
|
||||
* @param aListener
|
||||
* The TypeListener to add
|
||||
*/
|
||||
addTypeListener: function AMI_addTypeListener(aListener) {
|
||||
if (!aListener || typeof aListener != "object")
|
||||
throw Components.Exception("aListener must be a TypeListener object",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!this.typeListeners.some(function(i) { return i == aListener; }))
|
||||
this.typeListeners.push(aListener);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes an TypeListener if the listener is registered.
|
||||
*
|
||||
* @param aListener
|
||||
* The TypeListener to remove
|
||||
*/
|
||||
removeTypeListener: function AMI_removeTypeListener(aListener) {
|
||||
if (!aListener || typeof aListener != "object")
|
||||
throw Components.Exception("aListener must be a TypeListener object",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let pos = 0;
|
||||
while (pos < this.typeListeners.length) {
|
||||
if (this.typeListeners[pos] == aListener)
|
||||
@ -1707,8 +1912,8 @@ var AddonManagerPrivate = {
|
||||
AddonManagerInternal.removeStartupChange(aType, aID);
|
||||
},
|
||||
|
||||
notifyAddonChanged: function AMP_notifyAddonChanged(aId, aType, aPendingRestart) {
|
||||
AddonManagerInternal.notifyAddonChanged(aId, aType, aPendingRestart);
|
||||
notifyAddonChanged: function AMP_notifyAddonChanged(aID, aType, aPendingRestart) {
|
||||
AddonManagerInternal.notifyAddonChanged(aID, aType, aPendingRestart);
|
||||
},
|
||||
|
||||
updateAddonAppDisabledStates: function AMP_updateAddonAppDisabledStates() {
|
||||
@ -1913,16 +2118,16 @@ var AddonManager = {
|
||||
return AddonManagerInternal.startupChanges[aType].slice(0);
|
||||
},
|
||||
|
||||
getAddonByID: function AM_getAddonByID(aId, aCallback) {
|
||||
AddonManagerInternal.getAddonByID(aId, aCallback);
|
||||
getAddonByID: function AM_getAddonByID(aID, aCallback) {
|
||||
AddonManagerInternal.getAddonByID(aID, aCallback);
|
||||
},
|
||||
|
||||
getAddonBySyncGUID: function AM_getAddonBySyncGUID(aId, aCallback) {
|
||||
AddonManagerInternal.getAddonBySyncGUID(aId, aCallback);
|
||||
getAddonBySyncGUID: function AM_getAddonBySyncGUID(aGUID, aCallback) {
|
||||
AddonManagerInternal.getAddonBySyncGUID(aGUID, aCallback);
|
||||
},
|
||||
|
||||
getAddonsByIDs: function AM_getAddonsByIDs(aIds, aCallback) {
|
||||
AddonManagerInternal.getAddonsByIDs(aIds, aCallback);
|
||||
getAddonsByIDs: function AM_getAddonsByIDs(aIDs, aCallback) {
|
||||
AddonManagerInternal.getAddonsByIDs(aIDs, aCallback);
|
||||
},
|
||||
|
||||
getAddonsWithOperationsByTypes:
|
||||
@ -1995,7 +2200,18 @@ var AddonManager = {
|
||||
return AddonManagerInternal.addonTypes;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether an Addon should auto-update or not.
|
||||
*
|
||||
* @param aAddon
|
||||
* The Addon representing the add-on
|
||||
* @return true if the addon should auto-update, false otherwise.
|
||||
*/
|
||||
shouldAutoUpdate: function AM_shouldAutoUpdate(aAddon) {
|
||||
if (!aAddon || typeof aAddon != "object")
|
||||
throw Components.Exception("aAddon must be specified",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (!("applyBackgroundUpdates" in aAddon))
|
||||
return false;
|
||||
if (aAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_ENABLE)
|
||||
|
@ -443,10 +443,10 @@ var gInstallingPage = {
|
||||
actionItem.value = label;
|
||||
},
|
||||
|
||||
onInstallEnded: function(aInstall) {
|
||||
onInstallEnded: function(aInstall, aAddon) {
|
||||
// Remember that this add-on was updated during startup
|
||||
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED,
|
||||
aInstall.id);
|
||||
aAddon.id);
|
||||
|
||||
this.startNextInstall();
|
||||
},
|
||||
|
@ -61,7 +61,7 @@ function run_test_1() {
|
||||
var testPlugin = get_test_plugin();
|
||||
do_check_neq(testPlugin, null);
|
||||
|
||||
AddonManager.getAddonsByTypes("plugin", function(addons) {
|
||||
AddonManager.getAddonsByTypes(["plugin"], function(addons) {
|
||||
do_check_true(addons.length > 0);
|
||||
|
||||
addons.forEach(function(p) {
|
||||
|
Loading…
Reference in New Issue
Block a user