简体   繁体   English

Firefox SDK附加组件,左右两侧同时带有侧边栏

[英]Firefox SDK Add-on with a sidebar on both the right and left at the same time

I'm programming a Firefox Add-on SDK based extension. 我正在编写一个基于Firefox附加SDK的扩展程序。 I need to use both a left and a right-side sidebar, at the same time . 我需要同时使用左,右侧边栏, 在同一时间 By default, I can display one on the left side. 默认情况下,我可以在左侧显示一个。 I've already read about changing between having the ui/sidebar on the left and the right by using the CSS: 我已经读过关于使用CSS在左右两侧都有ui / sidebar之间进行切换的信息:

@namespace url(http://www.mozilla.org/keymaster/gat...re.is.only.xul);
hbox#browser { 
    direction: rtl !important;
}         
hbox#browser > vbox {
    direction: ltr !important; 
}

But, that seems to be something of the old-school, because I didn't define .xul files. 但是,这似乎有点老套了,因为我没有定义.xul文件。

Do you know any to have a sidebar on both the left and right of the browser at the same time? 您是否知道同时在浏览器的左侧和右侧都有侧边栏?

Your question is not clear as to exactly what you want. 您的问题不清楚您到底想要什么。 Thus, I have made some assumptions. 因此,我做了一些假设。

Ultimately, there is no officially supported way to have more than one "sidebar" displayed at a time. 最终,没有官方支持的方法可以一次显示多个“侧边栏”。 By default, only a single "sidebar" exist within the Firefox Browser windows. 默认情况下,Firefox浏览器窗口中仅存在一个“补充工具栏”。 While there is no supported API which provides you with more than one sidebar, it is possible to create multiple sidebars (interface panels) by modifying the XUL DOM for the Firefox Browser windows. 虽然没有支持的API为您提供多个侧边栏,但可以通过修改Firefox浏览器窗口的XUL DOM来创建多个侧边栏(界面面板)。

The code below creates user interface panels (side-bars, top-bars, bottom-bars and windows) which are on the top, bottom, left, right, of the browser window, or in a separate window. 下面的代码创建用户界面面板(侧栏,顶部栏,底部栏和窗口),这些面板位于浏览器窗口的顶部,底部,左侧,右侧或单独的窗口中。 The interface panels can be created such that they are with respect to the window (they stay visible when you switch tabs; like a bookmarks/history sidebar), or are with respect to the tab (they on only visible when the tab in which they were created is displayed; like the developer tools). 可以创建界面面板,使其相对于窗口(在切换选项卡时它们保持可见;如书签/历史边栏),或者相对于选项卡(仅当它们位于其中的选项卡时可见)将显示创建者;类似于开发者工具)。

The createInterfacePanelIframe() method creates an interface panel containing an <iframe> (or <browser> ) for which you can supply the URL and all attributes. createInterfacePanelIframe()方法创建一个包含<iframe> (或<browser> )的界面面板,您可以为其提供URL和所有属性。 The elements for the <iframe> and the <splitter> are returned to the caller so you can perform other operations on them, or remove them from the Firefox window's DOM to delete/hide them. <iframe><splitter>的元素将返回给调用方,因此您可以对它们执行其他操作,或者将它们从Firefox窗口的DOM中删除以删除/隐藏它们。 This method creates <iframe> and calls createInterfacePanel() to insert it into the Firefox browser in the location specified. 此方法创建<iframe>并调用createInterfacePanel()将其插入到Firefox浏览器中指定位置。

The createInterfacePanel() method will put the XUL element that you pass to it (use a Document Fragment to pass multiple elements) into the Firefox Browser window's DOM, along with a <splitter> in the location specified (left, right, top, bottom, window and relative to either the window or the tab). createInterfacePanel()方法会将您传递给它的XUL元素(使用文档片段传递多个元素)连同指定位置(左,右,上,下)中的<splitter>一起放入Firefox浏览器窗口的DOM中。 ,窗口以及相对于窗口或标签的窗口)。 You can specify the window and/or tab you desire the interface panel to be within, or, by default, the interface panel is inserted in the current window/tab. 您可以指定您希望界面面板位于其中的窗口和/或选项卡,或者默认情况下,界面面板将插入当前的窗口/选项卡中。 If an interface panel already exists where you are specifying one to be inserted, another panel will be created adjacent to the existing one. 如果您要指定要插入的接口面板已经存在,则会在现有面板的旁边创建另一个面板。 There is no inherent limit to the number you can create (eg you could have 10 panels on the right, if you wanted). 您可以创建的数量没有固有的限制(例如,如果需要,可以在右侧有10个面板)。

