repo: 373f1649c80dea9be7b5bc9c57e8395f94f93ab1
-node: a34a77b2caffe9b07ee32821a66342c9ec6e9e09
+node: 025b18cc985df652eb7ec1cb9d8920ba312de985
branch: default
-latesttag: pentadactyl-1.0rc1
-latesttagdistance: 247
+latesttag: pentadactyl-1.1
+latesttagdistance: 22
#### configuration
+_SH := $(shell if which dash >/dev/null 2>&1; \
+ then echo dash; \
+ else echo sh; \
+ fi)
+SH ?= $(_SH)
AWK ?= awk
B64ENCODE ?= base64
CURL ?= curl
SED := $(shell if [ "xoo" = x$$(echo foo | sed -E 's/f(o)/\1/' 2>/dev/null) ]; \
- then echo sed -E; else echo sed -r; \
+ then echo sed -E; \
+ else echo sed -r; \
fi)
TOP = $(shell pwd)
DOC_FILES = $(wildcard $(LOCALEDIR)/*/*.xml)
export VERSION BUILD_DATE
-MAKE_JAR = sh $(BASE)/make_jar.sh
+MAKE_JAR = $(SH) $(BASE)/make_jar.sh
# TODO: specify source files manually?
JAR_BASES = $(TOP) $(BASE)
jar: $(JAR)
-# This is not for you!
-dist: $(XPI)
- @echo DIST $(XPI) $(GOOGLE)
- set -e; \
- \
- proj=$$(echo -n $(NAME) | sed 's/\(.\).*/\1/' | tr a-z A-Z); \
- proj="$$proj$$(echo $(NAME) | sed 's/.//')"; \
- [ -z "$$summary" ] && summary="$$proj $(VERSION) Release"; \
- labels="Project-$$proj,$(labels)"; \
- [ -n "$(featured)" ] && labels="$$labels,Featured"; \
- \
- IFS=,; for l in $$labels; do \
- set -- "$$@" --form-string "label=$$l"; \
- done; \
- auth=$$(echo -n "$(GOOGLE_USER):$(GOOGLE_PASS)" | $(B64ENCODE)); \
- $(CURL) "$$@" --form-string "summary=$$summary" \
- -F "filename=@$(XPI)" \
- -H "Authorization: Basic $$auth" \
- -i "$(GOOGLE)" | sed -n '/^Location/{p;q;}'
-
install:
export dir; \
for dir in $(PROFILEPATHS); do \
-f $(BASE)/process_manifest.awk \
"$(TOP)/chrome.manifest" >"$(XPI_PATH)/chrome.manifest"
+ $(AWK) -v 'name=$(NAME)' -v 'suffix=$(MANGLE)' \
+ -f $(BASE)/process_config.awk \
+ "$(TOP)/config.json" >"$(XPI_PATH)/config.json"
+
version="$(VERSION)"; \
hg root >/dev/null 2>&1 && \
case "$$version" in \
-// Copyright (c) 2010-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2010-2014 by Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
var { XPCOMUtils } = module("resource://gre/modules/XPCOMUtils.jsm");
var { Services } = module("resource://gre/modules/Services.jsm");
+var Timer = Components.Constructor("@mozilla.org/timer;1", "nsITimer", "initWithCallback");
+
const resourceProto = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
const categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
let basePath = null;
let bootstrap;
let bootstrap_jsm;
-let categories = [];
let components = {};
-let resources = [];
let getURI = null;
let JSMLoader = {
- SANDBOX: Cu.nukeSandbox && false,
+ SANDBOX: Cu.nukeSandbox,
get addon() addon,
return this.modules[name] = this.globals[uri];
this.globals[uri] = this.modules[name];
- bootstrap_jsm.loadSubScript(url, this.modules[name]);
+ bootstrap_jsm.loadSubScript(url, this.modules[name], "UTF-8");
return;
}
catch (e) {
let module = this.modules[name];
if (target)
for each (let symbol in module.EXPORTED_SYMBOLS)
- target[symbol] = module[symbol];
+ try {
+ Object.defineProperty(target, symbol, {
+ configurable: true,
+ enumerable: true,
+ writable: true,
+ value: module[symbol]
+ });
+ }
+ catch (e) {
+ target[symbol] = module[symbol];
+ }
return module;
},
// Cuts down on stupid, fscking url mangling.
get loadSubScript() bootstrap_jsm.loadSubScript,
- cleanup: function unregister() {
- for each (let factory in this.factories.splice(0))
+ cleanup: function cleanup() {
+ for (let factory of this.factories.splice(0))
manager.unregisterFactory(factory.classID, factory);
},
function init() {
debug("bootstrap: init");
- let manifestURI = getURI("chrome.manifest");
- let manifest = httpGet(manifestURI)
- .responseText
- .replace(/#(resource)#/g, "$1")
- .replace(/^\s*|\s*$|#.*/g, "")
- .replace(/^\s*\n/gm, "");
-
- for each (let line in manifest.split("\n")) {
- let fields = line.split(/\s+/);
- switch (fields[0]) {
- case "category":
- categoryManager.addCategoryEntry(fields[1], fields[2], fields[3], false, true);
- categories.push([fields[1], fields[2]]);
- break;
- case "component":
- components[fields[1]] = new FactoryProxy(getURI(fields[2]).spec, fields[1]);
- break;
- case "contract":
- components[fields[2]].contractID = fields[1];
- break;
-
- case "resource":
- moduleName = moduleName || fields[1];
- resources.push(fields[1]);
- resourceProto.setSubstitution(fields[1], getURI(fields[2]));
- }
+ let manifest = JSON.parse(httpGet(getURI("config.json"))
+ .responseText);
+
+ if (!manifest.categories)
+ manifest.categories = [];
+
+ for (let [classID, { contract, path, categories }] of Iterator(manifest.components || {})) {
+ components[classID] = new FactoryProxy(getURI(path).spec, classID, contract);
+ if (categories)
+ for (let [category, id] in Iterator(categories))
+ manifest.categories.push([category, id, contract]);
+ }
+
+ for (let [category, id, value] of manifest.categories)
+ categoryManager.addCategoryEntry(category, id, value,
+ false, true);
+
+ for (let [pkg, path] in Iterator(manifest.resources || {})) {
+ moduleName = moduleName || pkg;
+ resourceProto.setSubstitution(pkg, getURI(path));
}
- JSMLoader.config = JSON.parse(httpGet("resource://dactyl-local/config.json").responseText);
+ JSMLoader.config = manifest;
bootstrap_jsm = module(BOOTSTRAP);
if (!JSMLoader.SANDBOX)
}
bootstrap.require = JSMLoader.load("base").require;
- // Flush the cache if necessary, just to be paranoid
let pref = "extensions.dactyl.cacheFlushCheck";
let val = addon.version;
if (!Services.prefs.prefHasUserValue(pref) || Services.prefs.getCharPref(pref) != val) {
var cacheFlush = true;
- Services.obs.notifyObservers(null, "startupcache-invalidate", "");
Services.prefs.setCharPref(pref, val);
}
- try {
- //JSMLoader.load("disable-acr").init(addon.id);
- }
- catch (e) {
- reportError(e);
- }
-
Services.obs.notifyObservers(null, "dactyl-rehash", null);
JSMLoader.bootstrap = global;
// Disable automatic updates when switching to nightlies,
// restore the default action when switching to stable.
if (!config.lastVersion || isDev(config.lastVersion) != isDev(addon.version))
- addon.applyBackgroundUpdates = AddonManager[isDev(addon.version) ? "AUTOUPDATE_DISABLE" : "AUTOUPDATE_DEFAULT"];
+ addon.applyBackgroundUpdates =
+ AddonManager[isDev(addon.version) ? "AUTOUPDATE_DISABLE"
+ : "AUTOUPDATE_DEFAULT"];
}
catch (e) {
reportError(e);
* @param {string} url The URL of the module housing the real factory.
* @param {string} classID The CID of the class this factory represents.
*/
-function FactoryProxy(url, classID) {
+function FactoryProxy(url, classID, contractID) {
this.url = url;
this.classID = Components.ID(classID);
+ this.contractID = contractID;
}
FactoryProxy.prototype = {
QueryInterface: XPCOMUtils.generateQI(Ci.nsIFactory),
}
}
+var timer;
function shutdown(data, reason) {
let strReason = reasonToString(reason);
debug("bootstrap: shutdown " + strReason);
if (reason != APP_SHUTDOWN) {
- try {
- //JSMLoader.load("disable-acr").cleanup(addon.id);
- }
- catch (e) {
- reportError(e);
- }
-
if (~[ADDON_UPGRADE, ADDON_DOWNGRADE, ADDON_UNINSTALL].indexOf(reason))
Services.obs.notifyObservers(null, "dactyl-purge", null);
JSMLoader.atexit(strReason);
JSMLoader.cleanup(strReason);
- if (JSMLoader.SANDBOX)
- Cu.nukeSandbox(bootstrap);
- bootstrap_jsm.require = null;
- Cu.unload(BOOTSTRAP);
- bootstrap = null;
- bootstrap_jsm = null;
-
- for each (let [category, entry] in categories)
+ for each (let [category, entry] in JSMLoader.config.categories)
categoryManager.deleteCategoryEntry(category, entry, false);
- for each (let resource in resources)
+ for (let resource in JSMLoader.config.resources)
resourceProto.setSubstitution(resource, null);
+
+ timer = Timer(() => {
+ bootstrap_jsm.require = null;
+ if (JSMLoader.SANDBOX)
+ Cu.nukeSandbox(bootstrap);
+ else
+ Cu.unload(BOOTSTRAP);
+ bootstrap = null;
+ bootstrap_jsm = null;
+ }, 5000, Ci.nsITimer.TYPE_ONE_SHOT);
}
}
-resource dactyl ../common/modules/
-resource dactyl-common ../common/
-resource dactyl-content ../common/content/
-resource dactyl-skin ../common/skin/
-resource dactyl-locale ../common/locale/
-
-resource dactyl-local ./
-resource dactyl-local-content content/
-resource dactyl-local-skin skin/
-resource dactyl-local-locale locale/
-
content dactyl ../common/content/
-
-component {16dc34f7-6d22-4aa4-a67f-2921fb5dcb69} components/commandline-handler.js
-contract @mozilla.org/commandlinehandler/general-startup;1?type=dactyl {16dc34f7-6d22-4aa4-a67f-2921fb5dcb69}
-category command-line-handler m-dactyl @mozilla.org/commandlinehandler/general-startup;1?type=dactyl
-
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2010 by anekos <anekos@snca.net>
-// Copyright (c) 2010-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2010-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
},
/** @property {boolean} True if there are no abbreviations. */
- get empty() !values(this._store).nth(util.identity, 0),
+ get empty() !values(this._store).find(util.identity),
/**
* Adds a new abbreviation.
*/
get: function (mode, lhs) {
let abbrevs = this._store[mode];
- return abbrevs && Set.has(abbrevs, lhs) ? abbrevs[lhs] : null;
+ return abbrevs && hasOwnProperty(abbrevs, lhs) ? abbrevs[lhs]
+ : null;
},
/**
get userHives() this.allHives.filter(h => h !== this.builtin),
- get: deprecated("group.abbrevs.get", { get: function get() this.user.closure.get }),
- set: deprecated("group.abbrevs.set", { get: function set() this.user.closure.set }),
- remove: deprecated("group.abbrevs.remove", { get: function remove() this.user.closure.remove }),
- removeAll: deprecated("group.abbrevs.clear", { get: function removeAll() this.user.closure.clear }),
+ get: deprecated("group.abbrevs.get", { get: function get() this.user.bound.get }),
+ set: deprecated("group.abbrevs.set", { get: function set() this.user.bound.set }),
+ remove: deprecated("group.abbrevs.remove", { get: function remove() this.user.bound.remove }),
+ removeAll: deprecated("group.abbrevs.clear", { get: function removeAll() this.user.bound.clear }),
/**
* Returns the abbreviation for the given *mode* if *text* matches the
let match = this._match.exec(text);
if (match)
return this.hives.map(h => h.get(mode, match[2] || match[4] || match[6]))
- .nth(util.identity, 0);
+ .find(util.identity);
return null;
},
let hives = (hives || this.userHives).filter(h => !h.empty);
function abbrevs(hive)
- hive.merged.filter(ab => (ab.inModes(modes) && ab.lhs.indexOf(lhs) == 0));
+ hive.merged.filter(ab => (ab.inModes(modes) && ab.lhs.startsWith(lhs)));
let list = ["table", {},
["tr", { highlight: "Title" },
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
*/
var AutoCommands = Module("autocommands", {
init: function () {
+ if (!config.haveGecko("26"))
+ delete config.autocommands.DownloadPost; // FIXME
},
get activeHives() contexts.allGroups.autocmd.filter(h => h._store.length),
- add: deprecated("group.autocmd.add", { get: function add() autocommands.user.closure.add }),
- get: deprecated("group.autocmd.get", { get: function get() autocommands.user.closure.get }),
- remove: deprecated("group.autocmd.remove", { get: function remove() autocommands.user.closure.remove }),
+ add: deprecated("group.autocmd.add", { get: function add() autocommands.user.bound.add }),
+ get: deprecated("group.autocmd.get", { get: function get() autocommands.user.bound.get }),
+ remove: deprecated("group.autocmd.remove", { get: function remove() autocommands.user.bound.remove }),
/**
* Lists all autocommands with a matching *event*, *regexp* and optionally
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
if (id != null)
var bmark = bookmarkcache.bookmarks[id];
else if (!force) {
- if (keyword && Set.has(bookmarkcache.keywords, keyword))
+ if (keyword && hasOwnProperty(bookmarkcache.keywords, keyword))
bmark = bookmarkcache.keywords[keyword];
else if (bookmarkcache.isBookmarked(uri))
for (bmark in bookmarkcache)
}
},
- isBookmarked: deprecated("bookmarkcache.isBookmarked", { get: function isBookmarked() bookmarkcache.closure.isBookmarked }),
+ isBookmarked: deprecated("bookmarkcache.isBookmarked", { get: function isBookmarked() bookmarkcache.bound.isBookmarked }),
/**
* Remove a bookmark or bookmarks. If *ids* is an array, removes the
let uri = util.newURI(ids);
ids = services.bookmarks
.getBookmarkIdsForURI(uri, {})
- .filter(bookmarkcache.closure.isRegularBookmark);
+ .filter(bookmarkcache.bound.isRegularBookmark);
}
ids.forEach(function (id) {
let bmark = bookmarkcache.bookmarks[id];
if (!alias)
alias = "search"; // for search engines which we can't find a suitable alias
- if (Set.has(aliases, alias))
+ if (hasOwnProperty(aliases, alias))
alias += ++aliases[alias];
else
aliases[alias] = 0;
}).toObject();
},
+ /**
+ * Returns true if the given search engine provides suggestions.
+ * engine based on the given *query*. The results are always in the
+ * form of an array of strings. If *callback* is provided, the
+ * request is executed asynchronously and *callback* is called on
+ * completion. Otherwise, the request is executed synchronously and
+ * the results are returned.
+ *
+ * @param {string} engineName The name of the search engine from
+ * which to request suggestions.
+ * @returns {boolean}
+ */
+ hasSuggestions: function hasSuggestions(engineName, query, callback) {
+ const responseType = "application/x-suggestions+json";
+
+ if (hasOwnProperty(this.suggestionProviders, engineName))
+ return true;
+
+ let engine = hasOwnProperty(this.searchEngines, engineName) && this.searchEngines[engineName];
+ if (engine && engine.supportsResponseType(responseType))
+ return true;
+
+ return false;
+ },
+
/**
* Retrieves a list of search suggestions from the named search
* engine based on the given *query*. The results are always in the
getSuggestions: function getSuggestions(engineName, query, callback) {
const responseType = "application/x-suggestions+json";
- if (Set.has(this.suggestionProviders, engineName))
+ if (hasOwnProperty(this.suggestionProviders, engineName))
return this.suggestionProviders[engineName](query, callback);
- let engine = Set.has(this.searchEngines, engineName) && this.searchEngines[engineName];
+ let engine = hasOwnProperty(this.searchEngines, engineName) && this.searchEngines[engineName];
if (engine && engine.supportsResponseType(responseType))
var queryURI = engine.getSubmission(query, responseType).uri.spec;
+
if (!queryURI)
- return (callback || util.identity)([]);
+ return promises.fail();
function parse(req) JSON.parse(req.responseText)[1].filter(isString);
return this.makeSuggestions(queryURI, parse, callback);
* @param {string} url The URL to fetch.
* @param {function(XMLHttpRequest):[string]} parser The function which
* parses the response.
+ * @returns {Promise<Array>}
*/
- makeSuggestions: function makeSuggestions(url, parser, callback) {
- function process(req) {
+ makeSuggestions: function makeSuggestions(url, parser) {
+ let deferred = Promise.defer();
+
+ let req = util.fetchUrl(url);
+ req.then(function process(req) {
let results = [];
try {
results = parser(req);
}
catch (e) {
- util.reportError(e);
+ return deferred.reject(e);
}
- if (callback)
- return callback(results);
- return results;
- }
+ deferred.resolve(results);
+ }, Cu.reportError);
- let req = util.httpGet(url, callback && process);
- if (callback)
- return req;
- return process(req);
+ promises.oncancel(deferred, r => promises.cancel(req, reason));
+ return deferred.promise;
},
suggestionProviders: {},
param = query.substr(offset + 1);
}
- var engine = Set.has(bookmarks.searchEngines, keyword) && bookmarks.searchEngines[keyword];
+ var engine = hasOwnProperty(bookmarks.searchEngines, keyword) && bookmarks.searchEngines[keyword];
if (engine) {
if (engine.searchForm && !param)
return engine.searchForm;
"Delete a bookmark",
function (args) {
if (args.bang)
- commandline.input(_("bookmark.prompt.deleteAll") + " ",
+ commandline.input(_("bookmark.prompt.deleteAll") + " ").then(
function (resp) {
if (resp && resp.match(/^y(es)?$/i)) {
bookmarks.remove(Object.keys(bookmarkcache.bookmarks));
},
completion: function initCompletion() {
- completion.bookmark = function bookmark(context, tags, extra = {}) {
+ completion.bookmark = function bookmark(context, tags, extra={}) {
context.title = ["Bookmark", "Title"];
context.format = bookmarks.format;
iter(extra).forEach(function ([k, v]) {
keyword, true);
let item = keywords[keyword];
- if (item && item.url.indexOf("%s") > -1)
+ if (item && item.url.contains("%s"))
context.fork("keyword/" + keyword, keyword.length + space.length, null, function (context) {
context.format = history.format;
context.title = [/*L*/keyword + " Quick Search"];
return history.get({ uri: util.newURI(begin), uriIsPrefix: true }).map(function (item) {
let rest = item.url.length - end.length;
let query = item.url.substring(begin.length, rest);
- if (item.url.substr(rest) == end && query.indexOf("&") == -1)
+ if (item.url.substr(rest) == end && query.contains("&"))
try {
item.url = decodeURIComponent(query.replace(/#.*/, "").replace(/\+/g, " "));
return item;
let engineList = (engineAliases || options["suggestengines"].join(",") || "google").split(",");
engineList.forEach(function (name) {
+ if (!bookmarks.hasSuggestions(name))
+ return;
+
var desc = name;
let engine = bookmarks.searchEngines[name];
if (engine)
- var desc = engine.description;
- else if (!Set.has(bookmarks.suggestionProviders, name))
- return;
+ desc = engine.description;
+
let [, word] = /^\s*(\S+)/.exec(context.filter) || [];
if (!kludge && word == name) // FIXME: Check for matching keywords
return;
+
let ctxt = context.fork(name, 0);
ctxt.title = [/*L*/desc + " Suggestions"];
return;
let words = ctxt.filter.toLowerCase().split(/\s+/g);
- ctxt.completions = ctxt.completions.filter(i => words.every(w => i.toLowerCase().indexOf(w) >= 0));
+ ctxt.completions = ctxt.completions.filter(i => words.every(w => i.toLowerCase().contains(w)));
ctxt.hasItems = ctxt.completions.length;
ctxt.incomplete = true;
- ctxt.cache.request = bookmarks.getSuggestions(name, ctxt.filter, function (compl) {
+ ctxt.cache.request = bookmarks.getSuggestions(name, ctxt.filter);
+ ctxt.cache.request.then(function (compl) {
ctxt.incomplete = false;
- ctxt.completions = array.uniq(ctxt.completions.filter(c => compl.indexOf(c) >= 0)
+ ctxt.completions = array.uniq(ctxt.completions.filter(c => compl.contains(c))
.concat(compl), true);
+ }, function (e) {
+ ctxt.incomplete = false;
+ ctxt.completions = [];
+ if (e)
+ Cu.reportError(e);
});
});
};
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
this.cleanupProgressListener = overlay.overlayObject(window.XULBrowserWindow,
this.progressListener);
util.addObserver(this);
+
+ this._unoverlay = overlay.overlayObject(FullZoom, {
+ get siteSpecific() false,
+ set siteSpecific(val) {}
+ });
},
destroy: function () {
this.cleanupProgressListener();
this.observe.unregister();
+ this._unoverlay();
},
observers: {
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
}
[this.commandbar.container, this.statusbar.container].forEach(check);
- // Work around a redrawing bug.
- if (changed && config.haveGecko("16", "20")) {
- util.delay(function () {
- // Urgh.
- statusline.statusBar.style.paddingRight = "1px";
- DOM(statusline.statusBar).rect; // Force reflow.
- statusline.statusBar.style.paddingRight = "";
- }, 0);
- }
-
- if (this.initialized && loaded.mow && mow.visible)
+ if (this.initialized && loaded.has("mow") && mow.visible)
mow.resize(false);
},
false);
this.messageCount = commandline.messageCount;
- modes.push(this.mode, this.extendedMode, this.closure);
+ modes.push(this.mode, this.extendedMode, this.bound);
this.widgets.active.commandline.collapsed = false;
this.widgets.prompt = this.prompt;
* Displays the multi-line output of a command, preceded by the last
* executed ex command string.
*
- * @param {XML} xml The output as an E4X XML object.
+ * @param {object} xml The output as a JSON XML object.
*/
commandOutput: function commandOutput(xml) {
if (!this.command)
let action = this._echoLine;
if ((flags & this.FORCE_MULTILINE) || (/\n/.test(data) || !isinstance(data, [_, "String"])) && !(flags & this.FORCE_SINGLELINE))
- action = mow.closure.echo;
+ action = mow.bound.echo;
let checkSingleLine = () => action == this._echoLine;
// So complicated...
if (checkSingleLine() && !this.widgets.mowContainer.collapsed) {
highlightGroup += " Message";
- action = mow.closure.echo;
+ action = mow.bound.echo;
}
else if (!checkSingleLine() && this.widgets.mowContainer.collapsed) {
if (this._lastEcho && this.widgets.message && this.widgets.message[1] == this._lastEcho.msg) {
* pop at any time to close the prompt.
*
* @param {string} prompt The input prompt to use.
- * @param {function(string)} callback
* @param {Object} extra
* @... {function} onChange - A function to be called with the current
* input every time it changes.
* @... {string} default - The initial value that will be returned
* if the user presses <CR> straightaway. @default ""
*/
- input: function _input(prompt, callback, extra = {}) {
- CommandPromptMode(prompt, update({ onSubmit: callback }, extra)).open();
- },
+ input: promises.withCallbacks(function _input([callback, reject], prompt, extra={}, thing={}) {
+ if (callable(extra))
+ // Deprecated.
+ [callback, extra] = [extra, thing];
+
+ CommandPromptMode(prompt, update({ onSubmit: callback, onCancel: reject }, extra)).open();
+ }),
readHeredoc: function readHeredoc(end) {
- let args;
- commandline.inputMultiline(end, function (res) { args = res; });
- util.waitFor(() => args !== undefined);
- return args;
+ return util.waitFor(commandline.inputMultiline(end));
},
/**
* callback with that string as a parameter.
*
* @param {string} end
- * @param {function(string)} callback
+ * @returns {Promise<string>}
*/
// FIXME: Buggy, especially when pasting.
- inputMultiline: function inputMultiline(end, callback) {
+ inputMultiline: promises.withCallbacks(function inputMultiline([callback], end) {
let cmd = this.command;
let self = {
end: "\n" + end + "\n",
this._autosizeMultilineInputWidget();
this.timeout(function () { dactyl.focus(this.widgets.multilineInput); }, 10);
- },
+ }),
get commandMode() this.commandSession && isinstance(modes.main, modes.COMMAND_LINE),
if (privateData == "never-save")
return;
- this.store = this.store.filter(line => (line.value || line) != str);
- dactyl.trapErrors(function () {
- this.store.push({ value: str, timestamp: Date.now() * 1000, privateData: privateData });
- }, this);
- this.store = this.store.slice(Math.max(0, this.store.length - options["history"]));
+ let store = Array.filter(this.store, line => (line.value || line) != str);
+ dactyl.trapErrors(
+ () => store.push({ value: str, timestamp: Date.now() * 1000, privateData: privateData }));
+ this.store = store.slice(Math.max(0, store.length - options["history"]));
},
/**
* @property {function} Returns whether a data item should be
this.itemList = commandline.completionList;
this.itemList.open(this.context);
- dactyl.registerObserver("events.doneFeeding", this.closure.onDoneFeeding, true);
+ dactyl.registerObserver("events.doneFeeding", this.bound.onDoneFeeding, true);
this.autocompleteTimer = Timer(200, 500, function autocompleteTell(tabPressed) {
if (events.feedingKeys && !tabPressed)
* called.
*/
cleanup: function cleanup() {
- dactyl.unregisterObserver("events.doneFeeding", this.closure.onDoneFeeding);
+ dactyl.unregisterObserver("events.doneFeeding", this.bound.onDoneFeeding);
this.previewClear();
this.tabTimer.reset();
* @default {@link #selected}
* @returns {object}
*/
- getItem: function getItem(tuple = this.selected)
+ getItem: function getItem(tuple=this.selected)
tuple && tuple[0] && tuple[0].items[tuple[1]],
/**
* @default false
* @private
*/
- select: function select(idx, count = 1, fromTab = false) {
+ select: function select(idx, count=1, fromTab=false) {
switch (idx) {
case this.UP:
case this.DOWN:
this.resize(flags);
}, this);
- DOM(this.win).resize(this._onResize.closure.tell);
+ DOM(this.win).resize(this._onResize.bound.tell);
},
get rootXML()
if (start < 0 || start >= this.itemCount)
return null;
- group = array.nth(groups, g => let (i = start - g.offsets.start) i >= 0 && i < g.itemCount, 0);
+ group = groups.find(g => let (i = start - g.offsets.start) i >= 0 && i < g.itemCount);
return [group.context, start - group.offsets.start];
},
// We need to collect all of the rescrolling functions in
// one go, as the height calculation that they need to do
- // would force a reflow after each DOM modification.
+ // would force an expensive reflow after each call due to
+ // DOM modifications, otherwise.
this.activeGroups.filter(g => !g.collapsed)
.map(g => g.rescrollFunc)
.forEach(call);
getGroup: function getGroup(context)
context instanceof ItemList.Group ? context
: context && context.getCache("itemlist-group",
- bind("Group", ItemList, this, context)),
+ () => ItemList.Group(this, context)),
getOffset: function getOffset(tuple) tuple && this.getGroup(tuple[0]).getOffset(tuple[1])
}, {
first = row;
let container = DOM(this.nodes.items);
- let before = first ? DOM(first).closure.before
- : DOM(this.nodes.items).closure.append;
+ let before = first ? DOM(first).bound.before
+ : DOM(this.nodes.items).bound.append;
for (let [i, row] in this.context.getRows(range.start, range.end,
this.doc)) {
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
&& !item.hidden
&& !/rdf:http:/.test(item.getAttribute("label"))) { // FIXME
item.dactylPath = parent + item.getAttribute("label");
- if (!targetPath || targetPath.indexOf(item.dactylPath) == 0)
+ if (!targetPath || targetPath.startsWith(item.dactylPath))
items.push(item);
}
else {
let path = parent;
if (item.localName == "menu")
path += item.getAttribute("label") + ".";
- if (!targetPath || targetPath.indexOf(path) == 0)
+ if (!targetPath || targetPath.startsWith(path))
addChildren(item, path);
}
}
registerObservers: function registerObservers(obj, prop) {
for (let [signal, func] in Iterator(obj[prop || "signals"]))
- this.registerObserver(signal, obj.closure(func), false);
+ this.registerObserver(signal, func.bind(obj), false);
},
unregisterObserver: function unregisterObserver(type, callback) {
applyTriggerObserver: function triggerObserver(type, args) {
if (type in this._observers)
- this._observers[type] = this._observers[type].filter(function (callback) {
- if (callback.get()) {
- try {
- try {
- callback.get().apply(null, args);
- }
- catch (e if e.message == "can't wrap XML objects") {
- // Horrible kludge.
- callback.get().apply(null, [String(args[0])].concat(args.slice(1)));
- }
- }
- catch (e) {
- dactyl.reportError(e);
- }
+ this._observers[type] = this._observers[type]
+ .filter(callback => {
+ callback = callback.get();
+ if (callback) {
+ util.trapErrors(() => callback.apply(null, args));
return true;
}
});
let filters = args.map(arg => let (re = util.regexp.escape(arg))
util.regexp("\\b" + re + "\\b|(?:^|[()\\s])" + re + "(?:$|[()\\s])", "i"));
if (filters.length)
- results = results.filter(item => filters.every(re => keys(item).some(re.closure.test)));
+ results = results.filter(item => filters.every(re => keys(item).some(re.bound.test)));
commandline.commandOutput(
template.usage(results, params.format));
let results = array((params.iterateIndex || params.iterate).call(params, commands.get(name).newArgs()))
.array.sort((a, b) => String.localeCompare(a.name, b.name));
- let haveTag = Set.has(help.tags);
for (let obj in values(results)) {
let res = dactyl.generateHelp(obj, null, null, true);
- if (!haveTag(obj.helpTag))
+ if (!hasOwnProperty(help.tags, obj.helpTag))
res[0][1].tag = obj.helpTag;
yield res;
},
dump: deprecated("util.dump",
- { get: function dump() util.closure.dump }),
+ { get: function dump() util.bound.dump }),
dumpStack: deprecated("util.dumpStack",
- { get: function dumpStack() util.closure.dumpStack }),
+ { get: function dumpStack() util.bound.dumpStack }),
/**
* Outputs a plain message to the command line.
* should be loaded.
*/
loadScript: function loadScript(uri, context) {
+ let prefix = "literal:" + uri + ":";
+ cache.flush(s => s.startsWith(prefix));
+ delete literal.files[uri];
JSMLoader.loadSubScript(uri, context, File.defaultEncoding);
},
userEval: function userEval(str, context, fileName, lineNumber) {
- let ctxt;
- if (jsmodules.__proto__ != window && jsmodules.__proto__ != XPCNativeWrapper(window) &&
- jsmodules.isPrototypeOf(context))
- str = "with (window) { with (modules) { (this.eval || eval)(" + str.quote() + ") } }";
+ let ctxt,
+ info = contexts.context;
- let info = contexts.context;
if (fileName == null)
if (info)
({ file: fileName, line: lineNumber, context: ctxt }) = info;
if (fileName && fileName[0] == "[")
fileName = "dactyl://command-line/";
else if (!context)
- context = ctxt || _userContext;
-
- if (isinstance(context, ["Sandbox"]))
- return Cu.evalInSandbox(str, context, "1.8", fileName, lineNumber);
+ context = ctxt || userContext;
if (!context)
context = userContext || ctxt;
+ if (isinstance(context, ["Sandbox"]))
+ return Cu.evalInSandbox(str, context, "1.8", fileName, lineNumber);
+
if (services.has("dactyl") && services.dactyl.evalInContext)
return services.dactyl.evalInContext(str, context, fileName, lineNumber);
* @param {boolean} silent Whether the command should be echoed on the
* command line.
*/
- execute: function execute(str, modifiers = {}, silent = false) {
+ execute: function execute(str, modifiers={}, silent=false) {
// skip comments and blank lines
if (/^\s*("|$)/.test(str))
return;
* @param {string} feature The feature name.
* @returns {boolean}
*/
- has: function has(feature) Set.has(config.features, feature),
+ has: function has(feature) config.has(feature),
/**
* @private
}
},
- help: deprecated("help.help", { get: function help() modules.help.closure.help }),
- findHelp: deprecated("help.findHelp", { get: function findHelp() help.closure.findHelp }),
+ help: deprecated("help.help", { get: function help() modules.help.bound.help }),
+ findHelp: deprecated("help.findHelp", { get: function findHelp() help.bound.findHelp }),
/**
* @private
}
if (obj.completer && false)
- add(completion._runCompleter(obj.closure.completer, "", null, args).items
+ add(completion._runCompleter(obj.bound.completer, "", null, args).items
.map(i => [i.text, i.description]));
if (obj.options && obj.options.some(o => o.description) && false)
},
events: {
+ beforecustomization: function onbeforecustomization(event) {
+ // Show navigation bar on Australis, where it's not supposed
+ // to be collapsible, and is therefore not handled by
+ // builtin code.
+ if ("CustomizableUI" in window)
+ this.setNodeVisible(document.getElementById("nav-bar"),
+ true);
+ },
+
+ aftercustomization: function onaftercustomization(event) {
+ // Restore toolbar states.
+ options["guioptions"] = options["guioptions"];
+ },
+
click: function onClick(event) {
let elem = event.originalTarget;
* tabs.
* @returns {boolean}
*/
- open: function open(urls, params = {}, force = false) {
+ open: function open(urls, params={}, force=false) {
if (typeof urls == "string")
urls = dactyl.parseURLs(urls);
if (urls.length > prefs.get("browser.tabs.maxOpenBeforeWarn", 20) && !force)
- return commandline.input(_("dactyl.prompt.openMany", urls.length) + " ",
- function (resp) {
+ return commandline.input(_("dactyl.prompt.openMany", urls.length) + " ")
+ .then(function (resp) {
if (resp && resp.match(/^y(es)?$/i))
dactyl.open(urls, params, true);
});
if (error instanceof FailedAssertion && error.noTrace || error.message === "Interrupted") {
let context = contexts.context;
let prefix = context ? context.file + ":" + context.line + ": " : "";
- if (error.message && error.message.indexOf(prefix) !== 0 &&
+ if (error.message && !error.message.startsWith(prefix) &&
prefix != "[Command Line]:1: ")
error.message = prefix + error.message;
return [];
}
},
- wrapCallback: function wrapCallback(callback, self = this) {
+ wrapCallback: function wrapCallback(callback, self=this) {
let save = ["forceOpen"];
let saved = save.map(p => dactyl[p]);
return function wrappedCallback() {
* @property {[Window]} Returns an array of all the host application's
* open windows.
*/
- get windows() [win for (win in iter(services.windowMediator.getEnumerator("navigator:browser"))) if (win.dactyl)],
+ get windows() [w for (w of overlay.windows)]
}, {
- toolbarHidden: function hidden(elem) (elem.getAttribute("autohide") || elem.getAttribute("collapsed")) == "true"
+ toolbarHidden: function toolbarHidden(elem) "true" == (elem.getAttribute("autohide") ||
+ elem.getAttribute("collapsed"))
}, {
cache: function initCache() {
cache.register("help/plugins.xml", function () {
try {
let info = contexts.getDocs(context);
if (DOM.isJSONXML(info)) {
- let langs = info.slice(2).filter(e => isArray(e) && isObject(e[1]) && e[1].lang);
+ let langs = info.slice(2)
+ .filter(e => isArray(e) && isObject(e[1]) && e[1].lang);
if (langs) {
- let lang = config.bestLocale(l[1].lang for each (l in langs));
+ let lang = config.bestLocale(langs.map(l => l[1].lang));
info = info.slice(0, 2).concat(
info.slice(2).filter(e => !isArray(e)
|| !isObject(e[1])
|| e[1].lang == lang));
- for each (let elem in info.slice(2).filter(e => isArray(e) && e[0] == "info" && isObject(e[1])))
- for (let attr in values(["name", "summary", "href"]))
+ info.slice(2)
+ .filter(e => isArray(e) && e[0] == "info" && isObject(e[1]))
+ .forEach(elem => {
+ for (let attr of ["name", "summary", "href"])
if (attr in elem[1])
info[attr] = elem[1][attr];
+ });
}
body.push(["h2", { xmlns: "dactyl", tag: info[1].name + '-plugin' },
String(info[1].summary)]);
["toc", { start: "2" }],
body]);
- });
+ }, true);
cache.register("help/index.xml", function () {
return '<?xml version="1.0"?>\n' +
["dl", { insertafter: name + "-index" },
template.map(iter(), util.identity)],
"\n\n")]);
- });
+ }, true);
cache.register("help/gui.xml", function () {
return '<?xml version="1.0"?>\n' +
["dd", {}, val[0]]]
: undefined,
"\n")]]);
- });
+ }, true);
cache.register("help/privacy.xml", function () {
return '<?xml version="1.0"?>\n' +
[["dt", {}, name],
["dd", {}, template.linkifyHelp(description, true)]],
"\n")]]);
- });
+ }, true);
},
events: function initEvents() {
events.listen(window, dactyl, "events", true);
M: ["Always show messages outside of the status line"]
},
setter: function (opts) {
- if (loaded.commandline || ~opts.indexOf("c"))
+ if (loaded.has("commandline") || ~opts.indexOf("c"))
commandline.widgets.updateVisibility();
}
},
styles.system.add("taboptions", "chrome://*",
classes.length ? classes.join(",") + "{ display: none; }" : "");
- if (!dactyl.has("Gecko2")) {
- tabs.tabBinding.enabled = Array.some(opts, k => k in this.opts);
- tabs.updateTabCount();
- }
if (config.tabbrowser.tabContainer._positionPinnedTabs)
config.tabbrowser.tabContainer._positionPinnedTabs();
},
if (args["+purgecaches"])
cache.flush();
- util.delay(function () { util.rehash(args) });
+ util.delay(() => { util.rehash(args) });
},
{
argCount: "0", // FIXME
});
}
+ if (config.has("default-theme") && "CustomizableUI" in window)
+ overlay.overlayWindow(window, {
+ append: [
+ ["window", { id: document.documentElement.id, "dactyl-australis": "true", xmlns: "xul" }]]
+ });
+
dactyl.timeout(function () {
try {
var args = config.prefs.get("commandline-args")
// dactyl.hideGUI();
if (dactyl.userEval("typeof document", null, "test.js") === "undefined")
- jsmodules.__proto__ = XPCSafeJSObjectWrapper(window);
+ jsmodules.__proto__ = window;
if (dactyl.commandLineOptions.preCommands)
dactyl.commandLineOptions.preCommands.forEach(function (cmd) {
+++ /dev/null
-// By Kris Maglione. Public Domain.
-// Please feel free to copy and use at will.
-
-var ADDON_ID;
-
-const OVERLAY_URLS = [
- "about:addons",
- "chrome://mozapps/content/extensions/extensions.xul"
-];
-
-let { interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-const TOPIC = "chrome-document-global-created";
-
-function observe(window, topic, url) {
- if (topic === TOPIC)
- checkDocument(window.document);
-}
-function init(id) {
- if (id)
- ADDON_ID = id;
-
- Services.obs[id ? "addObserver" : "removeObserver"](observe, TOPIC, false);
- for (let doc in chromeDocuments())
- checkDocument(doc, !id);
-}
-function cleanup() { init(null); }
-
-function checkPopup(event) {
- let doc = event.originalTarget.ownerDocument;
- let binding = doc.getBindingParent(event.originalTarget);
- if (binding && binding.addon && binding.addon.guid == ADDON_ID && !binding.addon.compatible) {
- let elem = doc.getAnonymousElementByAttribute(binding, "anonid", "stillworks");
- if (elem && elem.nextSibling) {
- elem.nextSibling.disabled = true;
- elem.nextSibling.setAttribute("tooltiptext", "Developer has opted out of incompatibility reports\n"+
- "Development versions are available with updated support");
- }
- }
-}
-
-function checkDocument(doc, disable, force) {
- if (["interactive", "complete"].indexOf(doc.readyState) >= 0 || force && doc.readyState === "uninitialized") {
- if (OVERLAY_URLS.indexOf(doc.documentURI) >= 0)
- doc[disable ? "removeEventListener" : "addEventListener"]("popupshowing", checkPopup, false);
- }
- else {
- doc.addEventListener("DOMContentLoaded", function listener() {
- doc.removeEventListener("DOMContentLoaded", listener, false);
- checkDocument(doc, disable, true);
- }, false);
- }
-}
-
-function chromeDocuments() {
- let windows = Services.wm.getXULWindowEnumerator(null);
- while (windows.hasMoreElements()) {
- let window = windows.getNext().QueryInterface(Ci.nsIXULWindow);
- for each (let type in ["typeChrome", "typeContent"]) {
- let docShells = window.docShell.getDocShellEnumerator(Ci.nsIDocShellTreeItem[type],
- Ci.nsIDocShell.ENUMERATE_FORWARDS);
- while (docShells.hasMoreElements())
- try {
- yield docShells.getNext().QueryInterface(Ci.nsIDocShell).contentViewer.DOMDocument;
- }
- catch (e) {}
- }
- }
-}
-
-var EXPORTED_SYMBOLS = ["cleanup", "init"];
-
-// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript:
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
//
// This work is licensed for reuse under an MIT license. Details are
}, this);
},
- defaultRegister: "*",
+ defaultRegister: "*+",
selectionRegisters: {
"*": "selection",
if (name == null)
name = editor.currentRegister || editor.defaultRegister;
+ name = String(name)[0];
if (name == '"')
name = 0;
if (name == "_")
var res = null;
- else if (Set.has(this.selectionRegisters, name))
+ else if (hasOwnProperty(this.selectionRegisters, name))
res = { text: dactyl.clipboardRead(this.selectionRegisters[name]) || "" };
else if (!/^[0-9]$/.test(name))
res = this.registers.get(name);
value = DOM.stringify(value);
value = { text: value, isLine: modes.extended & modes.LINE, timestamp: Date.now() * 1000 };
- if (name == '"')
- name = 0;
- if (name == "_")
- ;
- else if (Set.has(this.selectionRegisters, name))
- dactyl.clipboardWrite(value.text, verbose, this.selectionRegisters[name]);
- else if (!/^[0-9]$/.test(name))
- this.registers.set(name, value);
- else {
- this.registerRing.insert(value, name);
- this.registerRing.truncate(10);
+ for (let n of String(name)) {
+ if (n == '"')
+ n = 0;
+ if (n == "_")
+ ;
+ else if (hasOwnProperty(this.selectionRegisters, n))
+ dactyl.clipboardWrite(value.text, verbose, this.selectionRegisters[n]);
+ else if (!/^[0-9]$/.test(n))
+ this.registers.set(n, value);
+ else {
+ this.registerRing.insert(value, n);
+ this.registerRing.truncate(10);
+ }
}
},
let keepFocus = modes.stack.some(m => isinstance(m.main, modes.COMMAND_LINE));
if (!forceEditing && textBox && textBox.type == "password") {
- commandline.input(_("editor.prompt.editPassword") + " ",
- function (resp) {
+ commandline.input(_("editor.prompt.editPassword") + " ")
+ .then(function (resp) {
if (resp && resp.match(/^y(es)?$/i))
editor.editFieldExternally(true);
});
column = 1 + pre.replace(/[^]*\n/, "").length;
let origGroup = DOM(textBox).highlight.toString();
- let cleanup = util.yieldable(function cleanup(error) {
+ let cleanup = promises.task(function cleanup(error) {
if (timer)
timer.cancel();
DOM(textBox).highlight.remove("EditorEditing");
if (!keepFocus)
dactyl.focus(textBox);
+
for (let group in values(blink.concat(blink, ""))) {
highlight.highlightNode(textBox, origGroup + " " + group);
- yield 100;
+
+ yield promises.sleep(100);
}
}
});
completion: function initCompletion() {
completion.register = function complete_register(context) {
context = context.fork("registers");
- context.keys = { text: util.identity, description: editor.closure.getRegister };
+ context.keys = { text: util.identity, description: editor.bound.getRegister };
- context.match = function (r) !this.filter || ~this.filter.indexOf(r);
+ context.match = function (r) !this.filter || this.filter.contains(r);
context.fork("clipboard", 0, this, function (ctxt) {
ctxt.match = context.match;
args.push(obj["file"]);
return args;
},
- has: function (key) Set.has(util.compileMacro(this.value).seen, key),
+ has: function (key) util.compileMacro(this.value).seen.has(key),
validator: function (value) {
this.format({}, value);
- return Object.keys(util.compileMacro(value).seen)
- .every(k => ["column", "file", "line"].indexOf(k) >= 0);
+ let allowed = RealSet(["column", "file", "line"]);
+ return [k for (k of util.compileMacro(value).seen)]
+ .every(k => allowed.has(k));
}
});
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
else
[self, events] = [event, event[callback || "events"]];
- if (Set.has(events, "input") && !Set.has(events, "dactyl-input"))
+ if (hasOwnProperty(events, "input") && !hasOwnProperty(events, "dactyl-input"))
events["dactyl-input"] = events.input;
return [self, events];
let elem = args[0].get();
if (target == null || elem == target
&& self == args[1].get()
- && Set.has(events, args[2])
+ && hasOwnProperty(events, args[2])
&& args[3].wrapped == events[args[2]]
&& args[4] == capture) {
});
},
- get wrapListener() events.closure.wrapListener
+ get wrapListener() events.bound.wrapListener
});
/**
["window", { id: document.documentElement.id, xmlns: "xul" },
// http://developer.mozilla.org/en/docs/XUL_Tutorial:Updating_Commands
["commandset", { id: "dactyl-onfocus", commandupdater: "true", events: "focus",
- commandupdate: this.closure.onFocusChange }],
+ commandupdate: this.bound.onFocusChange }],
["commandset", { id: "dactyl-onselect", commandupdater: "true", events: "select",
- commandupdate: this.closure.onSelectionChange }]]]
+ commandupdate: this.bound.onSelectionChange }]]]
});
this._fullscreen = window.fullScreen;
this.listen(window, this, "events", true);
this.listen(window, this.popups, "events", true);
+
+ this.grabFocus = 0;
+ this.grabFocusTimer = Timer(100, 10000, () => {
+ this.grabFocus = 0;
+ });
},
cleanup: function cleanup() {
}
},
- get listen() this.builtin.closure.listen,
+ get listen() this.builtin.bound.listen,
addSessionListener: deprecated("events.listen", { get: function addSessionListener() this.listen }),
/**
* Wraps an event listener to ensure that errors are reported.
*/
- wrapListener: function wrapListener(method, self = this) {
+ wrapListener: function wrapListener(method, self=this) {
method.wrapper = wrappedListener;
wrappedListener.wrapped = method;
function wrappedListener(event) {
return true;
},
- canonicalKeys: deprecated("DOM.Event.canonicalKeys", { get: function canonicalKeys() DOM.Event.closure.canonicalKeys }),
+ canonicalKeys: deprecated("DOM.Event.canonicalKeys", { get: function canonicalKeys() DOM.Event.bound.canonicalKeys }),
create: deprecated("DOM.Event", function create() DOM.Event.apply(null, arguments)),
dispatch: deprecated("DOM.Event.dispatch", function dispatch() DOM.Event.dispatch.apply(DOM.Event, arguments)),
- fromString: deprecated("DOM.Event.parse", { get: function fromString() DOM.Event.closure.parse }),
- iterKeys: deprecated("DOM.Event.iterKeys", { get: function iterKeys() DOM.Event.closure.iterKeys }),
+ fromString: deprecated("DOM.Event.parse", { get: function fromString() DOM.Event.bound.parse }),
+ iterKeys: deprecated("DOM.Event.iterKeys", { get: function iterKeys() DOM.Event.bound.iterKeys }),
toString: function toString() {
if (!arguments.length)
events: {
blur: function onBlur(event) {
let elem = event.originalTarget;
- if (DOM(elem).isEditable)
+ if (DOM(elem).editor)
util.trapErrors("removeEditActionListener",
DOM(elem).editor, editor);
// TODO: Merge with onFocusChange
focus: function onFocus(event) {
let elem = event.originalTarget;
- if (DOM(elem).isEditable)
+ if (DOM(elem).editor)
util.trapErrors("addEditActionListener",
DOM(elem).editor, editor);
Ci.nsIDOMHTMLSelectElement,
Ci.nsIDOMHTMLTextAreaElement,
Ci.nsIDOMWindow])) {
-
- if (elem.frameElement)
- dactyl.focusContent(true);
- else if (!(elem instanceof Window) || Editor.getEditor(elem))
- dactyl.focus(window);
+ if (this.grabFocus++ > 5)
+ ; // Something is fighting us. Give up.
+ else {
+ this.grabFocusTimer.tell();
+ if (elem.frameElement)
+ dactyl.focusContent(true);
+ else if (!(elem instanceof Window) || Editor.getEditor(elem))
+ dactyl.focus(window);
+ }
}
if (elem instanceof Element)
return Events.kill(event);
}
- if (!this.processor) {
+ if (this.processor)
+ events.dbg("ON KEYPRESS " + key + " processor: " + this.processor,
+ event.originalTarget instanceof Element ? event.originalTarget : String(event.originalTarget));
+ else {
let mode = modes.getStack(0);
if (event.dactylMode)
mode = Modes.StackElement(event.dactylMode);
let haveInput = modes.stack.some(m => m.main.input);
if (DOM(elem || win).isEditable) {
- if (!haveInput)
- if (!isinstance(modes.main, [modes.INPUT, modes.TEXT_EDIT, modes.VISUAL]))
- if (options["insertmode"])
- modes.push(modes.INSERT);
- else {
- modes.push(modes.TEXT_EDIT);
- if (elem.selectionEnd - elem.selectionStart > 0)
- modes.push(modes.VISUAL);
- }
-
- if (hasHTMLDocument(win))
- buffer.lastInputField = elem || win;
- return;
+ let e = elem || win;
+ if (!(e instanceof Ci.nsIDOMWindow &&
+ DOM(e.document.activeElement).style.MozUserModify != "read-write")) {
+ if (!haveInput)
+ if (!isinstance(modes.main, [modes.INPUT, modes.TEXT_EDIT, modes.VISUAL]))
+ if (options["insertmode"])
+ modes.push(modes.INSERT);
+ else {
+ modes.push(modes.TEXT_EDIT);
+ if (elem.selectionEnd - elem.selectionStart > 0)
+ modes.push(modes.VISUAL);
+ }
+
+ if (hasHTMLDocument(win))
+ buffer.lastInputField = elem || win;
+ return;
+ }
}
if (elem && Events.isInputElement(elem)) {
},
isInputElement: function isInputElement(elem) {
- return DOM(elem).isEditable ||
+ return elem instanceof Ci.nsIDOMElement && DOM(elem).isEditable ||
isinstance(elem, [Ci.nsIDOMHTMLEmbedElement,
Ci.nsIDOMHTMLObjectElement,
Ci.nsIDOMHTMLSelectElement]);
"sitemap", "", {
flush: function flush() {
memoize(this, "filters", function () this.value.filter(function (f) f(buffer.documentURI)));
- memoize(this, "pass", function () Set(array.flatten(this.filters.map(function (f) f.keys))));
+ memoize(this, "pass", function () RealSet(array.flatten(this.filters.map(function (f) f.keys))));
memoize(this, "commandHive", function hive() Hive(this.filters, "command"));
memoize(this, "inputHive", function hive() Hive(this.filters, "input"));
},
- has: function (key) Set.has(this.pass, key) || Set.has(this.commandHive.stack.mappings, key),
+ has: function (key) this.pass.has(key) || hasOwnProperty(this.commandHive.stack.mappings, key),
get pass() (this.flush(), this.pass),
let value = parse.superapply(this, arguments);
value.forEach(function (filter) {
let vals = Option.splitList(filter.result);
- filter.keys = DOM.Event.parse(vals[0]).map(DOM.Event.closure.stringify);
+ filter.keys = DOM.Event.parse(vals[0]).map(DOM.Event.bound.stringify);
- filter.commandKeys = vals.slice(1).map(DOM.Event.closure.canonicalKeys);
+ filter.commandKeys = vals.slice(1).map(DOM.Event.bound.canonicalKeys);
filter.inputKeys = filter.commandKeys.filter(bind("test", /^<[ACM]-/));
});
return value;
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
var HintSession = Class("HintSession", CommandMode, {
get extendedMode() modes.HINTS,
- init: function init(mode, opts = {}) {
+ init: function init(mode, opts={}) {
init.supercall(this);
if (!opts.window)
this.activeTimeout = null; // needed for hinttimeout > 0
this.continue = Boolean(opts.continue);
this.docs = [];
- this.hintKeys = DOM.Event.parse(options["hintkeys"]).map(DOM.Event.closure.stringify);
+ this.hintKeys = DOM.Event.parse(options["hintkeys"]).map(DOM.Event.bound.stringify);
this.hintNumber = 0;
this.hintString = opts.filter || "";
this.pageHints = [];
this.open();
this.top = opts.window || content;
- this.top.addEventListener("resize", this.closure._onResize, true);
- this.top.addEventListener("dactyl-commandupdate", this.closure._onResize, false, true);
+ this.top.addEventListener("resize", this.bound._onResize, true);
+ this.top.addEventListener("dactyl-commandupdate", this.bound._onResize, false, true);
this.generate();
if (hints.hintSession == this)
hints.hintSession = null;
if (this.top) {
- this.top.removeEventListener("resize", this.closure._onResize, true);
- this.top.removeEventListener("dactyl-commandupdate", this.closure._onResize, true);
+ this.top.removeEventListener("resize", this.bound._onResize, true);
+ this.top.removeEventListener("dactyl-commandupdate", this.bound._onResize, true);
}
this.removeHints(0);
return false;
let computedStyle = doc.defaultView.getComputedStyle(elem, null);
+ if (!computedStyle)
+ return false;
if (computedStyle.visibility != "visible" || computedStyle.display == "none")
return false;
return true;
__proto__: this.Hint
});
- for (let hint in values(_hints)) {
+ for (let hint of _hints) {
let { elem, rect } = hint;
if (elem.hasAttributeNS(NS, "hint"))
updateValidNumbers: function updateValidNumbers(always) {
let string = this.getHintString(this.hintNumber);
for (let hint in values(this.validHints))
- hint.valid = always || hint.span.getAttribute("number").indexOf(string) == 0;
+ hint.valid = always || hint.span.getAttribute("number").startsWith(string);
},
tab: function tab(previous) {
let appContent = document.getElementById("appcontent");
if (appContent)
- events.listen(appContent, "scroll", this.resizeTimer.closure.tell, false);
+ events.listen(appContent, "scroll", this.resizeTimer.bound.tell, false);
const Mode = Hints.Mode;
Mode.prototype.__defineGetter__("matcher", function ()
options.get("extendedhinttags").getKey(this.name, options.get("hinttags").matcher));
+ function cleanLoc(loc) {
+ try {
+ let uri = util.newURI(loc);
+ if (uri.scheme == "mailto" && !~uri.path.indexOf("?"))
+ return uri.path;
+ }
+ catch (e) {}
+ return loc;
+ }
+
this.modes = {};
- this.addMode(";", "Focus hint", buffer.closure.focusElement);
+ this.addMode(";", "Focus hint", buffer.bound.focusElement);
this.addMode("?", "Show information for hint", elem => buffer.showElementInfo(elem));
// TODO: allow for ! override to overwrite existing paths -- where? --djk
this.addMode("s", "Save hint", elem => buffer.saveLink(elem, false));
this.addMode("f", "Focus frame", elem => dactyl.focus(elem.ownerDocument.defaultView));
- this.addMode("F", "Focus frame or pseudo-frame", buffer.closure.focusElement, isScrollable);
+ this.addMode("F", "Focus frame or pseudo-frame", buffer.bound.focusElement, isScrollable);
this.addMode("o", "Follow hint", elem => buffer.followLink(elem, dactyl.CURRENT_TAB));
this.addMode("t", "Follow hint in a new tab", elem => buffer.followLink(elem, dactyl.NEW_TAB));
this.addMode("b", "Follow hint in a background tab", elem => buffer.followLink(elem, dactyl.NEW_BACKGROUND_TAB));
this.addMode("S", "Add a search keyword", elem => bookmarks.addSearchKeyword(elem));
this.addMode("v", "View hint source", (elem, loc) => buffer.viewSource(loc, false));
this.addMode("V", "View hint source in external editor", (elem, loc) => buffer.viewSource(loc, true));
- this.addMode("y", "Yank hint location", (elem, loc) => editor.setRegister(null, loc, true));
+ this.addMode("y", "Yank hint location", (elem, loc) => editor.setRegister(null, cleanLoc(loc), true));
this.addMode("Y", "Yank hint description", elem => editor.setRegister(null, elem.textContent || "", true));
this.addMode("A", "Yank hint anchor url", function (elem) {
let uri = elem.ownerDocument.documentURIObject.clone();
let indexOf = String.indexOf;
if (options.get("hintmatching").has("transliterated"))
- indexOf = Hints.closure.indexOf;
+ indexOf = Hints.bound.indexOf;
switch (options["hintmatching"][0]) {
case "contains" : return containsMatcher(hintString);
return null;
}, //}}}
- open: function open(mode, opts = {}) {
+ open: function open(mode, opts={}) {
this._extendedhintCount = opts.count;
mappings.pushCommand();
- commandline.input(["Normal", mode], null, {
+ commandline.input(["Normal", mode], {
autocomplete: false,
completer: function (context) {
context.compare = () => 0;
context.completions = [[k, v.prompt] for ([k, v] in Iterator(hints.modes))];
},
- onCancel: mappings.closure.popCommand,
+ onCancel: mappings.bound.popCommand,
onSubmit: function (arg) {
if (arg)
hints.show(arg, opts);
mappings.popCommand();
},
onChange: function (arg) {
- if (Object.keys(hints.modes).some(m => m != arg && m.indexOf(arg) == 0))
+ if (Object.keys(hints.modes).some(m => m != arg && m.startsWith(arg)))
return;
this.accepted = true;
},
{
keepQuotes: true,
+
getKey: function (val, default_)
- let (res = array.nth(this.value, re => let (match = re.exec(val)) match && match[0] == val, 0))
- res ? res.matcher : default_,
+ let (res = this.value.find(re => let (match = re.exec(val)) match && match[0] == val))
+ res ? res.matcher
+ : default_,
+
parse: function parse(val) {
let vals = parse.supercall(this, val);
for (let value in values(vals))
value.matcher = DOM.compileMatcher(Option.splitList(value.result));
return vals;
},
+
testValues: function testValues(vals, validator) vals.every(re => Option.splitList(re).every(validator)),
+
validator: DOM.validateMatcher
});
options.add(["hinttags", "ht"],
"XPath or CSS selector strings of hintable elements for Hints mode",
// Make sure to update the docs when you change this.
- "stringlist", ":-moz-any-link,area,button,iframe,input:not([type=hidden]),label[for],select,textarea," +
+ "stringlist", ":-moz-any-link,area,button,iframe,input:not([type=hidden]):not([disabled])," +
+ "label[for],select,textarea," +
"[onclick],[onmouseover],[onmousedown],[onmouseup],[oncommand]," +
"[tabindex],[role=link],[role=button],[contenteditable=true]",
{
"asdfg;lkjh": "Home Row"
},
validator: function (value) {
- let values = DOM.Event.parse(value).map(DOM.Event.closure.stringify);
+ let values = DOM.Event.parse(value).map(DOM.Event.bound.stringify);
return Option.validIf(array.uniq(values).length === values.length && values.length > 1,
_("option.hintkeys.duplicate"));
}
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
get service() services.history,
- get: function get(filter, maxItems, sort = this.SORT_DEFAULT) {
+ get: function get(filter, maxItems, sort=this.SORT_DEFAULT) {
if (isString(filter))
filter = { searchTerms: filter };
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
this.timer = services.Timer(this, options["timeoutlen"], services.Timer.TYPE_ONE_SHOT);
}
else if (result !== Events.KILL && !this.actions.length &&
- !(this.events[0].isReplay || this.passUnknown
- || this.modes.some(function (m) m.passEvent(this), this.events[0]))) {
+ !(this.events[0].isReplay || this.passUnknown ||
+ this.modes.some(function (m) m.passEvent(this), this.events[0]))) {
// No patching processors, this isn't a fake, pass-through
// event, we're not in pass-through mode, and we're not
// choosing to pass unknown keys. Kill the event and beep.
let list = this.events.filter(e => e.defaultPrevented && !e.dactylDefaultPrevented);
if (result === Events.PASS)
- events.dbg("PASS THROUGH: " + list.slice(0, length).filter(e => e.type === "keypress").map(DOM.Event.closure.stringify));
+ events.dbg("PASS THROUGH: " + list.slice(0, length).filter(e => e.type === "keypress").map(DOM.Event.bound.stringify));
if (list.length > length)
- events.dbg("REFEED: " + list.slice(length).filter(e => e.type === "keypress").map(DOM.Event.closure.stringify));
+ events.dbg("REFEED: " + list.slice(length).filter(e => e.type === "keypress").map(DOM.Event.bound.stringify));
if (result === Events.PASS)
events.feedevents(null, list.slice(0, length), { skipmap: true, isMacro: true, isReplay: true });
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
Object.freeze(this.modes);
if (info) {
- if (Set.has(Map.types, info.type))
+ if (hasOwnProperty(Map.types, info.type))
this.update(Map.types[info.type]);
this.update(info);
}
*/
hasName: function (name) this.keys.indexOf(name) >= 0,
- get keys() array.flatten(this.names.map(mappings.closure.expand)),
+ get keys() array.flatten(this.names.map(mappings.bound.expand)),
/**
* Execute the action for this mapping.
* @param {[Modes.Mode]} modes The modes for which to return mappings.
*/
iterate: function (modes) {
- let stacks = Array.concat(modes).map(this.closure.getStack);
+ let stacks = Array.concat(modes).map(this.bound.getStack);
return values(stacks.shift().sort((m1, m2) => String.localeCompare(m1.name, m2.name))
.filter((map) => map.rhs &&
stacks.every(stack => stack.some(m => m.rhs && m.rhs === map.rhs && m.name === map.name))));
* @param {Object} extra An optional extra configuration hash.
* @optional
*/
- add: function (modes, keys, description, action, extra = {}) {
+ add: function (modes, keys, description, action, extra={}) {
modes = Array.concat(modes);
if (!modes.every(util.identity))
throw TypeError(/*L*/"Invalid modes: " + modes);
},
iterate: function (mode) {
- let seen = {};
+ let seen = RealSet();
for (let hive in this.hives.iterValues())
for (let map in array(hive.getStack(mode)).iterValues())
- if (!Set.add(seen, map.name))
+ if (!seen.add(map.name))
yield map;
},
}
};
function userMappings(hive) {
- let seen = {};
+ let seen = RealSet();
for (let stack in values(hive.stacks))
for (let map in array.iterValues(stack))
- if (!Set.add(seen, map.id))
+ if (!seen.add(map.id))
yield map;
}
function uniqueModes(modes) {
let chars = [k for ([k, v] in Iterator(modules.modes.modeChars))
if (v.every(mode => modes.indexOf(mode) >= 0))];
+
return array.uniq(modes.filter(m => chars.indexOf(m.char) < 0)
.map(m => m.name.toLowerCase())
.concat(chars));
if (!mainOnly)
modes = modes[0].allBases;
- let seen = {};
+ let seen = RealSet();
// Bloody hell. --Kris
for (let [i, mode] in Iterator(modes))
for (let hive in mappings.hives.iterValues())
for (let map in array.iterValues(hive.getStack(mode)))
for (let name in values(map.names))
- if (!Set.add(seen, name)) {
+ if (!seen.add(name))
yield {
name: name,
columns: [
],
__proto__: map
};
- }
},
format: {
description: function (map) [
name: [mode.char + "listk[eys]", mode.char + "lk"],
iterateIndex: function (args)
let (self = this, prefix = /^[bCmn]$/.test(mode.char) ? "" : mode.char + "_",
- haveTag = Set.has(help.tags))
+ haveTag = k => hasOwnProperty(help.tags, k))
({ helpTag: prefix + map.name, __proto__: map }
for (map in self.iterate(args, true))
if (map.hive === mappings.builtin || haveTag(prefix + map.name))),
});
},
completion: function initCompletion(dactyl, modules, window) {
- completion.userMapping = function userMapping(context, modes_ = [modes.NORMAL], hive = mappings.user) {
+ completion.userMapping = function userMapping(context, modes_=[modes.NORMAL], hive=mappings.user) {
context.keys = { text: function (m) m.names[0],
description: function (m) m.description + ": " + m.action };
context.completions = hive.iterate(modes_);
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
get localURI() buffer.focusedFrame.document.documentURI.replace(/#.*/, ""),
- Mark: function Mark(params = {}) {
+ Mark: function Mark(params={}) {
let win = buffer.focusedFrame;
let doc = win.document;
let mark = this.Mark();
if (Marks.isURLMark(name)) {
- mark.tab = util.weakReference(tabs.getTab());
+ // FIXME: Disabled due to cross-compartment magic.
+ // mark.tab = util.weakReference(tabs.getTab());
this._urlMarks.set(name, mark);
var message = "mark.addURL";
}
events: function () {
let appContent = document.getElementById("appcontent");
if (appContent)
- events.listen(appContent, "load", marks.closure._onPageLoad, true);
+ events.listen(appContent, "load", marks.bound._onPageLoad, true);
},
mappings: function () {
var myModes = config.browserModes;
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
this._recording = false;
this._replaying = false; // playing a macro
- this._modeStack = update([], {
- pop: function pop() {
- if (this.length <= 1)
- throw Error("Trying to pop last element in mode stack");
- return pop.superapply(this, arguments);
- }
- });
+ this._modeStack = Modes.ModeStack([]);
this._modes = [];
this._mainModes = [];
// show the current mode string in the command line
show: function show() {
- if (!loaded.modes)
+ if (!loaded.has("modes"))
return;
let msg = this._getModeMessage();
- if (msg || loaded.commandline)
+ if (msg || loaded.has("commandline"))
commandline.widgets.mode = msg || null;
},
remove: function remove(mode, covert) {
if (covert && this.topOfStack.main != mode) {
util.assert(mode != this.NORMAL);
- for (let m; m = array.nth(this.modeStack, m => m.main == mode, 0);)
- this._modeStack.splice(this._modeStack.indexOf(m));
+
+ this._modeStack = Modes.ModeStack(
+ this._modeStack.filter(m => m.main != mode));
}
else if (this.stack.some(m => m.main == mode)) {
this.pop(mode);
{ push: push }, push);
for (let [id, { obj, prop, test }] in Iterator(this.boundProperties)) {
- if (!obj.get())
+ obj = obj.get();
+ if (!obj)
delete this.boundProperties[id];
else
- this.topOfStack.saved[id] = { obj: obj.get(), prop: prop, value: obj.get()[prop], test: test };
+ this.topOfStack.saved[id] = { obj: obj, prop: prop, value: obj[prop], test: test };
}
}
this.allBases.indexOf(obj) >= 0 || callable(obj) && this instanceof obj,
allBases: Class.Memoize(function () {
- let seen = {}, res = [], queue = [this].concat(this.bases);
+ let seen = RealSet(),
+ res = [],
+ queue = [this].concat(this.bases);
for (let mode in array.iterValues(queue))
- if (!Set.add(seen, mode)) {
+ if (!seen.add(mode)) {
res.push(mode);
queue.push.apply(queue, mode.bases);
}
}, {
_id: 0
}),
+ ModeStack: function ModeStack(array)
+ update(array, {
+ pop: function pop() {
+ if (this.length <= 1)
+ throw Error("Trying to pop last element in mode stack");
+ return pop.superapply(this, arguments);
+ }
+ }),
StackElement: (function () {
const StackElement = Struct("main", "extended", "params", "saved");
StackElement.className = "Modes.StackElement";
StackElement.defaultValue("params", function () this.main.params);
update(StackElement.prototype, {
- get toStringParams() !loaded.modes ? this.main.name : [
+ get toStringParams() !loaded.has("modes") ? [this.main.name] : [
this.main.name,
["(", modes.all.filter(m => this.extended & m)
.map(m => m.name)
return StackElement;
})(),
cacheId: 0,
- boundProperty: function BoundProperty(desc = {}) {
+ boundProperty: function BoundProperty(desc={}) {
let id = this.cacheId++;
let value;
return rec(roots);
}
- cache.register("modes.dtd", () =>
- util.makeDTD(iter({ "modes.tree": makeTree() },
- config.dtd)));
+ cache.register("modes.dtd",
+ () => util.makeDTD(iter({ "modes.tree": makeTree() },
+ config.dtd)),
+ true);
},
mappings: function initMappings() {
mappings.add([modes.BASE, modes.NORMAL],
getKey: function getKey(val, default_) {
if (isArray(val))
- return (array.nth(this.value, v => val.some(m => m.name === v.mode), 0)
+ return (this.value.find(v => val.some(m => m.name === v.mode))
|| { result: default_ }).result;
- return Set.has(this.valueMap, val) ? this.valueMap[val] : default_;
+ return hasOwnProperty(this.valueMap, val) ? this.valueMap[val] : default_;
},
setter: function (vals) {
},
validator: function validator(vals) vals.map(v => v.replace(/^!/, ""))
- .every(Set.has(this.values)),
+ .every(k => hasOwnProperty(this.values, k)),
- get values() array.toObject([[m.name.toLowerCase(), m.description] for (m in values(modes._modes)) if (!m.hidden)])
+ get values() array.toObject([[m.name.toLowerCase(), m.description]
+ for (m in values(modes._modes)) if (!m.hidden)])
};
options.add(["passunknown", "pu"],
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
if (modes.main != modes.OUTPUT_MULTILINE) {
modes.push(modes.OUTPUT_MULTILINE, null, {
- onKeyPress: this.closure.onKeyPress,
+ onKeyPress: this.bound.onKeyPress,
- leave: this.closure(function leave(stack) {
+ leave: stack => {
if (stack.pop)
for (let message in values(this.messages))
if (message.leave)
message.leave(stack);
- }),
+ },
window: this.window
});
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
init: function init() {
this._statusLine = document.getElementById("status-bar");
this.statusBar = document.getElementById("addon-bar") || this._statusLine;
+
this.baseGroup = this.statusBar == this._statusLine ? "StatusLine " : "";
+ if (this.statusBar.localName == "toolbar" &&
+ this.statusBar.parentNode.id != "browser-bottombox")
+ overlay.overlayWindow(window, {
+ objects: this,
+ append: [
+ ["vbox", { id: "browser-bottombox", xmlns: "xul" },
+ ["toolbar", { id: "dactyl-addon-bar",
+ customizable: true,
+ defaultset: "",
+ toolboxid: "navigator-toolbox",
+ toolbarname: /*L*/ "Add-on Bar",
+ class: "toolbar-primary chromeclass-toolbar",
+ mode: "icons",
+ iconsize: "small", defaulticonsize: "small",
+ key: "statusBar" },
+ ["statusbar", { id: "dactyl-status-bar", key: "_statusLine" }]]]
+ ]
+ });
+
if (config.haveGecko("25"))
config.tabbrowser.getStatusPanel().hidden = true;
if (this.statusBar.localName == "toolbar") {
styles.system.add("addon-bar", config.styleableChrome, literal(/*
- #status-bar { margin-top: 0 !important; }
- #addon-bar > statusbar { -moz-box-flex: 1 }
+ #status-bar, #dactyl-status-bar { margin-top: 0 !important; }
+ #dactyl-status-bar { min-height: 0 !important; }
+ :-moz-any(#addon-bar, #dactyl-addon-bar) > statusbar { -moz-box-flex: 1 }
+ :-moz-any(#addon-bar, #dactyl-addon-bar) > xul|toolbarspring { visibility: collapse; }
#addon-bar > #addonbar-closebutton { visibility: collapse; }
- #addon-bar > xul|toolbarspring { visibility: collapse; }
*/));
overlay.overlayWindow(window, {
append: [
- ["statusbar", { id: "status-bar", ordinal: "0" }]]
+ ["statusbar", { id: this._statusLine.id, ordinal: "0" }]]
});
highlight.loadCSS(util.compileMacro(literal(/*
- !AddonBar;#addon-bar {
+ !AddonBar;#addon-bar,#dactyl-addon-bar {
padding-left: 0 !important;
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
min-height: 18px !important;
-moz-appearance: none !important;
<padding>
}
- !AddonButton;#addon-bar xul|toolbarbutton {
+ !AddonButton;,:-moz-any(#addon-bar, #dactyl-addon-bar) xul|toolbarbutton {
-moz-appearance: none !important;
padding: 0 !important;
border-width: 0px !important;
let prepend = [
["button", { id: "appmenu-button", label: "", image: "chrome://branding/content/icon16.png", highlight: "AppmenuButton", xmlns: "xul" }],
["toolbarbutton", { id: "appmenu-toolbar-button", label: "", image: "chrome://branding/content/icon16.png" }],
- ["statusbar", { id: "status-bar", highlight: "StatusLine", xmlns: "xul" },
+ ["statusbar", { id: this._statusLine.id, highlight: "StatusLine", xmlns: "xul" },
// <!-- insertbefore="dactyl.statusBefore;" insertafter="dactyl.statusAfter;" -->
["hbox", { key: "container", hidden: "false", align: "center", flex: "1" },
["stack", { orient: "horizontal", align: "stretch", flex: "1", highlight: "CmdLine StatusCmdLine", class: "dactyl-container" },
catch (e) {}
},
+ cleanup: function cleanup(reason) {
+ if (reason != "unload" && "CustomizableUI" in window)
+ CustomizableUI.unregisterArea(this.statusBar.id, false);
+ },
+
get visible() !this.statusBar.collapsed && !this.statusBar.hidden,
signals: {
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
config.tabStrip.collapsed = true;
this.tabStyle = styles.system.add("tab-strip-hiding", config.styleableChrome,
- (config.tabStrip.id ? "#" + config.tabStrip.id : ".tabbrowser-strip") +
+ (config.tabStrip.id ? "#" + config.tabStrip.id
+ : ".tabbrowser-strip") +
"{ visibility: collapse; }",
false, true);
updateTabCount: function updateTabCount() {
for (let [i, tab] in Iterator(this.visibleTabs)) {
- if (dactyl.has("Gecko2")) {
- let node = function node(class_) document.getAnonymousElementByAttribute(tab, "class", class_);
- if (!node("dactyl-tab-number")) {
- let img = node("tab-icon-image");
- if (img) {
- let dom = DOM([
- ["xul:hbox", { highlight: "tab-number" },
- ["xul:label", { key: "icon", align: "center", highlight: "TabIconNumber",
- class: "dactyl-tab-icon-number" }]],
- ["xul:hbox", { highlight: "tab-number" },
- ["html:div", { key: "label", highlight: "TabNumber",
- class: "dactyl-tab-number" }]]],
- document).appendTo(img.parentNode);
-
- update(tab, {
- get dactylOrdinal() Number(dom.nodes.icon.value),
- set dactylOrdinal(i) {
- dom.nodes.icon.value = dom.nodes.label.textContent = i;
- this.setAttribute("dactylOrdinal", i);
- }
- });
- }
+ let node = function node(class_) document.getAnonymousElementByAttribute(tab, "class", class_);
+ if (!node("dactyl-tab-number")) {
+ let img = node("tab-icon-image");
+ if (img) {
+ let dom = DOM([
+ ["xul:hbox", { highlight: "tab-number" },
+ ["xul:label", { key: "icon", align: "center", highlight: "TabIconNumber",
+ class: "dactyl-tab-icon-number" }]],
+ ["xul:hbox", { highlight: "tab-number" },
+ ["html:div", { key: "label", highlight: "TabNumber",
+ class: "dactyl-tab-number" }]]],
+ document).appendTo(img.parentNode);
+
+ update(tab, {
+ get dactylOrdinal() Number(dom.nodes.icon.value),
+ set dactylOrdinal(i) {
+ dom.nodes.icon.value = dom.nodes.label.textContent = i;
+ this.setAttribute("dactylOrdinal", i);
+ }
+ });
}
}
tab.dactylOrdinal = i + 1;
* @param {number} count How many tabs to remove.
* @param {boolean} focusLeftTab Focus the tab to the left of the removed tab.
*/
- remove: function remove(tab, count = 1, focusLeftTab = false) {
+ remove: function remove(tab, count=1, focusLeftTab=false) {
let res = this.count > count;
let tabs = this.visibleTabs;
if (focusLeftTab)
tabs.slice(Math.max(0, index + 1 - count),
index + 1)
- .forEach(config.closure.removeTab);
+ .forEach(config.bound.removeTab);
else
tabs.slice(index,
index + count)
- .forEach(config.closure.removeTab);
+ .forEach(config.bound.removeTab);
return res;
},
if (matches)
return tabs.select(this.allTabs[parseInt(matches[1], 10) - 1], false);
- matches = array.nth(tabs.allTabs, t => (t.linkedBrowser.lastURI || {}).spec === buffer, 0);
+ matches = tabs.allTabs.find(t => (t.linkedBrowser.lastURI || {}).spec === buffer);
if (matches)
return tabs.select(matches, false);
tabs.getGroups();
tabs[visible ? "visibleTabs" : "allTabs"].forEach(function (tab, i) {
let group = (tab.tabItem || tab._tabViewTabItem || defItem).parent || defItem.parent;
- if (!Set.has(tabGroups, group.id))
+ if (!hasOwnProperty(tabGroups, group.id))
tabGroups[group.id] = [group.getTitle(), []];
group = tabGroups[group.id];
}
for (let event in values(["TabMove", "TabOpen", "TabClose"]))
events.listen(tabContainer, event, callback, false);
- events.listen(tabContainer, "TabSelect", tabs.closure._onTabSelect, false);
+ events.listen(tabContainer, "TabSelect", tabs.bound._onTabSelect, false);
},
mappings: function initMappings() {
tabs.tabStyle.enabled = false;
}
- if (value !== "multitab" || !dactyl.has("Gecko2"))
+ if (value !== "multitab")
if (tabs.xulTabs)
tabs.xulTabs.visible = value !== "never";
else
values: activateGroups,
has: Option.has.toggleAll,
setter: function (newValues) {
- let valueSet = Set(newValues);
+ let valueSet = RealSet(newValues);
for (let group in values(activateGroups))
if (group[2])
prefs.safeSet("browser.tabs." + group[2],
- !(valueSet["all"] ^ valueSet[group[0]]),
+ !(valueSet.has("all") ^ valueSet.has(group[0])),
_("option.safeSet", "activate"));
return newValues;
}
download.almostDone = ~1 second
download.unknown = Unknown
-download.action.Cancel = Cancel
download.action.Clear = Clear
download.action.Delete = Delete
-download.action.Pause = Pause
+download.action.Stop = Stop
download.action.Remove = Remove
download.action.Resume = Resume
-download.action.Retry = Retry
editor.prompt.editPassword = Editing a password field externally will reveal the password. Would you like to continue? (yes/[no]):
<dt>time</dt> <dd>Time remaining</dd>
<dt>url</dt> <dd>Source URL</dd>
</dl>
+ <note>
+ This option is currently unavailable in &dactyl.host; 26 and greater.
+ </note>
</description>
</item>
<spec>:ha<oa>rdcopy</oa><oa>!</oa> ><a>filename</a></spec>
<description>
<p>As above, but write the output to <a>filename</a>.</p>
-
- <note>Not available on Windows.</note>
</description>
</item>
<item>
<tags><record-macro> q</tags>
<strut/>
- <spec>q<a>0-9a-zA-Z</a></spec>
+ <spec>q<a>a-zA-Z</a></spec>
<description>
<p>
Record a key sequence as a macro. Available macros are
- <a>0-9a-zA-Z</a>. If the macro is an uppercase letter, the
+ <a>a-zA-Z</a>. If the macro is an uppercase letter, the
recorded keys are appended to the lowercase macro of the same
name. Typing <k>q</k> again stops the recording.
</p>
<item>
<tags><play-macro> @</tags>
- <spec><oa>count</oa>@<a>a-z0-9</a></spec>
+ <spec><oa>count</oa>@<a>a-z</a></spec>
<description>
<p>
- Plays the contents of macro with name <a>a-z0-9</a> <oa>count</oa>
+ Plays the contents of macro with name <a>a-z</a> <oa>count</oa>
times.
</p>
</description>
-// Copyright (c) 2009-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2009-2014 Kris Maglione <maglione.k@gmail.com>
// Copyright (c) 2009-2010 by Doug Kearns <dougkearns@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
name: "extr[ehash]",
description: "Reload an extension",
action: function (addon) {
- util.assert(config.haveGecko("2b"), _("command.notUseful", config.host));
util.flushCache();
util.timeout(function () {
addon.userDisabled = true;
},
commandAllowed: function commandAllowed(cmd) {
- util.assert(Set.has(actions, cmd), _("addon.unknownCommand"));
+ util.assert(hasOwnProperty(actions, cmd),
+ _("addon.unknownCommand"));
let action = actions[cmd];
if ("perm" in action && !(this.permissions & AddonManager["PERM_CAN_" + action.perm.toUpperCase()]))
this.modules = modules;
this.filter = filter && filter.toLowerCase();
this.nodes = {};
- this.addons = [];
+ this.addons = {};
this.ready = false;
- AddonManager.getAddonsByTypes(types, this.closure(function (addons) {
+ AddonManager.getAddonsByTypes(types, addons => {
this._addons = addons;
if (this.document)
this._init();
- }));
+ });
AddonManager.addAddonListener(this);
},
cleanup: function cleanup() {
},
_init: function _init() {
- this._addons.forEach(this.closure.addAddon);
+ this._addons.forEach(this.bound.addAddon);
this.ready = true;
this.update();
},
-// Copyright (c) 2009-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2009-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
+var Cs = new Proxy(Components.stack, {
+ get: function Cs_get(target, prop) Components.stack.caller[prop]
+});
+
+function module(url) {
+ let obj = {};
+ Cu.import(url, obj);
+ return obj;
+}
+
+var { XPCOMUtils } = module("resource://gre/modules/XPCOMUtils.jsm");
try {
- var ctypes;
- Cu.import("resource://gre/modules/ctypes.jsm");
+ var ctypes = module("resource://gre/modules/ctypes.jsm");
}
catch (e) {}
let { __lookupGetter__, __lookupSetter__, __defineGetter__, __defineSetter__,
hasOwnProperty, propertyIsEnumerable } = objproto;
-if (typeof XPCSafeJSObjectWrapper === "undefined")
- this.XPCSafeJSObjectWrapper = XPCNativeWrapper;
+hasOwnProperty = Function.call.bind(hasOwnProperty);
+propertyIsEnumerable = Function.call.bind(propertyIsEnumerable);
-let getGlobalForObject = Cu.getGlobalForObject || (obj => obj.__parent__);
+// Gecko 24.
+if (!("find" in Array.prototype))
+ Object.defineProperty(Array.prototype, "find", {
+ configurable: true,
+ writable: true,
+ value: function Array_find(pred, self) {
+ for (let [i, elem] in Iterator(this))
+ if (pred.call(self, elem, i, this))
+ return elem;
+ }
+ });
-function require(module, target) JSMLoader.load(module, target);
+if (!("findIndex" in Array.prototype))
+ Object.defineProperty(Array.prototype, "findIndex", {
+ configurable: true,
+ writable: true,
+ value: function Array_findIndex(pred, self) {
+ for (let [i, elem] in Iterator(this))
+ if (pred.call(self, elem, i, this))
+ return i;
+ return -1;
+ }
+ });
+
+function require(module_, target) {
+ if (/^[A-Za-z0-9]+:/.test(module_))
+ return module(module_);
+ return JSMLoader.load(module_, target);
+}
function lazyRequire(module, names, target) {
- for each (let name in names)
+ for (let name of names)
memoize(target || this, name, name => require(module)[name]);
}
defineModule("base", {
// sed -n 's/^(const|var|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt
exports: [
- "ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Finished", "Module", "JSMLoader",
- "Set", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMShim", "XPCOMUtils",
- "XPCSafeJSObjectWrapper", "array", "bind", "call", "callable", "ctypes", "curry",
- "debuggerProperties", "defineModule", "deprecated", "endModule", "forEach", "isArray",
- "isGenerator", "isinstance", "isObject", "isString", "isSubclass", "isXML", "iter",
- "iterAll", "iterOwnProperties", "keys", "literal", "memoize", "octal", "properties",
- "require", "set", "update", "values", "update_"
+ "Cc",
+ "Ci",
+ "Class",
+ "Cr",
+ "Cs",
+ "Cu",
+ "ErrorBase",
+ "Finished",
+ "JSMLoader",
+ "Module",
+ "RealSet",
+ "Set",
+ "Struct",
+ "StructBase",
+ "Timer",
+ "UTF8",
+ "XPCOM",
+ "XPCOMShim",
+ "XPCOMUtils",
+ "array",
+ "bind",
+ "call",
+ "callable",
+ "ctypes",
+ "curry",
+ "defineModule",
+ "deprecated",
+ "endModule",
+ "forEach",
+ "hasOwnProperty",
+ "isArray",
+ "isGenerator",
+ "isObject",
+ "isString",
+ "isSubclass",
+ "isinstance",
+ "iter",
+ "iterAll",
+ "iterOwnProperties",
+ "keys",
+ "literal",
+ "memoize",
+ "modujle",
+ "octal",
+ "properties",
+ "require",
+ "set",
+ "update",
+ "values",
]
});
this.lazyRequire("cache", ["cache"]);
this.lazyRequire("config", ["config"]);
this.lazyRequire("messages", ["_", "Messages"]);
+this.lazyRequire("promises", ["Task", "promises"]);
this.lazyRequire("services", ["services"]);
this.lazyRequire("storage", ["File"]);
this.lazyRequire("util", ["FailedAssertion", "util"]);
+literal.files = {};
+literal.locations = {};
function literal(/* comment */) {
let { caller } = Components.stack;
while (caller && caller.language != 2)
caller = caller.caller;
let file = caller.filename.replace(/.* -> /, "");
- let key = "literal:" + file + ":" + caller.line;
-
- let source = File.readURL(file);
-
- let match = RegExp("(?:.*\\n){" + (caller.lineNumber - 1) + "}" +
- ".*literal\\(/\\*([^]*?)\\*/\\)").exec(source);
- return match[1];
-
- // Later...
- return cache.get(key, function () {
- let source = cache.get("literal:" + file,
- () => util.httpGet(file).responseText);
+ let key = "literal:" + file + ":" + caller.lineNumber;
+ return cache.get(key, function() {
+ let source = literal.files[file] || File.readURL(file);
+ literal.files[file] = source;
let match = RegExp("(?:.*\\n){" + (caller.lineNumber - 1) + "}" +
".*literal\\(/\\*([^]*?)\\*/\\)").exec(source);
});
}
-/**
- * Returns a list of all of the top-level properties of an object, by
- * way of the debugger.
- *
- * @param {object} obj
- * @returns [jsdIProperty]
- */
-function debuggerProperties(obj) {
- if (loaded.services && services.debugger.isOn) {
- let res = {};
- services.debugger.wrapValue(obj).getProperties(res, {});
- return res.value;
- }
-}
-
/**
* Iterates over the names of all of the top-level properties of an
* object or, if prototypes is given, all of the properties in the
- * prototype chain below the top. Uses the debugger if possible.
+ * prototype chain below the top.
*
* @param {object} obj The object to inspect.
* @param {boolean} properties Whether to inspect the prototype chain
XPCNativeWrapper.unwrap(obj).__proto__ ||
Object.getPrototypeOf(XPCNativeWrapper.unwrap(obj));
-function properties(obj, prototypes, debugger_) {
+function properties(obj, prototypes) {
let orig = obj;
- let seen = { dactylPropertyNames: true };
+ let seen = RealSet(["dactylPropertyNames"]);
try {
if ("dactylPropertyNames" in obj && !prototypes)
for (let key in values(obj.dactylPropertyNames))
- if (key in obj && !Set.add(seen, key))
+ if (key in obj && !seen.add(key))
yield key;
}
catch (e) {}
}
for (; obj; obj = prototypes && prototype(obj)) {
- try {
- if (!debugger_ || !services.debugger.isOn)
- var iter = (v for each (v in props(obj)));
- }
- catch (e) {}
- if (!iter)
- iter = (prop.name.stringValue for (prop in values(debuggerProperties(obj))));
-
- for (let key in iter)
- if (!prototypes || !Set.add(seen, key) && obj != orig)
+ for (let key of props(obj))
+ if (!prototypes || !seen.add(key) && obj != orig)
yield key;
}
}
function deprecated(alternative, fn) {
if (isObject(fn))
- return Class.Property(iter(fn).map(([k, v]) => [k, callable(v) ? deprecated(alternative, v) : v])
+ return Class.Property(iter(fn).map(([k, v]) => [k,
+ callable(v) ? deprecated(alternative, v)
+ : v])
.toObject());
- let name, func = callable(fn) ? fn : function () this[fn].apply(this, arguments);
+ let name,
+ func = callable(fn) ? fn
+ : function () this[fn].apply(this, arguments);
function deprecatedMethod() {
let obj = !this ? "" :
this.constructor.className ? this.constructor.className + "#" :
"";
- deprecated.warn(func, obj + (fn.name || name), alternative);
+ deprecated.warn(func,
+ obj + (fn.realName || fn.name || name || "").replace(/__/g, "."),
+ alternative);
return func.apply(this, arguments);
}
+ if (func.name)
+ deprecatedMethod.realName = func.name;
return callable(fn) ? deprecatedMethod : Class.Property({
get: function () deprecatedMethod,
}
deprecated.warn = function warn(func, name, alternative, frame) {
if (!func.seenCaller)
- func.seenCaller = Set([
+ func.seenCaller = RealSet([
"resource://dactyl/javascript.jsm",
"resource://dactyl/util.jsm"
]);
+ if (!(loaded.util && util && loaded.config && config.protocolLoaded)) {
+ dump("DACTYL: deprecated method called too early [" + [name, alternative] + "]:\n" + Error().stack + "\n\n");
+ return;
+ }
+
frame = frame || Components.stack.caller.caller;
+
let filename = util.fixURI(frame.filename || "unknown");
- if (!Set.add(func.seenCaller, filename))
+ if (!func.seenCaller.add(filename))
util.dactyl(func).warn([util.urlPath(filename), frame.lineNumber, " "].join(":")
+ _("warn.deprecated", name, alternative));
}
* @returns {Generator}
*/
function keys(obj) iter(function keys() {
- for (var k in obj)
- if (hasOwnProperty.call(obj, k))
+ if (isinstance(obj, ["Map"]))
+ for (let [k, v] of obj)
yield k;
+ else
+ for (var k in obj)
+ if (hasOwnProperty(obj, k))
+ yield k;
}());
/**
* @returns {Generator}
*/
function values(obj) iter(function values() {
- if (isinstance(obj, ["Generator", "Iterator", Iter]))
+ if (isinstance(obj, ["Map"]))
+ for (let [k, v] of obj)
+ yield v;
+ else if (isinstance(obj, ["Generator", "Iterator", Iter]))
for (let k in obj)
yield k;
+ else if (iter.iteratorProp in obj)
+ for (let v of obj)
+ yield v;
else
for (var k in obj)
- if (hasOwnProperty.call(obj, k))
+ if (hasOwnProperty(obj, k))
yield obj[k];
}());
var forEach = deprecated("iter.forEach", function forEach() iter.forEach.apply(iter, arguments));
var iterAll = deprecated("iter", function iterAll() iter.apply(null, arguments));
+var RealSet = Set;
+let Set_add = RealSet.prototype.add;
+RealSet.prototype.add = function RealSet_add(val) {
+ let res = this.has(val);
+ Set_add.apply(this, arguments);
+ return res;
+};
+
+RealSet.prototype.difference = function RealSet_difference(set) {
+ return RealSet(i for (i of this) if (!set.has(i)));
+};
+
+RealSet.prototype.intersection = function RealSet_intersection(set) {
+ return RealSet(i for (i of this) if (set.has(i)));
+};
+
+RealSet.prototype.union = function RealSet_union(set) {
+ let res = RealSet(this);
+ for (let item of set)
+ res.add(item);
+ return res;
+};
+
/**
* Utility for managing sets of strings. Given an array, returns an
* object with one key for each value thereof.
* @param {[string]} ary @optional
* @returns {object}
*/
-function Set(ary) {
+this.Set = deprecated("RealSet", function Set(ary) {
let obj = {};
if (ary)
for (let val in values(ary))
obj[val] = true;
return obj;
-}
+});
/**
* Adds an element to a set and returns true if the element was
* previously contained.
* @param {string} key The key to add.
* @returns boolean
*/
-Set.add = curry(function set_add(set, key) {
- let res = this.has(set, key);
- set[key] = true;
- return res;
-});
+Set.add = deprecated("RealSet#add",
+ curry(function Set__add(set, key) {
+ if (isinstance(set, ["Set"])) {
+ let res = set.has(key);
+ set.add(key);
+ return res;
+ }
+
+ let res = this.has(set, key);
+ set[key] = true;
+ return res;
+ }));
/**
* Returns true if the given set contains the given key.
*
* @param {string} key The key to check.
* @returns {boolean}
*/
-Set.has = curry(function set_has(set, key) hasOwnProperty.call(set, key) &&
- propertyIsEnumerable.call(set, key));
+Set.has = deprecated("hasOwnProperty or Set#has",
+ curry(function Set__has(set, key) {
+ if (isinstance(set, ["Set"]))
+ return set.has(key);
+
+ return hasOwnProperty(set, key) &&
+ propertyIsEnumerable(set, key);
+ }));
/**
* Returns a new set containing the members of the first argument which
* do not exist in any of the other given arguments.
* @param {object} set The set.
* @returns {object}
*/
-Set.subtract = function set_subtract(set) {
- set = update({}, set);
- for (let i = 1; i < arguments.length; i++)
- for (let k in keys(arguments[i]))
- delete set[k];
- return set;
-};
+Set.subtract = deprecated("RealSet#difference",
+ function set_subtract(set) {
+ set = update({}, set);
+ for (let i = 1; i < arguments.length; i++)
+ for (let k in keys(arguments[i]))
+ delete set[k];
+ return set;
+ });
+
/**
* Removes an element from a set and returns true if the element was
* previously contained.
* @param {string} key The key to remove.
* @returns boolean
*/
-Set.remove = curry(function set_remove(set, key) {
- let res = set.has(set, key);
- delete set[key];
- return res;
-});
+Set.remove = deprecated("RealSet#delete",
+ curry(function Set__remove(set, key) {
+ if (isinstance(set, ["Set"]))
+ return set.delete(key);
+
+ let res = set.has(set, key);
+ delete set[key];
+ return res;
+ }));
function set() {
deprecated.warn(set, "set", "Set");
if (acc == null)
acc = [];
- return function curried(...args) {
+ function curried(...args) {
// The curried result should preserve 'this'
if (args.length == 0)
return close(self || this, curried);
return curry(fn, length, self || this, args);
};
+ curried.realName = fn.realName || fn.name;
+ return curried;
}
-if (curry.bind)
- var bind = function bind(meth, self, ...args) let (func = callable(meth) ? meth : self[meth])
+var bind = function bind(meth, self, ...args)
+ let (func = callable(meth) ? meth : self[meth])
func.bind.apply(func, [self].concat(args));
-else
- var bind = function bind(func, self, ...args) {
- if (!callable(func))
- func = self[func];
-
- return function bound(...args2) func.apply(self, args.concat(args2));
- };
/**
* Returns true if both arguments are functions and
*/
function isObject(obj) typeof obj === "object" && obj != null || obj instanceof Ci.nsISupports;
-/**
- * Returns true if obje is an E4X XML object.
- * @deprecated
- */
-function isXML(obj) typeof obj === "xml";
-
/**
* Returns true if and only if its sole argument is an
* instance of the builtin Array type. The array may come from
* is not the case when using (obj instanceof Array).
*/
var isArray =
- Array.isArray
- // This is bloody stupid.
- ? function isArray(val) Array.isArray(val) || val && val.constructor && val.constructor.name === "Array"
- : function isArray(val) objproto.toString.call(val) == "[object Array]";
+ // This is bloody stupid.
+ function isArray(val) Array.isArray(val) || val && val.constructor && val.constructor.name === "Array";
/**
* Returns true if and only if its sole argument is an
function memoize(obj, key, getter) {
if (arguments.length == 1) {
let res = update(Object.create(obj), obj);
- for each (let prop in Object.getOwnPropertyNames(obj)) {
+ for (let prop of Object.getOwnPropertyNames(obj)) {
let get = __lookupGetter__.call(obj, prop);
if (get)
memoize(res, prop, get);
}
return target;
}
-function update_(target) {
- for (let i = 1; i < arguments.length; i++) {
- let src = arguments[i];
- Object.getOwnPropertyNames(src || {}).forEach(function (k) {
- let desc = Object.getOwnPropertyDescriptor(src, k);
- if (desc.value instanceof Class.Property)
- desc = desc.value.init(k, target) || desc.value;
-
- try {
- if (typeof desc.value === "function" && target.__proto__ && !(desc.value instanceof Ci.nsIDOMElement /* wtf? */)) {
- let func = desc.value.wrapped || desc.value;
- if (!func.superapply) {
- func.__defineGetter__("super", function get_super_() Object.getPrototypeOf(target)[k]);
- func.superapply = function super_apply(self, args)
- let (meth = Object.getPrototypeOf(target)[k])
- meth && meth.apply(self, args);
- func.supercall = function super_call(self, ...args)
- func.superapply(self, args);
- }
- }
- Object.defineProperty(target, k, desc);
- }
- catch (e) {}
- });
- }
- return target;
-}
/**
* @constructor Class
if (callable(args[0]))
superclass = args.shift();
- if (loaded.config && (config.haveGecko("5.*", "6.0") || config.haveGecko("6.*"))) // Bug 657418.
- var Constructor = function Constructor() {
- var self = Object.create(Constructor.prototype);
- self.instance = self;
- self.globalInstance = self;
-
- if ("_metaInit_" in self && self._metaInit_)
- self._metaInit_.apply(self, arguments);
-
- var res = self.init.apply(self, arguments);
- return res !== undefined ? res : self;
- };
- else
- var Constructor = eval(String.replace('\n\
- (function constructor(PARAMS) { \n\
- var self = Object.create(Constructor.prototype); \n\
- self.instance = self; \n\
- self.globalInstance = self; \n\
- \n\
- if ("_metaInit_" in self && self._metaInit_) \n\
- self._metaInit_.apply(self, arguments); \n\
- \n\
- var res = self.init.apply(self, arguments); \n\
- return res !== undefined ? res : self; \n\
- })',
- "constructor", (name || superclass.className).replace(/\W/g, "_"))
- .replace("PARAMS", /^function .*?\((.*?)\)/.exec(args[0] && args[0].init || Class.prototype.init)[1]
- .replace(/\b(self|res|Constructor)\b/g, "$1_")));
+ var Constructor = eval(String.replace('\n\
+ (function constructor(PARAMS) { \n\
+ var self = Object.create(Constructor.prototype); \n\
+ self.instance = self; \n\
+ self.globalInstance = self; \n\
+ \n\
+ if ("_metaInit_" in self && self._metaInit_) \n\
+ self._metaInit_.apply(self, arguments); \n\
+ \n\
+ var res = self.init.apply(self, arguments); \n\
+ return res !== undefined ? res : self; \n\
+ })',
+ "constructor", (name || superclass.className).replace(/\W/g, "_"))
+ .replace("PARAMS",
+ /^function .*?\((.*?)\)/
+ .exec(args[0] && args[0].init || Class.prototype.init)[1]
+ .replace(/\b(self|res|Constructor)\b/g, "$1_")));
Constructor.className = name || superclass.className || superclass.name;
}
Class.extend(Constructor, superclass, args[0]);
- memoize(Constructor, "closure", Class.makeClosure);
+ memoize(Constructor, "bound", Class.makeClosure);
+ if (Iter && array) // Hack. :/
+ Object.defineProperty(Constructor, "closure",
+ deprecated("bound", { get: function closure() this.bound }));
update(Constructor, args[1]);
Constructor.__proto__ = superclass;
return Constructor;
}
-if (Cu.getGlobalForObject)
- Class.objectGlobal = function (object) {
- try {
- return Cu.getGlobalForObject(object);
- }
- catch (e) {
- return null;
- }
- };
-else
- Class.objectGlobal = function (object) {
- while (object.__parent__)
- object = object.__parent__;
- return object;
- };
+Class.objectGlobal = function (object) {
+ try {
+ return Cu.getGlobalForObject(object);
+ }
+ catch (e) {
+ return null;
+ }
+};
/**
* @class Class.Property
}
});
- util.yieldable(function () {
+ Task.spawn(function () {
let wait;
for (var res in getter.call(obj)) {
if (wait !== undefined)
- yield wait;
+ yield promises.sleep(wait);
wait = res;
}
Class.replaceProperty(obj, key, res);
done = true;
- })();
+ });
return this[key];
};
util.rehashing && !isinstance(Cu.getGlobalForObject(callback), ["BackstagePass"]))
return;
this.timeouts.splice(this.timeouts.indexOf(timer), 1);
- util.trapErrors(callback, this);
+ try {
+ callback.call(this);
+ }
+ catch (e) {
+ try {
+ util.dump("Error invoking timer callback registered at " +
+ [frame.filename, frame.lineNumber, ""].join(":"));
+ util.reportError(e);
+ }
+ catch (e) {
+ Cu.reportError(e);
+ }
+ }
};
+ let frame = Components.stack.caller;
let timer = services.Timer(timeout_notify, timeout || 0, services.Timer.TYPE_ONE_SHOT);
this.timeouts.push(timer);
return timer;
}
try {
- if ("value" in desc && (k in this.localizedProperties || k in this.magicalProperties))
+ if ("value" in desc && (this.localizedProperties.has(k) || this.magicalProperties.has(k)))
this[k] = desc.value;
else
Object.defineProperty(this, k, desc);
return this;
},
- localizedProperties: {},
- magicalProperties: {}
+ localizedProperties: RealSet(),
+ magicalProperties: RealSet()
};
for (let name in properties(Class.prototype)) {
let desc = Object.getOwnPropertyDescriptor(Class.prototype, name);
Object.defineProperty(Class.prototype, name, desc);
}
-Class.makeClosure = function makeClosure() {
- const self = this;
- function closure(fn) {
- function _closure() {
- try {
- return fn.apply(self, arguments);
- }
- catch (e if !(e instanceof FailedAssertion)) {
- util.reportError(e);
- throw e.stack ? e : Error(e);
- }
+var closureHooks = {
+ get: function closure_get(target, prop) {
+ if (hasOwnProperty(target._closureCache, prop))
+ return target._closureCache[prop];
+
+ let p = target[prop]
+ if (callable(p))
+ return target._closureCache[prop] = p.bind(target);
+ return p;
+ }
+
+ /*
+ getOwnPropertyNames: function getOwnPropertyNames(target) {
+ return [k for (k in properties(target, true))];
+ },
+
+ getOwnPropertyDescriptor: function getOwnPropertyDescriptor(target, prop) {
+ let self = this;
+ return {
+ configurable: false,
+ writable: false,
+ get value() self.get(target, prop)
}
- _closure.wrapped = fn;
- return _closure;
}
+ */
+};
- iter(properties(this), properties(this, true)).forEach(function (k) {
- if (!__lookupGetter__.call(this, k) && callable(this[k]))
- closure[k] = closure(this[k]);
- else if (!(k in closure))
- Object.defineProperty(closure, k, {
- configurable: true,
- enumerable: true,
- get: function get_proxy() self[k],
- set: function set_proxy(val) self[k] = val,
- });
- }, this);
-
- return closure;
+Class.makeClosure = function makeClosure() {
+ this._closureCache = {};
+
+ return new Proxy(this, closureHooks);
};
-memoize(Class.prototype, "closure", Class.makeClosure);
+memoize(Class.prototype, "bound", Class.makeClosure);
/**
* A base class generator for classes which implement XPCOM interfaces.
*/
var ErrorBase = Class("ErrorBase", Error, {
level: 2,
- init: function EB_init(message, level = 0) {
+ init: function EB_init(message, level=0) {
let error = Error(message);
update(this, error);
this.stack = error.stack;
let proto = callable(prototype) ? args[0] : prototype;
proto._metaInit_ = function () {
- delete module.prototype._metaInit_;
+ module.prototype._metaInit_ = null;
currentModule[name.toLowerCase()] = this;
};
clone: function struct_clone() this.constructor.apply(null, this.slice()),
+ bound: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "bound")),
closure: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "closure")),
get: function struct_get(key, val) this[this.members[key]],
});
var Timer = Class("Timer", {
- init: function init(minInterval, maxInterval, callback, self = this) {
+ init: function init(minInterval, maxInterval, callback, self=this) {
this._timer = services.Timer();
this.callback = callback;
this.self = self;
* @param {nsIJSIID} iface The interface to which to query all elements.
* @returns {Generator}
*/
+iter.iteratorProp = "@@iterator" in [] ? "@@iterator" : "iterator";
function iter(obj, iface) {
if (arguments.length == 2 && iface instanceof Ci.nsIJSIID)
return iter(obj).map(item => item.QueryInterface(iface));
for (let j in iter(args[i]))
yield j;
})();
- else if (isinstance(obj, ["Iterator", "Generator"]))
+ else if (isinstance(obj, ["Iterator", "Generator", "Array"]))
;
+ else if (isinstance(obj, [Ci.nsIDOMHTMLCollection, Ci.nsIDOMNodeList]))
+ res = array.iterItems(obj);
+ else if (iter.iteratorProp in obj && callable(obj[iter.iteratorProp]) && !("__iterator__" in obj))
+ res = (x for (x of obj));
else if (ctypes && ctypes.CData && obj instanceof ctypes.CData) {
while (obj.constructor instanceof ctypes.PointerType)
obj = obj.contents;
else
return iter({});
}
- else if (isinstance(obj, [Ci.nsIDOMHTMLCollection, Ci.nsIDOMNodeList]))
- res = array.iterItems(obj);
else if (Ci.nsIDOMNamedNodeMap && obj instanceof Ci.nsIDOMNamedNodeMap ||
Ci.nsIDOMMozNamedAttrMap && obj instanceof Ci.nsIDOMMozNamedAttrMap)
res = (function () {
every: function every(iter, pred, self) {
pred = pred || util.identity;
- for (let elem in iter)
+ for (let elem of iter)
if (!pred.call(self, elem))
return false;
return true;
},
some: function every(iter, pred, self) {
pred = pred || util.identity;
- for (let elem in iter)
+ for (let elem of iter)
if (pred.call(self, elem))
return true;
return false;
},
filter: function filter(iter, pred, self) {
- for (let elem in iter)
+ for (let elem of iter)
if (pred.call(self, elem))
yield elem;
},
* @param {object} self The this object for *fn*.
*/
forEach: function forEach(iter, func, self) {
- for (let val in iter)
+ for (let val of iter)
func.call(self, val);
},
indexOf: function indexOf(iter, elem) {
let i = 0;
- for (let item in iter) {
+ for (let item of iter) {
if (item == elem)
return i;
i++;
* @returns {Array}
*/
map: function map(iter, func, self) {
- for (let i in iter)
+ for (let i of iter)
yield func.call(self, i);
},
if (typeof pred === "number")
[pred, n] = [() => true, pred]; // Hack.
- for (let elem in iter)
+ for (let elem of iter)
if (pred.call(self, elem) && n-- === 0)
return elem;
return undefined;
},
+ /**
+ * Analog of Array.find method. Returns the first item in the
+ * iterator for which `pred` returns true.
+ */
+ find: function find(iter, pred, self) {
+ for (let elem of iter)
+ if (pred.call(self, elem))
+ return elem;
+ return undefined;
+ },
+
sort: function sort(iter, fn, self)
array(this.toArray(iter).sort(fn, self)),
uniq: function uniq(iter) {
- let seen = {};
- for (let item in iter)
- if (!Set.add(seen, item))
+ let seen = RealSet();
+ for (let item of iter)
+ if (!seen.add(item))
yield item;
},
__iterator__: function () this.iter
});
+iter.Iter = Iter;
+
+function arrayWrap(fn) {
+ function wrapper() {
+ let res = fn.apply(this, arguments);
+ if (isArray(res))
+ return array(res);
+ if (isinstance(res, ["Iterator", "Generator"]))
+ return iter(res);
+ return res;
+ }
+ wrapper.wrapped = fn;
+ return wrapper;
+}
/**
* Array utility methods.
else if (ary.length)
ary = Array.slice(ary);
- return {
- __proto__: ary,
- __iterator__: function () this.iterItems(),
- __noSuchMethod__: function (meth, args) {
- var res = array[meth].apply(null, [this.array].concat(args));
- if (isArray(res))
- return array(res);
- if (isinstance(res, ["Iterator", "Generator"]))
- return iter(res);
- return res;
- },
- array: ary,
- toString: function () this.array.toString(),
- concat: function (...args) this.__noSuchMethod__("concat", args),
- filter: function (...args) this.__noSuchMethod__("filter", args),
- map: function (...args) this.__noSuchMethod__("map", args)
- };
+ let self = this;
+ return new Proxy(ary, {
+ get: function array_get(target, prop) {
+ if (prop in array && callable(array[prop]))
+ return arrayWrap(array[prop].bind(array, target));
+
+ if (prop == "array")
+ return target;
+
+ let p = target[prop];
+ if (!/^\d+$/.test(prop) &&
+ prop != "toString" &&
+ prop != "toSource" &&
+ callable(p))
+ return arrayWrap(p);
+
+ return p;
+ }
+ });
}
}, {
/**
};
});
+Object.defineProperty(Class.prototype, "closure",
+ deprecated("bound", { get: function closure() this.bound }));
+
endModule();
// catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack);}
-// Copyright ©2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright ©2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
try {
return services.bookmarks
.getBookmarkIdsForURI(uri, {})
- .some(this.closure.isRegularBookmark);
+ .some(this.bound.isRegularBookmark);
}
catch (e) {
return false;
-// Copyright (c) 2011-2012 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2011-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
var EXPORTED_SYMBOLS = ["require"];
-// Deal with cross-compartment XML passing issues.
function create(proto) Object.create(proto);
+
this["import"] = function import_(obj) {
let res = {};
- for each (let key in Object.getOwnPropertyNames(obj))
+ for (let key of Object.getOwnPropertyNames(obj))
Object.defineProperty(res, key, Object.getOwnPropertyDescriptor(obj, key));
return res;
}
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
lazyRequire("io", ["io"]);
lazyRequire("finder", ["RangeFind"]);
lazyRequire("overlay", ["overlay"]);
+lazyRequire("promises", ["Promise", "promises"]);
lazyRequire("sanitizer", ["sanitizer"]);
lazyRequire("storage", ["File", "storage"]);
lazyRequire("template", ["template"]);
this.win = win;
},
- get addPageInfoSection() Buffer.closure.addPageInfoSection,
+ get addPageInfoSection() Buffer.bound.addPageInfoSection,
get pageInfo() Buffer.pageInfo,
);
},
+ /**
+ * The load context of the window bound to this buffer.
+ */
+ get loadContext() sanitizer.getContext(this.win),
+
+ /**
+ * Content preference methods.
+ */
+ prefs: Class.Memoize(function ()
+ let (self = this) ({
+ /**
+ * Returns a promise for the given preference name.
+ *
+ * @param {string} pref The name of the preference to return.
+ * @returns {Promise<*>}
+ */
+ get: promises.withCallbacks(function get([resolve, reject], pref) {
+ let val = services.contentPrefs.getCachedByDomainAndName(
+ self.uri.spec, pref, self.loadContext);
+
+ let found = false;
+ if (val)
+ resolve(val.value);
+ else
+ services.contentPrefs.getByDomainAndName(
+ self.uri.spec, pref, self.loadContext,
+ { handleCompletion: () => {
+ if (!found)
+ resolve(undefined);
+ },
+ handleResult: (pref) => {
+ found = true;
+ resolve(pref.value);
+ },
+ handleError: reject });
+ }),
+
+ /**
+ * Sets a content preference for the given buffer.
+ *
+ * @param {string} pref The preference to set.
+ * @param {string} value The value to store.
+ */
+ set: promises.withCallbacks(function set([resolve, reject], pref, value) {
+ services.contentPrefs.set(
+ self.uri.spec, pref, value, self.loadContext,
+ { handleCompletion: () => {},
+ handleResult: resolve,
+ handleError: reject });
+ }),
+
+ /**
+ * Clear a content preference for the given buffer.
+ *
+ * @param {string} pref The preference to clear.
+ */
+ clear: promises.withCallbacks(function clear([resolve, reject], pref) {
+ services.contentPrefs.removeByDomainAndName(
+ self.uri.spec, pref, self.loadContext,
+ { handleCompletion: () => {},
+ handleResult: resolve,
+ handleError: reject });
+ })
+ })),
+
/**
* Gets a content preference for the given buffer.
*
* @returns {string|number|boolean} The value of the preference, if
* callback is not provided.
*/
- getPref: function getPref(pref, callback) {
- // God damn it.
- if (config.haveGecko("19.0a1"))
- services.contentPrefs.getPref(this.uri, pref,
- sanitizer.getContext(this.win), callback);
- else
- services.contentPrefs.getPref(this.uri, pref, callback);
- },
+ getPref: deprecated("prefs.get", function getPref(pref, callback) {
+ services.contentPrefs.getPref(this.uri, pref,
+ this.loadContext, callback);
+ }),
/**
* Sets a content preference for the given buffer.
* @param {string} pref The preference to set.
* @param {string} value The value to store.
*/
- setPref: function setPref(pref, value) {
+ setPref: deprecated("prefs.set", function setPref(pref, value) {
services.contentPrefs.setPref(
- this.uri, pref, value, sanitizer.getContext(this.win));
- },
+ this.uri, pref, value, this.loadContext);
+ }),
/**
* Clear a content preference for the given buffer.
*
* @param {string} pref The preference to clear.
*/
- clearPref: function clearPref(pref) {
+ clearPref: deprecated("prefs.clear", function clearPref(pref) {
services.contentPrefs.removePref(
- this.uri, pref, sanitizer.getContext(this.win));
- },
+ this.uri, pref, this.loadContext);
+ }),
climbUrlPath: function climbUrlPath(count) {
let { dactyl } = this.modules;
};
DOM(elem).mousedown(params).mouseup(params);
- if (!config.haveGecko("2b"))
- DOM(elem).click(params);
let sel = util.selectionController(win);
sel.getSelection(sel.SELECTION_FOCUS_REGION).collapseToStart();
return newURI.spec;
}
- for each (let shortener in Buffer.uriShorteners)
+ for (let shortener of Buffer.uriShorteners)
try {
let shortened = shortener(uri, doc);
if (shortened)
}
let link = DOM("link[href][rev=canonical], \
- link[href][rel=shortlink]", doc);
- if (link.length)
- return hashify(link.attr("href"));
+ link[href][rel=shortlink]", doc)
+ .attr("href");
+ if (link)
+ return hashify(link);
return null;
},
* @param {number} count The multiple of 'scroll' lines to scroll.
* @optional
*/
- scrollByScrollSize: function scrollByScrollSize(direction, count = 1) {
+ scrollByScrollSize: function scrollByScrollSize(direction, count=1) {
let { options } = this.modules;
direction = direction ? 1 : -1;
else {
let url = loc || doc.location.href;
const PREFIX = "view-source:";
- if (url.indexOf(PREFIX) == 0)
+ if (url.startsWith(PREFIX))
url = url.substr(PREFIX.length);
else
url = PREFIX + url;
if (prefs.get("browser.zoom.siteSpecific")) {
var privacy = sanitizer.getContext(this.win);
if (value == 1) {
- this.clearPref("browser.content.full-zoom");
- this.clearPref("dactyl.content.full-zoom");
+ this.prefs.clear("browser.content.full-zoom");
+ this.prefs.clear("dactyl.content.full-zoom");
}
else {
- this.setPref("browser.content.full-zoom", value);
- this.setPref("dactyl.content.full-zoom", fullZoom);
+ this.prefs.set("browser.content.full-zoom", value);
+ this.prefs.set("dactyl.content.full-zoom", fullZoom);
}
}
/**
* Updates the zoom level of this buffer from a content preference.
*/
- updateZoom: util.wrapCallback(function updateZoom() {
+ updateZoom: promises.task(function updateZoom() {
let uri = this.uri;
if (prefs.get("browser.zoom.siteSpecific")) {
- this.getPref("dactyl.content.full-zoom", (val) => {
- if (val != null && uri.equals(this.uri) && val != prefs.get("browser.zoom.full"))
- [this.contentViewer.textZoom, this.contentViewer.fullZoom] =
- [this.contentViewer.fullZoom, this.contentViewer.textZoom];
- });
+ let val = yield this.prefs.get("dactyl.content.full-zoom");
+
+ if (val != null && uri.equals(this.uri) && val != prefs.get("browser.zoom.full"))
+ [this.contentViewer.textZoom, this.contentViewer.fullZoom] =
+ [this.contentViewer.fullZoom, this.contentViewer.textZoom];
}
}),
let arg = args[0];
// FIXME: arg handling is a bit of a mess, check for filename
- dactyl.assert(!arg || arg[0] == ">" && !config.OS.isWindows,
+ dactyl.assert(!arg || arg[0] == ">",
_("error.trailingCharacters"));
const PRINTER = "PostScript/default";
BRANCHES.forEach(function (branch) { prefs.set(branch + pref, value); });
}
- prefs.withContext(function () {
- if (arg) {
- prefs.set("print.print_printer", PRINTER);
-
- let { path } = io.File(arg.substr(1));
- set("print_to_file", true);
- set("print_to_filename", path);
- prefs.set("print_to_filename", path);
+ let settings = services.printSettings.newPrintSettings;
+ settings.printSilent = args.bang;
+ if (arg) {
+ settings.printToFile = true;
+ settings.toFileName = io.File(arg.substr(1)).path;
+ settings.outputFormat = settings.kOutputFormatPDF;
- dactyl.echomsg(_("print.toFile", arg.substr(1)));
- }
- else
- dactyl.echomsg(_("print.sending"));
+ dactyl.echomsg(_("print.toFile", arg.substr(1)));
+ }
+ else {
+ dactyl.echomsg(_("print.sending"));
- prefs.set("print.always_print_silent", args.bang);
if (false)
prefs.set("print.show_print_progress", !args.bang);
+ }
- config.browser.contentWindow.print();
- });
+ config.browser.contentWindow
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebBrowserPrint).print(settings, null);
dactyl.echomsg(_("print.sent"));
},
events: function initEvents(dactyl, modules, window) {
let { buffer, config, events } = modules;
- events.listen(config.browser, "scroll", buffer.closure._updateBufferPosition, false);
+ events.listen(config.browser, "scroll", buffer.bound._updateBufferPosition, false);
},
mappings: function initMappings(dactyl, modules, window) {
let { Editor, Events, buffer, editor, events, ex, mappings, modes, options, tabs } = modules;
elem = DOM(elem);
- if (elem[0].readOnly || !DOM(elem).isEditable)
+ if (elem[0].readOnly || elem[0].disabled || !DOM(elem).isEditable)
return false;
let style = elem.style;
if (/^func:/.test(filter.result))
var res = dactyl.userEval("(" + Option.dequote(filter.result.substr(5)) + ")")(doc, line);
else
- res = iter.nth(filter.matcher(doc),
- elem => ((elem.nodeValue || elem.textContent).trim() == line &&
- DOM(elem).display != "none"),
- 0)
+ res = iter.find(filter.matcher(doc),
+ elem => ((elem.nodeValue || elem.textContent).trim() == line &&
+ DOM(elem).display != "none"))
|| iter.nth(filter.matcher(doc), util.identity, line - 1);
if (res)
break;
-// Copyright (c) 2011-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2011-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
});
lazyRequire("overlay", ["overlay"]);
-lazyRequire("storage", ["File"]);
+lazyRequire("storage", ["File", "storage"]);
var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), {
init: function init() {
this.queue = [];
- this.cache = {};
+ this.storage = storage.newMap("cache", { store: true });
this.providers = {};
this.globalProviders = this.providers;
- this.providing = {};
- this.localProviders = {};
+ this.providing = RealSet();
+ this.localProviders = RealSet();
if (JSMLoader.cacheFlush)
this.flush();
update(services["dactyl:"].providers, {
- "cache": function (uri, path) {
+ "cache": (uri, path) => {
let contentType = "text/plain";
try {
contentType = services.mime.getTypeFromURI(uri);
}
catch (e) {}
- if (!cache.cacheReader || !cache.cacheReader.hasEntry(path))
- return [contentType, cache.force(path)];
+ if (this.storage.has(path) ||
+ !this.cacheReader ||
+ !this.cacheReader.hasEntry(path))
+ return [contentType, this.force(path)];
let channel = services.StreamChannel(uri);
- channel.contentStream = cache.cacheReader.getInputStream(path);
+ try {
+ channel.contentStream = this.cacheReader.getInputStream(path);
+ }
+ catch (e if e.result = Cr.NS_ERROR_FILE_CORRUPTED) {
+ this.flushDiskCache();
+ throw e;
+ }
channel.contentType = contentType;
channel.contentCharset = "UTF-8";
return channel;
}),
parse: function parse(str) {
- if (~'{['.indexOf(str[0]))
+ if ('{['.contains(str[0]))
return JSON.parse(str);
return str;
},
}
catch (e if e.result == Cr.NS_ERROR_FILE_CORRUPTED) {
util.reportError(e);
- this.closeWriter();
- this.cacheFile.remove(false);
+ this.flushDiskCache();
}
return this._cacheReader;
closeReader: function closeReader() {
if (cache._cacheReader) {
this.cacheReader.close();
- delete cache._cacheReader;
+ cache._cacheReader = null;
}
},
if (this._cacheWriter) {
this._cacheWriter.close();
- delete cache._cacheWriter;
+ cache._cacheWriter = null;
// ZipWriter bug.
if (this.cacheFile.fileSize <= 22)
}
}),
- flush: function flush() {
- cache.cache = {};
+ flush: function flush(filter) {
+ if (filter) {
+ this.storage.keys().filter(filter)
+ .forEach(bind("remove", this.storage));
+ }
+ else {
+ this.storage.clear();
+ this.flushDiskCache();
+ }
+ },
+
+ flushDiskCache: function flushDiskCache() {
if (this.cacheFile.exists()) {
- this.closeReader();
+ this.closeWriter();
this.flushJAR(this.cacheFile);
this.cacheFile.remove(false);
cache.processQueue();
}
- delete this.cache[name];
+ this.storage.remove(name);
},
flushJAR: function flushJAR(file) {
},
force: function force(name, localOnly) {
+ if (this.storage.has(name))
+ return this.storage.get(name);
+
util.waitFor(() => !this.inQueue);
if (this.cacheReader && this.cacheReader.hasEntry(name)) {
- return this.parse(File.readStream(
- this.cacheReader.getInputStream(name)));
+ try {
+ return this.parse(File.readStream(
+ this.cacheReader.getInputStream(name)));
+ }
+ catch (e if e.result == Cr.NS_ERROR_FILE_CORRUPTED) {
+ this.flushDiskCache();
+ }
}
- if (Set.has(this.localProviders, name) && !this.isLocal) {
- for each (let { cache } in overlay.modules)
+ if (this.localProviders.has(name) && !this.isLocal) {
+ for (let { cache } of overlay.modules)
if (cache._has(name))
return cache.force(name, true);
}
- if (Set.has(this.providers, name)) {
- util.assert(!Set.add(this.providing, name),
+ if (hasOwnProperty(this.providers, name)) {
+ util.assert(!this.providing.add(name),
"Already generating cache for " + name,
false);
+
+ let [func, long] = this.providers[name];
try {
- let [func, self] = this.providers[name];
- this.cache[name] = func.call(self || this, name);
+ var value = func.call(this, name);
}
finally {
- delete this.providing[name];
+ this.providing.delete(name);
}
- cache.queue.push([Date.now(), name]);
- cache.processQueue();
+ if (!long)
+ this.storage.set(name, value);
+ else {
+ cache.queue.push([Date.now(), name, value]);
+ cache.processQueue();
+ }
- return this.cache[name];
+ return value;
}
if (this.isLocal && !localOnly)
return cache.force(name);
},
- get: function get(name, callback, self) {
- if (!Set.has(this.cache, name)) {
- if (callback && !(Set.has(this.providers, name) ||
- Set.has(this.localProviders, name)))
- this.register(name, callback, self);
+ get: function get(name, callback, long) {
+ if (this.storage.has(name))
+ return this.storage.get(name);
- this.cache[name] = this.force(name);
- util.assert(this.cache[name] !== undefined,
- "No such cache key", false);
- }
+ if (callback && !(hasOwnProperty(this.providers, name) ||
+ this.localProviders.has(name)))
+ this.register(name, callback, long);
- return this.cache[name];
+ var result = this.force(name);
+ util.assert(result !== undefined, "No such cache key", false);
+
+ return result;
},
- _has: function _has(name) Set.has(this.providers, name) || set.has(this.cache, name),
+ _has: function _has(name) hasOwnProperty(this.providers, name)
+ || this.storage.has(name),
- has: function has(name) [this.globalProviders, this.cache, this.localProviders]
- .some(obj => Set.has(obj, name)),
+ has: function has(name) [this.globalProviders, this.localProviders]
+ .some(obj => isinstance(obj, ["Set"]) ? obj.has(name)
+ : hasOwnProperty(obj, name)),
- register: function register(name, callback, self) {
+ register: function register(name, callback, long) {
if (this.isLocal)
- Set.add(this.localProviders, name);
+ this.localProviders.add(name);
- this.providers[name] = [callback, self];
+ this.providers[name] = [callback, long];
},
processQueue: function processQueue() {
if (this.queue.length && !this.inQueue) {
// removeEntry does not work properly with queues.
let removed = 0;
- for each (let [, entry] in this.queue)
+ for (let [, entry] of this.queue)
if (this.getCacheWriter().hasEntry(entry)) {
this.getCacheWriter().removeEntry(entry, false);
removed++;
}
- if (removed)
+ if (removed) {
this.closeWriter();
+ util.flushCache(this.cacheFile);
+ }
- this.queue.splice(0).forEach(function ([time, entry]) {
- if (time && Set.has(this.cache, entry)) {
+ this.queue.splice(0).forEach(function ([time, entry, value]) {
+ if (time && value != null) {
let stream = services.CharsetConv("UTF-8")
- .convertToInputStream(this.stringify(this.cache[entry]));
+ .convertToInputStream(this.stringify(value));
this.getCacheWriter().addEntryStream(entry, time * 1000,
this.compression, stream,
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
* @param {Args} args The Args object passed to {@link #action}.
* @param {Object} modifiers Any modifiers to be passed to {@link #action}.
*/
- execute: function execute(args, modifiers = {}) {
+ execute: function execute(args, modifiers={}) {
const { dactyl } = this.modules;
let context = args.context;
extra: extra
}),
- complained: Class.Memoize(function () ({})),
+ complained: Class.Memoize(function () RealSet()),
/**
* @property {[string]} All of this command's name specs. e.g., "com[mand]"
explicitOpts: Class.Memoize(function () ({})),
- has: function AP_has(opt) Set.has(this.explicitOpts, opt) || typeof opt === "number" && Set.has(this, opt),
+ has: function AP_has(opt) hasOwnProperty(this.explicitOpts, opt)
+ || typeof opt === "number" && hasOwnProperty(this, opt),
get literalArg() this.command.literal != null && this[this.command.literal] || "",
warn: function warn(context, type, message) {
let loc = !context ? "" : [context.file, context.line, " "].join(":");
- if (!Set.add(this.complained, type + ":" + (context ? context.file : "[Command Line]")))
+ let key = type + ":" + (context ? context.file : "[Command Line]");
+
+ if (!this.complained.add(key))
this.modules.dactyl.warn(loc + message);
}
}, {
*/
cache: function cache() {
- let self = this;
let { cache } = this.modules;
this.cached = true;
- let cached = cache.get(this.cacheKey, function () {
- self.cached = false;
+ let cached = cache.get(this.cacheKey, () => {
+ this.cached = false;
this.modules.moduleManager.initDependencies("commands");
let map = {};
- for (let [name, cmd] in Iterator(self._map))
+ for (let [name, cmd] in Iterator(this._map))
if (cmd.sourceModule)
map[name] = { sourceModule: cmd.sourceModule, isPlaceholder: true };
let specs = [];
- for (let cmd in values(self._list))
- for each (let spec in cmd.parsedSpecs)
+ for (let cmd of this._list)
+ for (let spec of cmd.parsedSpecs)
specs.push(spec.concat(cmd.name));
return { map: map, specs: specs };
* @param {boolean} replace Replace an existing command of the same name.
* @optional
*/
- add: function add(specs, description, action, extra = {}, replace = false) {
+ add: function add(specs, description, action, extra={}, replace=false) {
const { commands, contexts } = this.modules;
if (!extra.definedAt)
return name;
},
- _add: function _add(names, description, action, extra = {}, replace = false) {
+ _add: function _add(names, description, action, extra={}, replace=false) {
const { contexts } = this.modules;
extra.definedAt = contexts.getCaller(Components.stack.caller.caller);
return this.add.apply(this, arguments);
*/
get: function get(name, full) {
let cmd = this._map[name]
- || !full && array.nth(this._list, cmd => cmd.hasName(name), 0)
+ || !full && this._list.find(cmd => cmd.hasName(name))
|| null;
if (!cmd && full) {
- let name = array.nth(this.specs, spec => Command.hasName(spec, name), 0);
+ // Hrm. This is wrong. -Kris
+ let name = this._specs.find(spec => Command.hasName(spec, name));
return name && this.get(name);
}
const { commandline, completion } = this.modules;
function completerToString(completer) {
if (completer)
- return [k for ([k, v] in Iterator(config.completers)) if (completer == completion.closure[v])][0] || "custom";
+ return [k for ([k, v] in Iterator(config.completers)) if (completer == completion.bound[v])][0] || "custom";
return "";
}
// TODO: allow matching of aliases?
- function cmds(hive) hive._list.filter(cmd => cmd.name.indexOf(filter || "") == 0)
+ function cmds(hive) hive._list.filter(cmd => cmd.name.startsWith(filter || ""))
let hives = (hives || this.userHives).map(h => [h, cmds(h)])
.filter(([h, c]) => c.length);
return group._add.apply(group, arguments);
},
- addUserCommand: deprecated("group.commands.add", { get: function addUserCommand() this.user.closure._add }),
+ addUserCommand: deprecated("group.commands.add", { get: function addUserCommand() this.user.bound._add }),
getUserCommands: deprecated("iter(group.commands)", function getUserCommands() iter(this.user).toArray()),
- removeUserCommand: deprecated("group.commands.remove", { get: function removeUserCommand() this.user.closure.remove }),
+ removeUserCommand: deprecated("group.commands.remove", { get: function removeUserCommand() this.user.bound.remove }),
/**
* Returns the specified command invocation object serialized to
* @returns {Command}
*/
get: function get(name, full) iter(this.hives).map(([i, hive]) => hive.get(name, full))
- .nth(util.identity, 0),
+ .find(util.identity),
/**
* Returns true if a command invocation contains a URL referring to the
* Args object.
* @returns {Args}
*/
- parseArgs: function parseArgs(str, params = {}) {
+ parseArgs: function parseArgs(str, params={}) {
const self = this;
function getNextArg(str, _keepQuotes=keepQuotes) {
let matchOpts = function matchOpts(arg) {
// Push possible option matches into completions
if (complete && !onlyArgumentsRemaining)
- completeOpts = options.filter(opt => (opt.multiple || !Set.has(args, opt.names[0])));
+ completeOpts = options.filter(opt => (opt.multiple || !hasOwnProperty(args, opt.names[0])));
};
let resetCompletions = function resetCompletions() {
completeOpts = null;
if (!onlyArgumentsRemaining) {
for (let [, opt] in Iterator(options)) {
for (let [, optname] in Iterator(opt.names)) {
- if (sub.indexOf(optname) == 0) {
+ if (sub.startsWith(optname)) {
let count = 0;
let invalid = false;
let arg, quote, quoted;
if (arg == null || (typeof arg == "number" && isNaN(arg))) {
if (!complete || orig != "" || args.completeStart != str.length)
- fail(_("command.invalidOptTypeArg", opt.type.description, optname, argString));
+ fail(_("command.invalidOptTypeArg", opt.type.description, optname, quoted));
if (complete)
complete.highlight(args.completeStart, count - 1, "SPELLCHECK");
}
// we have a validator function
if (typeof opt.validator == "function") {
if (opt.validator(arg, quoted) == false && (arg || !complete)) {
- fail(_("command.invalidOptArg", optname, argString));
+ fail(_("command.invalidOptArg", optname, quoted));
if (complete) // Always true.
complete.highlight(args.completeStart, count - 1, "SPELLCHECK");
}
function (args) {
let cmd = args[0];
- util.assert(!cmd || cmd.split(",").every(commands.validName.closure.test),
+ util.assert(!cmd || cmd.split(",").every(commands.validName.bound.test),
_("command.invalidName", cmd));
if (args.length <= 1)
};
}
else
- completerFunc = context => modules.completion.closure[config.completers[completer]](context);
+ completerFunc = context => modules.completion.bound[config.completers[completer]](context);
}
let added = args["-group"].add(cmd.split(","),
]
})),
iterateIndex: function (args) let (tags = help.tags)
- this.iterate(args).filter(cmd => (cmd.hive === commands.builtin || Set.has(tags, cmd.helpTag))),
+ this.iterate(args).filter(cmd => (cmd.hive === commands.builtin || hasOwnProperty(tags, cmd.helpTag))),
format: {
headings: ["Command", "Group", "Description"],
description: function (cmd) template.linkifyHelp(cmd.description + (cmd.replacementText ? ": " + cmd.action : "")),
}
});
-let quote = function quote(q, list, map = Commands.quoteMap) {
+let quote = function quote(q, list, map=Commands.quoteMap) {
let re = RegExp("[" + list + "]", "g");
function quote(str) (q + String.replace(str, re, $0 => ($0 in map ? map[$0] : ("\\" + $0)))
+ q);
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
* @constructor
*/
var CompletionContext = Class("CompletionContext", {
- init: function cc_init(editor, name = "", offset = 0) {
+ init: function cc_init(editor, name="", offset=0) {
let self = this;
if (editor instanceof this.constructor) {
let parent = editor;
filtered.sort(this.compare);
if (!this.anchored) {
let filter = this.filter;
- filtered.sort(function s(a, b) (b.text.indexOf(filter) == 0) - (a.text.indexOf(filter) == 0));
+ filtered.sort(function s(a, b) b.text.startsWith(filter) - a.text.startsWith(filter));
}
}
var substrings = [text];
}
else {
- var compare = function compare(text, s) text.indexOf(s) >= 0;
+ var compare = function compare(text, s) text.contains(s);
var substrings = [];
let start = 0;
let idx;
let alias = (prop) => {
context.__defineGetter__(prop, () => this[prop]);
context.__defineSetter__(prop, (val) => this[prop] = val);
- }
+ };
alias("_cache");
alias("_completions");
alias("_generate");
}
this.waitingForTab = false;
this.runCount++;
- for each (let context in this.contextList)
+ for (let context of this.contextList)
context.lastActivated = this.runCount;
this.contextList = [];
},
context.generate = function generate_() {
return [[k.substr(services.ABOUT.length), ""]
for (k in Cc)
- if (k.indexOf(services.ABOUT) == 0)];
+ if (k.startsWith(services.ABOUT))];
};
});
let contains = String.indexOf;
if (context.ignoreCase) {
compare = util.compareIgnoreCase;
- contains = function contains_(a, b) a && a.toLowerCase().indexOf(b.toLowerCase()) > -1;
+ contains = function contains_(a, b) a && a.toLowerCase().contains(b.toLowerCase());
}
if (tags)
.concat([let (name = k.substr(services.AUTOCOMPLETE.length))
["native:" + name, _("autocomplete.description", name)]
for (k in Cc)
- if (k.indexOf(services.AUTOCOMPLETE) == 0)]),
+ if (k.startsWith(services.AUTOCOMPLETE))]),
setter: function setter(values) {
- if (values.length == 1 && !Set.has(values[0], this.values)
- && Array.every(values[0], Set.has(this.valueMap)))
- return Array.map(values[0], function m(v) this[v], this.valueMap);
+ if (values.length == 1 && !hasOwnProperty(values[0], this.values)
+ && Array.every(values[0], v => hasOwnProperty(this.valueMap, v)))
+ return Array.map(values[0], v => this.valueMap[v]);
+
return values;
},
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
let global = this;
defineModule("config", {
exports: ["ConfigBase", "Config", "config"],
- require: ["dom", "io", "protocol", "services", "util", "template"]
+ require: ["io", "protocol", "services"]
});
lazyRequire("addons", ["AddonManager"]);
lazyRequire("cache", ["cache"]);
+lazyRequire("dom", ["DOM"]);
lazyRequire("highlight", ["highlight"]);
lazyRequire("messages", ["_"]);
lazyRequire("prefs", ["localPrefs", "prefs"]);
lazyRequire("storage", ["storage", "File"]);
lazyRequire("styles", ["Styles"]);
+lazyRequire("template", ["template"]);
+lazyRequire("util", ["util"]);
function AboutHandler() {}
AboutHandler.prototype = {
* initialization code. Must call superclass's init function.
*/
init: function init() {
- this.loadConfig();
+ if (!config.haveGecko("26"))
+ this.modules.global = this.modules.global.filter(m => m != "downloads"); // FIXME
- this.features.push = deprecated("Set.add", function push(feature) Set.add(this, feature));
- if (this.haveGecko("2b"))
- Set.add(this.features, "Gecko2");
+ this.loadConfig();
- JSMLoader.registerFactory(JSMLoader.Factory(AboutHandler));
- JSMLoader.registerFactory(JSMLoader.Factory(
- Protocol("dactyl", "{9c8f2530-51c8-4d41-b356-319e0b155c44}",
- "resource://dactyl-content/")));
+ util.trapErrors(() => {
+ JSMLoader.registerFactory(JSMLoader.Factory(AboutHandler));
+ });
+ util.withProperErrors(() => {
+ JSMLoader.registerFactory(JSMLoader.Factory(
+ Protocol("dactyl", "{9c8f2530-51c8-4d41-b356-319e0b155c44}",
+ "resource://dactyl-content/")));
+ });
+ this.protocolLoaded = true;
this.timeout(function () {
- cache.register("config.dtd", () => util.makeDTD(config.dtd));
+ cache.register("config.dtd", () => util.makeDTD(config.dtd),
+ true);
+ });
+
+ // FIXME: May not be ready before first window opens.
+ AddonManager.getAddonByID("{972ce4c6-7e08-4474-a285-3208198ce6fd}", a => {
+ if (!a.isActive)
+ config.features.delete("default-theme");
});
services["dactyl:"].pages["dtd"] = () => [null, cache.get("config.dtd")];
get prefs() localPrefs,
- get has() Set.has(this.features),
+ has: function (feature) this.features.has(feature),
configFiles: [
"resource://dactyl-common/config.json",
loadConfig: function loadConfig(documentURL) {
- for each (let config in this.configs) {
+ for (let config of this.configs) {
if (documentURL)
config = config.overlays && config.overlays[documentURL] || {};
if (isArray(this[prop]))
this[prop] = [].concat(this[prop], value);
+ else if (isinstance(this[prop], ["Set"]))
+ for (let key of value)
+ this[prop].add(key);
else if (isObject(this[prop])) {
if (isArray(value))
value = Set(value);
"options",
"overlay",
"prefs",
+ ["promises", "Promise", "Task", "promises"],
"protocol",
"sanitizer",
"services",
highlight.loadCSS(this.helpCSS.replace(/__MSG_(.*?)__/g,
(m0, m1) => _(m1)));
- if (!this.haveGecko("2b"))
- highlight.loadCSS(literal(/*
- !TabNumber font-weight: bold; margin: 0px; padding-right: .8ex;
- !TabIconNumber {
- font-weight: bold;
- color: white;
- text-align: center;
- text-shadow: black -1px 0 1px, black 0 1px 1px, black 1px 0 1px, black 0 -1px 1px;
- }
- */));
-
let hl = highlight.set("Find", "");
hl.onChange = function () {
function hex(val) ("#" + util.regexp.iterate(/\d+/g, val)
bestLocale: function (list) {
return values([this.appLocale, this.appLocale.replace(/-.*/, ""),
"en", "en-US", list[0]])
- .nth(Set.has(Set(list)), 0);
+ .find(bind("has", RealSet(list)));
},
/**
// Horrible hack.
let res = {};
function process(manifest) {
- for each (let line in manifest.split(/\n+/)) {
+ for (let line of manifest.split(/\n+/)) {
let match = /^\s*(content|skin|locale|resource)\s+([^\s#]+)\s/.exec(line);
if (match)
res[match[2]] = true;
}
}
- for each (let dir in ["UChrm", "AChrom"]) {
+ for (let dir of ["UChrm", "AChrom"]) {
dir = File(services.directory.get(dir, Ci.nsIFile));
if (dir.exists() && dir.isDirectory())
for (let file in dir.iterDirectory())
dtd: Class.Memoize(function ()
iter(this.dtdExtra,
(["dactyl." + k, v] for ([k, v] in iter(config.dtdDactyl))),
- (["dactyl." + s, config[s]] for each (s in config.dtdStrings)))
+ (["dactyl." + s, config[s]] for (s of config.dtdStrings)))
.toObject()),
dtdDactyl: memoize({
["menupopup", { id: "viewSidebarMenu", xmlns: "xul" }],
["broadcasterset", { id: "mainBroadcasterSet", xmlns: "xul" }]];
- for each (let [id, [name, key, uri]] in Iterator(this.sidebars)) {
+ for (let [id, [name, key, uri]] in Iterator(this.sidebars)) {
append[0].push(
["menuitem", { observes: "pentadactyl-" + id + "Sidebar", label: name,
accesskey: key }]);
* dactyl.has(feature) to check for a feature's presence
* in this array.
*/
- features: {},
+ features: RealSet(["default-theme"]),
/**
* @property {string} The file extension used for command script files.
init: function init(dactyl, modules, window) {
init.superapply(this, arguments);
- let img = window.Image();
+ let img = new window.Image;
img.src = this.logo || "resource://dactyl-local-content/logo.png";
img.onload = util.wrapCallback(function () {
highlight.loadCSS(literal(/*
-// Copyright (c) 2010-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2010-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
delete this[hive];
if (reason != "shutdown")
- this.children.splice(0).forEach(this.contexts.closure.removeGroup);
+ this.children.splice(0).forEach(this.contexts.bound.removeGroup);
},
destroy: function destroy(reason) {
for (let hive in values(this.hives))
util.trapErrors("destroy", hive);
if (reason != "shutdown")
- this.children.splice(0).forEach(this.contexts.closure.removeGroup);
+ this.children.splice(0).forEach(this.contexts.bound.removeGroup);
},
argsExtra: function argsExtra() ({}),
}, {
compileFilter: function (patterns, default_=false) {
function siteFilter(uri)
- let (match = array.nth(siteFilter.filters, f => f(uri), 0))
- match ? match.result : default_;
+ let (match = siteFilter.filters.find(f => f(uri)))
+ match ? match.result
+ : default_;
return update(siteFilter, {
toString: function () this.filters.join(","),
completer: function (context) modules.completion.group(context)
});
- memoize(modules, "userContext", () => contexts.Context(modules.io.getRCFile("~", true), contexts.user, [modules, true]));
- memoize(modules, "_userContext", () => contexts.Context(modules.io.getRCFile("~", true), contexts.user, [modules.userContext]));
+ memoize(modules, "userContext", () => contexts.Context(modules.io.getRCFile("~", true), contexts.user, [modules, false]));
+ memoize(modules, "_userContext", () => modules.userContext);
},
cleanup: function () {
- for each (let hive in this.groupList.slice())
+ for (let hive of this.groupList.slice())
util.trapErrors("cleanup", hive, "shutdown");
},
destroy: function () {
- for each (let hive in values(this.groupList.slice()))
+ for (let hive of values(this.groupList.slice()))
util.trapErrors("destroy", hive, "shutdown");
- for (let [name, plugin] in iter(this.modules.plugins.contexts))
+ for each (let plugin in this.modules.plugins.contexts) {
if (plugin && "onUnload" in plugin && callable(plugin.onUnload))
util.trapErrors("onUnload", plugin);
+
+ if (isinstance(plugin, ["Sandbox"]))
+ util.trapErrors("nukeSandbox", Cu, plugin);
+ }
},
signals: {
{ _hive: { value: name } })));
memoize(contexts.groupsProto, name,
- function () [group[name] for (group in values(this.groups)) if (Set.has(group, name))]);
+ function () [group[name]
+ for (group in values(this.groups))
+ if (hasOwnProperty(group, name))]);
},
get toStringParams() [this.name, this.Hive]
Context: function Context(file, group, args) {
const { contexts, io, newContext, plugins, userContext } = this.modules;
- let isPlugin = array.nth(io.getRuntimeDirectories("plugins"),
- dir => dir.contains(file, true),
- 0);
- let isRuntime = array.nth(io.getRuntimeDirectories(""),
- dir => dir.contains(file, true),
- 0);
+ let isPlugin = io.getRuntimeDirectories("plugins")
+ .find(dir => dir.contains(file, true));
+ let isRuntime = io.getRuntimeDirectories("")
+ .find(dir => dir.contains(file, true));
let name = isPlugin ? file.getRelativeDescriptor(isPlugin).replace(File.PATH_SEP, "-")
: file.leafName;
let id = util.camelCase(name.replace(/\.[^.]*$/, ""));
let contextPath = file.path;
- let self = Set.has(plugins, contextPath) && plugins.contexts[contextPath];
+ let self = hasOwnProperty(plugins, contextPath) && plugins.contexts[contextPath];
if (!self && isPlugin && false)
- self = Set.has(plugins, id) && plugins[id];
+ self = hasOwnProperty(plugins, id) && plugins[id];
if (self) {
- if (Set.has(self, "onUnload"))
+ if (hasOwnProperty(self, "onUnload"))
util.trapErrors("onUnload", self);
}
else {
if (uri instanceof Ci.nsIFileURL)
var file = File(uri.file);
- let isPlugin = array.nth(io.getRuntimeDirectories("plugins"),
- dir => dir.contains(file, true),
- 0);
+ let isPlugin = io.getRuntimeDirectories("plugins")
+ .find(dir => dir.contains(file, true));
let name = isPlugin && file && file.getRelativeDescriptor(isPlugin)
.replace(File.PATH_SEP, "-");
let id = util.camelCase(name.replace(/\.[^.]*$/, ""));
- let self = Set.has(this.pluginModules, canonical) && this.pluginModules[canonical];
+ let self = hasOwnProperty(this.pluginModules, canonical) && this.pluginModules[canonical];
if (!self) {
self = Object.create(jsmodules);
delete contexts.pluginModules[canonical];
}
- for each (let { plugins } in overlay.modules)
+ for (let { plugins } of overlay.modules)
if (plugins[this.NAME] == this)
delete plugins[this.name];
})
initializedGroups: function (hive)
let (need = hive ? [hive] : Object.keys(this.hives))
- this.groupList.filter(group => need.some(Set.has(group))),
+ this.groupList.filter(group => need.some(hasOwnProperty.bind(null, group))),
addGroup: function addGroup(name, description, filter, persist, replace) {
let group = this.getGroup(name);
getGroup: function getGroup(name, hive) {
if (name === "default")
var group = this.context && this.context.context && this.context.context.GROUP;
- else if (Set.has(this.groupMap, name))
+ else if (hasOwnProperty(this.groupMap, name))
group = this.groupMap[name];
if (group && hive)
getDocs: function getDocs(context) {
try {
- if (isinstance(context, ["Sandbox"])) {
- let info = "INFO" in context && Cu.evalInSandbox("this.INFO instanceof XML ? INFO.toXMLString() : this.INFO", context);
- return /^</.test(info) ? XML(info) : info;
- }
if (DOM.isJSONXML(context.INFO))
return context.INFO;
- if (typeof context.INFO == "xml" && config.haveGecko(null, "14.*"))
- return context.INFO;
}
catch (e) {}
return null;
util.assert(!group.builtin ||
!["-description", "-locations", "-nopersist"]
- .some(Set.has(args.explicitOpts)),
+ .some(hasOwnProperty.bind(null, args.explicitOpts)),
_("group.cantModifyBuiltin"));
},
{
+++ /dev/null
-// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
-//
-// This work is licensed for reuse under an MIT license. Details are
-// given in the LICENSE.txt file included with this file.
-/* use strict */
-
-defineModule("dom", {
- exports: ["fromXML"]
-});
-
-lazyRequire("highlight", ["highlight"]);
-
-var XBL = Namespace("xbl", "http://www.mozilla.org/xbl");
-var XHTML = Namespace("html", "http://www.w3.org/1999/xhtml");
-var XUL = Namespace("xul", "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-var NS = Namespace("dactyl", "http://vimperator.org/namespaces/liberator");
-
-function fromXML(node, doc, nodes) {
- XML.ignoreWhitespace = XML.prettyPrinting = false;
- if (typeof node === "string") // Sandboxes can't currently pass us XML objects.
- node = XML(node);
-
- if (node.length() != 1) {
- let domnode = doc.createDocumentFragment();
- for each (let child in node)
- domnode.appendChild(fromXML(child, doc, nodes));
- return domnode;
- }
-
- switch (node.nodeKind()) {
- case "text":
- return doc.createTextNode(String(node));
- case "element":
- let domnode = doc.createElementNS(node.namespace(), node.localName());
-
- for each (let attr in node.@*::*)
- if (attr.name() != "highlight")
- domnode.setAttributeNS(attr.namespace(), attr.localName(), String(attr));
-
- for each (let child in node.*::*)
- domnode.appendChild(fromXML(child, doc, nodes));
- if (nodes && node.@key)
- nodes[node.@key] = domnode;
-
- if ("@highlight" in node)
- highlight.highlightNode(domnode, String(node.@highlight), nodes || true);
- return domnode;
- default:
- return null;
- }
-}
-
-// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript:
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
if (val == null)
;
- else if (typeof val == "xml" && context instanceof Ci.nsIDOMDocument)
- this[length++] = DOM.fromXML(val, context, this.nodes);
else if (DOM.isJSONXML(val)) {
if (context instanceof Ci.nsIDOMDocument)
this[length++] = DOM.fromJSON(val, context, this.nodes);
let charset = doc.characterSet;
let converter = services.CharsetConv(charset);
- for each (let cs in form.acceptCharset.split(/\s*,\s*|\s+/)) {
+ for (let cs of form.acceptCharset.split(/\s*,\s*|\s+/)) {
let c = services.CharsetConv(cs);
if (c) {
converter = services.CharsetConv(cs);
if (callable(v))
v = v.call(this, elem, i);
- if (Set.has(hooks, k) && hooks[k].set)
+ if (hasOwnProperty(hooks, k) && hooks[k].set)
hooks[k].set.call(this, elem, v, k);
else if (v == null)
elem.removeAttributeNS(ns, k);
if (!this.length)
return null;
- if (Set.has(hooks, key) && hooks[key].get)
+ if (hasOwnProperty(hooks, key) && hooks[key].get)
return hooks[key].get.call(this, this[0], key);
if (!this[0].hasAttributeNS(ns, key))
keyTable: Class.Memoize(function (prop) this.init()[prop]),
key_code: Class.Memoize(function (prop) this.init()[prop]),
key_key: Class.Memoize(function (prop) this.init()[prop]),
- pseudoKeys: Set(["count", "leader", "nop", "pass"]),
+ pseudoKeys: RealSet(["count", "leader", "nop", "pass"]),
/**
* Converts a user-input string of keys into a canonical
* @returns {string} Canonical form.
*/
canonicalKeys: function canonicalKeys(keys, unknownOk=true) {
- return this.parse(keys, unknownOk).map(this.closure.stringify).join("");
+ return this.parse(keys, unknownOk).map(this.bound.stringify).join("");
},
iterKeys: function iterKeys(keys) iter(function () {
}
else {
let [match, modifier, keyname] = evt_str.match(/^<((?:[*12CASM⌘]-)*)(.+?)>$/i) || [false, '', ''];
- modifier = Set(modifier.toUpperCase());
+ modifier = RealSet(modifier.toUpperCase());
keyname = keyname.toLowerCase();
evt_obj.dactylKeyname = keyname;
if (/^u[0-9a-f]+$/.test(keyname))
keyname = String.fromCharCode(parseInt(keyname.substr(1), 16));
if (keyname && (unknownOk || keyname.length == 1 || /mouse$/.test(keyname) ||
- this.key_code[keyname] || Set.has(this.pseudoKeys, keyname))) {
- evt_obj.globKey ="*" in modifier;
- evt_obj.ctrlKey ="C" in modifier;
- evt_obj.altKey ="A" in modifier;
- evt_obj.shiftKey ="S" in modifier;
- evt_obj.metaKey ="M" in modifier || "⌘" in modifier;
+ this.key_code[keyname] || this.pseudoKeys.has(keyname))) {
+ evt_obj.globKey = modifier.has("*");
+ evt_obj.ctrlKey = modifier.has("C");
+ evt_obj.altKey = modifier.has("A");
+ evt_obj.shiftKey = modifier.has("S");
+ evt_obj.metaKey = modifier.has("M") || modifier.has("⌘");
evt_obj.dactylShift = evt_obj.shiftKey;
if (keyname.length == 1) { // normal characters
evt_obj.charCode = keyname.charCodeAt(0);
evt_obj.keyCode = this.key_code[keyname.toLowerCase()];
}
- else if (Set.has(this.pseudoKeys, keyname)) {
+ else if (this.pseudoKeys.has(keyname)) {
evt_obj.dactylString = "<" + this.key_key[keyname] + ">";
}
else if (/mouse$/.test(keyname)) { // mouse events
- evt_obj.type = (/2-/.test(modifier) ? "dblclick" : "click");
+ evt_obj.type = (modifier.has("2") ? "dblclick" : "click");
evt_obj.button = ["leftmouse", "middlemouse", "rightmouse"].indexOf(keyname);
delete evt_obj.keyCode;
delete evt_obj.charCode;
* @param {Node} target The DOM node to which to dispatch the event.
* @param {Event} event The event to dispatch.
*/
- dispatch: Class.Memoize(function ()
- config.haveGecko("2b")
- ? function dispatch(target, event, extra) {
- try {
- this.feedingEvent = extra;
-
- if (target instanceof Ci.nsIDOMElement)
- // This causes a crash on Gecko<2.0, it seems.
- return (target.ownerDocument || target.document || target).defaultView
- .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
- .dispatchDOMEventViaPresShell(target, event, true);
- else {
- target.dispatchEvent(event);
- return !event.defaultPrevented;
- }
- }
- catch (e) {
- util.reportError(e);
- }
- finally {
- this.feedingEvent = null;
- }
+ dispatch: function dispatch(target, event, extra) {
+ try {
+ this.feedingEvent = extra;
+
+ if (target instanceof Ci.nsIDOMElement)
+ return (target.ownerDocument || target.document || target).defaultView
+ .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
+ .dispatchDOMEventViaPresShell(target, event, true);
+ else {
+ target.dispatchEvent(event);
+ return !event.defaultPrevented;
}
- : function dispatch(target, event, extra) {
- try {
- this.feedingEvent = extra;
- target.dispatchEvent(update(event, extra));
- }
- finally {
- this.feedingEvent = null;
- }
- })
+ }
+ catch (e) {
+ util.reportError(e);
+ }
+ finally {
+ this.feedingEvent = null;
+ }
+ }
}),
createContents: Class.Memoize(() => services.has("dactyl") && services.dactyl.createContents
* The set of input element type attribute values that mark the element as
* an editable field.
*/
- editableInputs: Set(["date", "datetime", "datetime-local", "email", "file",
- "month", "number", "password", "range", "search",
- "tel", "text", "time", "url", "week"]),
+ editableInputs: RealSet(["date", "datetime", "datetime-local", "email", "file",
+ "month", "number", "password", "range", "search",
+ "tel", "text", "time", "url", "week"]),
/**
* Converts a given DOM Node, Range, or Selection to a string. If
* @returns {boolean} True when the patterns are all valid.
*/
validateMatcher: function validateMatcher(list) {
- return this.testValues(list, DOM.closure.testMatcher);
+ return this.testValues(list, DOM.bound.testMatcher);
},
testMatcher: function testMatcher(value) {
return str.replace(regexp, m => map[m]);
},
- /**
- * Converts an E4X XML literal to a DOM node. Any attribute named
- * highlight is present, it is transformed into dactyl:highlight,
- * and the named highlight groups are guaranteed to be loaded.
- *
- * @param {Node} node
- * @param {Document} doc
- * @param {Object} nodes If present, nodes with the "key" attribute are
- * stored here, keyed to the value thereof.
- * @returns {Node}
- */
- fromXML: deprecated("DOM.fromJSON", { get: function fromXML()
- prefs.get("javascript.options.xml.chrome") !== false
- && require("dom-e4x").fromXML }),
-
fromJSON: update(function fromJSON(xml, doc, nodes, namespaces) {
if (!doc)
doc = document;
if (isinstance(args, ["String", "Number", "Boolean", _]))
return doc.createTextNode(args);
- if (isXML(args))
- return DOM.fromXML(args, doc, nodes);
if (isObject(args) && "toDOM" in args)
return args.toDOM(doc, namespaces, nodes);
if (args instanceof Ci.nsIDOMNode)
toPrettyXML: function toPrettyXML(xml, asXML, indent, namespaces) {
const INDENT = indent || " ";
- const EMPTY = Set("area base basefont br col frame hr img input isindex link meta param"
+ const EMPTY = RealSet("area base basefont br col frame hr img input isindex link meta param"
.split(" "));
function namespaced(namespaces, namespace, localName) {
return indent +
DOM.escapeHTML(String(args), true);
- if (isXML(args))
- return indent +
- args.toXMLString()
- .replace(/^/m, indent);
-
if (isObject(args) && "toDOM" in args)
return indent +
services.XMLSerializer()
let res = [indent, "<", name];
for (let [key, val] in Iterator(attr)) {
- if (Set.has(skipAttr, key))
+ if (hasOwnProperty(skipAttr, key))
continue;
let vals = parseNamespace(key);
'="', DOM.escapeHTML(val), '"');
}
- if ((vals[0] || namespaces[""]) == String(XHTML) && Set.has(EMPTY, vals[1])
+ if ((vals[0] || namespaces[""]) == String(XHTML) && EMPTY.has(vals[1])
|| asXML && !args.length)
res.push("/>");
else {
Object.keys(DOM.Event.types).forEach(function (event) {
let name = event.replace(/-(.)/g, (m, m1) => m1.toUpperCase());
- if (!Set.has(DOM.prototype, name))
+ if (!hasOwnProperty(DOM.prototype, name))
DOM.prototype[name] =
function _event(arg, extra) {
return this[callable(arg) ? "listen" : "dispatch"](event, arg, extra);
-// Copyright (c) 2011-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2011-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
});
lazyRequire("overlay", ["overlay"]);
+lazyRequire("promises", ["Task", "promises"]);
-Cu.import("resource://gre/modules/DownloadUtils.jsm", this);
+lazyRequire("resource://gre/modules/Downloads.jsm", ["Downloads"]);
+lazyRequire("resource://gre/modules/DownloadUtils.jsm", ["DownloadUtils"]);
var MAX_LOAD_TIME = 10 * 1000;
let prefix = "DOWNLOAD_";
var states = iter([v, k.slice(prefix.length).toLowerCase()]
for ([k, v] in Iterator(Ci.nsIDownloadManager))
- if (k.indexOf(prefix) == 0))
+ if (k.startsWith(prefix)))
.toObject();
var Download = Class("Download", {
- init: function init(id, list) {
- this.download = services.downloadManager.getDownload(id);
+ init: function init(download, list) {
+ this.download = download;
this.list = list;
this.nodes = {
this.targetFile.path]]],
["td", { highlight: "DownloadState", key: "state" }],
["td", { highlight: "DownloadButtons Buttons" },
- ["a", { highlight: "Button", href: "javascript:0", key: "pause" }, _("download.action.Pause")],
+ ["a", { highlight: "Button", href: "javascript:0", key: "stop" }, _("download.action.Stop")],
["a", { highlight: "Button", href: "javascript:0", key: "remove" }, _("download.action.Remove")],
["a", { highlight: "Button", href: "javascript:0", key: "resume" }, _("download.action.Resume")],
- ["a", { highlight: "Button", href: "javascript:0", key: "retry" }, _("download.action.Retry")],
- ["a", { highlight: "Button", href: "javascript:0", key: "cancel" }, _("download.action.Cancel")],
["a", { highlight: "Button", href: "javascript:0", key: "delete" }, _("download.action.Delete")]],
["td", { highlight: "DownloadProgress", key: "progress" },
["span", { highlight: "DownloadProgressHave", key: "progressHave" }],
["td", { highlight: "DownloadSpeed", key: "speed" }],
["td", { highlight: "DownloadTime", key: "time" }],
["td", {},
- ["a", { highlight: "DownloadSource", key: "source", href: this.source.spec },
- this.source.spec]]],
+ ["a", { highlight: "DownloadSource", key: "source", href: this.source.url },
+ this.source.url]]],
this.list.document, this.nodes);
this.nodes.launch.addEventListener("click", (event) => {
return this;
},
+ get active() !this.stopped,
+
+ get targetFile() File(this.download.target.path),
+
+ get displayName() this.targetFile.leafName,
+
get status() states[this.state],
inState: function inState(states) states.indexOf(this.status) >= 0,
- get alive() this.inState(["downloading", "notstarted", "paused", "queued", "scanning"]),
-
allowedCommands: Class.Memoize(function () let (self = this) ({
- get cancel() self.cancelable && self.inState(["downloading", "paused", "starting"]),
- get delete() !this.cancel && self.targetFile.exists(),
- get launch() self.targetFile.exists() && self.inState(["finished"]),
- get pause() self.inState(["downloading"]),
- get remove() self.inState(["blocked_parental", "blocked_policy",
- "canceled", "dirty", "failed", "finished"]),
- get resume() self.resumable && self.inState(["paused"]),
- get retry() self.inState(["canceled", "failed"])
+ get delete() !self.active && (self.targetFile.exists() || self.hasPartialData),
+ get launch() self.targetFile.exists() && self.succeeded,
+ get stop() self.active,
+ get remove() !self.active,
+ get resume() self.canceled
})),
command: function command(name) {
- util.assert(Set.has(this.allowedCommands, name), _("download.unknownCommand"));
+ util.assert(hasOwnProperty(this.allowedCommands, name), _("download.unknownCommand"));
util.assert(this.allowedCommands[name], _("download.commandNotAllowed"));
- if (Set.has(this.commands, name))
+ if (hasOwnProperty(this.commands, name))
this.commands[name].call(this);
- else
- services.downloadManager[name + "Download"](this.id);
},
commands: {
- delete: function delete_() {
- this.targetFile.remove(false);
+ delete: promises.task(function delete_() {
+ if (this.hasPartialData)
+ yield this.removePartialData();
+ else if (this.targetFile.exists())
+ this.targetFile.remove(false);
this.updateStatus();
- },
+ }),
launch: function launch() {
// Behavior mimics that of the builtin Download Manager.
function action() {
});
else
action.call(this);
- }
+ },
+ resume: function resume() {
+ this.download.start();
+ },
+ remove: promises.task(function remove() {
+ yield this.list.list.remove(this.download);
+ yield this.download.finalize(true);
+ }),
+ stop: function stop() {
+ this.download.cancel();
+ },
},
_compare: {
- active: (a, b) => a.alive - b.alive,
+ active: (a, b) => a.active - b.active,
complete: (a, b) => a.percentComplete - b.percentComplete,
- date: (a, b) => a.startTime - b.startTime,
+ date: (a, b) => a.startTime - b.startTime,
filename: (a, b) => String.localeCompare(a.targetFile.leafName, b.targetFile.leafName),
- size: (a, b) => a.size - b.size,
- speed: (a, b) => a.speed - b.speed,
- time: (a, b) => a.timeRemaining - b.timeRemaining,
- url: (a, b) => String.localeCompare(a.source.spec, b.source.spec)
+ size: (a, b) => a.totalBytes - b.totalBytes,
+ speed: (a, b) => a.speed - b.speed,
+ time: (a, b) => a.timeRemaining - b.timeRemaining,
+ url: (a, b) => String.localeCompare(a.source.url, b.source.url)
},
compare: function compare(other) values(this.list.sortOrder).map(function (order) {
let val = this._compare[order.substr(1)](this, other);
return (order[0] == "-") ? -val : val;
- }, this).nth(util.identity, 0) || 0,
+ }, this).find(util.identity) || 0,
timeRemaining: Infinity,
updateProgress: function updateProgress() {
let self = this.__proto__;
- if (this.amountTransferred === this.size) {
+ if (!this.active) {
this.nodes.speed.textContent = "";
this.nodes.time.textContent = "";
}
else {
this.nodes.speed.textContent = util.formatBytes(this.speed, 1, true) + "/s";
- if (this.speed == 0 || this.size == 0)
+ if (this.speed == 0 || !this.hasProgress)
this.nodes.time.textContent = _("download.unknown");
else {
- let seconds = (this.size - this.amountTransferred) / this.speed;
+ let seconds = (this.totalBytes - this.currentBytes) / this.speed;
[, self.timeRemaining] = DownloadUtils.getTimeLeft(seconds, this.timeRemaining);
if (this.timeRemaining)
this.nodes.time.textContent = util.formatSeconds(this.timeRemaining);
}
}
- let total = this.nodes.progressTotal.textContent = this.size || !this.nActive ? util.formatBytes(this.size, 1, true)
- : _("download.unknown");
+ let total = this.nodes.progressTotal.textContent =
+ this.hasProgress && (this.totalBytes || !this.nActive)
+ ? util.formatBytes(this.totalBytes, 1, true)
+ : _("download.unknown");
+
let suffix = RegExp(/( [a-z]+)?$/i.exec(total)[0] + "$");
- this.nodes.progressHave.textContent = util.formatBytes(this.amountTransferred, 1, true).replace(suffix, "");
+ this.nodes.progressHave.textContent = util.formatBytes(this.currentBytes, 1, true).replace(suffix, "");
- this.nodes.percent.textContent = this.size ? Math.round(this.amountTransferred * 100 / this.size) + "%" : "";
+ this.nodes.percent.textContent = this.hasProgress ? this.progress + "%" : "";
},
updateStatus: function updateStatus() {
- this.nodes.row[this.alive ? "setAttribute" : "removeAttribute"]("active", "true");
+ this.nodes.row[this.active ? "setAttribute" : "removeAttribute"]("active", "true");
this.nodes.row.setAttribute("status", this.status);
this.nodes.state.textContent = util.capitalize(this.status);
this.updateProgress();
}
});
-Object.keys(XPCOMShim([Ci.nsIDownload])).forEach(function (key) {
- if (!(key in Download.prototype))
- Object.defineProperty(Download.prototype, key, {
- get: function get() this.download[key],
- set: function set(val) this.download[key] = val,
- configurable: true
- });
-});
var DownloadList = Class("DownloadList",
XPCOM([Ci.nsIDownloadProgressListener,
this.nodes = {
commandTarget: this
};
- this.downloads = {};
+ this.downloads = Map();
},
cleanup: function cleanup() {
- this.observe.unregister();
- services.downloadManager.removeListener(this);
+ if (this.list)
+ this.list.removeView(this);
+ this.dead = true;
},
message: Class.Memoize(function () {
this.index = Array.indexOf(this.nodes.list.childNodes,
this.nodes.head);
- let start = Date.now();
- for (let row in iter(services.downloadManager.DBConnection
- .createStatement("SELECT id FROM moz_downloads"))) {
- if (Date.now() - start > MAX_LOAD_TIME) {
- util.dactyl.warn(_("download.givingUpAfter", (Date.now() - start) / 1000));
- break;
+ Task.spawn(function () {
+ this.list = yield Downloads.getList(Downloads.ALL);
+
+ let start = Date.now();
+ for (let download of yield this.list.getAll()) {
+ if (Date.now() - start > MAX_LOAD_TIME) {
+ util.dactyl.warn(_("download.givingUpAfter", (Date.now() - start) / 1000));
+ break;
+ }
+ this.addDownload(download);
}
- this.addDownload(row.id);
- }
- this.update();
+ this.update();
- util.addObserver(this);
- services.downloadManager.addListener(this);
+ if (!this.dead)
+ this.list.addView(this);
+ }.bind(this));
return this.nodes.list;
}),
- addDownload: function addDownload(id) {
- if (!(id in this.downloads)) {
- let download = Download(id, this);
- if (this.filter && download.displayName.indexOf(this.filter) === -1)
+ addDownload: function addDownload(download) {
+ if (!this.downloads.has(download)) {
+ download = Download(download, this);
+ if (this.filter && !download.displayName.contains(this.filter))
return;
- this.downloads[id] = download;
- let index = values(this.downloads).sort((a, b) => a.compare(b))
- .indexOf(download);
+ this.downloads.set(download.download, download);
+ let index = values(this.downloads).toArray()
+ .sort((a, b) => a.compare(b))
+ .indexOf(download);
this.nodes.list.insertBefore(download.nodes.row,
this.nodes.list.childNodes[index + this.index + 1]);
}
},
- removeDownload: function removeDownload(id) {
- if (id in this.downloads) {
- this.nodes.list.removeChild(this.downloads[id].nodes.row);
- delete this.downloads[id];
+ removeDownload: function removeDownload(download) {
+ if (this.downloads.has(download)) {
+ this.nodes.list.removeChild(this.downloads.get(download).nodes.row);
+ delete this.downloads.delete(download);
}
},
},
allowedCommands: Class.Memoize(function () let (self = this) ({
- get clear() values(self.downloads).some(dl => dl.allowedCommands.remove)
+ get clear() iter(self.downloads.values()).some(dl => dl.allowedCommands.remove)
})),
commands: {
clear: function () {
- services.downloadManager.cleanUp();
+ this.list.removeFinished();
}
},
sort: function sort() {
- let list = values(this.downloads).sort((a, b) => a.compare(b));
+ let list = iter(this.downloads.values()).sort((a, b) => a.compare(b));
for (let [i, download] in iter(list))
if (this.nodes.list.childNodes[i + 1] != download.nodes.row)
timeRemaining: Infinity,
updateProgress: function updateProgress() {
- let downloads = values(this.downloads).toArray();
- let active = downloads.filter(d => d.alive);
+ let downloads = iter(this.downloads.values()).toArray();
+ let active = downloads.filter(d => d.active);
let self = Object.create(this);
- for (let prop in values(["amountTransferred", "size", "speed", "timeRemaining"]))
+ for (let prop in values(["currentBytes", "totalBytes", "speed", "timeRemaining"]))
this[prop] = active.reduce((acc, dl) => dl[prop] + acc, 0);
+ this.hasProgress = active.every(d => d.hasProgress);
+ this.progress = Math.round((this.currentBytes / this.totalBytes) * 100);
+ this.nActive = active.length;
+
Download.prototype.updateProgress.call(self);
- this.nActive = active.length;
if (active.length)
this.nodes.total.textContent = _("download.nActive", active.length);
else for (let key in values(["total", "percent", "speed", "time"]))
this.sort();
},
- observers: {
- "download-manager-remove-download": function (id) {
- if (id == null)
- id = [k for ([k, dl] in iter(this.downloads)) if (dl.allowedCommands.remove)];
- else
- id = [id.QueryInterface(Ci.nsISupportsPRUint32).data];
+ onDownloadAdded: function onDownloadAdded(download) {
+ this.addDownload(download);
- Array.concat(id).map(this.closure.removeDownload);
- this.update();
- }
+ this.modules.mow.resize(false);
+ this.nodes.list.scrollIntoView(false);
},
- onDownloadStateChange: function (state, download) {
- try {
- if (download.id in this.downloads)
- this.downloads[download.id].updateStatus();
- else {
- this.addDownload(download.id);
+ onDownloadRemoved: function onDownloadRemoved(download) {
+ this.removeDownload(download);
+ },
+
+ onDownloadChanged: function onDownloadChanged(download) {
+ if (this.downloads.has(download)) {
+ download = this.downloads.get(download)
+
+ download.updateStatus();
+ download.updateProgress();
- this.modules.mow.resize(false);
- this.nodes.list.scrollIntoView(false);
- }
this.update();
if (this.shouldSort("active"))
this.sort();
}
- catch (e) {
- util.reportError(e);
- }
- },
-
- onProgressChange: function (webProgress, request,
- curProgress, maxProgress,
- curTotalProgress, maxTotalProgress,
- download) {
- try {
- if (download.id in this.downloads)
- this.downloads[download.id].updateProgress();
- this.updateProgress();
- }
- catch (e) {
- util.reportError(e);
- }
}
});
+["canceled",
+ "contentType",
+ "currentBytes",
+ "error",
+ "hasPartialData",
+ "hasProgress",
+ "launchWhenSucceeded",
+ "launcherPath",
+ "progress",
+ "saver",
+ "source",
+ "speed",
+ "startTime",
+ "stopped",
+ "succeeded",
+ "target",
+ "totalBytes",
+ "tryToKeepPartialData"].forEach(key => {
+ if (!(key in Download.prototype))
+ Object.defineProperty(Download.prototype, key, {
+ get: function get() this.download[key],
+ set: function set(val) this.download[key] = val,
+ configurable: true
+ });
+});
+
-var Downloads = Module("downloads", XPCOM(Ci.nsIDownloadProgressListener), {
+var Downloads_ = Module("downloads", XPCOM(Ci.nsIDownloadProgressListener), {
init: function () {
- services.downloadManager.addListener(this);
+ Downloads.getList(Downloads.ALL).then(list => {
+ this.list = list;
+ if (!this.dead)
+ this.list.addView(this);
+ });
},
cleanup: function destroy() {
- services.downloadManager.removeListener(this);
+ if (this.list)
+ this.list.removeView(this);
+ this.dead = true;
+ },
+
+ onDownloadAdded: function onDownloadAdded(download) {
},
- onDownloadStateChange: function (state, download) {
- if (download.state == services.downloadManager.DOWNLOAD_FINISHED) {
- let url = download.source.spec;
- let title = download.displayName;
- let file = download.targetFile.path;
- let size = download.size;
+ onDownloadRemoved: function onDownloadRemoved(download) {
+ },
+
+ onDownloadChanged: function onDownloadChanged(download) {
+ if (download.succeeded) {
+ let target = File(download.target.path);
+
+ let url = download.source.url;
+ let title = target.leafName;
+ let file = target.path;
+ let size = download.totalBytes;
overlay.modules.forEach(function (modules) {
modules.dactyl.echomsg({ domains: [util.getHost(url)], message: _("io.downloadFinished", title, file) },
commands.add(["dlc[lear]"],
"Clear completed downloads",
- function (args) { services.downloadManager.cleanUp(); });
+ function (args) { downloads.list.removeFinished(); });
},
options: function initOptions(dactyl, modules, window) {
const { options } = modules;
},
completer: function (context, extra) {
- let seen = Set.has(Set(extra.values.map(val => val.substr(1))));
+ let seen = RealSet(extra.values.map(val => val.substr(1)));
- context.completions = iter(this.values).filter(([k, v]) => !seen(k))
+ context.completions = iter(this.values).filter(([k, v]) => !seen.has(k))
.map(([k, v]) => [["+" + k, [v, " (", _("sort.ascending"), ")"].join("")],
["-" + k, [v, " (", _("sort.descending"), ")"].join("")]])
.flatten().array;
has: function () Array.some(arguments, val => this.value.some(v => v.substr(1) == val)),
validator: function (value) {
- let seen = {};
- return value.every(val => /^[+-]/.test(val) && Set.has(this.values, val.substr(1))
- && !Set.add(seen, val.substr(1)))
+ let seen = RealSet();
+ return value.every(val => /^[+-]/.test(val) && hasOwnProperty(this.values, val.substr(1))
+ && !seen.add(val.substr(1)))
&& value.length;
}
});
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
get prompt() this.mode === modules.modes.FIND_BACKWARD ? "?" : "/",
- get onCancel() modules.rangefinder.closure.onCancel,
- get onChange() modules.rangefinder.closure.onChange,
- get onHistory() modules.rangefinder.closure.onHistory,
- get onSubmit() modules.rangefinder.closure.onSubmit
+ get onCancel() modules.rangefinder.bound.onCancel,
+ get onChange() modules.rangefinder.bound.onChange,
+ get onHistory() modules.rangefinder.bound.onHistory,
+ get onSubmit() modules.rangefinder.bound.onSubmit
});
},
mappings: function initMappings(dactyl, modules, window) {
if (!this.matchCase)
pattern = pattern.toLowerCase();
- if (!again && (pattern === "" || pattern.indexOf(this.lastString) !== 0 || this.backward)) {
+ if (!again && (pattern === "" || !pattern.startsWith(this.lastString) || this.backward)) {
if (!private_)
this.range.deselect();
if (pattern === "")
addListeners: function addListeners() {
for (let range in array.iterValues(this.ranges))
- range.window.addEventListener("unload", this.closure.onUnload, true);
+ range.window.addEventListener("unload", this.bound.onUnload, true);
},
purgeListeners: function purgeListeners() {
for (let range in array.iterValues(this.ranges))
try {
- range.window.removeEventListener("unload", this.closure.onUnload, true);
+ range.window.removeEventListener("unload", this.bound.onUnload, true);
}
catch (e if e.result === Cr.NS_ERROR_FAILURE) {}
},
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
["toc", { start: "2" }],
body]);
- });
+ }, true);
},
initialize: function initialize() {
* @returns {string}
*/
findHelp: function (topic, consolidated) {
- if (!consolidated && Set.has(help.files, topic))
+ if (!consolidated && hasOwnProperty(help.files, topic))
return topic;
let items = modules.completion._runCompleter("help", topic, null, !!consolidated).items;
let partialMatch = null;
if (!topic) {
let helpFile = consolidated ? "all" : modules.options["helpfile"];
- if (Set.has(help.files, helpFile))
+ if (hasOwnProperty(help.files, helpFile))
dactyl.open("dactyl://help/" + helpFile, { from: "help" });
else
dactyl.echomsg(_("help.noFile", helpFile.quote()));
addURIEntry(file, "data:text/plain;charset=UTF-8," + encodeURI(data));
}
- let empty = Set("area base basefont br col frame hr img input isindex link meta param"
+ let empty = RealSet("area base basefont br col frame hr img input isindex link meta param"
.split(" "));
function fix(node) {
switch (node.nodeType) {
for (let { name, value } in array.iterValues(node.attributes)) {
if (name == "dactyl:highlight") {
- Set.add(styles, value);
+ styles.add(value);
name = "class";
value = "hl-" + value;
}
if (name == "href") {
value = node.href || value;
- if (value.indexOf("dactyl://help-tag/") == 0) {
+ if (value.startsWith("dactyl://help-tag/")) {
try {
let uri = services.io.newChannel(value, null, null).originalURI;
value = uri.spec == value ? "javascript:;" : uri.path.substr(1);
data.push(" ", name, '="', DOM.escapeHTML(value), '"');
}
- if (node.localName in empty)
+ if (empty.has(node.localName))
data.push(" />");
else {
data.push(">");
let { buffer, content, events } = modules;
let chromeFiles = {};
- let styles = {};
+ let styles = RealSet();
for (let [file, ] in Iterator(help.files)) {
let url = "dactyl://help/" + file;
addDataEntry(file + ".xhtml", data.join(""));
}
- let data = [h for (h in highlight) if (Set.has(styles, h.class) || /^Help/.test(h.class))]
+ let data = [h for (h in highlight) if (styles.has(h.class) || /^Help/.test(h.class))]
.map(h => h.selector
.replace(/^\[.*?=(.*?)\]/, ".hl-$1")
.replace(/html\|/g, "") + "\t" + "{" + h.cssText + "}")
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
if (/^[[>+: ]/.test(args[1]))
obj.selector = this.selector(obj.class) + args[1];
else if (args[1])
- obj.selector = this.selector(args[1]);
+ obj.selector = this.selector(args[1].replace(/^,/, ""));
if (old && old.value != old.defaultValue)
obj.value = old.value;
obj.style.enabled = true;
else
this.loaded.__defineSetter__(obj.class, function () {
- delete this[obj.class];
- this[obj.class] = true;
+ Object.defineProperty(this, obj.class, {
+ value: true,
+ configurable: true,
+ enumerable: true,
+ writable: true
+ });
if (obj.class === obj.baseClass)
for (let h in highlight)
node.setAttributeNS(NS, "highlight", group);
let groups = group.split(" ");
- for each (let group in groups)
+ for (let group of groups)
this.loaded[group] = true;
if (applyBindings)
- for each (let group in groups) {
+ for (let group of groups) {
if (applyBindings.bindings && group in applyBindings.bindings)
applyBindings.bindings[group](node, applyBindings);
else if (group in template.bindings)
* If Star is provided, the style is applied as an agent sheet.
*
* The new styles are lazily activated unless Bang or *eager* is
- * provided. See {@link Util#xmlToDom}.
+ * provided.
*
* @param {string} css The rules to load. See {@link Highlights#css}.
* @param {boolean} eager When true, load all provided rules immediately.
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2012 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
-// Some code based on Venkman
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
lazyRequire("config", ["config"]);
lazyRequire("contexts", ["Contexts", "contexts"]);
+lazyRequire("promises", ["Promise"]);
lazyRequire("storage", ["File", "storage"]);
lazyRequire("styles", ["styles"]);
lazyRequire("template", ["template"]);
this._oldcwd = null;
this._lastRunCommand = ""; // updated whenever the users runs a command with :!
- this._scriptNames = [];
+ this._scriptNames = RealSet();
},
CommandFileMode: Class("CommandFileMode", modules.CommandMode, {
else if (/\.js$/.test(filename)) {
try {
var context = contexts.Script(file, params.group);
- if (Set.has(this._scriptNames, file.path))
+ if (this._scriptNames.has(file.path))
util.flushCache();
dactyl.loadScript(uri.spec, context);
dactyl.triggerObserver("io.source", context, file, file.lastModifiedTime);
}
- Set.add(this._scriptNames, file.path);
+ this._scriptNames.add(file.path);
dactyl.echomsg(_("io.sourcingEnd", filename.quote()), 2);
dactyl.log(_("dactyl.sourced", filename), 3);
* @default ""
* @returns {File}
*/
- createTempFile: function createTempFile(ext = "txt", label = "") {
+ createTempFile: function createTempFile(ext="txt", label="") {
let file = services.directory.get("TmpD", Ci.nsIFile);
file.append(config.name + label + "." + ext);
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, octal(666));
let process = services.Process(file.file);
process.run(false, args.map(String), args.length);
- try {
- if (callable(blocking))
- var timer = services.Timer(
- function () {
- if (!process.isRunning) {
- timer.cancel();
- util.trapErrors(blocking, self, process.exitValue);
- }
- },
- 100, services.Timer.TYPE_REPEATING_SLACK);
- else if (blocking)
- while (process.isRunning)
- util.threadYield(false, true);
- }
- catch (e) {
- process.kill();
- throw e;
+
+ let deferred = Promise.defer();
+
+ if (callable(blocking))
+ // Deprecated.
+ deferred.promise.then(blocking);
+ else if (blocking) {
+ // Deprecated?
+ while (process.isRunning)
+ util.threadYield(false, true);
+ return process.exitValue;
}
- return process.exitValue;
+ let timer = services.Timer(
+ function () {
+ if (!process.isRunning) {
+ timer.cancel();
+ deferred.resolve(process.exitValue);
+ }
+ },
+ 100, services.Timer.TYPE_REPEATING_SLACK);
+
+ return deferred.promise;
},
// TODO: when https://bugzilla.mozilla.org/show_bug.cgi?id=68702 is
system: function system(command, input, callback) {
util.dactyl.echomsg(_("io.callingShell", command), 4);
- let { shellEscape } = util.closure;
+ let { shellEscape } = util.bound;
return this.withTempFiles(function (stdin, stdout, cmd) {
if (input instanceof File)
commands.add(["scrip[tnames]"],
"List all sourced script names",
function () {
- let names = Object.keys(io._scriptNames);
+ let names = [k for (k of io._scriptNames)];
if (!names.length)
dactyl.echomsg(_("command.scriptnames.none"));
else
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
lazyInit: true,
- newContext: function () this.modules.newContext(this.modules.userContext, true, "Dactyl JS Temp Context"),
+ newContext: function () this.modules.newContext(this.modules.userContext, false,
+ "Dactyl JS Temp Context"),
completers: Class.Memoize(() => Object.create(JavaScript.completers)),
if (obj == null)
return;
- let seen = isinstance(obj, ["Sandbox"]) ? Set(JavaScript.magicalNames) : {};
+ let seen = RealSet(isinstance(obj, ["Sandbox"]) ? JavaScript.magicalNames : []);
let globals = values(toplevel && this.window === obj ? this.globalNames : []);
if (toplevel && isObject(obj) && "wrappedJSObject" in obj)
- if (!Set.add(seen, "wrappedJSObject"))
+ if (!seen.add("wrappedJSObject"))
yield "wrappedJSObject";
- for (let key in iter(globals, properties(obj, !toplevel, true)))
- if (!Set.add(seen, key))
+ for (let key in iter(globals, properties(obj, !toplevel)))
+ if (!seen.add(key))
yield key;
// Properties aren't visible in an XPCNativeWrapper until
// they're accessed.
- for (let key in properties(this.getKey(obj, "wrappedJSObject"), !toplevel, true))
+ for (let key in properties(this.getKey(obj, "wrappedJSObject"),
+ !toplevel))
try {
- if (key in obj && !Set.has(seen, key))
+ if (key in obj && !seen.has(key))
yield key;
}
catch (e) {}
_complete: function (objects, key, compl, string, last) {
const self = this;
- if (!getOwnPropertyNames && !services.debugger.isOn && !this.context.message)
- this.context.message = /*L*/"For better completion data, please enable the JavaScript debugger (:set jsdebugger)";
-
let base = this.context.fork("js", this._top.offset);
base.forceAnchored = true;
base.filter = last == null ? key : string;
else {
base.quote = [last, text => util.escapeString(text, ""), last];
if (prefix)
- base.filters.push(item => item.item.indexOf(prefix) === 0);
+ base.filters.push(item => item.item.startsWith(prefix));
}
if (!compl) {
}
this.context.getCache("evalled", Object);
- this.context.getCache("evalContext", this.closure.newContext);
+ this.context.getCache("evalContext", this.bound.newContext);
// Okay, have parse stack. Figure out what we're completing.
"ROCSSPrimitiveValue", "RangeError", "ReferenceError", "RegExp",
"StopIteration", "String", "SyntaxError", "TypeError", "URIError",
"Uint16Array", "Uint32Array", "Uint8Array", "XML", "XMLHttpProgressEvent",
- "XMLList", "XMLSerializer", "XPCNativeWrapper", "XPCSafeJSWrapper",
+ "XMLList", "XMLSerializer", "XPCNativeWrapper",
"XULControllers", "constructor", "decodeURI", "decodeURIComponent",
"encodeURI", "encodeURIComponent", "escape", "eval", "isFinite", "isNaN",
"isXMLName", "parseFloat", "parseInt", "undefined", "unescape", "uneval"
completion: function (dactyl, modules, window) {
const { completion } = modules;
update(modules.completion, {
- get javascript() modules.javascript.closure.complete,
+ get javascript() modules.javascript.bound.complete,
javascriptCompleter: JavaScript // Backwards compatibility
});
},
leave: function leave(params) {
leave.superapply(this, arguments);
- if (!params.push)
+ if (!params.push) {
modes.delay(function () { modes.pop(); });
+ Cu.nukeSandbox(this.context);
+ }
},
updatePrompt: function updatePrompt() {
-// Copyright (c) 2009-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2009-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
var BASE = "resource://dactyl-content/";
+var global = this;
+
/**
* @class ModuleBase
* The base class for all modules.
Module.list = [];
Module.constructors = {};
- const create = window.Object.create.bind(window.Object);
+ function newContext(proto, normal, name) {
+ if (normal)
+ return create(proto);
+
+ sandbox = Components.utils.Sandbox(window, { sandboxPrototype: proto || modules,
+ sandboxName: name || ("Dactyl Sandbox " + ++_id),
+ wantXrays: true });
+
+ // Hack:
+ // sandbox.Object = jsmodules.Object;
+ sandbox.File = global.File;
+ sandbox.Math = global.Math;
+ sandbox.Set = global.Set;
+ return sandbox;
+ };
+
const BASES = [BASE, "resource://dactyl-local-content/"];
- jsmodules = Cu.createObjectIn(window);
+ let proxyCache = {};
+ if (config.haveGecko(29))
+ var proxy = new Proxy(window, {
+ get: function window_get(target, prop) {
+ // `in`, not `hasOwnProperty`, because we want to return
+ // unbound methods in `Object.prototype`
+ if (prop in proxyCache)
+ return proxyCache[prop];
+
+ let p = target[prop];
+ if (callable(p))
+ return proxyCache[prop] = p.bind(target);
+
+ return p;
+ },
+
+ set: function window_set(target, prop, val) {
+ return target[prop] = val;
+ }
+ });
+ else {
+ // Bug 814892
+ let o = {};
+ // Oh, the brokenness... See bug 793210
+ Object.preventExtensions(o);
+ proxy = new Proxy(o, {
+ get: function window_get(target, prop) {
+ // `in`, not `hasOwnProperty`, because we want to return
+ // unbound methods in `Object.prototype`
+ if (prop in proxyCache)
+ return proxyCache[prop];
+
+ let p = window[prop];
+ if (callable(p))
+ return proxyCache[prop] = p.bind(window);
+
+ return p;
+ },
+
+ set: function window_set(target, prop, val) {
+ return window[prop] = val;
+ },
+
+ getOwnPropertyDescriptor: function (target, prop) Object.getOwnPropertyDescriptor(window, prop),
+ getOwnPropertyNames: function (target, prop) Object.getOwnPropertyNames(window),
+ defineProperty: function (target, prop, desc) Object.defineProperty(window, prop, desc),
+ deleteProperty: function (target, prop) { delete window[prop]; },
+ has: function (target, prop) prop in window,
+ hasOwn: function (target, prop) hasOwnProperty(window, prop),
+ enumerate: function (target) (p for (p in window)),
+ iterate: function (target) (p for (p of window))
+ });
+ }
+
+ var jsmodules = newContext(proxy, false, "Dactyl `jsmodules`");
jsmodules.NAME = "jsmodules";
+
+ const create = bind("create", jsmodules.Object);
+
const modules = update(create(jsmodules), {
yes_i_know_i_should_not_report_errors_in_these_branches_thanks: [],
jsmodules: jsmodules,
- get content() this.config.browser.contentWindow || window.content,
-
- window: window,
-
Module: Module,
load: function load(script) {
}
},
- newContext: function newContext(proto, normal, name) {
- if (normal)
- return create(proto);
-
- if (services.has("dactyl") && services.dactyl.createGlobal)
- var sandbox = services.dactyl.createGlobal();
- else
- sandbox = Components.utils.Sandbox(window, { sandboxPrototype: proto || modules,
- sandboxName: name || ("Dactyl Sandbox " + ++_id),
- wantXrays: false });
-
- // Hack:
- // sandbox.Object = jsmodules.Object;
- sandbox.File = jsmodules.File;
- sandbox.Math = jsmodules.Math;
- sandbox.__proto__ = proto || modules;
- return sandbox;
- },
+ newContext: newContext,
get ownPropertyValues() array.compact(
Object.getOwnPropertyNames(this)
const modules = Modules(window);
modules.moduleManager = this;
this.modules = modules;
+ this.jsmodules = modules.jsmodules;
window.dactyl = { modules: modules };
this.startTime = Date.now();
this.deferredInit = { load: {} };
- this.seen = {};
- this.loaded = {};
+ this.seen = RealSet();
+ this.loaded = RealSet();
modules.loaded = this.loaded;
this.modules = modules;
},
cleanup: function cleanup(window) {
- overlay.windows = overlay.windows.filter(w => w != window);
+ overlay.windows.delete(window);
+
+ Cu.nukeSandbox(this.jsmodules);
},
unload: function unload(window) {
- for each (let mod in this.modules.moduleList.reverse()) {
+ for (let mod of this.modules.moduleList.reverse()) {
mod.stale = true;
if ("destroy" in mod)
defineModule.loadLog.push("Loaded in " + (Date.now() - this.startTime) + "ms");
- overlay.windows = array.uniq(overlay.windows.concat(window), true);
+ overlay.windows.add(window);
},
loadModule: function loadModule(module, prereq, frame) {
}
try {
- if (Set.has(loaded, module.className))
+ if (loaded.has(module.className))
return;
- if (Set.add(seen, module.className))
+ if (seen.add(module.className))
throw Error("Module dependency loop.");
for (let dep in values(module.requires))
let obj = defineModule.time(module.className, "init", module);
Class.replaceProperty(modules, module.className, obj);
- Set.add(loaded, module.className);
+ loaded.add(module.className);
- if (loaded.dactyl && obj.signals)
+ if (loaded.has("dactyl") && obj.signals)
modules.dactyl.registerObservers(obj);
if (!module.lazyDepends)
let className = mod.className || mod.constructor.className;
- if (!Set.has(init, className)) {
+ if (!hasOwnProperty(init, className)) {
init[className] = function callee() {
function finish() {
this.currentDependency = className;
let { Module, modules } = this.modules;
defineModule.modules.forEach((mod) => {
- let names = Set(Object.keys(mod.INIT));
+ let names = RealSet(Object.keys(mod.INIT));
if ("init" in mod.INIT)
- Set.add(names, "init");
+ names.add("init");
- keys(names).forEach((name) => { this.deferInit(name, mod.INIT, mod); });
+ for (let name of names)
+ this.deferInit(name, mod.INIT, mod);
});
Module.list.forEach((mod) => {
-// Copyright (c) 2011-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2011-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
var Messages = Module("messages", {
- init: function init(name = "messages") {
+ init: function init(name="messages") {
let self = this;
this.name = name;
"resource://dactyl-locale-local/en-US/" + this.name + ".properties"],
true)
.map(services.stringBundle.createBundle)
- .filter(function (bundle) { try { bundle.getSimpleEnumeration(); return true; } catch (e) { return false; } })),
+ .filter(function (bundle) {
+ try {
+ bundle.getSimpleEnumeration();
+ return true;
+ }
+ catch (e) {
+ return false;
+ }
+ })),
iterate: function () {
- let seen = {};
+ let seen = RealSet();
for (let bundle in values(this.bundles))
for (let { key, value } in iter(bundle.getSimpleEnumeration(), Ci.nsIPropertyElement))
- if (!Set.add(seen, key))
+ if (!seen.add(key))
yield [key, value];
},
let { Buffer, commands, hints, io, mappings, modes, options, sanitizer } = overlay.activeModules;
file = io.File(file);
- function properties(base, iter_, prop = "description") iter(function _properties() {
+ function properties(base, iter_, prop="description") iter(function _properties() {
function key(...args) [base, obj.identifier || obj.name].concat(args).join(".").replace(/[\\:=]/g, "\\$&");
for (var obj in iter_) {
return { configurable: true, enumerable: true, value: this.default, writable: true };
*/
- if (!Set.has(obj, "localizedProperties"))
- obj.localizedProperties = { __proto__: obj.localizedProperties };
- obj.localizedProperties[prop] = true;
+ if (!hasOwnProperty(obj, "localizedProperties"))
+ obj.localizedProperties = RealSet(obj.localizedProperties);
+ obj.localizedProperties.add(prop);
obj[_prop] = this.default;
return {
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 by Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
this.globalValue = this.defaultValue;
},
- magicalProperties: Set(["cleanupValue"]),
+ magicalProperties: RealSet(["cleanupValue"]),
/**
* @property {string} This option's description, as shown in :listoptions.
return this.globalValue = this.defaultValue;
},
set globalValue(val) {
- options.store.set(this.name, { value: val, time: Date.now() });
+ options.store.set(this.name,
+ { value: this.parse(this.stringify(val)),
+ time: Date.now() });
},
/**
*/
parse: function parse(value) Option.dequote(value),
+ parseKey: function parseKey(value) value,
+
/**
* Returns *values* packed in the appropriate format for the option type.
*
if ((scope & Option.SCOPE_GLOBAL) && (values == undefined))
values = this.globalValue;
+ if (hasOwnProperty(this, "_value"))
+ values = this._value;
+
if (this.getter)
return util.trapErrors(this.getter, this, values);
*/
if ((scope & Option.SCOPE_GLOBAL) && !skipGlobal)
this.globalValue = newValues;
+ this._value = newValues;
this.hasChanged = true;
this.setFrom = null;
let defaultValue = this._defaultValue;
delete this._defaultValue;
- if (Set.has(this.modules.config.optionDefaults, this.name))
+ if (hasOwnProperty(this.modules.config.optionDefaults, this.name))
defaultValue = this.modules.config.optionDefaults[this.name];
if (defaultValue == null && this.getter)
}, this))
},
+ parseKey: {
+ number: Number,
+ boolean: function boolean(value) value == "true" || value == true ? true : false,
+ },
+
testValues: {
regexpmap: function regexpmap(vals, validator) vals.every(re => validator(re.result)),
get sitemap() this.regexpmap,
values = Array.concat(values);
function uniq(ary) {
- let seen = {};
- return ary.filter(elem => !Set.add(seen, elem));
+ let seen = RealSet();
+ return ary.filter(elem => !seen.add(elem));
}
switch (operator) {
// NOTE: Vim doesn't prepend if there's a match in the current value
return uniq(Array.concat(values, this.value), true);
case "-":
- return this.value.filter(function (item) !Set.has(this, item), Set(values));
+ return this.value.filter(function (item) !this.has(item), RealSet(values));
case "=":
if (invert) {
- let keepValues = this.value.filter(function (item) !Set.has(this, item), Set(values));
- let addValues = values.filter(function (item) !Set.has(this, item), Set(this.value));
+ let keepValues = this.value.filter(function (item) !this.has(item), RealSet(values));
+ let addValues = values.filter(function (item) !this.has(item), RealSet(this.value));
return addValues.concat(keepValues);
}
return values;
if (isObject(vals) && !isArray(vals)) {
let k = values(completions.call(this, { values: {} })).toObject();
let v = values(completions.call(this, { value: "" })).toObject();
- return Object.keys(vals).every(Set.has(k)) && values(vals).every(Set.has(v));
+
+ return Object.keys(vals).every(hasOwnProperty.bind(null, k)) &&
+ values(vals).every(hasOwnProperty.bind(null, v));
}
if (this.values)
acceptable = completions.call(this);
if (isArray(acceptable))
- acceptable = Set(acceptable.map(([k]) => (k)));
+ acceptable = RealSet(acceptable.map(([k]) => k));
+ else
+ acceptable = RealSet(this.parseKey(k)
+ for (k of Object.keys(acceptable)));
if (this.type === "regexpmap" || this.type === "sitemap")
- return Array.concat(vals).every(re => Set.has(acceptable, re.result));
+ return Array.concat(vals).every(re => acceptable.has(re.result));
- return Array.concat(vals).every(Set.has(acceptable));
+ return Array.concat(vals).every(v => acceptable.has(v));
},
types: {}
if (type in Option.parse)
class_.prototype.parse = Option.parse[type];
+ if (type in Option.parseKey)
+ class_.prototype.parseKey = Option.parse[type];
+
if (type in Option.stringify)
class_.prototype.stringify = Option.stringify[type];
init: function init(group) {
init.supercall(this, group);
this.values = {};
- this.has = Set.has(this.values);
+ this.has = v => hasOwnProperty(this.values, v);
},
add: function add(names, description, type, defaultValue, extraInfo) {
opt.set(opt.globalValue, Option.SCOPE_GLOBAL, true);
}, window);
- modules.cache.register("options.dtd", () =>
- util.makeDTD(
- iter(([["option", o.name, "default"].join("."),
- o.type === "string" ? o.defaultValue.replace(/'/g, "''") :
- o.defaultValue === true ? "on" :
- o.defaultValue === false ? "off" : o.stringDefaultValue]
- for (o in self)),
+ modules.cache.register("options.dtd",
+ () => util.makeDTD(
+ iter(([["option", o.name, "default"].join("."),
+ o.type === "string" ? o.defaultValue.replace(/'/g, "''") :
+ o.defaultValue === true ? "on" :
+ o.defaultValue === false ? "off" : o.stringDefaultValue]
+ for (o in self)),
- ([["option", o.name, "type"].join("."), o.type] for (o in self)),
+ ([["option", o.name, "type"].join("."), o.type] for (o in self)),
- config.dtd)));
+ config.dtd)),
+ true);
},
signals: {
let list = [];
function flushList() {
- let names = Set(list.map(opt => opt.option ? opt.option.name : ""));
+ let names = RealSet(list.map(opt => opt.option ? opt.option.name : ""));
if (list.length)
if (list.some(opt => opt.all))
options.list(opt => !(list[0].onlyNonDefault && opt.isDefault),
list[0].scope);
else
- options.list(opt => Set.has(names, opt.name),
+ options.list(opt => names.has(opt.name),
list[0].scope);
list = [];
}
// Fill in the current values if we're removing
if (opt.operator == "-" && isArray(opt.values)) {
- let have = Set([i.text for (i in values(context.allItems.items))]);
+ let have = RealSet((i.text for (i in values(context.allItems.items))));
context = context.fork("current-values", 0);
context.anchored = optcontext.anchored;
context.maxItems = optcontext.maxItems;
- context.filters.push(i => !Set.has(have, i.text));
+ context.filters.push(i => !have.has(i.text));
modules.completion.optionValue(context, opt.name, opt.operator, null,
function (context) {
context.generate = () => option.value.map(o => [o, ""]);
util.assert(scope == "g:" || scope == null,
_("command.let.illegalVar", scope + name));
- util.assert(Set.has(globalVariables, name) || (expr && !op),
+ util.assert(hasOwnProperty(globalVariables, name) || (expr && !op),
_("command.let.undefinedVar", fullName));
if (!expr)
function (args) {
for (let [, name] in args) {
name = name.replace(/^g:/, ""); // throw away the scope prefix
- if (!Set.has(dactyl._globalVariables, name)) {
+ if (!hasOwnProperty(dactyl._globalVariables, name)) {
if (!args.bang)
dactyl.echoerr(_("command.let.noSuch", name));
return;
function val(obj) {
if (isArray(opt.defaultValue)) {
- let val = array.nth(obj, re => (re.key == extra.key),
- 0);
+ let val = [].find.call(obj, re => (re.key == extra.key));
return val && val.result;
}
- if (Set.has(opt.defaultValue, extra.key))
+ if (hasOwnProperty(opt.defaultValue, extra.key))
return obj[extra.key];
}
-// Copyright (c) 2009-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2009-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
target = null;
this.setData(doc, "listeners", listeners.filter(function (args) {
- if (target == null || args[0].get() == target && args[1] == event && args[2].wrapped == callback && args[3] == capture) {
- args[0].get().removeEventListener.apply(args[0].get(), args.slice(1));
+ let elem = args[0].get();
+ if (target == null || elem == target && args[1] == event && args[2].wrapped == callback && args[3] == capture) {
+ elem.removeEventListener.apply(elem, args.slice(1));
return false;
}
- return !args[0].get();
+ return elem;
}));
},
cleanup: function cleanup(reason) {
for (let doc in util.iterDocuments()) {
+ for (let callback in values(this.getData(doc, "cleanup")))
+ util.trapErrors(callback, doc, reason);
+
for (let elem in values(this.getData(doc, "overlayElements")))
if (elem.parentNode)
elem.parentNode.removeChild(elem);
if (getAttr(elem, ns, name) === value)
setAttr(elem, ns, name, orig);
- for (let callback in values(this.getData(doc, "cleanup")))
- util.trapErrors(callback, doc, reason);
-
this.unlisten(doc, true);
delete doc[this.id];
setData: function setData(obj, key, val) {
let data = this.getData(obj);
+ if (val !== undefined)
+ return data[key] = val;
- return data[key] = val;
+ delete data[key];
},
overlayWindow: function overlayWindow(url, fn) {
_loadOverlays: function _loadOverlays(window) {
let overlays = this.getData(window, "overlays");
- for each (let obj in overlay.overlays[window.document.documentURI] || []) {
+ for (let obj of overlay.overlays[window.document.documentURI] || []) {
if (~overlays.indexOf(obj))
continue;
overlays.push(obj);
if (elem = doc.getElementById(String(elem))) {
// Urgh. Hack.
let namespaces;
- if (attrs && !isXML(attrs))
+ if (attrs)
namespaces = iter([k.slice(6), DOM.fromJSON.namespaces[v] || v]
for ([k, v] in Iterator(attrs))
if (/^xmlns(?:$|:)/.test(k))).toObject();
- let node;
- if (isXML(xml))
- node = DOM.fromXML(xml, doc, obj.objects);
- else
- node = DOM.fromJSON(xml, doc, obj.objects, namespaces);
+ let node = DOM.fromJSON(xml, doc, obj.objects, namespaces);
if (!(node instanceof Ci.nsIDOMDocumentFragment))
savedElems.push(node);
fn(elem, node);
- if (isXML(attrs))
- // Evilness and such.
- let (oldAttrs = attrs) {
- attrs = (attr for each (attr in oldAttrs));
- }
-
for (let attr in attrs || []) {
let [ns, localName] = DOM.parseNamespace(attr);
let name = attr;
overrides = update(Object.create(original), overrides);
Object.getOwnPropertyNames(overrides).forEach(function (k) {
- let orig, desc = Object.getOwnPropertyDescriptor(overrides, k);
+ let desc = Object.getOwnPropertyDescriptor(overrides, k);
+
if (desc.value instanceof Class.Property)
desc = desc.value.init(k) || desc.value;
if (k in object) {
- for (let obj = object; obj && !orig; obj = Object.getPrototypeOf(obj))
- if (orig = Object.getOwnPropertyDescriptor(obj, k))
+ for (let obj = object; obj && !orig; obj = Object.getPrototypeOf(obj)) {
+ var orig = Object.getOwnPropertyDescriptor(obj, k);
+ if (orig)
Object.defineProperty(original, k, orig);
+ }
- if (!orig)
- if (orig = Object.getPropertyDescriptor(object, k))
+ if (!orig) {
+ orig = Object.getPropertyDescriptor(object, k);
+ if (orig)
Object.defineProperty(original, k, orig);
+ }
}
// Guard against horrible add-ons that use eval-based monkey
delete desc.writable;
desc.get = function get() value;
desc.set = function set(val) {
- if (!callable(val) || Function.prototype.toString(val).indexOf(sentinel) < 0)
+ if (!callable(val) || !Function.prototype.toString(val).contains(sentinel))
Class.replaceProperty(this, k, val);
else {
let package_ = util.newURI(Components.stack.caller.filename).host;
}, this);
return function unwrap() {
- for each (let k in Object.getOwnPropertyNames(original))
+ for (let k of Object.getOwnPropertyNames(original))
if (Object.getOwnPropertyDescriptor(object, k).configurable)
Object.defineProperty(object, k, Object.getOwnPropertyDescriptor(original, k));
else {
get activeModules() this.activeWindow && this.activeWindow.dactyl.modules,
- get modules() this.windows.map(w => w.dactyl.modules),
+ get modules() [w.dactyl.modules for (w of this.windows)],
/**
* The most recently active dactyl window.
*/
- get activeWindow() this.windows[0],
+ get activeWindow() {
+ let win = this._activeWindow && this._activeWindow.get();
+ return this.windows.has(win) && win;
+ },
- set activeWindow(win) this.windows = [win].concat(this.windows.filter(w => w != win)),
+ set activeWindow(win) this._activeWindow = util.weakReference(win),
/**
* A list of extant dactyl windows.
*/
- windows: Class.Memoize(() => [])
+ windows: Class.Memoize(() => RealSet())
});
endModule();
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
* @param {string} branch The preference name. @optional
*/
resetBranch: function resetBranch(branch) {
- this.getNames(branch).forEach(this.closure.reset);
+ this.getNames(branch).forEach(this.bound.reset);
},
/**
if (observers) {
let value = this.get(data, false);
this._observers[data] = observers.filter(function (callback) {
- if (!callback.get())
+ callback = callback.get();
+ if (!callback)
return false;
- util.trapErrors(callback.get(), null, value);
+ util.trapErrors(callback, null, value);
return true;
});
}
function prefs() {
for (let [, pref] in Iterator(prefArray)) {
let userValue = services.pref.prefHasUserValue(pref);
- if (onlyNonDefault && !userValue || pref.indexOf(filter) == -1)
+ if (onlyNonDefault && !userValue || !pref.contains(filter))
continue;
let value = this.get(pref);
--- /dev/null
+// Copyright (c) 2014 Kris Maglione <maglione.k at Gmail>
+//
+// This work is licensed for reuse under an MIT license. Details are
+// given in the LICENSE.txt file included with this file.
+"use strict";
+
+defineModule("promises", {
+ exports: ["Promise", "Task", "promises"],
+ require: []
+});
+
+lazyRequire("services", ["services"]);
+
+lazyRequire("resource://gre/modules/Promise.jsm", ["Promise"]);
+lazyRequire("resource://gre/modules/Task.jsm", ["Task"]);
+
+function withCallbacks(fn) {
+ return function wrapper(...args) {
+ let deferred = Promise.defer();
+ function resolve(arg) { deferred.resolve(arg); }
+ function reject(arg) { deferred.reject(arg); }
+ fn.apply(this, [[resolve, reject, deferred]].concat(args));
+ return deferred.promise;
+ }
+}
+
+var Promises = Module("Promises", {
+ _cancel: WeakMap(),
+
+ /**
+ * Allows promises to be canceled..
+ *
+ * @param {Promise} promise The promise to cancel.
+ * @param {*} arg Argument to be passed to the cancellation
+ * function.
+ */
+ cancel: function cancel(promise, reason) {
+ let cleanup = this._cancel.get(promise);
+ if (cleanup) {
+ cleanup[0](promise);
+ cleanup[1].reject(reason);
+ }
+ this._cancel.delete(promise);
+ },
+
+ /**
+ * Registers a cleanup function for the given deferred promise.
+ *
+ * @param {Deferred} promise The promise to cancel.
+ * @param {function} fn The cleanup function.
+ */
+ oncancel: function oncancel(deferred, fn) {
+ this._cancel.set(deferred.promise, [fn, deferred]);
+ },
+
+ /**
+ * Returns a promise which resolves after a brief delay.
+ */
+ delay: withCallbacks(function delay([accept]) {
+ let { mainThread } = services.threading;
+ mainThread.dispatch(accept, mainThread.DISPATCH_NORMAL);
+ }),
+
+ /**
+ * Returns a promise which resolves with the given argument.
+ */
+ accept: function fail(arg) {
+ let deferred = Promise.defer();
+ deferred.resolve(arg);
+ return deferred.promise;
+ },
+
+ /**
+ * Returns a promise which fails with the given argument.
+ */
+ fail: function fail(arg) {
+ let deferred = Promise.defer();
+ deferred.reject(arg);
+ return deferred.promise;
+ },
+
+ /**
+ * Returns a promise which resolves after the given number of
+ * milliseconds.
+ *
+ * @param {number} delay The number of milliseconds to wait.
+ */
+ sleep: withCallbacks(function sleep([callback], delay) {
+ this.timeout(callback, delay);
+ }),
+
+ /**
+ * Wraps the given function so that each call spawns a Task.
+ *
+ * @param {function} fn The function to wrap.
+ * @returns {function}
+ */
+ task: function task(fn) {
+ return function task_(...args) {
+ return Task.spawn(fn.bind.apply(fn, [this].concat(args)));
+ }
+ },
+
+ /**
+ * Returns a promise which resolves when the function *test* returns
+ * true, or *timeout* milliseconds have expired.
+ *
+ * @param {function} test The predicate on which to wait.
+ * @param {Number} timeout The maximum number of milliseconds to
+ * wait.
+ * @optional
+ * @param {number} pollInterval The poll interval, in milliseconds.
+ * @default 10
+ */
+ waitFor: withCallbacks(function waitFor([accept, reject], test, timeout=null, pollInterval=10) {
+ let end = timeout && Date.now() + timeout, result;
+
+ let timer = services.Timer(
+ () => {
+ try {
+ var result = test();
+ }
+ catch (e) {
+ timer.cancel();
+ reject(e);
+ }
+ if (result) {
+ timer.cancel();
+ accept(result);
+ }
+ },
+ pollInterval, services.Timer.TYPE_REPEATING_SLACK);
+ }),
+
+ /**
+ * Wraps the given function so that its first argument is an array
+ * of success and failure callbacks which, when called, resolve the
+ * returned promise.
+ *
+ * @param {function} fn The function to wrap.
+ * @returns {Promise}
+ */
+ withCallbacks: withCallbacks,
+});
+
+endModule();
+
+// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript:
-// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
};
function LocaleChannel(pkg, locale, path, orig) {
- for each (let locale in [locale, "en-US"])
- for each (let sep in "-/") {
+ for (let locale of [locale, "en-US"])
+ for (let sep of "-/") {
var channel = Channel(["resource:/", pkg + sep + locale, path].join("/"), orig, true, true);
if (channel)
return channel;
// Copyright (c) 2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2009-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2009-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
// "Allow this site to open popups" ...
services.permissions.removeAll();
// Zoom level, ...
- services.contentPrefs.removeGroupedPrefs();
+ services.contentPrefs.removeAllDomains(null);
}
// "Never remember passwords" ...
- for each (let domain in services.loginManager.getAllDisabledHosts())
+ for (let domain of services.loginManager.getAllDisabledHosts())
if (!host || util.isSubdomain(domain, host))
services.loginManager.setLoginSavingEnabled(host, true);
},
if (!("value" in prop) || !callable(prop.value) && !(k in item))
Object.defineProperty(item, k, prop);
- let names = Set([name].concat(params.contains || []).map(e => "clear-" + e));
+ function getWindow(obj) {
+ obj = Class.objectGlobal(obj);
+ return obj.window || obj;
+ }
+
+ let names = RealSet([name].concat(params.contains || []).map(e => "clear-" + e));
if (params.action)
storage.addObserver("sanitizer",
function (key, event, arg) {
- if (event in names)
+ if (names.has(event))
params.action.apply(params, arg);
},
- Class.objectGlobal(params.action));
+ getWindow(params.action));
if (params.privateEnter || params.privateLeave)
storage.addObserver("private-mode",
if (meth)
meth.call(params);
},
- Class.objectGlobal(params.action));
+ getWindow(params.privateEnter || params.privateLeave));
},
observers: {
UNPERMS: Class.Memoize(function () iter(this.PERMS).map(Array.reverse).toObject()),
COMMANDS: {
- unset: /*L*/"Unset",
- allow: /*L*/"Allowed",
- deny: /*L*/"Denied",
- session: /*L*/"Allowed for the current session",
- list: /*L*/"List all cookies for domain",
- clear: /*L*/"Clear all cookies for domain",
+ "unset": /*L*/"Unset",
+ "allow": /*L*/"Allowed",
+ "deny": /*L*/"Denied",
+ "session": /*L*/"Allowed for the current session",
+ "list": /*L*/"List all cookies for domain",
+ "clear": /*L*/"Clear all cookies for domain",
"clear-persistent": /*L*/"Clear all persistent cookies for domain",
"clear-session": /*L*/"Clear all session cookies for domain"
},
for (let c in iter(services.cookies, Ci.nsICookie2))
if (!host || util.isSubdomain(c.rawHost, host) ||
c.host[0] == "." && c.host.length < host.length
- && host.indexOf(c.host) == host.length - c.host.length)
+ && host.endsWith(c.host))
yield c;
},
if (args.bang)
dactyl.assert(args.length == 0, _("error.trailingCharacters"));
else {
+ dactyl.assert(args.length, _("error.argumentRequired"));
dactyl.assert(opt.validator(args), _("error.invalidArgument"));
opt = { __proto__: opt, value: args.slice() };
}
- let items = Object.keys(sanitizer.itemMap).slice(1).filter(opt.has, opt);
+ let items = Object.keys(sanitizer.itemMap)
+ .slice(1)
+ .filter(opt.has, opt);
function sanitize(items) {
sanitizer.range = range.native;
sanitizer.sanitize(items, range);
}
- if (array.nth(opt.value, i => i == "all" || /^!/.test(i), 0) == "all" && !args["-host"])
+ if ("all" == opt.value.find(i => (i == "all" ||
+ /^!/.test(i)))
+ && !args["-host"])
+
modules.commandline.input(_("sanitize.prompt.deleteAll") + " ",
function (resp) {
if (resp.match(/^y(es)?$/i)) {
completion: function initCompletion(dactyl, modules, window) {
modules.completion.visibleHosts = function completeHosts(context) {
let res = util.visibleHosts(window.content);
- if (context.filter && !res.some(host => host.indexOf(context.filter) >= 0))
+ if (context.filter && !res.some(host => host.contains(context.filter)))
res.push(context.filter);
context.title = ["Domain"];
},
has: function has(val)
- let (res = array.nth(this.value, v => (v == "all" || v.replace(/^!/, "") == val),
- 0))
+ let (res = this.value.find(v => (v == "all" || v.replace(/^!/, "") == val)))
res && !/^!/.test(res),
validator: function (values) values.length &&
- values.every(val => (val === "all" || Set.has(sanitizer.itemMap, val.replace(/^!/, ""))))
+ values.every(val => (val === "all" || hasOwnProperty(sanitizer.itemMap, val.replace(/^!/, ""))))
});
options.add(["sanitizeshutdown", "ss"],
sanitizer.runAtShutdown = false;
else {
sanitizer.runAtShutdown = true;
- let have = Set(value);
+ let have = RealSet(value);
for (let item in values(sanitizer.itemMap))
prefs.set(item.shutdownPref,
- Boolean(Set.has(have, item.name) ^ Set.has(have, "all")));
+ Boolean(have.has(item.name) ^ have.has("all")));
}
return value;
}
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
this.add("clipboardHelper", "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
this.add("commandLineHandler", "@mozilla.org/commandlinehandler/general-startup;1?type=dactyl");
this.add("console", "@mozilla.org/consoleservice;1", "nsIConsoleService");
- this.add("contentPrefs", "@mozilla.org/content-pref/service;1", "nsIContentPrefService");
+ this.add("contentPrefs", "@mozilla.org/content-pref/service;1", ["nsIContentPrefService",
+ "nsIContentPrefService2"]);
this.add("dactyl", "@dactyl.googlecode.com/extra/utils", "dactylIUtils");
this.add("dactyl:", this.PROTOCOL + "dactyl");
this.add("debugger", "@mozilla.org/js/jsd/debugger-service;1", "jsdIDebuggerService");
this.add("mime", "@mozilla.org/mime;1", "nsIMIMEService");
this.add("observer", "@mozilla.org/observer-service;1", "nsIObserverService");
this.add("pref", "@mozilla.org/preferences-service;1", ["nsIPrefBranch2", "nsIPrefService"]);
+ this.add("printSettings", "@mozilla.org/gfx/printsettings-service;1", "nsIPrintSettingsService");
this.add("privateBrowsing", "@mozilla.org/privatebrowsing;1", "nsIPrivateBrowsingService");
this.add("profile", "@mozilla.org/toolkit/profile-service;1", "nsIToolkitProfileService");
this.add("resource:", this.PROTOCOL + "resource", ["nsIProtocolHandler", "nsIResProtocolHandler"]);
function () callable(XPCOMShim(this.interfaces)[this.init]));
this[name] = (function Create() this._create(name, arguments)).bind(this);
- update.apply(null, [this[name]].concat([Ci[i] for each (i in Array.concat(ifaces))]));
+ update.apply(null, [this[name]].concat([Ci[i] for (i of Array.concat(ifaces))]));
return this[name];
},
*
* @param {string} name The service's cache key.
*/
- has: function has(name) Set.has(this.services, name) && this.services[name].class in Cc &&
+ has: function has(name) hasOwnProperty(this.services, name) && this.services[name].class in Cc &&
this.services[name].interfaces.every(iface => iface in Ci)
});
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
defineModule("storage", {
exports: ["File", "Storage", "storage"],
- require: ["services", "util"]
+ require: ["promises", "services", "util"]
});
lazyRequire("config", ["config"]);
lazyRequire("io", ["IO"]);
lazyRequire("overlay", ["overlay"]);
+lazyRequire("resource://gre/modules/osfile.jsm", ["OS"]);
+
var win32 = /^win(32|nt)$/i.test(services.runtime.OS);
var myObject = JSON.parse("{}").constructor;
+var global = Cu.getGlobalForObject(this);
+
var StoreBase = Class("StoreBase", {
OPTIONS: ["privateData", "replacer"],
get serial() JSON.stringify(this._object, this.replacer),
- init: function (name, store, load, options) {
+ init: function init(name, store, load, options) {
this._load = load;
this._options = options;
this.reload();
},
- clone: function (storage) {
+ clone: function clone(storage) {
let store = storage.privateMode ? false : this.store;
let res = this.constructor(this.name, store, this._load, this._options);
res.storage = storage;
return res;
},
+ makeOwn: function makeOwn(val) {
+ if (typeof val != "object")
+ return val;
+ if (Cu.getGlobalForObject(val) == global)
+ return val;
+ return JSON.parse(JSON.stringify(val, this.replacer));
+ },
+
changed: function () { this.timer && this.timer.tell(); },
reload: function reload() {
delete: function delete_() {
delete storage.keys[this.name];
delete storage[this.name];
- storage.infoPath.child(this.name).remove(false);
+ return OS.File.remove(
+ storage.infoPath.child(this.name).path);
},
save: function () { (self.storage || storage)._saveData(this); },
set: function set(index, value, quiet) {
var orig = this._object[index];
- this._object[index] = value;
+ this._object[index] = this.makeOwn(value);
if (!quiet)
this.fireEvent("change", index);
},
push: function push(value) {
- this._object.push(value);
+ this._object.push(this.makeOwn(value));
this.fireEvent("push", this._object.length);
},
},
insert: function insert(value, ord) {
+ value = this.makeOwn(value);
if (ord == 0)
this._object.unshift(value);
else
mutate: function mutate(funcName) {
var _funcName = funcName;
arguments[0] = this._object;
- this._object = Array[_funcName].apply(Array, arguments);
+ this._object = Array[_funcName].apply(Array, arguments)
+ .map(this.makeOwn.bind(this));
this.fireEvent("change", null);
},
},
get: function get(key, default_) {
- return key in this._object ? this._object[key] :
+ return this.has(key) ? this._object[key] :
arguments.length > 1 ? this.set(key, default_) :
undefined;
},
+ has: function has(key) hasOwnProperty(this._object, key),
+
keys: function keys() Object.keys(this._object),
remove: function remove(key) {
set: function set(key, val) {
var defined = key in this._object;
var orig = this._object[key];
- this._object[key] = val;
+ this._object[key] = this.makeOwn(val);
if (!defined)
this.fireEvent("add", key);
else if (orig != val)
}
},
- _saveData: function saveData(obj) {
+ _saveData: promises.task(function saveData(obj) {
if (obj.privateData && storage.privateMode)
return;
- if (obj.store && storage.infoPath)
- storage.infoPath.child(obj.name).write(obj.serial);
- },
+ if (obj.store && storage.infoPath) {
+ var { path } = storage.infoPath.child(obj.name);
+ yield OS.File.makeDir(storage.infoPath.path,
+ { ignoreExisting: true });
+ yield OS.File.writeAtomic(
+ path, obj.serial,
+ { tmpPath: path + ".part" });
+ }
+ }),
storeForSession: function storeForSession(key, val) {
if (val)
this[key].timer.flush();
delete this[key];
delete this.keys[key];
- this.infoPath.child(key).remove(false);
+ return OS.File.remove(
+ this.infoPath.child(key).path);
}
},
- newObject: function newObject(key, constructor, params) {
+ newObject: function newObject(key, constructor, params={}) {
if (params == null || !isObject(params))
throw Error("Invalid argument type");
return this.keys[key];
},
- newMap: function newMap(key, options) {
+ newMap: function newMap(key, options={}) {
return this.newObject(key, ObjectStore, options);
},
- newArray: function newArray(key, options) {
+ newArray: function newArray(key, options={}) {
return this.newObject(key, ArrayStore, update({ type: Array }, options));
},
- addObserver: function addObserver(key, callback, ref) {
- if (ref) {
- let refs = overlay.getData(ref, "storage-refs");
- refs.push(callback);
- var callbackRef = util.weakReference(callback);
- }
- else {
- callbackRef = { get: function () callback };
- }
-
- this.removeDeadObservers();
-
- if (!(key in this.observers))
- this.observers[key] = [];
-
- if (!this.observers[key].some(o => o.callback.get() == callback))
- this.observers[key].push({ ref: ref && Cu.getWeakReference(ref),
- callback: callbackRef });
+ get observerMaps() {
+ yield this.observers;
+ for (let window of overlay.windows)
+ yield overlay.getData(window, "storage-observers", Object);
},
- removeObserver: function (key, callback) {
- this.removeDeadObservers();
+ addObserver: function addObserver(key, callback, window) {
+ var { observers } = this;
+ if (window instanceof Ci.nsIDOMWindow)
+ observers = overlay.getData(window, "storage-observers", Object);
- if (!(key in this.observers))
- return;
+ if (!hasOwnProperty(observers, key))
+ observers[key] = RealSet();
- this.observers[key] = this.observers[key].filter(elem => elem.callback.get() != callback);
- if (this.observers[key].length == 0)
- delete obsevers[key];
+ observers[key].add(callback);
},
- removeDeadObservers: function () {
- function filter(o) {
- if (!o.callback.get())
- return false;
-
- let ref = o.ref && o.ref.get();
- return ref && !ref.closed && overlay.getData(ref, "storage-refs", null);
- }
-
- for (let [key, ary] in Iterator(this.observers)) {
- this.observers[key] = ary = ary.filter(filter);
- if (!ary.length)
- delete this.observers[key];
- }
+ removeObserver: function (key, callback) {
+ for (let observers in this.observerMaps)
+ if (key in observers)
+ observers[key].remove(callback);
},
fireEvent: function fireEvent(key, event, arg) {
- this.removeDeadObservers();
-
- if (key in this.observers)
- // Safe, since we have our own Array object here.
- for each (let observer in this.observers[key])
- observer.callback.get()(key, event, arg);
+ for (let observers in this.observerMaps)
+ for (let observer of observers[key] || [])
+ observer(key, event, arg);
if (key in this.keys && this.keys[key].timer)
this[key].timer.tell();
}
}, {
cleanup: function (dactyl, modules, window) {
- overlay.setData(window, "storage-refs", null);
- this.removeDeadObservers();
+ overlay.setData(window, "storage-callbacks", undefined);
}
});
child: function child() {
let f = this.constructor(this);
for (let [, name] in Iterator(arguments))
- for each (let elem in name.split(File.pathSplit))
+ for (let elem of name.split(File.pathSplit))
f.append(elem);
return f;
},
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
},
cleanup: function cleanup() {
- for (let sheet in values(this.sheets))
- sheet.enabled = false;
+ for (let sheet of this.sheets)
+ util.trapErrors(() => {
+ sheet.enabled = false;
+ });
},
__iterator__: function () Iterator(this.sheets),
*/
add: function add(name, filter, css, agent, lazy) {
- if (!isArray(filter))
+ if (isArray(filter))
+ // Need an array from the same compartment.
+ filter = Array.slice(filter);
+ else
filter = filter.split(",");
+
if (name && name in this.names) {
var sheet = this.names[name];
sheet.agent = agent;
name = null;
}
- if (filter && filter.indexOf(",") > -1)
+ if (filter && filter.contains(","))
return filter.split(",").reduce(
(n, f) => n + this.removeSheet(name, f, index), 0);
update(services["dactyl:"].providers, {
"style": function styleProvider(uri, path) {
let id = parseInt(path);
- if (Set.has(styles.allSheets, id))
+ if (hasOwnProperty(styles.allSheets, id))
return ["text/css", styles.allSheets[id].fullCSS];
return null;
}
},
cleanup: function cleanup() {
- for each (let hive in this.hives)
+ for (let hive of this.hives || [])
util.trapErrors("cleanup", hive);
this.hives = [];
this.user = this.addHive("user", this, true);
},
addHive: function addHive(name, ref, persist) {
- let hive = array.nth(this.hives, h => h.name === name,
- 0);
+ let hive = this.hives.find(h => h.name === name);
if (!hive) {
hive = Hive(name, persist);
this.hives.push(hive);
}, {
append: function (dest, src, sort) {
let props = {};
- for each (let str in [dest, src])
+ for (let str of [dest, src])
for (let prop in Styles.propertyIter(str))
props[prop.name] = prop.value;
return val;
},
- completeSite: function (context, content, group = styles.user) {
+ completeSite: function (context, content, group=styles.user) {
context.anchored = false;
try {
context.fork("current", 0, this, function (context) {
let uris = util.visibleURIs(window.content);
context.compare = modules.CompletionContext.Sort.number;
context.generate = () => args["-group"].sheets;
- context.keys.active = sheet => uris.some(sheet.closure.match);
+ context.keys.active = sheet => uris.some(sheet.bound.match);
context.keys.description = sheet => [sheet.formatSites(uris), ": ", sheet.css.replace("\n", "\\n")];
if (filter)
context.filters.push(({ item }) => filter(item));
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
"click": function onClick(event) {
event.preventDefault();
if (this.commandAllowed) {
- if (Set.has(this.target.commands || {}, this.command))
+ if (hasOwnProperty(this.target.commands || {}, this.command))
this.target.commands[this.command].call(this.target);
else
this.target.command(this.command);
},
get commandAllowed() {
- if (Set.has(this.target.allowedCommands || {}, this.command))
+ if (hasOwnProperty(this.target.allowedCommands || {}, this.command))
return this.target.allowedCommands[this.command];
if ("commandAllowed" in this.target)
return this.target.commandAllowed(this.command);
let obj = params.eventTarget;
let events = obj[this.getAttribute("events") || "events"];
- if (Set.has(events, "input"))
+ if (hasOwnProperty(events, "input"))
events["dactyl-input"] = events["input"];
for (let [event, handler] in Iterator(events))
- node.addEventListener(event, util.wrapCallback(obj.closure(handler), true), false);
+ node.addEventListener(event, util.wrapCallback(handler.bind(obj), true), false);
}
})
},
let res = [];
let n = 0;
- for each (let i in Iterator(iter)) {
+ for (let i in Iterator(iter)) {
let val = func(i, n);
if (val == undefined)
continue;
else if (/^n_/.test(topic))
topic = topic.slice(2);
- if (help.initialized && !Set.has(help.tags, topic))
+ if (help.initialized && !hasOwnProperty(help.tags, topic))
return ["span", { highlight: type || ""}, text || token];
type = type || (/^'.*'$/.test(token) ? "HelpOpt" :
else if (/^n_/.test(topic))
topic = topic.slice(2);
- if (help.initialized && !Set.has(help.tags, topic))
+ if (help.initialized && !hasOwnProperty(help.tags, topic))
return token;
let tag = (/^'.*'$/.test(token) ? "o" :
})(), this[help ? "HelpLink" : "helpLink"]);
},
- // Fixes some strange stack rewinds on NS_ERROR_OUT_OF_MEMORY
- // exceptions that we can't catch.
- stringify: function stringify(arg) {
- if (!callable(arg))
- return String(arg);
-
- try {
- this._sandbox.arg = arg;
- return Cu.evalInSandbox("String(arg)", this._sandbox);
- }
- finally {
- this._sandbox.arg = null;
- }
- },
-
- _sandbox: Class.Memoize(() => Cu.Sandbox(Cu.getGlobalForObject(global),
- { wantXrays: false })),
-
// if "processStrings" is true, any passed strings will be surrounded by " and
// any line breaks are displayed as \n
highlight: function highlight(arg, processStrings, clip, bw) {
// some objects like window.JSON or getBrowsers()._browsers need the try/catch
try {
- let str = this.stringify(arg);
+ let str = String(arg);
if (clip)
str = util.clip(str, clip);
switch (arg == null ? "undefined" : typeof arg) {
["td", { style: style[i] || "" }, d])])];
},
- usage: function usage(iter, format = {}) {
+ usage: function usage(iter, format={}) {
let desc = format.description || (item => this.linkifyHelp(item.description));
let help = format.help || (item => item.name);
let sourceLink = (frame) => {
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2013 Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
defineModule("util", {
exports: ["DOM", "$", "FailedAssertion", "Math", "NS", "Point", "Util", "XBL", "XHTML", "XUL", "util"],
- require: ["dom", "services"]
+ require: ["dom", "promises", "services"]
});
lazyRequire("overlay", ["overlay"]);
},
activeWindow: deprecated("overlay.activeWindow", { get: function activeWindow() overlay.activeWindow }),
- overlayObject: deprecated("overlay.overlayObject", { get: function overlayObject() overlay.closure.overlayObject }),
- overlayWindow: deprecated("overlay.overlayWindow", { get: function overlayWindow() overlay.closure.overlayWindow }),
+ overlayObject: deprecated("overlay.overlayObject", { get: function overlayObject() overlay.bound.overlayObject }),
+ overlayWindow: deprecated("overlay.overlayWindow", { get: function overlayWindow() overlay.bound.overlayWindow }),
compileMatcher: deprecated("DOM.compileMatcher", { get: function compileMatcher() DOM.compileMatcher }),
computedStyle: deprecated("DOM#style", function computedStyle(elem) DOM(elem).style),
parseForm: deprecated("DOM#formData", function parseForm(elem) values(DOM(elem).formData).toArray()),
scrollIntoView: deprecated("DOM#scrollIntoView", function scrollIntoView(elem, alignWithTop) DOM(elem).scrollIntoView(alignWithTop)),
validateMatcher: deprecated("DOM.validateMatcher", { get: function validateMatcher() DOM.validateMatcher }),
- xmlToDom: deprecated("DOM.fromJSON", function xmlToDom() DOM.fromXML.apply(DOM, arguments)),
map: deprecated("iter.map", function map(obj, fn, self) iter(obj).map(fn, self).toArray()),
writeToClipboard: deprecated("dactyl.clipboardWrite", function writeToClipboard(str, verbose) util.dactyl.clipboardWrite(str, verbose)),
readFromClipboard: deprecated("dactyl.clipboardRead", function readFromClipboard() util.dactyl.clipboardRead(false)),
chromePackages: deprecated("config.chromePackages", { get: function chromePackages() config.chromePackages }),
- haveGecko: deprecated("config.haveGecko", { get: function haveGecko() config.closure.haveGecko }),
+ haveGecko: deprecated("config.haveGecko", { get: function haveGecko() config.bound.haveGecko }),
OS: deprecated("config.OS", { get: function OS() config.OS }),
dactyl: update(function dactyl(obj) {
let cleanup = ["dactyl-cleanup-modules", "quit-application"];
function register(meth) {
- for (let target in Set(cleanup.concat(Object.keys(obj.observers))))
+ for (let target of RealSet(cleanup.concat(Object.keys(obj.observers))))
try {
services.observer[meth](obj, target, true);
}
: "",
{
elements: [],
- seen: {},
+ seen: RealSet(),
valid: function valid(obj) this.elements.every(e => (!e.test || e.test(obj)))
});
}
else {
let [, flags, name] = /^((?:[a-z]-)*)(.*)/.exec(macro);
- flags = Set(flags);
+ flags = RealSet(flags);
let quote = util.identity;
- if (flags.q)
+ if (flags.has("q"))
quote = function quote(obj) typeof obj === "number" ? obj : String.quote(obj);
- if (flags.e)
+ if (flags.has("e"))
quote = function quote(obj) "";
- if (Set.has(defaults, name))
+ if (hasOwnProperty(defaults, name))
stack.top.elements.push(quote(defaults[name]));
else {
let index = idx;
idx = Number(idx) - 1;
stack.top.elements.push(update(
obj => obj[name] != null && idx in obj[name] ? quote(obj[name][idx])
- : Set.has(obj, name) ? "" : unknown(full),
+ : hasOwnProperty(obj, name) ? "" : unknown(full),
{
test: function test(obj) obj[name] != null && idx in obj[name]
&& obj[name][idx] !== false
else {
stack.top.elements.push(update(
obj => obj[name] != null ? quote(obj[name])
- : Set.has(obj, name) ? "" : unknown(full),
+ : hasOwnProperty(obj, name) ? "" : unknown(full),
{
test: function test(obj) obj[name] != null
&& obj[name] !== false
}
for (let elem in array.iterValues(stack))
- elem.seen[name] = true;
+ elem.seen.add(name);
}
}
}
return obj.res;
}
- if (pattern.indexOf("{") == -1)
+ if (!pattern.contains("{"))
return [pattern];
let res = [];
rec([]);
return res;
}
- catch (e if e.message && ~e.message.indexOf("res is undefined")) {
+ catch (e if e.message && e.message.contains("res is undefined")) {
// prefs.safeSet() would be reset on :rehash
prefs.set("javascript.options.methodjit.chrome", false);
util.dactyl.warn(_(UTF8("error.damnYouJägermonkey")));
* @returns {string}
*/
dequote: function dequote(pattern, chars)
- pattern.replace(/\\(.)/, (m0, m1) => chars.indexOf(m1) >= 0 ? m1 : m0),
+ pattern.replace(/\\(.)/, (m0, m1) => chars.contains(m1) ? m1 : m0),
/**
* Returns the nsIDocShell for the given window.
*
* @returns {XMLHttpRequest}
*/
- httpGet: function httpGet(url, callback, self) {
- let params = callback;
- if (!isObject(params))
- params = { callback: params && ((...args) => callback.apply(self, args)) };
+ httpGet: function httpGet(url, params={}, self) {
+ if (callable(params))
+ // Deprecated.
+ params = { callback: params.bind(self) };
try {
let xmlhttp = services.Xmlhttp();
- xmlhttp.mozBackgroundRequest = Set.has(params, "background") ? params.background : true;
+ xmlhttp.mozBackgroundRequest = hasOwnProperty(params, "background") ? params.background : true;
let async = params.callback || params.onload || params.onerror;
if (async) {
- xmlhttp.addEventListener("load", function handler(event) { util.trapErrors(params.onload || params.callback, params, xmlhttp, event); }, false);
- xmlhttp.addEventListener("error", function handler(event) { util.trapErrors(params.onerror || params.callback, params, xmlhttp, event); }, false);
+ xmlhttp.addEventListener("load", event => { util.trapErrors(params.onload || params.callback, params, xmlhttp, event); }, false);
+ xmlhttp.addEventListener("error", event => { util.trapErrors(params.onerror || params.callback, params, xmlhttp, event); }, false);
}
if (isObject(params.params)) {
}
},
+ /**
+ * Like #httpGet, but returns a promise rather than accepting
+ * callbacks.
+ *
+ * @param {string} url The URL to fetch.
+ * @param {object} params Parameter object, as in #httpGet.
+ */
+ fetchUrl: promises.withCallbacks(function fetchUrl([accept, reject, deferred], url, params) {
+ params = update({}, params);
+ params.onload = accept;
+ params.onerror = reject;
+
+ let req = this.httpGet(url, params);
+ promises.oncancel(deferred, req.cancel);
+ }),
+
/**
* The identity function.
*
let windows = services.windowMediator.getXULWindowEnumerator(null);
while (windows.hasMoreElements()) {
let window = windows.getNext().QueryInterface(Ci.nsIXULWindow);
- for each (let type in types) {
+ for (let type of types) {
let docShells = window.docShell.getDocShellEnumerator(Ci.nsIDocShellTreeItem[type],
Ci.nsIDocShell.ENUMERATE_FORWARDS);
while (docShells.hasMoreElements())
// window.content often does not want to be queried with "var i in object"
try {
let hasValue = !("__iterator__" in object || isinstance(object, ["Generator", "Iterator"]));
+
if (object.dactyl && object.modules && object.modules.modules == object.modules) {
object = Iterator(object);
hasValue = false;
}
+
let keyIter = object;
- if ("__iterator__" in object && !callable(object.__iterator__))
+ if (iter.iteratorProp in object) {
+ keyIter = (k for (k of object));
+ hasValue = false;
+ }
+ else if ("__iterator__" in object && !callable(object.__iterator__))
keyIter = keys(object);
for (let i in keyIter) {
value = object[i];
}
catch (e) {}
+
if (!hasValue) {
if (isArray(i) && i.length == 2)
[i, value] = i;
function rec(data, level, seen) {
if (isObject(data)) {
- if (~seen.indexOf(data))
+ seen = RealSet(seen);
+ if (seen.add(data))
throw Error("Recursive object passed");
- seen = seen.concat([data]);
}
let prefix = level + INDENT;
}
let res = [];
- rec(data, "", []);
+ rec(data, "", RealSet());
return res.join("");
},
util.dump("cleanup: " + module.constructor.className);
util.trapErrors(module.cleanup, module, reason);
}
-
- JSMLoader.cleanup();
-
- if (!this.rehashing)
- services.observer.addObserver(this, "dactyl-rehash", true);
- },
- "dactyl-rehash": function dactylRehash() {
- services.observer.removeObserver(this, "dactyl-rehash");
-
- defineModule.loadLog.push("dactyl: util: observe: dactyl-rehash");
- if (!this.rehashing)
- for (let module in values(defineModule.modules)) {
- defineModule.loadLog.push("dactyl: util: init(" + module + ")");
- if (module.reinit)
- module.reinit();
- else
- module.init();
- }
- },
- "dactyl-purge": function dactylPurge() {
- this.rehashing = 1;
- },
+ }
},
/**
*
* This is similar to Perl's extended regular expression format.
*
- * @param {string|XML} expr The expression to compile into a RegExp.
+ * @param {string} expr The expression to compile into a RegExp.
* @param {string} flags Flags to apply to the new RegExp.
* @param {object} tokens The tokens to substitute. @optional
* @returns {RegExp} A custom regexp object.
// Replace replacement <tokens>.
if (tokens)
expr = String.replace(expr, /(\(?P)?<(\w+)>/g,
- (m, n1, n2) => !n1 && Set.has(tokens, n2) ? tokens[n2].dactylSource
- || tokens[n2].source
- || tokens[n2]
- : m);
+ (m, n1, n2) => !n1 && hasOwnProperty(tokens, n2) ? tokens[n2].dactylSource
+ || tokens[n2].source
+ || tokens[n2]
+ : m);
// Strip comments and white space.
if (/x/.test(flags))
}
let res = update(RegExp(expr, flags.replace("x", "")), {
- closure: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "closure")),
+ bound: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "bound")),
+ closure: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "bound")),
dactylPropertyNames: ["exec", "match", "test", "toSource", "toString", "global", "ignoreCase", "lastIndex", "multiLine", "source", "sticky"],
iterate: function iterate(str, idx) util.regexp.iterate(this, str, idx)
});
storage.storeForSession("commandlineArgs", args);
this.timeout(function () {
this.flushCache();
- this.rehashing = true;
+ cache.flush(bind("test", /^literal:/));
let addon = config.addon;
addon.userDisabled = true;
addon.userDisabled = false;
* Waits for the function *test* to return true, or *timeout*
* milliseconds to expire.
*
- * @param {function} test The predicate on which to wait.
+ * @param {function|Promise} test The predicate on which to wait.
* @param {object} self The 'this' object for *test*.
* @param {Number} timeout The maximum number of milliseconds to
* wait.
* thrown.
*/
waitFor: function waitFor(test, self, timeout, interruptable) {
+ if (!callable(test)) {
+ let done = false;
+ var promise = test,
+ retVal;
+ promise.then((arg) => { retVal = arg; done = true; },
+ (arg) => { retVal = arg; done = true; });
+ test = () => done;
+ }
+
let end = timeout && Date.now() + timeout, result;
let timer = services.Timer(function () {}, 10, services.Timer.TYPE_REPEATING_SLACK);
finally {
timer.cancel();
}
- return result;
+ return promise ? retVal: result;
},
/**
* @returns {function} A new function which may not execute
* synchronously.
*/
- yieldable: function yieldable(func)
+ yieldable: deprecated("Task.spawn", function yieldable(func)
function magic() {
let gen = func.apply(this, arguments);
(function next() {
}
catch (e if e instanceof StopIteration) {};
})();
- },
+ }),
/**
* Wraps a callback function such that its errors are not lost. This
* @returns {[string]} The visible domains.
*/
visibleHosts: function visibleHosts(win) {
- let res = [], seen = {};
+ let res = [],
+ seen = RealSet();
(function rec(frame) {
try {
if (frame.location.hostname)
catch (e) {}
Array.forEach(frame.frames, rec);
})(win);
- return res.filter(h => !Set.add(seen, h));
+ return res.filter(h => !seen.add(h));
},
/**
* @returns {[nsIURI]} The visible URIs.
*/
visibleURIs: function visibleURIs(win) {
- let res = [], seen = {};
+ let res = [],
+ seen = RealSet();
(function rec(frame) {
try {
res = res.concat(util.newURI(frame.location.href));
catch (e) {}
Array.forEach(frame.frames, rec);
})(win);
- return res.filter(h => !Set.add(seen, h.spec));
+ return res.filter(h => !seen.add(h.spec));
},
/**
--- /dev/null
+BEGIN {
+ chrome = "chrome"
+ if (suffix)
+ chrome = suffix
+}
+/^ \}/ { on = 0 }
+
+on && $NF ~ /^"([a-z]|\.\/)/ {
+ $NF = "\"/" name "/" substr($NF, 2)
+}
+/./ && on {
+ sub(/^"\.\./, "\"", $NF);
+ $NF = "\"" chrome substr($NF, 2)
+}
+/./ && on {
+ gsub(/\/\.\//, "/")
+ sub(/^\"\.\.\/common\//, "\"", $NF)
+ $0 = " " $0
+}
+//
+
+/^ "resources": \{/ { on = 1 }
if (suffix)
chrome = suffix
}
+
{ content = $1 ~ /^(content|skin|locale|resource)$/ }
-content && $NF ~ /^[a-z]|^\.\// { $NF = "/" name "/" $NF }
+
+content && $NF ~ /^([a-z]|\.\/)/ {
+ $NF = "/" name "/" $NF
+}
content {
sub(/^\.\./, "", $NF);
if (isjar)
visibility: collapse;
}
+:-moz-any(#addon-bar, #dactyl-addon-bar) .toolbarbutton-1 > xul|dropmarker {
+ margin-left: 0 !important;
+ margin-right: 0 !important;
+}
+
+#dactyl-addon-bar .toolbarbutton-1 > xul|dropmarker::after {
+ content: "▾";
+ color: white;
+ font-size: 18px;
+ line-height: 18px;
+}
+
+#nav-bar {
+ padding-top: 0px !important;
+ padding-bottom: 0px !important;
+}
+
.dactyl-commandline-prompt {
/* background-color: inherit; */
margin: 0px;
}
+@-moz-document url(chrome://browser/content/browser.xul) {
+
+/* Fix ginormous Australis tabs. */
+[dactyl-australis=true] xul|tab.tabbrowser-tab .tab-background > * {
+ min-height: 24px !important;
+ max-height: 24px !important;
+}
+
+[dactyl-australis=true] xul|tab.tabbrowser-tab
+ .tab-background > :-moz-any(.tab-background-start, .tab-background-end)::after {
+ background-size: 30px 24px !important;
+ max-height: 24px !important;
+ min-height: 24px !important;
+}
+
+[dactyl-australis=true] .tabbrowser-tabs {
+ min-height: 0 !important;
+}
+
+/* Fix stupid line... */
+[dactyl-australis=true] #navigator-toolbox::after {
+ height: 0 !important;
+}
+
+#nav-bar-customization-target > .toolbarbutton-1 {
+ margin-top: -5px !important;
+ margin-bottom: -5px !important;
+}
+
+/*
+#PanelUI-button,
+#PanelUI-menu-button,
+#nav-bar-customization-target > .toolbarbutton-1,
+#nav-bar-customization-target > .toolbarbutton-1 > xul|toolbarbutton {
+ padding: 0 !important;
+}
+
+#nav-bar-customization-target > xul|toolbaritem > .toolbarbutton-1 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+}
+
+#nav-bar-customization-target > .toolbarbutton-1,
+#nav-bar-customization-target > .toolbarbutton-1 > xul|dropmarker > xul|image {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ max-height: 24px !important;
+}
+
+#nav-bar-customization-target #urlbar {
+ margin-bottom: 0 !important;
+}
+*/
+
+}
+
/* vim: set fdm=marker sw=4 ts=4 et: */
"resource://dactyl/"
],
+ "resources": {
+ "dactyl": "../common/modules/",
+ "dactyl-common": "../common/",
+ "dactyl-content": "../common/content/",
+ "dactyl-skin": "../common/skin/",
+ "dactyl-locale": "../common/locale/",
+
+ "dactyl-local": "./",
+ "dactyl-local-content": "content/",
+ "dactyl-local-skin": "skin/",
+ "dactyl-local-locale": "locale/"
+ },
+
+ "components": {
+ "{16dc34f7-6d22-4aa4-a67f-2921fb5dcb69}": {
+ "path": "components/commandline-handler.js",
+ "contract": "@mozilla.org/commandlinehandler/general-startup;1?type=dactyl",
+ "categories": {
+ "command-line-handler": "m-dactyl"
+ }
+ }
+ },
+
"autocommands": {
"BookmarkAdd": "Triggered after a page is bookmarked",
"BookmarkChange": "Triggered after a page's bookmark is changed",
em:id="pentadactyl@dactyl.googlecode.com"
em:type="2"
em:name="Pentadactyl"
- em:version="1.1pre"
+ em:version="1.2pre"
em:description="Firefox for Vim and Links addicts"
em:homepageURL="http://5digits.org/pentadactyl"
em:bootstrap="true"
<em:targetApplication>
<Description
em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
- em:minVersion="24.0"
- em:maxVersion="25.*"/>
+ em:minVersion="25.0"
+ em:maxVersion="31.*"/>
</em:targetApplication>
</Description>
</RDF>