diff --git a/.hgignore b/.hgignore index e55fa075..9cb94cb8 100644 --- a/.hgignore +++ b/.hgignore @@ -13,6 +13,7 @@ syntax: glob */contrib/vim/*.vba */bak/* downloads/* +.git/* *.py[co] diff --git a/common/Makefile b/common/Makefile index 827164c0..470ddb33 100644 --- a/common/Makefile +++ b/common/Makefile @@ -25,7 +25,7 @@ CHROME = chrome/ JAR = $(CHROME)$(NAME).jar XPI_BASES = $(JAR_BASES) $(TOP)/.. -XPI_FILES = install.rdf TODO AUTHORS Donors NEWS LICENSE.txt +XPI_FILES = bootstrap.js install.rdf TODO AUTHORS Donors NEWS LICENSE.txt XPI_DIRS = modules components chrome defaults XPI_TEXTS = js jsm $(JAR_TEXTS) XPI_BINS = $(JAR_BINS) diff --git a/common/bootstrap.js b/common/bootstrap.js new file mode 100755 index 00000000..7fb41e91 --- /dev/null +++ b/common/bootstrap.js @@ -0,0 +1,169 @@ +// https://wiki.mozilla.org/Extension_Manager:Bootstrapped_Extensions + +const NAME = "bootstrap"; +const global = this; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; + +Cu.import("resource://gre/modules/AddonManager.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +const io = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); +const resourceProto = io.getProtocolHandler("resource") + .QueryInterface(Ci.nsIResProtocolHandler); +const categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager); +const manager = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); + +function httpGet(url) { + let xmlhttp = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); + xmlhttp.open("GET", url, false); + xmlhttp.send(null); + return xmlhttp; +} + +function writeFile(file, buf) { + let fstream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); + let stream = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream); + + fstream.init(file, 0x02 | 0x08 | 0x20, parseInt("0644", 8), 0); + stream.init(fstream, "UTF-8", 0, "?"); + stream.writeString(buf); + stream.close(); + fstream.close(); +} + +let initialized = false; +let addon = null; +let basePath = null; + +function startup(data, reason) { + dump("dactyl: bootstrap: startup\n"); + basePath = data.installPath; + + if (!initialized) { + initialized = true; + + dump("dactyl: bootstrap: init" + " " + data.id + "\n"); + + AddonManager.getAddonByID(data.id, function (res) { + try { + addon = res; + init(); + } + catch (e) { + dump("dactyl: bootstrap: " + e + "\n"); + Cu.reportError(e); + } + }); + + } +} + +function FactoryProxy(url, classID) { + this.url = url; + this.classID = Components.ID(classID); +} +FactoryProxy.prototype = { + QueryInterface: XPCOMUtils.generateQI(Ci.nsIFactory), + init: function () { + manager.registerFactory(this.classID, + String(this.classID), + this.contractID, + this); + }, + get module() { + Class.replaceProperty(this, "module", {}); + Cu.import(this.url, this.module); + return this.module; + }, + createInstance: function () + let (factory = this.module.NSGetFactory(this.classID)) + factory.createInstance.apply(factory, arguments) +} + +function init() { + dump("dactyl: bootstrap: init: " + addon + "\n"); + + let manifestURI = addon.getResourceURI("chrome.manifest"); + let manifest = httpGet(manifestURI.spec) + .responseText + .replace(/^\s*|\s*$|#.*/g, "") + .replace(/^\s*\n/gm, ""); + + function url(path) addon.getResourceURI(path).spec; + + let result = []; + let components = {}; + + for each (let line in manifest.split("\n")) { + let fields = line.split(/\s+/); + switch(fields[0]) { + case "content": + fields[2] = url(fields[2]); + default: + result.push(fields); + break; + + case "locale": + case "skin": + fields[3] = url(fields[3]); + result.push(fields); + break; + + case "category": + categoryManager.addCategoryEntry(fields[1], fields[2], fields[3], false, true); + break; + case "component": + components[fields[1]] = new FactoryProxy(url(fields[2]), fields[1]); + break; + case "contract": + components[fields[2]].contractID = fields[1]; + components[fields[2]].init(); + break; + + case "resource": + resourceProto.setSubstitution(fields[1], addon.getResourceURI(fields[2])); + } + } + + Cu.import("resource://dactyl/base.jsm"); + require(global, "prefs"); + require(global, "services"); + + services.subscriptLoader.loadSubScript( + url("defaults/preferences/dactyl.js"), + { + pref: function pref(name, val) { + if (prefs.get(name, null) == null) + prefs.set(name, val); + } + }); + + if (manifestURI instanceof Ci.nsIFileURL) + manager.autoRegister(file.QueryInterface(Ci.nsIFileURL).file); + else { + var file = basePath.parent; + file.append(addon.id + ".manifest"); + + writeFile(file, result.map(function (line) line.join(" ")).join("\n")); + manager.autoRegister(file); + //file.remove(false); + } +} + +function reasonToString(reason) { + for each (let name in ["disable", "downgrade", "enable", + "install", "shutdown", "startup", + "uninstall", "upgrade"]) + if (reason == global["ADDON_" + name.toUpperCase()] || + reason == global["APP_" + name.toUpperCase()]) + return name; +} + +function install(data, reason) { dump("dactyl: bootstrap: install\n") } +function shutdown(data, reason) { dump("dactyl: bootstrap: shutdown\n") } +function uninstall(data, reason) { dump("dactyl: bootstrap: uninstall\n") } + diff --git a/common/components/commandline-handler.js b/common/components/commandline-handler.js index fa60f73c..3083af0f 100644 --- a/common/components/commandline-handler.js +++ b/common/components/commandline-handler.js @@ -48,5 +48,6 @@ if (XPCOMUtils.generateNSGetFactory) const NSGetFactory = XPCOMUtils.generateNSGetFactory([CommandLineHandler]); else const NSGetModule = XPCOMUtils.generateNSGetModule([CommandLineHandler]); +var EXPORTED_SYMBOLS = ["NSGetFactory"]; // vim: set fdm=marker sw=4 ts=4 et: diff --git a/common/components/protocols.js b/common/components/protocols.js index 0bedf607..8b8069a5 100644 --- a/common/components/protocols.js +++ b/common/components/protocols.js @@ -12,13 +12,15 @@ * By Kris Maglione, ideas from Ed Anuff's nsChromeExtensionHandler. */ -const Ci = Components.interfaces, Cc = Components.classes; +const NAME = "protocols"; +const global = this; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); -const prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService) - .getBranch("extensions.dactyl."); const systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].getService(Ci.nsIPrincipal); function dataURL(type, data) "data:" + (type || "application/xml;encoding=UTF-8") + "," + escape(data); @@ -97,10 +99,15 @@ function Dactyl() { this.OVERLAY_MAP = {}; this.pages = {}; - for each (let pref in ["appName", "fileExt", "host", "hostbin", "idName", "name"]) - this[pref] = prefs.getComplexValue(pref, Ci.nsISupportsString).data; - this.addonID = this.name + "@dactyl.googlecode.com"; + Cu.import("resource://dactyl/base.jsm"); + require(global, "prefs"); + + ["appName", "fileExt", "host", "hostbin", "idName", "name", "version"].forEach(function (pref) + this.__defineGetter__(pref, function () prefs.get("extensions.dactyl." + pref, "dactyl")), + this); + + memoize(this, "addonID", function () this.name + "@dactyl.googlecode.com"); } Dactyl.prototype = { contractID: "@mozilla.org/network/protocol;1?name=dactyl", @@ -109,8 +116,6 @@ Dactyl.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]), _xpcom_factory: Factory(Dactyl), - get version() prefs.getComplexValue("version", Ci.nsISupportsString).data, - init: function (obj) { for each (let prop in ["HELP_TAGS", "FILE_MAP", "OVERLAY_MAP"]) { this[prop] = this[prop].constructor(); @@ -202,5 +207,6 @@ if (XPCOMUtils.generateNSGetFactory) const NSGetFactory = XPCOMUtils.generateNSGetFactory([AboutHandler, ChromeData, Dactyl, Shim]); else const NSGetModule = XPCOMUtils.generateNSGetModule([AboutHandler, ChromeData, Dactyl, Shim]); +var EXPORTED_SYMBOLS = ["NSGetFactory"]; // vim: set fdm=marker sw=4 ts=4 et: diff --git a/common/content/completion.js b/common/content/completion.js index 5c5d72e9..c58c604f 100644 --- a/common/content/completion.js +++ b/common/content/completion.js @@ -530,9 +530,9 @@ const CompletionContext = Class("CompletionContext", { // of the given string which also matches the current // item's text. let len = substring.length; - let i = 0, m, n = len; + let i = 0, n = len; while (n) { - m = Math.floor(n / 2); + let m = Math.floor(n / 2); let keep = compare(fixCase(item.text), substring.substring(0, i + m)); if (!keep) len = i + m - 1; diff --git a/common/content/dactyl.js b/common/content/dactyl.js index d7b46415..422fb9ad 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -391,7 +391,6 @@ const Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), focus: function focus(elem, flags) { flags = flags || services.focus.FLAG_BYMOUSE; - util.dumpStack(); try { if (elem instanceof Document) elem = elem.defaultView; diff --git a/common/content/modes.js b/common/content/modes.js index 715d4b0e..c59e85b6 100644 --- a/common/content/modes.js +++ b/common/content/modes.js @@ -286,7 +286,6 @@ const Modes = Module("modes", { }, push: function push(mainMode, extendedMode, params) { - util.dumpStack(); this.set(mainMode, extendedMode, params, { push: this.topOfStack }); }, diff --git a/common/modules/base.jsm b/common/modules/base.jsm index e2abf9d4..bd382c1d 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -126,7 +126,7 @@ defineModule.dump = function dump_() { msg = util.objectToString(msg); return msg; }).join(", "); - let name = loaded.services ? services["dactyl:"].name : "dactyl"; + let name = loaded.services && loaded.prefs && services["dactyl:"] ? services["dactyl:"].name : "dactyl"; dump(String.replace(msg, /\n?$/, "\n") .replace(/^./gm, name + ": $&")); } @@ -179,8 +179,8 @@ defineModule("base", { "call", "callable", "ctypes", "curry", "debuggerProperties", "defineModule", "deprecated", "endModule", "forEach", "isArray", "isGenerator", "isinstance", "isObject", "isString", "isSubclass", "iter", "iterAll", - "keys", "memoize", "octal", "properties", "set", "update", "values", - "withCallerGlobal" + "keys", "memoize", "octal", "properties", "require", "set", "update", + "values", "withCallerGlobal" ], use: ["services", "util"] }); diff --git a/common/modules/services.jsm b/common/modules/services.jsm index 7be520f6..38212cf8 100644 --- a/common/modules/services.jsm +++ b/common/modules/services.jsm @@ -8,8 +8,7 @@ try { Components.utils.import("resource://dactyl/base.jsm"); defineModule("services", { - exports: ["Services", "services"], - use: ["util"] + exports: ["AddonManager", "Services", "services"] }); /** @@ -72,6 +71,9 @@ const Services = Module("Services", { this.addClass("Xmlhttp", "@mozilla.org/xmlextras/xmlhttprequest;1", Ci.nsIXMLHttpRequest); this.addClass("ZipReader", "@mozilla.org/libjar/zip-reader;1", Ci.nsIZipReader, "open"); this.addClass("ZipWriter", "@mozilla.org/zipwriter;1", Ci.nsIZipWriter); + + if (!this.extensionManager) + Components.utils.import("resource://gre/modules/AddonManager.jsm"); }, _create: function (classes, ifaces, meth, init, args) { @@ -85,7 +87,7 @@ const Services = Module("Services", { return res; } catch (e) { - util.dump("Service creation failed for '" + classes + "': " + e + "\n"); + dump("dactyl: Service creation failed for '" + classes + "': " + e + "\n"); return null; } }, @@ -105,8 +107,12 @@ const Services = Module("Services", { if (name in this && ifaces && !this.__lookupGetter__(name) && !(this[name] instanceof Ci.nsISupports)) throw TypeError(); this.__defineGetter__(name, function () { + let res = self._create(class_, ifaces, meth); + if (!res) + return null; + delete this[name]; - return this[name] = self._create(class_, ifaces, meth); + return this[name] = res; }); }, @@ -140,10 +146,6 @@ const Services = Module("Services", { get: function (name) this[name], }, { }, { - init: function (dactyl, modules) { - if (!modules.AddonManager && !this.get("extensionManager")) - Components.utils.import("resource://gre/modules/AddonManager.jsm", modules); - }, javascript: function (dactyl, modules) { modules.JavaScript.setCompleter(this.get, [function () [[k, v] for ([k, v] in Iterator(services)) if (v instanceof Ci.nsISupports)]]); modules.JavaScript.setCompleter(this.create, [function () [[c, ""] for (c in services.classes)]]); diff --git a/pentadactyl/bootstrap.js b/pentadactyl/bootstrap.js new file mode 120000 index 00000000..ff1024d5 --- /dev/null +++ b/pentadactyl/bootstrap.js @@ -0,0 +1 @@ +../common/bootstrap.js \ No newline at end of file diff --git a/pentadactyl/install.rdf b/pentadactyl/install.rdf index ce5e76b4..7e7429b7 100644 --- a/pentadactyl/install.rdf +++ b/pentadactyl/install.rdf @@ -8,7 +8,8 @@ em:description="Firefox for Vim and Links addicts" em:homepageURL="http://dactyl.sourceforge.net/pentadactyl" em:iconURL="chrome://pentadactyl/skin/icon.png" - em:optionsURL="chrome://dactyl/content/preferences.xul"> + em:optionsURL="chrome://dactyl/content/preferences.xul" + em:bootstrap="true"> Kris Maglione, Doug Kearns Štěpán Němec