In addition, a demo Firefox Add-on SDK extension is below which adds 6 different buttons. 另外,下面是一个演示Firefox附加SDK扩展示例,其中添加了6个不同的按钮。 The first 5 buttons create or destroy interface panels. 前5个按钮创建或销毁界面面板。 The badge indicates which panel the button will affect (left, right, top, bottom, and window). 徽章指示按钮将影响哪个面板(左侧,右侧,顶部,底部和窗口)。 A green badge indicates an interface panel will be created. 绿色徽章指示将创建一个界面面板。 A red badge indicates clicking will destroy the already existing panel. 红色标志表示单击将破坏现有面板。 The sixth button toggles the other buttons between Tab relative interface panels, and Window relative interface panels. 第六个按钮在“ Tab”相对界面面板和“ Window”相对界面面板之间切换其他按钮。 If you create all the panels your will have 8 panels (4 for the Window and 4 for the current tab) along with two separate windows (per Browser Window). 如果创建所有面板,将有8个面板(4个用于窗口,而4个用于当前选项卡)以及两个单独的窗口(每个浏览器窗口)。

The following is what the demo add-on looks like. 以下是该演示插件的外观。 The panels shown in the image below are narrow and/or short to allow them to be displayed on this page. 下图中显示的面板很窄和/或很短,可以显示在此页面上。 The code below allows you to make the panels whatever size you desire and for the user to be able to resize them. 下面的代码使您可以根据需要调整面板的尺寸,并使用户能够调整面板的尺寸。
演示附加组件的实际应用

This is the code which creates the sidebars (interface panels): 这是创建侧栏(界面面板)的代码:

sidebars.js : sidebars.js

/**
 * createInterfacePanelIframe(location,options)
 *   Creates an <iframe> based panel within the current tab, within the
 *   current window, or opens a window, for use as an user interface
 *   box.  If it is not a window, it is associated with the current
 *   browser tab, or the current browser window depending on the
 *   byWindow option.

 * @param location 
 *   Placement of the panel [right|left|top|bottom|window]
 *   The default location is 'right'.
 * @param options
 *   An Object containing optional parameters. 
 *     height
 *       The height of a top or bottom sidebar
 *       Default is 200.
 *     width
 *       The width of a left or right sidebar
 *       Default is 200.
 *     size
 *       Width if on left or right. Height if top or bottom.
 *       Both width and height if location='window' unless
 *       features is a string. 
 *       Default is 200.
 *     id
 *       The ID to assign to the iframe. Default is
 *       'makyen-interface-panel'
 *       The <splitter> will be assigned the
 *       ID = id + '-splitter'
 *     url
 *       This is the chrome://  URL to use for the contents
 *       of the iframe or the window.
 *       the default is:
 *       'chrome://devtools/content/framework/toolbox.xul'
 *     iframeAttributes
 *       An Object
 *       Contains key/value pairs which are applies as attributes
 *       of the iframe. These will override any defaults or other
 *       attributes derived from other options (e.g. id, height,
 *       width, type, etc.). If the value of the property is null
 *       then that attribute will be removed.
 *     useBrowser
 *       If true, a <browser> element is used instead of an <iframe>.
 *     byWindow
 *       If true then the created sidebar is for the window
 *       not the tab.
 *     tab
 *       The tab for which to create the sidebar. If not
 *       specified, the current tab is used.
 *     window
 *       The window for which to create the sidebar. If not
 *       specified, the current window is used.
 *     features
 *       The features string for the window. See:
 *       https://developer.mozilla.org/en-US/docs/Web/API/Window.open
 *
 * returns [splitterEl, iframeEl]
 *   The elements for the <splitter> and <iframe>.
 *
 * Copyright 2014-2016 by Makyen.
 * Released under the MPL 2.0. http://mozilla.org/MPL/2.0/.
 **/
