diff options
Diffstat (limited to 'tools/addon-sdk-1.5/packages/addon-kit/lib/panel.js')
-rw-r--r-- | tools/addon-sdk-1.5/packages/addon-kit/lib/panel.js | 369 |
1 files changed, 0 insertions, 369 deletions
diff --git a/tools/addon-sdk-1.5/packages/addon-kit/lib/panel.js b/tools/addon-sdk-1.5/packages/addon-kit/lib/panel.js deleted file mode 100644 index 1365c02..0000000 --- a/tools/addon-sdk-1.5/packages/addon-kit/lib/panel.js +++ /dev/null @@ -1,369 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -if (!require("api-utils/xul-app").is("Firefox")) { - throw new Error([ - "The panel module currently supports only Firefox. In the future ", - "we would like it to support other applications, however. Please see ", - "https://bugzilla.mozilla.org/show_bug.cgi?id=jetpack-panel-apps ", - "for more information." - ].join("")); -} - -const { Cc, Ci } = require("chrome"); - -const { validateOptions: valid } = require("api-utils/api-utils"); -const { Symbiont } = require("api-utils/content"); -const { EventEmitter } = require('api-utils/events'); -const timer = require("api-utils/timer"); -const runtime = require("api-utils/runtime"); - -const windowMediator = Cc['@mozilla.org/appshell/window-mediator;1']. - getService(Ci.nsIWindowMediator); - -const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", - ON_SHOW = 'popupshown', - ON_HIDE = 'popuphidden', - validNumber = { is: ['number', 'undefined', 'null'] }; - -/** - * Emits show and hide events. - */ -const Panel = Symbiont.resolve({ - constructor: '_init', - _onInit: '_onSymbiontInit', - destroy: '_symbiontDestructor', - _documentUnload: '_workerDocumentUnload' -}).compose({ - _frame: Symbiont.required, - _init: Symbiont.required, - _onSymbiontInit: Symbiont.required, - _symbiontDestructor: Symbiont.required, - _emit: Symbiont.required, - _asyncEmit: Symbiont.required, - on: Symbiont.required, - removeListener: Symbiont.required, - - _inited: false, - - /** - * If set to `true` frame loaders between xul panel frame and - * hidden frame are swapped. If set to `false` frame loaders are - * set back to normal. Setting the value that was already set will - * have no effect. - */ - set _frameLoadersSwapped(value) { - if (this.__frameLoadersSwapped == value) return; - this._frame.QueryInterface(Ci.nsIFrameLoaderOwner) - .swapFrameLoaders(this._viewFrame); - this.__frameLoadersSwapped = value; - }, - __frameLoadersSwapped: false, - - constructor: function Panel(options) { - this._onShow = this._onShow.bind(this); - this._onHide = this._onHide.bind(this); - this.on('inited', this._onSymbiontInit.bind(this)); - - options = options || {}; - if ('onShow' in options) - this.on('show', options.onShow); - if ('onHide' in options) - this.on('hide', options.onHide); - if ('width' in options) - this.width = options.width; - if ('height' in options) - this.height = options.height; - if ('contentURL' in options) - this.contentURL = options.contentURL; - - this._init(options); - }, - _destructor: function _destructor() { - this.hide(); - this._removeAllListeners('show'); - // defer cleanup to be performed after panel gets hidden - this._xulPanel = null; - this._symbiontDestructor(this); - this._removeAllListeners(); - }, - destroy: function destroy() { - this._destructor(); - }, - /* Public API: Panel.width */ - get width() this._width, - set width(value) - this._width = valid({ $: value }, { $: validNumber }).$ || this._width, - _width: 320, - /* Public API: Panel.height */ - get height() this._height, - set height(value) - this._height = valid({ $: value }, { $: validNumber }).$ || this._height, - _height: 240, - - /* Public API: Panel.isShowing */ - get isShowing() !!this._xulPanel && this._xulPanel.state == "open", - - /* Public API: Panel.show */ - show: function show(anchor) { - anchor = anchor || null; - let document = getWindow(anchor).document; - let xulPanel = this._xulPanel; - if (!xulPanel) { - xulPanel = this._xulPanel = document.createElementNS(XUL_NS, 'panel'); - xulPanel.setAttribute("type", "arrow"); - - // One anonymous node has a big padding that doesn't work well with - // Jetpack, as we would like to display an iframe that completely fills - // the panel. - // -> Use a XBL wrapper with inner stylesheet to remove this padding. - let css = ".panel-inner-arrowcontent, .panel-arrowcontent {padding: 0;}"; - let originalXBL = "chrome://global/content/bindings/popup.xml#arrowpanel"; - let binding = - '<bindings xmlns="http://www.mozilla.org/xbl">' + - '<binding id="id" extends="' + originalXBL + '">' + - '<resources>' + - '<stylesheet src="data:text/css,' + - document.defaultView.encodeURIComponent(css) + '"/>' + - '</resources>' + - '</binding>' + - '</bindings>'; - xulPanel.style.MozBinding = 'url("data:text/xml,' + - document.defaultView.encodeURIComponent(binding) + '")'; - - let frame = document.createElementNS(XUL_NS, 'iframe'); - frame.setAttribute('type', 'content'); - frame.setAttribute('flex', '1'); - frame.setAttribute('transparent', 'transparent'); - if (runtime.OS === "Darwin") { - frame.style.borderRadius = "6px"; - frame.style.padding = "1px"; - } - - // Load an empty document in order to have an immediatly loaded iframe, - // so swapFrameLoaders is going to work without having to wait for load. - frame.setAttribute("src","data:,"); - - xulPanel.appendChild(frame); - document.getElementById("mainPopupSet").appendChild(xulPanel); - } - let { width, height } = this, x, y, position; - - if (!anchor) { - // Open the popup in the middle of the window. - x = document.documentElement.clientWidth / 2 - width / 2; - y = document.documentElement.clientHeight / 2 - height / 2; - position = null; - } - else { - // Open the popup by the anchor. - let rect = anchor.getBoundingClientRect(); - - let window = anchor.ownerDocument.defaultView; - - let zoom = window.mozScreenPixelsPerCSSPixel; - let screenX = rect.left + window.mozInnerScreenX * zoom; - let screenY = rect.top + window.mozInnerScreenY * zoom; - - // Set up the vertical position of the popup relative to the anchor - // (always display the arrow on anchor center) - let horizontal, vertical; - if (screenY > window.screen.availHeight / 2 + height) - vertical = "top"; - else - vertical = "bottom"; - - if (screenY > window.screen.availWidth / 2 + width) - horizontal = "left"; - else - horizontal = "right"; - - let verticalInverse = vertical == "top" ? "bottom" : "top"; - position = vertical + "center " + verticalInverse + horizontal; - - // Allow panel to flip itself if the panel can't be displayed at the - // specified position (useful if we compute a bad position or if the - // user moves the window and panel remains visible) - xulPanel.setAttribute("flip","both"); - } - - // Resize the iframe instead of using panel.sizeTo - // because sizeTo doesn't work with arrow panels - xulPanel.firstChild.style.width = width + "px"; - xulPanel.firstChild.style.height = height + "px"; - - // Wait for the XBL binding to be constructed - function waitForBinding() { - if (!xulPanel.openPopup) { - timer.setTimeout(waitForBinding, 50); - return; - } - xulPanel.openPopup(anchor, position, x, y); - } - waitForBinding(); - - return this._public; - }, - /* Public API: Panel.hide */ - hide: function hide() { - // The popuphiding handler takes care of swapping back the frame loaders - // and removing the XUL panel from the application window, we just have to - // trigger it by hiding the popup. - // XXX Sometimes I get "TypeError: xulPanel.hidePopup is not a function" - // when quitting the host application while a panel is visible. To suppress - // them, this now checks for "hidePopup" in xulPanel before calling it. - // It's not clear if there's an actual issue or the error is just normal. - let xulPanel = this._xulPanel; - if (xulPanel && "hidePopup" in xulPanel) - xulPanel.hidePopup(); - return this._public; - }, - - /* Public API: Panel.resize */ - resize: function resize(width, height) { - this.width = width; - this.height = height; - // Resize the iframe instead of using panel.sizeTo - // because sizeTo doesn't work with arrow panels - let xulPanel = this._xulPanel; - if (xulPanel) { - xulPanel.firstChild.style.width = width + "px"; - xulPanel.firstChild.style.height = height + "px"; - } - }, - - // While the panel is visible, this is the XUL <panel> we use to display it. - // Otherwise, it's null. - get _xulPanel() this.__xulPanel, - set _xulPanel(value) { - let xulPanel = this.__xulPanel; - if (value === xulPanel) return; - if (xulPanel) { - xulPanel.removeEventListener(ON_HIDE, this._onHide, false); - xulPanel.removeEventListener(ON_SHOW, this._onShow, false); - xulPanel.parentNode.removeChild(xulPanel); - } - if (value) { - value.addEventListener(ON_HIDE, this._onHide, false); - value.addEventListener(ON_SHOW, this._onShow, false); - } - this.__xulPanel = value; - }, - __xulPanel: null, - get _viewFrame() this.__xulPanel.children[0], - /** - * When the XUL panel becomes hidden, we swap frame loaders back to move - * the content of the panel to the hidden frame & remove panel element. - */ - _onHide: function _onHide() { - try { - this._frameLoadersSwapped = false; - this._xulPanel = null; - this._emit('hide'); - } catch(e) { - this._emit('error', e); - } - }, - /** - * When the XUL panel becomes shown, we swap frame loaders between panel - * frame and hidden frame to preserve state of the content dom. - */ - _onShow: function _onShow() { - try { - if (!this._inited) { // defer if not initialized yet - this.on('inited', this._onShow.bind(this)); - } else { - this._frameLoadersSwapped = true; - - // Retrieve computed text color style in order to apply to the iframe - // document. As MacOS background is dark gray, we need to use skin's - // text color. - let win = this._xulPanel.ownerDocument.defaultView; - let node = win.document.getAnonymousElementByAttribute(this._xulPanel, - "class", "panel-inner-arrowcontent"); - let textColor = win.getComputedStyle(node).getPropertyValue("color"); - let doc = this._xulPanel.firstChild.contentDocument; - let style = doc.createElement("style"); - style.textContent = "body { color: " + textColor + "; }"; - let container = doc.head ? doc.head : doc.documentElement; - - if (container.firstChild) - container.insertBefore(style, container.firstChild); - else - container.appendChild(style); - - this._emit('show'); - } - } catch(e) { - this._emit('error', e); - } - }, - /** - * Notification that panel was fully initialized. - */ - _onInit: function _onInit() { - this._inited = true; - - // Avoid panel document from resizing the browser window - // New platform capability added through bug 635673 - if ("allowWindowControl" in this._frame.docShell) - this._frame.docShell.allowWindowControl = false; - - // perform all deferred tasks like initSymbiont, show, hide ... - // TODO: We're publicly exposing a private event here; this - // 'inited' event should really be made private, somehow. - this._emit('inited'); - }, - - // Catch document unload event in order to rebind load event listener with - // Symbiont._initFrame if Worker._documentUnload destroyed the worker - _documentUnload: function(subject, topic, data) { - if (this._workerDocumentUnload(subject, topic, data)) { - this._initFrame(this._frame); - return true; - } - return false; - } -}); -exports.Panel = function(options) Panel(options) -exports.Panel.prototype = Panel.prototype; - -function getWindow(anchor) { - let window; - - if (anchor) { - let anchorWindow = anchor.ownerDocument.defaultView.top; - let anchorDocument = anchorWindow.document; - - let enumerator = windowMediator.getEnumerator("navigator:browser"); - while (enumerator.hasMoreElements()) { - let enumWindow = enumerator.getNext(); - - // Check if the anchor is in this browser window. - if (enumWindow == anchorWindow) { - window = anchorWindow; - break; - } - - // Check if the anchor is in a browser tab in this browser window. - let browser = enumWindow.gBrowser.getBrowserForDocument(anchorDocument); - if (browser) { - window = enumWindow; - break; - } - - // Look in other subdocuments (sidebar, etc.)? - } - } - - // If we didn't find the anchor's window (or we have no anchor), - // return the most recent browser window. - if (!window) - window = windowMediator.getMostRecentWindow("navigator:browser"); - - return window; -} - |