-// 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.
const DEBUG = true;
-__defineGetter__("BOOTSTRAP", function () "resource://" + moduleName + "/bootstrap.jsm");
+__defineGetter__("BOOTSTRAP", () => "resource://" + moduleName + "/bootstrap.jsm");
var { AddonManager } = module("resource://gre/modules/AddonManager.jsm");
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);
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
.logStringMessage(stack);
}
-function debug() {
+function debug(...args) {
if (DEBUG)
- dump(name + ": " + Array.join(arguments, ", ") + "\n");
+ dump(name + ": " + args.join(", ") + "\n");
}
function httpGet(uri) {
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 resourceProto.resolveURI(uri);
let chan = Services.io.newChannelFromURI(uri);
- try { chan.cancel(Cr.NS_BINDING_ABORTED) } catch (e) {}
+ try { chan.cancel(Cr.NS_BINDING_ABORTED); } catch (e) {}
return chan.name;
},
_load: function _load(name, target) {
let urls = [name];
if (name.indexOf(":") === -1)
- urls = this.config["module-paths"].map(function (path) path + name + ".jsm");
+ urls = this.config["module-paths"].map(path => path + name + ".jsm");
for each (let url in urls)
try {
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);
}
}