function createInterfacePanelIframe(location,options){
    //options
    let size,width,height,id,chromeUrl;
    if(typeof options === 'object'){
        size = options.size;
        width = options.width;
        height = options.height;
        id = options.id;
        chromeUrl = options.url;
    }
    if(!width && !height && size){
        width = size;
        height = size;
    }
    [width,height] = getSizeWithDefaults(location,width,height);

    //defaults
    id = typeof id !== 'string' ? 'makyen-interface-panel' : id;
    chromeUrl = typeof chromeUrl !== 'string'
        ? 'chrome://devtools/content/framework/toolbox.xul'
        : chromeUrl;

    //Create some common variables if they do not exist.
    //This gets the currently active Firefox XUL window.
    //  Add/remove a '/' to comment/un-comment the code appropriate for your add-on type.
    //* Add-on SDK:
    let activeWindow = options.window ?
            options.window : require('sdk/window/utils').getMostRecentBrowserWindow();
    //*/
    /* Overlay and bootstrap (from almost any context/scope):
    Components.utils.import('resource://gre/modules/Services.jsm');//Services
    let activeWindow = options.window ?
            options.window : Services.wm.getMostRecentWindow('navigator:browser');
    //*/
    let mainDocument = activeWindow.document;

    //Create the <iframe> use
    //mainDocument for the XUL namespace.
    let iframeEl;
    if(options.useBrowser){
        iframeEl = mainDocument.createElement('browser');
    } else {
        iframeEl = mainDocument.createElement('iframe');
    }
    iframeEl.id = id;
    iframeEl.setAttribute('src',chromeUrl);
    iframeEl.setAttribute("tooltip", "aHTMLTooltip");
    iframeEl.setAttribute("autocompleteenabled", true);
    iframeEl.setAttribute("autocompletepopup", "PopupAutoComplete");
    iframeEl.setAttribute("disablehistory",true);
    iframeEl.setAttribute('type', 'content');
    if(typeof height === 'number'){
        iframeEl.setAttribute('height', height.toString());
    }
    if(typeof width === 'number'){
        iframeEl.setAttribute('width', width.toString());
    }
    if(typeof options.iframeAttributes === 'object'){
        let attrs = options.iframeAttributes;
        for(let attr in attrs){
            if(attrs.hasOwnProperty(attr)) {
                if(attrs[attr]===null){
                    iframeEl.removeAttribute(attr);
                }else{
                    iframeEl.setAttribute(attr, attrs[attr]);
                }
            }
        }
    }

    //Call createInterfacePanel
    let splitterEl;
    let newOptions = {};
    if(height) {
        newOptions.height = height;
    }
    if(width) {
        newOptions.width = width;
    }
    newOptions.url = chromeUrl;
    if(options.tab){
        newOptions.tab = options.tab;
    }
    if(options.window){
        newOptions.window = options.window;
    }
    if(options.features){
        newOptions.features = options.features;
    }
    if(options.byWindow){
        newOptions.byWindow = options.byWindow;
    }
    newOptions.id = id + '-splitter';
    splitterEl = createInterfacePanel(location, iframeEl, newOptions)
    return [splitterEl, iframeEl];
}

