// Copyright (c) 2009 by Martin Stubenschrott // Copyright (c) 2009 by Prathyush Thota // Copyright (c) 2009-2011 by Doug Kearns // Copyright (c) 2009-2011 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"; Components.utils.import("resource://gre/modules/utils.js"); // XXX: PlacesUtils const Config = Module("config", ConfigBase, { name: "melodactyl", appName: "Melodactyl", idName: "MELODACTYL", host: "Songbird", hostbin: "songbird", commandContainer: "mainplayer", Local: function Local(dactyl, modules, window) let ({ config } = modules, { document } = window) { init: function init() { init.supercall(this); // TODO: mention this to SB devs, they seem keen to provide these // functions to make porting from FF as simple as possible. window.toJavaScriptConsole = () => { toOpenWindowByType("global:console", "chrome://global/content/console.xul"); }; }, // FIXME: unless I'm seeing double in in the wee small hours gBrowser is // first set from getBrowser which they've deprecated in FF. get browser() { return window.getBrowser(); }, get tabbrowser() { return window.getBrowser(); }, dialogs: { about: ["About Songbird", () => { window.openDialog("chrome://songbird/content/xul/about.xul", "_blank", "chrome,dialog,modal,centerscreen"); }], addons: ["Manage Add-ons", () => { window.SBOpenPreferences("paneAddons"); }], checkupdates: ["Check for updates", () => { window.checkForUpdates(); }], cookies: ["List your cookies", () => { window.toOpenWindowByType("Browser:Cookies", "chrome://browser/content/preferences/cookies.xul", "chrome,dialog=no,resizable"); }], console: ["JavaScript console", () => { window.toJavaScriptConsole(); }], dominspector: ["DOM Inspector", () => { window.inspectDOMDocument(window.content.document); }, () => "inspectDOMDocument" in window], downloads: ["Manage Downloads", () => { window.toOpenWindowByType("Download:Manager", "chrome://mozapps/content/downloads/downloads.xul", "chrome,dialog=no,resizable"); }], newsmartplaylist: ["Open the file selector dialog", () => { window.SBNewSmartPlaylist(); }], openfile: ["Open the file selector dialog", () => { window.SBFileOpen(); }], pagesource: ["View page source", () => { window.BrowserViewSourceOfDocument(window.content.document); }], preferences: ["Show Songbird preferences dialog", () => { window.openPreferences(); }], printsetup: ["Setup the page size and orientation before printing", () => { window.PrintUtils.showPageSetup(); }], print: ["Show print dialog", () => { window.PrintUtils.print(); }], saveframe: ["Save frame to disk", () => { window.saveFrameDocument(); }], savepage: ["Save page to disk", () => { window.saveDocument(window.content.document); }], searchengines: ["Manage installed search engines", () => { window.openDialog("chrome://browser/content/search/engineManager.xul", "_blank", "chrome,dialog,modal,centerscreen"); }], selectionsource: ["View selection source", () => { modules.buffer.viewSelectionSource(); }], subscribe: ["Add a new subscription", () => { window.SBSubscribe(); }] }, // TODO: clean this up focusChange: function (win) { const { modes } = modules; // Switch to -- PLAYER -- mode for Songbird Media Player. if (this.isPlayerWindow) modes.set(modes.PLAYER); else if (modes.main == modes.PLAYER) modes.pop(); }, get isPlayerWindow() { let browser = window.SBGetBrowser(); return browser.mCurrentTab == browser.mediaTab; }, /** * Shows or hides the main service pane. * * @param {boolean} value Show the service pane if true, hide it if false. */ showServicePane: function (value) { const key = "splitter.servicepane_splitter.was_collapsed"; window.gServicePane.open = value; window.SBDataSetBoolValue(key, window.gServicePane.open); }, /** * Opens the display panel with the specified *id*. * * @param {string} id The ID of the display pane. */ openDisplayPane: function (id) { if (id == "servicepane") this.showServicePane(true); else { let pane = document.getElementById(id); let manager = services.displayPaneManager; let paneinfo = manager.getPaneInfo(pane._lastURL.stringValue); if (!paneinfo) paneinfo = manager.defaultPaneInfo; pane.loadContent(paneinfo); } }, /** * Closes the display panel with the specified *id* * * @param {string} id The ID of the display pane. */ closeDisplayPane: function (id) { if (id == "servicepane") this.showServicePane(false); else document.getElementById(id).hide(); } }, /*** optional options, there are checked for existence and a fallback provided ***/ features: Set(["bookmarks", "hints", "marks", "history", "quickmarks", "session", "tabs", "player"]), defaults: { guioptions: "bCmprs", showtabline: 2, get titlestring() { return config.name; } }, guioptions: { m: ["Menubar", ["main-menubar"]], T: ["Toolbar", ["nav-bar"]], p: ["Player controls", ["player_wrapper"]] }, overlayChrome: ["chrome://purplerain/content/xul/mainplayer.xul"], styleableChrome: ["chrome://purplerain/content/xul/mainplayer.xul"], autocommands: { BookmarkAdd: "Triggered after a page is bookmarked", ColorScheme: "Triggered after a color scheme has been loaded", DOMLoad: "Triggered when a page's DOM content has fully loaded", DownloadPost: "Triggered when a download has completed", Fullscreen: "Triggered when the browser's fullscreen state changes", LocationChange: "Triggered when changing tabs or when navigation to a new location", PageLoadPre: "Triggered after a page load is initiated", PageLoad: "Triggered when a page gets (re)loaded/opened", ShellCmdPost: "Triggered after executing a shell command with :!cmd", TrackChangePre: "Triggered before a playing track is changed", TrackChange: "Triggered after a playing track has changed", ViewChangePre: "Triggered before a sequencer view is changed", ViewChange: "Triggered after a sequencer view is changed", StreamStart: "Triggered after a stream has started", StreamPause: "Triggered after a stream has paused", StreamEnd: "Triggered after a stream has ended", StreamStop: "Triggered after a stream has stopped", Enter: "Triggered after Songbird starts", LeavePre: "Triggered before exiting Songbird, just before destroying each module", Leave: "Triggered before exiting Songbird" }, completers: Class.memoize(function () { return update({ displaypane: "displayPane", playlist: "playlist", mediaview: "mediaView", mediasort: "mediaListSort", song: "song" }, this.__proto__.completers); }), removeTab: function (tab) { if (config.tabbrowser.mTabs.length > 1) config.tabbrowser.removeTab(tab); else { if (buffer.URL != "about:blank" || window.getWebNavigation().sessionHistory.count > 0) { dactyl.open("about:blank", dactyl.NEW_BACKGROUND_TAB); config.tabbrowser.removeTab(tab); } else dactyl.beep(); } }, scripts: [ "browser", "bookmarks", "history", "quickmarks", "tabs", "player", "library" ], sidebars: { viewAddons: ["Add-ons", "A", "chrome://mozapps/content/extensions/extensions.xul"], viewConsole: ["Console", "C", "chrome://global/content/console.xul"], viewDownloads: ["Downloads", "D", "chrome://mozapps/content/downloads/downloads.xul"], viewPreferences: ["Preferences", "P", "about:config"] }, // FIXME: tab arg and media tab exception? stop: function (tab) { window.SBGetBrowser().mCurrentBrowser.stop(); } }, { /** * @property {object} A map of display pane command argument strings to * panel element IDs. */ displayPanes: { "leftservice" : "servicepane", "bottomcontent": "displaypane_contentpane_bottom", "bottomservice": "displaypane_servicepane_bottom", "rightsidebar" : "displaypane_right_sidebar" } }, { commands: function initCommands(dactyl, modules, window) { const { commands, completion, options } = modules; commands.add(["dpcl[ose]"], "Close a display pane", function (args) { let arg = args.literalArg; dactyl.assert(arg in Config.displayPanes, _("error.invalidArgument", arg)); config.closeDisplayPane(Config.displayPanes[arg]); }, { argCount: "1", completer: function (context) { completion.displayPane(context); }, literal: 0 }); // TODO: this should accept a second arg to specify content commands.add(["displayp[ane]", "dp[ane]", "dpope[n]"], "Open a display pane", function (args) { let arg = args.literalArg; dactyl.assert(arg in Config.displayPanes, _("error.invalidArgument", arg)); // TODO: focus when we have better key handling of these extended modes config.openDisplayPane(Config.displayPanes[arg]); }, { argCount: "1", completer: function (context) { completion.displayPane(context); }, literal: 0 }); commands.add(["pref[erences]", "prefs"], "Show " + config.host + " preferences", function (args) { if (args.bang) { // open Songbird settings GUI dialog dactyl.open("about:config", (options["newtab"] && options.get("newtab").has("all", "prefs")) ? dactyl.NEW_TAB : dactyl.CURRENT_TAB); } else window.openPreferences(); }, { argCount: "0", bang: true }); }, completion: function initCompletion(dactyl, modules, window) { const completion = require("completion"); completion.displayPane = context => { context.title = ["Display Pane"]; context.completions = Config.displayPanes; // FIXME: useful description etc }; }, modes: function initModes(dactyl, modules, window) { const { modes } = modules; this.ignoreKeys = { "": modes.NORMAL | modes.INSERT, "": modes.NORMAL | modes.INSERT, "": modes.NORMAL | modes.INSERT, "": modes.NORMAL | modes.INSERT }; modes.addMode("PLAYER", { char: "p" }); }, options: function initOptions(dactyl, modules, window) { const { options } = modules; // TODO: SB doesn't explicitly support an offline mode. Should we? --djk options.add(["online"], "Set the 'work offline' option", "boolean", true, { setter: function (value) { const ioService = services.io; ioService.offline = !value; prefs.set("browser.offline", ioService.offline); return value; }, getter: function () { return !services.io.offline; } }); }, services: function initServices(dactyl, modules, window) { services.add("displayPaneManager", "@songbirdnest.com/Songbird/DisplayPane/Manager;1", Ci.sbIDisplayPaneManager); services.add("mediaPageManager", "@songbirdnest.com/Songbird/MediaPageManager;1", Ci.sbIMediaPageManager); services.add("propertyManager", "@songbirdnest.com/Songbird/Properties/PropertyManager;1", Ci.sbIPropertyManager); services.addClass("mutablePropertyArray", "@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1", Ci.sbIMutablePropertyArray); } }); // vim: set fdm=marker sw=4 sts=4 ts=8 et: