michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: 'use strict'; michael@0: michael@0: module.metadata = { michael@0: 'stability': 'unstable', michael@0: 'engines': { michael@0: 'Firefox': '*' michael@0: } michael@0: }; michael@0: michael@0: const { models, buttons, views, viewsFor, modelFor } = require('./namespace'); michael@0: const { isBrowser, getMostRecentBrowserWindow, windows, isWindowPrivate } = require('../../window/utils'); michael@0: const { setStateFor } = require('../state'); michael@0: const { defer } = require('../../core/promise'); michael@0: const { isPrivateBrowsingSupported } = require('../../self'); michael@0: michael@0: const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; michael@0: const WEB_PANEL_BROWSER_ID = 'web-panels-browser'; michael@0: michael@0: function create(window, details) { michael@0: let id = makeID(details.id); michael@0: let { document } = window; michael@0: michael@0: if (document.getElementById(id)) michael@0: throw new Error('The ID "' + details.id + '" seems already used.'); michael@0: michael@0: let menuitem = document.createElementNS(XUL_NS, 'menuitem'); michael@0: menuitem.setAttribute('id', id); michael@0: menuitem.setAttribute('label', details.title); michael@0: menuitem.setAttribute('sidebarurl', details.sidebarurl); michael@0: menuitem.setAttribute('checked', 'false'); michael@0: menuitem.setAttribute('type', 'checkbox'); michael@0: menuitem.setAttribute('group', 'sidebar'); michael@0: menuitem.setAttribute('autoCheck', 'false'); michael@0: michael@0: document.getElementById('viewSidebarMenu').appendChild(menuitem); michael@0: michael@0: return menuitem; michael@0: } michael@0: exports.create = create; michael@0: michael@0: function dispose(menuitem) { michael@0: menuitem.parentNode.removeChild(menuitem); michael@0: } michael@0: exports.dispose = dispose; michael@0: michael@0: function updateTitle(sidebar, title) { michael@0: let button = buttons.get(sidebar); michael@0: michael@0: for (let window of windows(null, { includePrivate: true })) { michael@0: let { document } = window; michael@0: michael@0: // update the button michael@0: if (button) { michael@0: setStateFor(button, window, { label: title }); michael@0: } michael@0: michael@0: // update the menuitem michael@0: let mi = document.getElementById(makeID(sidebar.id)); michael@0: if (mi) { michael@0: mi.setAttribute('label', title) michael@0: } michael@0: michael@0: // update sidebar, if showing michael@0: if (isSidebarShowing(window, sidebar)) { michael@0: document.getElementById('sidebar-title').setAttribute('value', title); michael@0: } michael@0: } michael@0: } michael@0: exports.updateTitle = updateTitle; michael@0: michael@0: function updateURL(sidebar, url) { michael@0: let eleID = makeID(sidebar.id); michael@0: michael@0: for (let window of windows(null, { includePrivate: true })) { michael@0: // update the menuitem michael@0: let mi = window.document.getElementById(eleID); michael@0: if (mi) { michael@0: mi.setAttribute('sidebarurl', url) michael@0: } michael@0: michael@0: // update sidebar, if showing michael@0: if (isSidebarShowing(window, sidebar)) { michael@0: showSidebar(window, sidebar, url); michael@0: } michael@0: } michael@0: } michael@0: exports.updateURL = updateURL; michael@0: michael@0: function isSidebarShowing(window, sidebar) { michael@0: let win = window || getMostRecentBrowserWindow(); michael@0: michael@0: // make sure there is a window michael@0: if (!win) { michael@0: return false; michael@0: } michael@0: michael@0: // make sure there is a sidebar for the window michael@0: let sb = win.document.getElementById('sidebar'); michael@0: let sidebarTitle = win.document.getElementById('sidebar-title'); michael@0: if (!(sb && sidebarTitle)) { michael@0: return false; michael@0: } michael@0: michael@0: // checks if the sidebar box is hidden michael@0: let sbb = win.document.getElementById('sidebar-box'); michael@0: if (!sbb || sbb.hidden) { michael@0: return false; michael@0: } michael@0: michael@0: if (sidebarTitle.value == modelFor(sidebar).title) { michael@0: // checks if the sidebar is loading michael@0: if (win.gWebPanelURI == modelFor(sidebar).url) { michael@0: return true; michael@0: } michael@0: michael@0: // checks if the sidebar loaded already michael@0: let ele = sb.contentDocument && sb.contentDocument.getElementById(WEB_PANEL_BROWSER_ID); michael@0: if (!ele) { michael@0: return false; michael@0: } michael@0: michael@0: if (ele.getAttribute('cachedurl') == modelFor(sidebar).url) { michael@0: return true; michael@0: } michael@0: michael@0: if (ele && ele.contentWindow && ele.contentWindow.location == modelFor(sidebar).url) { michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: // default michael@0: return false; michael@0: } michael@0: exports.isSidebarShowing = isSidebarShowing; michael@0: michael@0: function showSidebar(window, sidebar, newURL) { michael@0: window = window || getMostRecentBrowserWindow(); michael@0: michael@0: let { promise, resolve, reject } = defer(); michael@0: let model = modelFor(sidebar); michael@0: michael@0: if (!newURL && isSidebarShowing(window, sidebar)) { michael@0: resolve({}); michael@0: } michael@0: else if (!isPrivateBrowsingSupported && isWindowPrivate(window)) { michael@0: reject(Error('You cannot show a sidebar on private windows')); michael@0: } michael@0: else { michael@0: sidebar.once('show', resolve); michael@0: michael@0: let menuitem = window.document.getElementById(makeID(model.id)); michael@0: menuitem.setAttribute('checked', true); michael@0: michael@0: window.openWebPanel(model.title, newURL || model.url); michael@0: } michael@0: michael@0: return promise; michael@0: } michael@0: exports.showSidebar = showSidebar; michael@0: michael@0: michael@0: function hideSidebar(window, sidebar) { michael@0: window = window || getMostRecentBrowserWindow(); michael@0: michael@0: let { promise, resolve, reject } = defer(); michael@0: michael@0: if (!isSidebarShowing(window, sidebar)) { michael@0: reject(Error('The sidebar is already hidden')); michael@0: } michael@0: else { michael@0: sidebar.once('hide', resolve); michael@0: michael@0: // Below was taken from http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#4775 michael@0: // the code for window.todggleSideBar().. michael@0: let { document } = window; michael@0: let sidebarEle = document.getElementById('sidebar'); michael@0: let sidebarTitle = document.getElementById('sidebar-title'); michael@0: let sidebarBox = document.getElementById('sidebar-box'); michael@0: let sidebarSplitter = document.getElementById('sidebar-splitter'); michael@0: let commandID = sidebarBox.getAttribute('sidebarcommand'); michael@0: let sidebarBroadcaster = document.getElementById(commandID); michael@0: michael@0: sidebarBox.hidden = true; michael@0: sidebarSplitter.hidden = true; michael@0: michael@0: sidebarEle.setAttribute('src', 'about:blank'); michael@0: //sidebarEle.docShell.createAboutBlankContentViewer(null); michael@0: michael@0: sidebarBroadcaster.removeAttribute('checked'); michael@0: sidebarBox.setAttribute('sidebarcommand', ''); michael@0: sidebarTitle.value = ''; michael@0: sidebarBox.hidden = true; michael@0: sidebarSplitter.hidden = true; michael@0: michael@0: // TODO: perhaps this isn't necessary if the window is not most recent? michael@0: window.gBrowser.selectedBrowser.focus(); michael@0: } michael@0: michael@0: return promise; michael@0: } michael@0: exports.hideSidebar = hideSidebar; michael@0: michael@0: function makeID(id) { michael@0: return 'jetpack-sidebar-' + id; michael@0: }