/**
 * createInterfacePanel(location,objectEl,options)
 *   Creates a panel within the current tab, or opens a window, for use as a
 *   user interface box. If not a window, it is associated with the current
 *   browser tab.
 * @param location 
 *   Placement of the panel [right|left|top|bottom|window]
 *   The default location is 'right'.
 * @param objectEl
 *   The element of an XUL object that will be inserted into
 *   the DOM such that it is within the current tab.
 *   Some examples of possible objects are <iframe>,
 *   <browser>, <box>, <hbox>, <vbox>, etc.
 *   If the location='window' and features is not a string
 *   and this is a number then it is used as the width of the
 *   window.
 * @param options
 *   An Object containing optional parameters. 
 *     height
 *       The height of a top or bottom sidebar
 *       Default is 200.
 *     width
 *       The width of a left or right sidebar
 *       Default is 200.
 *     size
 *       Width if on left or right. Height if top or bottom.
 *       Both width and height if location='window' unless
 *       features is a string. 
 *       Default is 200.
 *       If none of height, width or size is specified, then the
 *       size of the sidebar should be specified within the XUL
 *       elements referenced by objectEl.
 *     sizeEl
 *       The element that is to contain attributes of 'width' and 
 *       'height'. If location=='left'|'right' then the 
 *       'height' attribute is removed prior to the objectEl
 *       being inserted into the DOM.
 *       This is an optional spearate reference for the size element
 *       in case the objectEl is a documentFragment containing
 *       multiple elements. However, normal usage is for
 *       objectEl === sizeEl (which is default if unspecified)
 *       when location != 'window'.
 *       When location == 'window' and features is not a string,
 *       and sizeEl is a number then it is used as the height
 *       of the window.
 *       If features is a string, it is assumed the height is
 *       set in that, or elsewhere (e.g. in the XUL).
 *     id
 *       The ID to assign to the <splitter>. The default is:
 *       'makyen-interface-panel-splitter'.
 *     url
 *       This is the chrome://  URL to use for the contents
 *       of the window.
 *       the default is:
 *       'chrome://devtools/content/framework/toolbox.xul'
 *     byWindow
 *       If true then the created sidebar is for the window
 *       not the tab.
 *     tab
 *       The tab for which to create the sidebar. If not
 *       specified, the current tab is used.
 *     window
 *       The window for which to create the sidebar. If not
 *       specified, the current window is used.
 *     features
 *       The features string for the window. See:
 *       https://developer.mozilla.org/en-US/docs/Web/API/Window.open
 *       If features is a string, it is assumed the width is
 *       set in that, or elsewhere (e.g. in the XUL).
 *
 * returns
 *   if location != 'window':
 *     splitterEl, The element for the <splitter>.
 *   if location == 'window':
 *     The windowObjectReference returned by window.open().
 *
 * Copyright 2014-2016 by Makyen.
 * Released under the MPL 2.0. http://mozilla.org/MPL/2.0/.
 **/
