]> git.donarmstrong.com Git - dactyl.git/blobdiff - common/modules/main.jsm
Imported Upstream version 1.1+hg7904
[dactyl.git] / common / modules / main.jsm
index ffc89ee8e5d25f643bc291a79fa4ca12c4d37ea0..80e64a797bfce4f3e6e4e8fe61b2545fd377dea4 100644 (file)
@@ -1,19 +1,20 @@
-// Copyright (c) 2009-2011 by 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.
-/* use strict */
+"use strict";
 
 try {
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("main", {
     exports: ["ModuleBase"],
     require: ["config", "overlay", "services", "util"]
-}, this);
+});
 
 var BASE = "resource://dactyl-content/";
 
+var global = this;
+
 /**
  * @class ModuleBase
  * The base class for all modules.
@@ -66,14 +67,13 @@ var Modules = function Modules(window) {
      *
      * @returns {function} The constructor for the resulting module.
      */
-    function Module(name) {
-        let args = Array.slice(arguments);
+    function Module(name, ...args) {
 
         var base = ModuleBase;
-        if (callable(args[1]))
-            base = args.splice(1, 1)[0];
+        if (callable(args[0]))
+            base = args.shift();
 
-        let [prototype, classProperties, moduleInit] = args;
+        let [prototype, classProperties, moduleInit] = args;
         prototype._metaInit_ = function () {
             delete module.prototype._metaInit_;
             Class.replaceProperty(modules, module.className, this);
@@ -91,29 +91,89 @@ var Modules = function Modules(window) {
     Module.list = [];
     Module.constructors = {};
 
-    const create = window.Object.create || (function () {
-        window.__dactyl_eval_string = "(function (proto) ({ __proto__: proto }))";
-        JSMLoader.loadSubScript(BASE + "eval.js", window);
+    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 });
 
-        let res = window.__dactyl_eval_result;
-        delete window.__dactyl_eval_string;
-        delete window.__dactyl_eval_result;
-        return res;
-    })();
+        // 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/"];
 
-    const jsmodules = { NAME: "jsmodules" };
+    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) {
@@ -130,7 +190,7 @@ var Modules = function Modules(window) {
                 }
             }
             try {
-                require(jsmodules, script);
+                require(script, jsmodules);
             }
             catch (e) {
                 util.dump("Loading script " + script + ":");
@@ -138,30 +198,13 @@ var Modules = function Modules(window) {
             }
         },
 
-        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)
-                      .map(function (name) Object.getOwnPropertyDescriptor(this, name).value, this)),
+                      .map(name => Object.getOwnPropertyDescriptor(this, name).value)),
 
-        get moduleList() this.ownPropertyValues.filter(function (mod) mod instanceof this.ModuleBase || mod.isLocalModule, this)
+        get moduleList() this.ownPropertyValues.filter(mod => (mod instanceof this.ModuleBase || mod.isLocalModule))
     });
 
     modules.plugins = create(modules);
@@ -171,20 +214,27 @@ var Modules = function Modules(window) {
 
 config.loadStyles();
 
-overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({
+overlay.overlayWindow(Object.keys(config.overlays),
+                      function _overlay(window) ({
     ready: function onInit(document) {
         const modules = Modules(window);
         modules.moduleManager = this;
         this.modules = modules;
+        this.jsmodules = modules.jsmodules;
 
         window.dactyl = { modules: modules };
 
         defineModule.time("load", null, function _load() {
             config.modules.global
-                  .forEach(function (name) defineModule.time("load", name, require, null, modules.jsmodules, name));
+                  .forEach(function (name) {
+                      if (!isArray(name))
+                          defineModule.time("load", name, require, null, name, modules.jsmodules);
+                      else
+                          lazyRequire(name[0], name.slice(1), modules.jsmodules);
+                  });
 
             config.modules.window
-                  .forEach(function (name) defineModule.time("load", name, modules.load, modules, name));
+                  .forEach(name => { defineModule.time("load", name, modules.load, modules, name); });
         }, this);
     },
 
@@ -196,8 +246,8 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({
 
         this.startTime = Date.now();
         this.deferredInit = { load: {} };
-        this.seen = {};
-        this.loaded = {};
+        this.seen = RealSet();
+        this.loaded = RealSet();
         modules.loaded = this.loaded;
 
         this.modules = modules;
@@ -229,11 +279,13 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({
     },
 
     cleanup: function cleanup(window) {
-        overlay.windows = overlay.windows.filter(function (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)
@@ -248,7 +300,7 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({
 
         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) {
@@ -262,10 +314,10 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({
         }
 
         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))
@@ -281,9 +333,9 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({
             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)
@@ -304,7 +356,7 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({
 
         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;
@@ -325,25 +377,25 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({
     },
 
     scanModules: function scanModules() {
-        let self = this;
         let { Module, modules } = this.modules;
 
-        defineModule.modules.forEach(function defModule(mod) {
-            let names = Set(Object.keys(mod.INIT));
+        defineModule.modules.forEach((mod) => {
+            let names = RealSet(Object.keys(mod.INIT));
             if ("init" in mod.INIT)
-                Set.add(names, "init");
+                names.add("init");
 
-            keys(names).forEach(function (name) { self.deferInit(name, mod.INIT, mod); });
+            for (let name of names)
+                this.deferInit(name, mod.INIT, mod);
         });
 
-        Module.list.forEach(function frobModule(mod) {
+        Module.list.forEach((mod) => {
             if (!mod.frobbed) {
-                modules.__defineGetter__(mod.className, function () {
+                modules.__defineGetter__(mod.className, () => {
                     delete modules[mod.className];
-                    return self.loadModule(mod.className, null, Components.stack.caller);
+                    return this.loadModule(mod.className, null, Components.stack.caller);
                 });
                 Object.keys(mod.prototype.INIT)
-                      .forEach(function (name) { self.deferInit(name, mod.prototype.INIT, mod); });
+                      .forEach((name) => { this.deferInit(name, mod.prototype.INIT, mod); });
             }
             mod.frobbed = true;
         });
@@ -360,4 +412,4 @@ endModule();
 
 } catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
 
-// vim: set fdm=marker sw=4 ts=4 et ft=javascript:
+// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript: