diff --git a/common/Makefile b/common/Makefile index ef118e80..e2d7bfb4 100644 --- a/common/Makefile +++ b/common/Makefile @@ -16,7 +16,7 @@ GOOGLE_PROJ = dactyl GOOGLE = https://$(GOOGLE_PROJ).googlecode.com/files VERSION ?= $(shell $(SED) -n 's/.*em:version(>|=")(.*)["<].*/\2/p' $(TOP)/install.rdf | sed 1q) UUID := $(shell $(SED) -n 's/.*em:id(>|=")(.*)["<].*/\2/p' $(TOP)/install.rdf | sed 1q) -MANGLE := $(shell date '+%s' | awk '{ printf "%x", $$1 }') +MANGLE := chrome MOZMILL = mozmill HOSTAPP_PATH = $(shell which $(HOSTAPP)) TEST_DIR = $(BASE)/tests/functional diff --git a/common/bootstrap.js b/common/bootstrap.js index e029387c..d81411ea 100755 --- a/common/bootstrap.js +++ b/common/bootstrap.js @@ -195,8 +195,6 @@ function init() { break; case "resource": - var hardSuffix = /^[^\/]*/.exec(fields[2])[0]; - resources.push(fields[1], fields[1] + suffix); resourceProto.setSubstitution(fields[1], getURI(fields[2])); resourceProto.setSubstitution(fields[1] + suffix, getURI(fields[2])); @@ -205,7 +203,7 @@ function init() { // Flush the cache if necessary, just to be paranoid let pref = "extensions.dactyl.cacheFlushCheck"; - let val = addon.version + "-" + hardSuffix; + let val = addon.version; if (!Services.prefs.prefHasUserValue(pref) || Services.prefs.getCharPref(pref) != val) { var cacheFlush = true; Services.obs.notifyObservers(null, "startupcache-invalidate", ""); diff --git a/common/modules/config.jsm b/common/modules/config.jsm index c9c1420f..3db046d1 100644 --- a/common/modules/config.jsm +++ b/common/modules/config.jsm @@ -215,7 +215,8 @@ var ConfigBase = Class("ConfigBase", { let jar = io.isJarURL(uri); if (jar) { let prefix = getDir(jar.JAREntry); - var res = iter(s.slice(prefix.length).replace(/\/.*/, "") for (s in io.listJar(jar.JARFile, prefix))) + var res = iter(s.slice(prefix.length).replace(/\/.*/, "") + for (s in io.listJar(jar.JARFile, prefix))) .toArray(); } else { @@ -225,7 +226,7 @@ var ConfigBase = Class("ConfigBase", { if (f.isDirectory())).array; } - function exists(pkg) services["resource:"].hasSubstitution("dactyl-locale-" + pkg); + let exists = function exists(pkg) services["resource:"].hasSubstitution("dactyl-locale-" + pkg); return array.uniq([this.appLocale, this.appLocale.replace(/-.*/, "")] .filter(exists) diff --git a/common/modules/io.jsm b/common/modules/io.jsm index 5eefcc17..3e0015dd 100644 --- a/common/modules/io.jsm +++ b/common/modules/io.jsm @@ -331,14 +331,19 @@ var IO = Module("io", { * * @returns {File} */ - createTempFile: function createTempFile(name) { - if (name instanceof Ci.nsIFile) + createTempFile: function createTempFile(name, type) { + if (name instanceof Ci.nsIFile) { var file = name.clone(); + if (!type || type == "file") + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, octal(666)); + else + file.createUnique(Ci.nsIFile.DIRECTORY_TYPE, octal(777)); + } else { file = services.directory.get("TmpD", Ci.nsIFile); file.append(this.config.tempFile + (name ? "." + name : "")); + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, octal(666)); } - file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, octal(600)); services.externalApp.deleteTemporaryFileOnExit(file); @@ -414,7 +419,8 @@ var IO = Module("io", { if (bin instanceof File || File.isAbsolutePath(bin)) return this.File(bin); - let dirs = services.environment.get("PATH").split(config.OS.isWindows ? ";" : ":"); + let dirs = services.environment.get("PATH") + .split(config.OS.pathListSep); // Windows tries the CWD first TODO: desirable? if (config.OS.isWindows) dirs = [io.cwd].concat(dirs); @@ -556,7 +562,8 @@ var IO = Module("io", { * otherwise, the return value of *func*. */ withTempFiles: function withTempFiles(func, self, checked, ext) { - let args = array(util.range(0, func.length)).map(bind("createTempFile", this, ext)).array; + let args = array(util.range(0, func.length)) + .map(bind("createTempFile", this, ext)).array; try { if (!args.every(util.identity)) return false; diff --git a/common/modules/prefs.jsm b/common/modules/prefs.jsm index f8e7e403..8df88684 100644 --- a/common/modules/prefs.jsm +++ b/common/modules/prefs.jsm @@ -68,19 +68,279 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) } }, + /** + * Returns a new Prefs instance for the sub-branch *branch* of this + * branch. + * + * @param {string} branch The sub-branch to branch to. + * @returns {Prefs} + */ + Branch: function Branch(branch) Prefs(this.root + branch), + + /** + * Clears the entire branch. + * + * @param {string} name The name of the preference branch to delete. + */ + clear: function clear(branch) { + this.branch.deleteBranch(branch || ""); + }, + /** * Returns the full name of this object's preference branch. */ get root() this.branch.root, /** - * Returns a new Prefs instance for the sub-branch *branch* of this - * branch. + * Returns the value of the preference *name*, or *defaultValue* if + * the preference does not exist. * - * @param {string} branch The branch to branch to. - * @returns {Prefs} + * @param {string} name The name of the preference to return. + * @param {*} defaultValue The value to return if the preference has no value. + * @optional */ - Branch: function Branch(branch) Prefs(this.root + branch), + get: function get(name, defaultValue) { + if (defaultValue == null) + defaultValue = null; + if (isArray(name)) + name = name.join("."); + + let type = this.branch.getPrefType(name); + try { + switch (type) { + case Ci.nsIPrefBranch.PREF_STRING: + let value = this.branch.getComplexValue(name, Ci.nsISupportsString).data; + // try in case it's a localized string (will throw an exception if not) + if (!this.branch.prefIsLocked(name) && !this.branch.prefHasUserValue(name) && + RegExp("chrome://.+/locale/.+\\.properties").test(value)) + value = this.branch.getComplexValue(name, Ci.nsIPrefLocalizedString).data; + return value; + case Ci.nsIPrefBranch.PREF_INT: + return this.branch.getIntPref(name); + case Ci.nsIPrefBranch.PREF_BOOL: + return this.branch.getBoolPref(name); + default: + return defaultValue; + } + } + catch (e) { + return defaultValue; + } + }, + + getDefault: deprecated("Prefs#defaults.get", function getDefault(name, defaultValue) this.defaults.get(name, defaultValue)), + + /** + * Returns an array of all preference names in this branch or the + * given sub-branch. + * + * @param {string} branch The sub-branch for which to return preferences. + * @optional + */ + getNames: function getNames(branch) this.branch.getChildList(branch || "", { value: 0 }), + + /** + * Returns true if the given preference exists in this branch. + * + * @param {string} name The name of the preference to check. + */ + has: function has(name) this.branch.getPrefType(name) !== 0, + + /** + * Returns true if the given preference is set to its default value. + * + * @param {string} name The name of the preference to check. + */ + isDefault: function isDefault(name) !this.branch.prefHasUserValue(name), + + _checkSafe: function _checkSafe(name, message, value) { + let curval = this.get(name, null); + + if (this.branches.original.get(name) == null && !this.branches.saved.has(name)) + this.branches.original.set(name, curval, true); + + if (arguments.length > 2 && curval === value) + return; + + let defval = this.defaults.get(name, null); + let saved = this.branches.saved.get(name); + + if (saved == null && curval != defval || saved != null && curval != saved) { + let msg = _("pref.safeSet.warnChanged", name); + if (message) + msg = template.linkifyHelp(msg + " " + message); + util.dactyl.warn(msg); + } + }, + + /** + * Resets the preference *name* to *value* but warns the user if the value + * is changed from its default. + * + * @param {string} name The preference name. + * @param {value} value The new preference value. + * @param {boolean} silent Ignore errors. + */ + safeReset: function safeReset(name, message, silent) { + this._checkSafe(name, message); + this.set(name, this.branches.original.get(name), silent); + this.branches.original.reset(name); + this.branches.saved.reset(name); + }, + + /** + * Sets the preference *name* to *value* but warns the user if the value is + * changed from its default. + * + * @param {string} name The preference name. + * @param {value} value The new preference value. + */ + safeSet: function safeSet(name, value, message, skipSave) { + this._checkSafe(name, message, value); + this.set(name, value); + this.branches.saved[skipSave ? "reset" : "set"](name, value); + }, + + /** + * Sets the preference *name* to *value*. If the preference already + * exists, it must have the same type as the given value. + * + * @param {name} name The name of the preference to change. + * @param {string|number|boolean} value The value to set. + * @param {boolean} silent Ignore errors. + */ + set: function set(name, value, silent) { + if (this._prefContexts.length) + this._prefContexts[this._prefContexts.length - 1][name] = this.get(name, null); + + function assertType(needType) + util.assert(type === Ci.nsIPrefBranch.PREF_INVALID || type === needType, + type === Ci.nsIPrefBranch.PREF_INT + ? /*L*/"E521: Number required after =: " + name + "=" + value + : /*L*/"E474: Invalid argument: " + name + "=" + value); + + let type = this.branch.getPrefType(name); + try { + switch (typeof value) { + case "string": + assertType(Ci.nsIPrefBranch.PREF_STRING); + + this.branch.setComplexValue(name, Ci.nsISupportsString, services.String(value)); + break; + case "number": + assertType(Ci.nsIPrefBranch.PREF_INT); + + this.branch.setIntPref(name, value); + break; + case "boolean": + assertType(Ci.nsIPrefBranch.PREF_BOOL); + + this.branch.setBoolPref(name, value); + break; + default: + if (value == null && this != this.defaults) + this.reset(name); + else + throw FailedAssertion("Unknown preference type: " + typeof value + " (" + name + "=" + value + ")"); + } + } + catch (e if silent) {} + return value; + }, + + /** + * Saves the current value of a preference to be restored at next + * startup. + * + * @param {string} name The preference to save. + */ + save: function save(name) { + let val = this.get(name); + this.set(this.RESTORE + name, val); + this.safeSet(name, val); + }, + + /** + * Restores saved preferences in the given branch. + * + * @param {string} branch The branch from which to restore + * preferences. @optional + */ + restore: function restore(branch) { + this.getNames(this.RESTORE + (branch || "")).forEach(function (pref) { + this.safeSet(pref.substr(this.RESTORE.length), this.get(pref), null, true); + this.reset(pref); + }, this); + }, + + /** + * Resets the preference *name* to its default value. + * + * @param {string} name The name of the preference to reset. + */ + reset: function reset(name) { + if (this.branch.prefHasUserValue(name)) + this.branch.clearUserPref(name); + }, + + /** + * Resets the preference branch *branch* to its default value. + * + * @param {string} branch The preference name. @optional + */ + resetBranch: function resetBranch(branch) { + this.getNames(branch).forEach(this.closure.reset); + }, + + /** + * Toggles the value of the boolean preference *name*. + * + * @param {string} name The preference name. + */ + toggle: function toggle(name) { + util.assert(this.branch.getPrefType(name) === Ci.nsIPrefBranch.PREF_BOOL, + _("error.trailingCharacters", name + "!")); + this.set(name, !this.get(name)); + }, + + /** + * Pushes a new preference context onto the context stack. + * + * @see #withContext + */ + pushContext: function pushContext() { + this._prefContexts.push({}); + }, + + /** + * Pops the top preference context from the stack. + * + * @see #withContext + */ + popContext: function popContext() { + for (let [k, v] in Iterator(this._prefContexts.pop())) + this.set(k, v); + }, + + /** + * Executes *func* with a new preference context. When *func* returns, the + * context is popped and any preferences set via {@link #setPref} or + * {@link #invertPref} are restored to their previous values. + * + * @param {function} func The function to call. + * @param {Object} func The 'this' object with which to call *func* + * @see #pushContext + * @see #popContext + */ + withContext: function withContext(func, self) { + try { + this.pushContext(); + return func.call(self); + } + finally { + this.popContext(); + } + }, observe: null, observers: { @@ -154,248 +414,6 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) return template.options(_("pref.hostPreferences", config.host), prefs.call(this)); }, - - /** - * Returns the value of a preference. - * - * @param {string} name The preference name. - * @param {value} defaultValue The value to return if the preference - * is unset. - */ - get: function get(name, defaultValue) { - if (defaultValue == null) - defaultValue = null; - - let type = this.branch.getPrefType(name); - try { - switch (type) { - case Ci.nsIPrefBranch.PREF_STRING: - let value = this.branch.getComplexValue(name, Ci.nsISupportsString).data; - // try in case it's a localized string (will throw an exception if not) - if (!this.branch.prefIsLocked(name) && !this.branch.prefHasUserValue(name) && - RegExp("chrome://.+/locale/.+\\.properties").test(value)) - value = this.branch.getComplexValue(name, Ci.nsIPrefLocalizedString).data; - return value; - case Ci.nsIPrefBranch.PREF_INT: - return this.branch.getIntPref(name); - case Ci.nsIPrefBranch.PREF_BOOL: - return this.branch.getBoolPref(name); - default: - return defaultValue; - } - } - catch (e) { - return defaultValue; - } - }, - - getDefault: deprecated("Prefs#defaults.get", function getDefault(name, defaultValue) this.defaults.get(name, defaultValue)), - - /** - * Returns the names of all preferences. - * - * @param {string} branch The branch in which to search preferences. - * @default "" - */ - getNames: function getNames(branch) this.branch.getChildList(branch || "", { value: 0 }), - - /** - * Returns true if the current branch has the given preference. - * - * @param {string} name The preference name. - * @returns {boolean} - */ - has: function get(name) this.branch.getPrefType(name) != 0, - - _checkSafe: function _checkSafe(name, message, value) { - let curval = this.get(name, null); - - if (this.branches.original.get(name) == null && !this.branches.saved.has(name)) - this.branches.original.set(name, curval, true); - - if (arguments.length > 2 && curval === value) - return; - - let defval = this.defaults.get(name, null); - let saved = this.branches.saved.get(name); - - if (saved == null && curval != defval || saved != null && curval != saved) { - let msg = _("pref.safeSet.warnChanged", name); - if (message) - msg = template.linkifyHelp(msg + " " + message); - util.dactyl.warn(msg); - } - }, - - /** - * Resets the preference *name* to *value* but warns the user if the value - * is changed from its default. - * - * @param {string} name The preference name. - * @param {value} value The new preference value. - * @param {boolean} silent Ignore errors. - */ - safeReset: function safeReset(name, message, silent) { - this._checkSafe(name, message); - this.set(name, this.branches.original.get(name), silent); - this.branches.original.reset(name); - this.branches.saved.reset(name); - }, - - /** - * Sets the preference *name* to *value* but warns the user if the value is - * changed from its default. - * - * @param {string} name The preference name. - * @param {value} value The new preference value. - */ - safeSet: function safeSet(name, value, message, skipSave) { - this._checkSafe(name, message, value); - this.set(name, value); - this.branches.saved[skipSave ? "reset" : "set"](name, value); - }, - - /** - * Sets the preference *name* to *value*. - * - * @param {string} name The preference name. - * @param {value} value The new preference value. - * @param {boolean} silent Ignore errors. - */ - set: function set(name, value, silent) { - if (this._prefContexts.length) - this._prefContexts[this._prefContexts.length - 1][name] = this.get(name, null); - - function assertType(needType) - util.assert(type === Ci.nsIPrefBranch.PREF_INVALID || type === needType, - type === Ci.nsIPrefBranch.PREF_INT - ? /*L*/"E521: Number required after =: " + name + "=" + value - : /*L*/"E474: Invalid argument: " + name + "=" + value); - - let type = this.branch.getPrefType(name); - try { - switch (typeof value) { - case "string": - assertType(Ci.nsIPrefBranch.PREF_STRING); - - this.branch.setComplexValue(name, Ci.nsISupportsString, services.String(value)); - break; - case "number": - assertType(Ci.nsIPrefBranch.PREF_INT); - - this.branch.setIntPref(name, value); - break; - case "boolean": - assertType(Ci.nsIPrefBranch.PREF_BOOL); - - this.branch.setBoolPref(name, value); - break; - default: - if (value == null && this != this.defaults) - this.reset(name); - else - throw FailedAssertion("Unknown preference type: " + typeof value + " (" + name + "=" + value + ")"); - } - } - catch (e if silent) {} - return value; - }, - - /** - * Saves the current value of a preference to be restored at next - * startup. - * - * @param {string} name The preference to save. - */ - save: function save(name) { - let val = this.get(name); - this.set(this.RESTORE + name, val); - this.safeSet(name, val); - }, - - /** - * Restores saved preferences in the given branch. - * - * @param {string} branch The branch from which to restore - * preferences. @optional - */ - restore: function restore(branch) { - this.getNames(this.RESTORE + (branch || "")).forEach(function (pref) { - this.safeSet(pref.substr(this.RESTORE.length), this.get(pref), null, true); - this.reset(pref); - }, this); - }, - - /** - * Resets the preference *name* to its default value. - * - * @param {string} name The preference name. - */ - reset: function reset(name) { - try { - this.branch.clearUserPref(name); - } - catch (e) {} // ignore - thrown if not a user set value - }, - - /** - * Resets the preference branch *branch* to its default value. - * - * @param {string} branch The preference name. @optional - */ - resetBranch: function resetBranch(branch) { - this.getNames(branch).forEach(this.closure.reset); - }, - - /** - * Toggles the value of the boolean preference *name*. - * - * @param {string} name The preference name. - */ - toggle: function toggle(name) { - util.assert(this.branch.getPrefType(name) === Ci.nsIPrefBranch.PREF_BOOL, - _("error.trailingCharacters", name + "!")); - this.set(name, !this.get(name)); - }, - - /** - * Pushes a new preference context onto the context stack. - * - * @see #withContext - */ - pushContext: function pushContext() { - this._prefContexts.push({}); - }, - - /** - * Pops the top preference context from the stack. - * - * @see #withContext - */ - popContext: function popContext() { - for (let [k, v] in Iterator(this._prefContexts.pop())) - this.set(k, v); - }, - - /** - * Executes *func* with a new preference context. When *func* returns, the - * context is popped and any preferences set via {@link #setPref} or - * {@link #invertPref} are restored to their previous values. - * - * @param {function} func The function to call. - * @param {Object} func The 'this' object with which to call *func* - * @see #pushContext - * @see #popContext - */ - withContext: function withContext(func, self) { - try { - this.pushContext(); - return func.call(self); - } - finally { - this.popContext(); - } - } }, { }, { completion: function init_completion(dactyl, modules) { diff --git a/common/modules/protocol.jsm b/common/modules/protocol.jsm index 98d8e3bc..d2ba9e9b 100644 --- a/common/modules/protocol.jsm +++ b/common/modules/protocol.jsm @@ -142,7 +142,7 @@ ProtocolBase.prototype = { function LocaleChannel(pkg, locale, path, orig) { for each (let locale in [locale, "en-US"]) for each (let sep in "-/") { - var channel = Channel(["resource:/", pkg + sep + locale, path].join("/"), orig, true); + var channel = Channel(["resource:/", pkg + sep + locale, path].join("/"), orig, true, true); if (channel) return channel; } diff --git a/common/modules/template.jsm b/common/modules/template.jsm index 22aff796..18e9435e 100644 --- a/common/modules/template.jsm +++ b/common/modules/template.jsm @@ -81,23 +81,15 @@ var Binding = Class("Binding", { return res; }) }); -for (let [k, v] in Iterator(XPCOMShim([Ci.nsIDOMElement]))) { - let key = k; - let prop = { configurable: true, enumerable: false }; - if (callable(v)) - update(prop, { - value: function () this.node[key].apply(this.node, arguments), - writable: true - }); - else - update(prop, { - get: function () this.node[k], - set: function (val) this.node[k] = val - }); - - Object.defineProperty(Binding.prototype, key, prop); -} +["appendChild", "getAttribute", "insertBefore", "setAttribute"].forEach(function (key) { + Object.defineProperty(Binding.prototype, key, { + configurable: true, + enumerable: false, + value: function () this.node[key].apply(this.node, arguments), + writable: true + }); +}); var Template = Module("Template", { add: function add(a, b) a + b,