function createInterfacePanel(location,objectEl,options) {
//function createInterfacePanel(location,objectEl,sizeEl,id,chromeUrl,features) {
    //options
    let size,width,height,sizeEl,id,chromeUrl,byWindow,features;
    if(typeof options === 'object'){
        size = options.size;
        width = options.width;
        height = options.height;
        //If a separate sizeEl is not specified, then use the ObjectEl for sizeEl.
        //  This is so we could pass a document fragment with multiple elements,
        //  But only one which should have a specified size.
        sizeEl = options.sizeEl? options.sizeEl:objectEl;
        id = options.id;
        chromeUrl = options.url;
        byWindow = options.byWindow;
        features = options.features;
    }
    if(!width && !height && size){
        width = size;
        height = size;
    }
    [width,height] = getSizeWithDefaults(location,width,height);

    //Set location default:
    location = typeof location !== 'string' ? 'right' : location;
    if(location == 'window') {
        if(typeof features !== 'string') {
            let widthText =  'width=' + width.toString() + ',';
            let heightText = 'height=' + height.toString() + ',';
            features = widthText + heightText
                       + 'menubar=no,toolbar=no,location=no,personalbar=no'
                       + ',status=no,chrome=yes,resizable,centerscreen';
        }
    }
    id = typeof id !== 'string' ? 'makyen-interface-panel-splitter' : id;
    chromeUrl = typeof chromeUrl !== 'string'
        ? 'chrome://devtools/content/framework/toolbox.xul'
        : chromeUrl;

    //Create some common variables if they do not exist.
    //This gets the currently active Firefox XUL window.
    //  Add/remove a '/' to comment/un-comment the code appropriate for your add-on type.
    //* Add-on SDK:
    let activeWindow = options.window ?
            options.window : require('sdk/window/utils').getMostRecentBrowserWindow();
    //*/
    /* Overlay and bootstrap (from almost any context/scope):
    Components.utils.import('resource://gre/modules/Services.jsm');//Services
    let activeWindow = options.window ?
            options.window : Services.wm.getMostRecentWindow('navigator:browser');
    //*/
    if (typeof gBrowser === 'undefined') {
        //If there is no gBrowser defined, get it
        var gBrowser = activeWindow.gBrowser;
    }

    //Get the tab & notification box (container for tab UI).
    let tab = options.tab?options.tab:gBrowser.selectedTab;
    let browserForTab = gBrowser.getBrowserForTab( tab );
    let notificationBox = gBrowser.getNotificationBox( browserForTab );
    let ownerDocument = gBrowser.ownerDocument;

    //Create a Document Fragment.
    //If doing multiple DOM additions, we should be in the habit
    //  of doing things in a way which causes the least number of reflows.
    //  We know that we are going to add more than one thing, so use a
    //  document fragment.
    let docFrag = ownerDocument.createDocumentFragment();

    //ownerDocument must be used here in order to have the XUL namespace
    //  or the splitter causes problems.
    //  createElementNS() does not work here.
    let splitterEl = ownerDocument.createElement('splitter');
    splitterEl.id =  id ;

    //Look for the child element with class='browserSidebarContainer'.
    //It is the element in procimity to which the <splitter>
    //and objectEl will be placed.
    let theChild = notificationBox.firstChild;
    while (!theChild.hasAttribute('class')
        || (theChild.getAttribute('class').indexOf('browserSidebarContainer') === -1)
    ) {
        theChild = theChild.nextSibling;
        if(!theChild) {
            //We failed to find the correct node.
            //This implies that the structure Firefox
            //  uses has changed significantly and it should 
            //  be assumed that the extension is no longer compatible.
            return null;
        }
    }
    let tabBrowser = ownerDocument.getElementById('content');
    let heightAttr='height';
    let widthAttr='width';
    if(byWindow) {
        notificationBox = ownerDocument.getElementById('browser');
        theChild = ownerDocument.getElementById('appcontent');
        //When Window referenced, where we need to put the elements is
        //  slightly different, but works out to just being a swapping
        //  of 'location' values.
        //Swap the width and height attributes and options.
        heightAttr='width';
        widthAttr='height';
        let foo = width;
        width = height;
        height = foo;
        foo = options.width;
        options.width = options.height;
        options.height = foo;
        switch(location) {
            case 'window'  :
                //no change
                break;
            case 'top'    :
                location = 'left'
                break;
            case 'bottom' :
                location = 'right'
                break;
            case 'left'   :
                location = 'top'
                break;
            case 'right'  :
            default       :
                location = 'bottom'
                break;
        }
    }

    switch(location) {
        case 'window'    :
            return activeWindow.open(chromeUrl,'_blank',features);
            break;
        case 'top'    :
            if(options.size || options.height) {
                //Don't mess with the height/size unless it was specified
                sizeEl.removeAttribute(widthAttr);
                sizeEl.setAttribute(heightAttr,height);
            }
            docFrag.appendChild(objectEl);
            docFrag.appendChild(splitterEl);
            //Inserting the document fragment results in the same
            //  DOM structure as if you Inserted each child of the
            //  fragment separately. (i.e. the document fragment
            //  is just a temporary container).
            //Insert the interface prior to theChild.
            notificationBox.insertBefore(docFrag,theChild);
            break;
        case 'bottom' :
            if(options.size || options.height) {
                //Don't mess with the height/size unless it was specified
                sizeEl.removeAttribute(widthAttr);
                sizeEl.setAttribute(heightAttr,height);
            }
            docFrag.appendChild(splitterEl);
            docFrag.appendChild(objectEl);
            //Insert the interface just after theChild.
            notificationBox.insertBefore(docFrag,theChild.nextSibling);
            break;
        case 'left'   :
            if(options.size || options.width) {
                //Don't mess with the height/size unless it was specified
                sizeEl.removeAttribute(heightAttr);
                sizeEl.setAttribute(widthAttr,width);
            }
            docFrag.appendChild(objectEl);
            //Splitter is second in this orientaiton.
            docFrag.appendChild(splitterEl);
            if(byWindow) {
                //Insert the interface prior to the tabbrowser to put
                //  global notifications above the top sidebar.
                theChild.insertBefore(docFrag,tabBrowser);
            }else{
                //Insert the interface as the first child of theChild.
                theChild.insertBefore(docFrag,theChild.firstChild);
            }
            break;
        case 'right'  :
        default       :
            //Right orientaiton, the default.
            if(options.size || options.width) {
                //Don't mess with the height/size unless it was specified
                sizeEl.removeAttribute(heightAttr);
                sizeEl.setAttribute(widthAttr,width);
            }
            docFrag.appendChild(splitterEl);
            docFrag.appendChild(objectEl);
            //Insert the interface as the last child of theChild.
            theChild.appendChild(docFrag);
            break;
    }
    return splitterEl;
}

