+ Module: function Module(uri, isPlugin) {
+ const { io, plugins } = this.modules;
+
+ let canonical = uri.spec;
+ if (uri.scheme == "resource")
+ canonical = services["resource:"].resolveURI(uri);
+
+ if (uri instanceof Ci.nsIFileURL)
+ var file = File(uri.file);
+
+ let isPlugin = array.nth(io.getRuntimeDirectories("plugins"),
+ function (dir) dir.contains(file, true),
+ 0);
+
+ 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];
+
+ if (!self) {
+ self = Object.create(jsmodules);
+
+ update(self, {
+ NAME: Const(id),
+
+ PATH: Const(file && file.path),
+
+ CONTEXT: Const(self),
+
+ get isGlobalModule() true,
+ set isGlobalModule(val) {
+ util.assert(val, "Loading non-global module as global",
+ false);
+ },
+
+ unload: Const(function unload() {
+ if (contexts.pluginModules[canonical] == this) {
+ if (this.onUnload)
+ util.trapErrors("onUnload", this);
+
+ delete contexts.pluginModules[canonical];
+ }
+
+ for each (let { plugins } in overlay.modules)
+ if (plugins[this.NAME] == this)
+ delete plugins[this.name];
+ })
+ });
+
+ JSMLoader.loadSubScript(uri.spec, self, File.defaultEncoding);
+ this.pluginModules[canonical] = self;
+ }
+
+ // This belongs elsewhere
+ if (isPlugin)
+ Object.defineProperty(plugins, self.NAME, {
+ configurable: true,
+ enumerable: true,
+ get: function () self,
+ set: function (val) {
+ util.dactyl(val).reportError(FailedAssertion(_("plugin.notReplacingContext", self.NAME), 3, false), true);
+ }
+ });
+
+ return self;
+ },
+