diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 1b75fdc0e81b..e86f34e90dc1 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1012,8 +1012,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); diff --git a/browser/devtools/commandline/GcliTiltCommands.jsm b/browser/devtools/commandline/GcliTiltCommands.jsm index 06b1e861677d..0519656d87fd 100644 --- a/browser/devtools/commandline/GcliTiltCommands.jsm +++ b/browser/devtools/commandline/GcliTiltCommands.jsm @@ -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"); diff --git a/browser/devtools/commandline/gcli.jsm b/browser/devtools/commandline/gcli.jsm index 41eb42404b14..22c483f27b40 100644 --- a/browser/devtools/commandline/gcli.jsm +++ b/browser/devtools/commandline/gcli.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; }; /** @@ -4186,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) { @@ -4269,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) { @@ -4354,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; } @@ -4398,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 @@ -4421,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 */ @@ -8034,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", [], "
\n" + + "

${l10n.prefSetCheckHeading}

\n" + + "

${l10n.prefSetCheckBody}

\n" + + " \n" + + "
\n" + + ""); + /* * Copyright 2009-2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE.txt or: diff --git a/browser/devtools/commandline/test/Makefile.in b/browser/devtools/commandline/test/Makefile.in index e4824a8807e4..43a751fd7965 100644 --- a/browser/devtools/commandline/test/Makefile.in +++ b/browser/devtools/commandline/test/Makefile.in @@ -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) diff --git a/browser/devtools/commandline/test/browser_gcli_pref.js b/browser/devtools/commandline/test/browser_gcli_pref.js new file mode 100755 index 000000000000..ef3cdbdda0c9 --- /dev/null +++ b/browser/devtools/commandline/test/browser_gcli_pref.js @@ -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: [ " " ] + }); + + 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"); +} diff --git a/browser/devtools/commandline/test/browser_gcli_settings.js b/browser/devtools/commandline/test/browser_gcli_settings.js new file mode 100755 index 000000000000..53537a06e1a4 --- /dev/null +++ b/browser/devtools/commandline/test/browser_gcli_settings.js @@ -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"); +} diff --git a/browser/devtools/commandline/test/browser_gcli_web.js b/browser/devtools/commandline/test/browser_gcli_web.js index 541ebbf98b03..86ec035c0a39 100644 --- a/browser/devtools/commandline/test/browser_gcli_web.js +++ b/browser/devtools/commandline/test/browser_gcli_web.js @@ -672,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); }; @@ -2624,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: [ ' ' ] + }); + + 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; } @@ -2657,13 +2725,6 @@ exports.testPrefSetStatus = function(options) { emptyParameters: [ ' ' ] }); - helpers.status(options, { - typed: 'pref set ', - markup: 'VVVVVVVVV', - status: 'ERROR', - emptyParameters: [ ' ' ] - }); - helpers.status(options, { typed: 'pref set tempTBo', markup: 'VVVVVVVVVIIIIIII', @@ -2691,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; } @@ -2752,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", [], "
\n" + - "
\n" + - " ${l10n.prefOutputFilter}:\n" + - " \n" + - "
\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "
${l10n.prefOutputName}${l10n.prefOutputValue}
\n" + - "
\n" + - " \n" + - "
\n" + - "
\n" + - "
\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", [], "
\n" + - "

${l10n.prefSetCheckHeading}

\n" + - "

${l10n.prefSetCheckBody}

\n" + - " \n" + - "
\n" + - ""); - -define("text!gcli/commands/pref_list_inner.html", [], "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "
${preference.name}\n" + - " ${preference.value}\n" + - " \n" + - "
\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) { @@ -4137,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', diff --git a/browser/devtools/commandline/test/head.js b/browser/devtools/commandline/test/head.js index e710dd084f1a..7935ade831b9 100644 --- a/browser/devtools/commandline/test/head.js +++ b/browser/devtools/commandline/test/head.js @@ -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); } } diff --git a/browser/locales/en-US/chrome/browser/devtools/gcli.properties b/browser/locales/en-US/chrome/browser/devtools/gcli.properties index 48cebfa5851c..456c960329c2 100644 --- a/browser/locales/en-US/chrome/browser/devtools/gcli.properties +++ b/browser/locales/en-US/chrome/browser/devtools/gcli.properties @@ -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