function getSizeWithDefaults(location,width,height){
    let defaultSize = 200;
    switch(location) {
        case 'window'    :
            width = ( (typeof width !== 'number') || width<1) ? defaultSize : width; 
            height = ( (typeof height !== 'number') || height<1) ? defaultSize : height; 
            break;
        case 'top'    :
        case 'bottom' :
            width = null;
            height = ( (typeof height !== 'number') || height<1) ? defaultSize : height; 
            break;
        case 'left'   :
        case 'right'  :
        default       :
            width = ( (typeof width !== 'number') || width<1) ? defaultSize : width; 
            height = null;
            break;
    }
    return [width,height];
}

exports.createInterfacePanel=createInterfacePanel;
exports.createInterfacePanelIframe=createInterfacePanelIframe;

The demo Firefox Add-on SDK extension is: 演示版Firefox附加SDK扩展为:

package.json : package.json

{
    "title": "Demo Sidebars",
    "name": "demo-sidebars",
    "version": "0.0.1",
    "description": "Demo creating Window related sidebars",
    "main": "index.js",
    "author": "Makyen",
    "permissions": {"private-browsing": true},
    "engines": {
        "firefox": ">=38.0a1",
        "fennec": ">=38.0a1"
    },
    "license": "MIT",
    "keywords": [
        "jetpack"
    ]
}

data/sidebar.html : data / sidebar.html

<html>
<head>
    <meta charset="utf-8">
</head>
<body style="background-color:white;">
    This is a Window.
</body>
</html>

index.js : index.js

var utils = require('sdk/window/utils');
var tabs = require('sdk/tabs');
var tabsUtils = require('sdk/tabs/utils');
var self = require('sdk/self');

//For testing: Open the Browser Console
var activeWin = utils.getMostRecentBrowserWindow();
activeWin.document.getElementById('menu_browserConsole').doCommand();

var mySidebars = require('./sidebars.js');
var sidebarSize = 100;  //Width & height to use

var sidebarByWindow = false;
var sidebars = {};
//The buttons
var buttons = {
    '◀': {where:'Left'},
    '▶': {where:'Right'},
    '▲': {where:'Top'},
    '▼': {where:'Bottom'},
    '☐': {where:'Window'}
};

//Create Buttons
var sdkActionButtons     = require('sdk/ui/button/action');

for(let badge in buttons){
    buttons[badge].button = sdkActionButtons.ActionButton({
        id: 'openSidebar' + buttons[badge].where,
        label: 'Open ' + buttons[badge].where + ' Sidebar',
        badge: badge,
        badgeColor: 'green',
        icon: './icons/Aurora-icon64.png',
        onClick: handleButtonClick
    });
}

