// Copyright (c) 2006-2008 by Martin Stubenschrott // Copyright (c) 2007-2009 by Doug Kearns // Copyright (c) 2008-2010 by Kris Maglione // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. "use strict"; /** @scope modules */ default xml namespace = XHTML; XML.ignoreWhitespace = false; XML.prettyPrinting = false; const plugins = { __proto__: modules }; const userContext = newContext(modules); const EVAL_ERROR = "__dactyl_eval_error"; const EVAL_RESULT = "__dactyl_eval_result"; const EVAL_STRING = "__dactyl_eval_string"; function deprecated(reason, fn) { let name, func = callable(fn) ? fn : function () this[fn].apply(this, arguments); function deprecatedMethod() { let frame = Components.stack.caller; let obj = this.className || this.constructor.className; if (!set.add(deprecatedMethod.seen, frame.filename)) dactyl.echoerr( (frame.filename || "unknown").replace(/^.*? -> /, "") + ":" + frame.lineNumber + ": " + (obj ? obj + "." : "") + (fn.name || name) + " is deprecated: " + reason); return func.apply(this, arguments); } deprecatedMethod.seen = { "chrome://dactyl/content/javascript.js": true }; return callable(fn) ? deprecatedMethod : Class.Property({ get: function () deprecatedMethod, init: function (prop) { name = prop; } }); } const Dactyl = Module("dactyl", { init: function () { window.dactyl = this; // cheap attempt at compatibility let prop = { get: deprecated("Please use dactyl instead", function liberator() dactyl) }; Object.defineProperty(window, "liberator", prop); Object.defineProperty(modules, "liberator", prop); this.commands = {}; this.modules = modules; this.observers = {}; }, /** @property {string} The name of the current user profile. */ profileName: Class.memoize(function () { // NOTE: services.profile.selectedProfile.name doesn't return // what you might expect. It returns the last _actively_ selected // profile (i.e. via the Profile Manager or -P option) rather than the // current profile. These will differ if the current process was run // without explicitly selecting a profile. let dir = services.directory.get("ProfD", Ci.nsIFile); for (let prof in iter(services.profile.profiles)) if (prof.QueryInterface(Ci.nsIToolkitProfile).rootDir.path === dir.path) return prof.name; return "unknown"; }), destroy: function () { autocommands.trigger("LeavePre", {}); storage.saveAll(); dactyl.triggerObserver("shutdown", null); util.dump("All dactyl modules destroyed\n"); autocommands.trigger("Leave", {}); }, /** * @property {number} The current main mode. * @see modes#mainModes */ get mode() modes.main, set mode(value) modes.main = value, get menuItems() Dactyl.getMenuItems(), /** @property {Element} The currently focused element. */ get focus() document.commandDispatcher.focusedElement, // Global constants CURRENT_TAB: [], NEW_TAB: [], NEW_BACKGROUND_TAB: [], NEW_WINDOW: [], forceNewTab: false, forceNewWindow: false, /** @property {string} The Dactyl version string. */ version: null, /** * @property {Object} The map of command-line options. These are * specified in the argument to the host application's -{config.name} * option. E.g. $ firefox -pentadactyl '+u=/tmp/rcfile ++noplugin' * Supported options: * +u=RCFILE Use RCFILE instead of .pentadactylrc. * ++noplugin Don't load plugins. */ commandLineOptions: { /** @property Whether plugin loading should be prevented. */ noPlugins: false, /** @property An RC file to use rather than the default. */ rcFile: null, /** @property An Ex command to run before any initialization is performed. */ preCommands: null, /** @property An Ex command to run after all initialization has been performed. */ postCommands: null }, registerObserver: function (type, callback, weak) { if (!(type in this.observers)) this.observers[type] = []; this.observers[type].push(weak ? Cu.getWeakReference(callback) : { get: function () callback }); }, unregisterObserver: function (type, callback) { if (type in this.observers) this.observers[type] = this.observers[type].filter(function (c) c.get() != callback); }, // TODO: "zoom": if the zoom value of the current buffer changed triggerObserver: function (type) { let args = Array.slice(arguments, 1); if (type in this.observers) this.observers[type] = this.observers[type].filter(function (callback) { if (callback.get()) { callback.get().apply(null, args); return true; } }); }, /** * Triggers the application bell to notify the user of an error. The * bell may be either audible or visual depending on the value of the * 'visualbell' option. */ beep: function () { if (options["visualbell"]) { let bell = document.getElementById("dactyl-bell"); let strut = document.getElementById("dactyl-bell-strut"); if (!bell) { bell = document.documentElement.insertBefore( util.xmlToDom(