function handleButtonClick(state){
    let where = buttons[state.badge].where.toLowerCase();
    let stateType = getSidebarByWindowText();
    let sidebarId = getSidebarId(state.badge,sidebarByWindow);
    //With this state being kept by window and tab, the checked property does
    //  not accurately track what we need to be doing, so use badgeColor and
    //  action buttons.
    if(sidebars[sidebarId]){
        //If we have a sidebar for this combo, then
        let elements = sidebars[sidebarId];
        if(elements){
            if(where==='window'){
                try{
                    elements[0].close();
                }catch(e){
                    //Do nothing. We should be tracking the state of the window so
                    //  users can use the close button. We are not, so trying to
                    //  close an already closed window could throw an error.
                }
            } else {
                elements.forEach(el => {el.remove();});
            }
        }
        delete sidebars[sidebarId];
    }else{
        //Create the sidebar and keep track of it so it can be removed.
        sidebars[sidebarId] = mySidebars.createInterfacePanelIframe(where,{
            url:self.data.url('sidebar.html'),
            byWindow:sidebarByWindow,
            size:sidebarSize,
            id:'makyen-interface-panel-' + stateType + '- ' + where
        });
        //Make the text reflect the sidebar
        if(where !== 'window'){
            setBodyText(sidebarId, 'This is a ' +stateType + ' ' + where + ' Sidebar.');
            sidebars[sidebarId][1].addEventListener('load', setBodyText.bind(null
                ,sidebarId
                ,'This is a ' + stateType.toUpperCase() + ' ' + where + ' Sidebar.'),true);
        }
    }
    updateButtonBadgeColors();
}

function setBodyText(sidebarId,text){
    let doc = sidebars[sidebarId][1].contentDocument; 
    doc.body.textContent = text;
}

function getSidebarId(badge,sidebarByWindow,domWin){
    let where = buttons[badge].where.toLowerCase();
    let stateType = getSidebarByWindowText();
    domWin = domWin?domWin:utils.getMostRecentBrowserWindow();
    let winId = utils.getOuterId(domWin);
    //This should get the tab ID from any window, not just the active window.
    let tabId = tabsUtils.getTabId(tabsUtils.getActiveTab(domWin));
    let id = sidebarByWindow?winId:tabId;
    return stateType+id+where;
}

function getSidebarByWindowText(){
    return sidebarByWindow?'window':'tab';
}

function updateButtonBadgeColors(){
    //Update the badge colors in all windows based on if there is a sidebar of the
    //  current type for the window/tab.
    let allWindows = utils.windows('navigator:browser',{includePrivate:true});
    for(let win of allWindows){
        for(let badge in buttons){
            let sidebarId = getSidebarId(badge,sidebarByWindow,win);
            buttons[badge].button.state(win,{
                badgeColor : sidebars[sidebarId]?'red':'green'
            });
        }
    }
}
//update badge colors each time the active tab changes.
tabs.on('activate',updateButtonBadgeColors);

//var sdkToggleButtons     = require('sdk/ui/button/toggle');
var windowTabLabelText = 'Sidebars are associated with ';
var windowTabToggleButton = sdkActionButtons.ActionButton({
    id: 'windowTabToggleButton',
    label: windowTabLabelText + getSidebarByWindowText(),
    icon: './icons/Aurora-icon64.png',
    onClick: handlewindowTabToggle
});

function handlewindowTabToggle(state){
    if(!state.badge){
        windowTabToggleButton.badge= '☐';
        windowTabToggleButton.badgeColor= 'blue';
        sidebarByWindow = true;
    } else {
        windowTabToggleButton.badge= '';
        sidebarByWindow = false;
    }
    windowTabToggleButton.label = windowTabLabelText + getSidebarByWindowText();
    updateButtonBadgeColors();
}

The code in this answer was adapted and significantly expanded from my answer to " Firefox Extension, Window related sidebar ". 该答案中的代码经过修改,并从我的答案显着扩展到“ Firefox扩展,与窗口相关的侧边栏 ”。 That answer has significant additional information as how sidebars (interface panels) are structured within the Firefox Browser. 该答案具有重要的附加信息,如Firefox浏览器中的侧边栏(界面面板)的结构。

There is a sidebar API in firefox, this addon makes excellent use of it - https://addons.mozilla.org/en-US/firefox/addon/whatsapp-web-messenger/ firefox中有一个侧边栏API,此插件很好地利用了它-https: //addons.mozilla.org/en-US/firefox/addon/whatsapp-web-messenger/

There seems to be a window.SidebarUI object in each chrome window. 每个镶边窗口中似乎都有一个window.SidebarUI对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM