Firefox扩展,窗口相关的侧边栏 [英] Firefox Extension, Window related sidebar

查看:138
本文介绍了Firefox扩展,窗口相关的侧边栏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为Firefox编写了一个扩展,我需要这个扩展的用户界面在侧边栏上,我跟着一些mozilla的教程,但是侧边栏与一个窗口没有关系。



我需要一个像UI这样的边栏,它可以保存来自同一个窗口的导航数据,并且需要它与窗口相关,就像萤火虫一样。
$ b $我到目前为止所做的只是创建一个菜单和一个项目,我需要点击这个项目将切换我的侧边栏。



我拿了一个看看firebug的源代码,我没有在它的XUL上找到任何的侧边栏的覆盖,脚本对我来说是复杂的,所以我不知道他们如何将他们的UI添加到窗口。

任何想法,或者我可以读到的关于这方面的资源?

解决方案

要小心术语。 Mozilla在Firefox中使用的特定术语补充工具栏指的是在UI侧面的内容框。如果打开,侧边栏是UI的一个常量部分,显示与所选标签无关。只有一个可以选择在左边或右边。它是常规用于内容不会改变从选项卡到标签(例如书签,或历史)。

用于Firefox开发工具(和放置的用户界面是被FireBug采用)是当前选项卡中的一个子面板。它只显示在被调用的标签中。它在 < iframe>中执行; 。它也可以作为一个单独的窗口打开。



当你有一个已知的工作示例,一种方法来弄清楚如何在DOM中实现这种类型的事情整个浏览器窗口是一个DOM)是安装 add-在 DOM Inspector 上,并用它来调查什么内容DOM看起来像。您可能还需要元素检查器插件这是一个非常有用的添加到DOM检查器(shift-right-click打开DOM Inspector到单击的元素)。您也可能会发现堆叠检查器有帮助。

另一个弄清楚如何完成的方法是查看源代码。对于devtools来说,接口实际上是在 resource:///modules/devtools/framework/toolbox-hosts.js中的 SH_create code $ <$ p
$ b 当放置在底部位置时,UI将作为 < notificationbox> 。您可以使用 gBrowser.getNotificationBox(browserForTab)方法找到< notificationbox> 插入的元素是< splitter> < iframe> 。当放置在浏览器选项卡中的其他位置时,这两个元素将作为< notificationbox> 的子元素插入浏览器DOM中的位置,或作为其子元素的子元素< hbox> 其中 class =browserSidebarContainer



作为一个例子,根据[位置]参数,以下函数将在当前选项卡的左侧,右侧,顶部或底部创建一个面板,或作为一个单独的窗口。默认情况下,面板是由< splitter> < iframe> >。 createInterfacePanel()函数更为通用,将接受任何元素或DOM对象作为第二个参数,该参数根据[位置]在适当的位置插入到DOM中,并由内容形式分隔。这样的对象可能是文档片段或< a href =https://developer.mozilla.org/en-US/docs/Web/API/Element =nofollow noreferrer>元素。

  / ** 
*创建一个< iframe>在当前选项卡中的
*或者打开一个窗口,用作用户界面框。
*如果它不是一个窗口,它将与当前的
*浏览器选项卡关联。
* @param location
*放置面板[right | left | top | bottom | window]
*默认位置是right。
* @param size
*如果左边或右边有宽度。如果顶部或底部高度。
*如果位置=窗口,则宽度和高度都不相同,除非
* features是一个字符串。
*默认为400.
* @param id
*要分配给iframe的ID。默认是
*makyen-interface-panel
*< splitter>将分配
* ID = id +-splitter
* @param chromeUrl
*这是用于内容
*的chrome:// URL iframe或窗口。
*默认为:
*chrome://browser/content/devtools/framework/toolbox.xul
* @param features
*窗口的特性字符串。请参阅:
* https://developer.mozilla.org/en-US/docs/Web/API/Window.open
* returns [splitterEl,iframeEl]
* <分离器>和< iframe>
*
*版权所有2014 Makyen。
*在MPL 2.0下发布。 http://mozilla.org/MPL/2.0/。
** /
函数createInterfacePanelIframe(location,size,id,chromeUrl,features){
//默认值
size =((typeof size!==number)| |大小<1)? 400:尺寸;
id = typeof id!==string? makyen-interface-panel:id;
chromeUrl = typeof chromeUrl!==string
? chrome://browser/content/devtools/framework/toolbox.xul
:chromeUrl;

//创建一些公共变量,如果它们不存在的话。
//这可以在任何Firefox环境下工作。
//根据函数运行的上下文,
//这可以被简化。
if(typeof window ===undefined){
//如果没有定义窗口,则获取最近的。
var window = Components.classes [@ mozilla.org/appshell/window-mediator;1]
.getService(Components.interfaces.nsIWindowMediator)
.getMostRecentWindow(navigator:browser );

if(typeof document ===undefined){
//如果没有定义文档,可以获取
var document = window.content.document;

if(typeof gBrowser ===undefined){
//如果没有定义gBrowser,可以获取
var gBrowser = window.gBrowser;
}

//获取当前标签&通知框(标签UI的容器)。
让tab = gBrowser.selectedTab;
let browserForTab = gBrowser.getBrowserForTab(tab);
let notificationBox = gBrowser.getNotificationBox(browserForTab);
让ownerDocument = gBrowser.ownerDocument;

//创建< iframe>使用
// ownerDocument作为XUL命名空间。
let iframeEl = ownerDocument.createElement(iframe);
iframeEl.id = id;
iframeEl.setAttribute(src,chromeUrl);
iframeEl.setAttribute(height,size.toString());
iframeEl.setAttribute(width,size.toString());

//调用createInterfacePanel,如果它是一个窗口,则传递大小。
让splitterEl;
if(location ==window){
splitterEl = createInterfacePanel(location,size,size
,id +-splitter,chromeUrl,features);
return [splitterEl,null];
} else {
splitterEl = createInterfacePanel(location,iframeEl,iframeEl
,id +-splitter,chromeUrl,features);
}
return [splitterEl,iframeEl];

$ b / **
*在当前选项卡中创建一个面板,或者打开一个窗口,用作
*用户界面框。如果不是窗口,则与当前的
*浏览器选项卡关联。
* @param location
*放置面板[right | left | top | bottom | window]
*默认位置是right。
* @param objectEl
* XUL对象的元素,将插入到
* DOM中,使其位于当前选项卡内。
*可能对象的一些示例是< iframe>,
*< browser>< box>,< hbox>,< vbox>等。位置=窗口和功能不是一个字符串
*,这是一个数字,那么它被用作
*窗口的宽度。
*如果要素是一个字符串,则假定宽度为
*,或者其他地方(例如XUL)。
* @param sizeEl
*包含width和
*height属性的元素。如果location ==left|right,那么在将objectEl
*插入到DOM之前,将删除
*height属性。
*在
* objectEl是包含多个元素的documentFragment的情况下,size元素的特殊引用。
*但是,当
* location!=window时,正常的用法是针对objectEl === sizeEl。
*当位置==窗口和要素不是字符串时,
*和sizeEl是一个数字,它被用作窗口的高度
*。
*如果特征是一个字符串,则假定高度为
*,或者在其他位置(例如在XUL中)设置。
* @param id
*分配给< splitter>的ID。默认值是:
*makyen-interface-panel-splitter。
* @param chromeUrl
*这是用于窗口内容
*的chrome:// URL。
*默认为:
*chrome://browser/content/devtools/framework/toolbox.xul
* @param features
*窗口的特性字符串。请参阅:
* https://developer.mozilla.org/en-US/docs/Web/API/Window.open
*返回
* if location!=window:
* splitterEl,< splitter>的元素。
* if location ==window:
* window.open()返回的windowObjectReference。
*
*版权所有2014 Makyen。
*在MPL 2.0下发布。 http://mozilla.org/MPL/2.0/。
** /
函数createInterfacePanel(location,objectEl,sizeEl,id,chromeUrl,features){
//设置位置默认值:
位置= typeof位置!==string ? 对:位置;
if(location ==window){
if(typeof features!==string){
let width =;
let height =;
if(typeof objectEl ==number){
width =width =+ objectEl.toString()+,;

if(typeof sizeEl ==number){
height =height =+ sizeEl.toString()+,;

features = width + height
+menubar = no,toolbar = no,location = no,personalbar = no
+,status = no,chrome = yes ,可调整大小,中心屏幕;
}
}
id = typeof id!==string? makyen-interface-panel-splitter:id;
chromeUrl = typeof chromeUrl!==string
? chrome://browser/content/devtools/framework/toolbox.xul
:chromeUrl;

//创建一些通用变量(如果它们不存在)。
//这可以在任何Firefox环境下工作。
//根据函数运行的上下文,
//这可以被简化。
if(typeof window ===undefined){
//如果没有定义窗口,则获取最近的。
var window = Components.classes [@ mozilla.org/appshell/window-mediator;1]
.getService(Components.interfaces.nsIWindowMediator)
.getMostRecentWindow(navigator:browser );

if(typeof document ===undefined){
//如果没有定义文档,可以获取
var document = window.content.document;

if(typeof gBrowser ===undefined){
//如果没有定义gBrowser,可以获取
var gBrowser = window.gBrowser;
}

//获取当前标签&通知框(标签UI的容器)。
让tab = gBrowser.selectedTab;
let browserForTab = gBrowser.getBrowserForTab(tab);
let notificationBox = gBrowser.getNotificationBox(browserForTab);
让ownerDocument = gBrowser.ownerDocument;


//创建一个文档片段。
//如果做多个DOM添加,我们应该习惯
//做一些导致回流次数最少的方法。
//我们知道我们要添加多个东西,所以使用
//文档片段。
let docFrag = ownerDocument.createDocumentFragment();

//为了让XUL命名空间
// // splitter会导致问题,必须在这里使用ownerDocument。
// createElementNS()在这里不起作用。
让splitterEl = ownerDocument.createElement(splitter);
splitterEl.id = id;

//查找class =browserSidebarContainer的子元素。
//这是< splitter><
//和objectEl将被放置。
let theChild = notificationBox.firstChild;
while(!theChild.hasAttribute(class)
||!theChild.getAttribute(class)。contains(browserSidebarContainer)
){
theChild = theChild .nextSibling;
if(!theChild){
//我们找不到正确的节点。
//这意味着Firefox
//使用的结构已经发生了很大的变化,应该假设
//被认为不再兼容。
返回null;
}
}

let toReturn = null;
switch(location){
casewindow:
return window.open(chromeUrl,_ blank,features);
break;
casetop:
if(sizeEl){
sizeEl.removeAttribute(width);
}
docFrag.appendChild(objectEl);
docFrag.appendChild(splitterEl);
//插入文档片段会得到相同的
// DOM结构,就像分别插入
//片段的每个子元素一样。 (即文档片段
//只是一个临时容器)。
//在儿童之前插入接口。
toReturn = notificationBox.insertBefore(docFrag,theChild);
break;
casebottom:
if(sizeEl){
sizeEl.removeAttribute(width);
}
docFrag.appendChild(splitterEl);
docFrag.appendChild(objectEl);
//在theChild之后插入接口。
toReturn = notificationBox.insertBefore(docFrag,theChild.nextSibling);
break;
caseleft:
if(sizeEl){
sizeEl.removeAttribute(height);
}
docFrag.appendChild(objectEl);
//分配器在这方面排名第二。
docFrag.appendChild(splitterEl);
//将接口作为孩子的第一个孩子插入。
toReturn = theChild.insertBefore(docFrag,theChild.firstChild);
break;
案例权利:
默认:
//正确的方向,默认值。
if(sizeEl){
sizeEl.removeAttribute(height);
}
docFrag.appendChild(splitterEl);
docFrag.appendChild(objectEl);
//将接口作为孩子的最后一个孩子插入。
toReturn = theChild.appendChild(docFrag);
break;
}
return splitterEl;

$ / code>



更新:



这个答案中的代码显着增强了我对 Firefox SDK插件的解答,右侧和左侧都有一个侧栏同一时间。使用包含在答案中的代码,而不是在这里找到的代码,可能会更好。


I'm writing an extension for Firefox, and I need the UI of this extension to be on a sidebar, I followed some mozilla tutorials, but sidebars are not related to just one window.

I need a sidebar like UI, that will save navigation data from the same window, and need it to be related to just that window, something like firebug.

What I did so far is just creating a menu, and an item, I need that a click on this item will toggle my sidebar.

I took a look at firebug source, I didn't find any overlay of sidebar in its XUL, the scripts are complicated for me, so i didn't know how they can add their UI to the window.

Any ideas, or sources I can read about this ?

解决方案

When talking about a Sidebar one needs to be careful about terminology. The specific term that Mozilla uses within Firefox for "Sidebar" refers to a content box that is on the side of the UI. The Sidebar, if open, is a constant part of the UI which is shown independent of the tab selected. Only one is provided for which can be chosen to be on the left or the right. It is routinely used for content that does not change from tab to tab (e.g. Bookmarks, or History).

The UI that is used for the Firefox devtools (and placement was adopted for use by FireBug) is a sub-panel within the current tab. It is shown only within the tab in which it was invoked. It is implemented within an <iframe>. It can also be opened as a separate window.

When you have a known working example, one way to figure out how this type of thing is implemented in the DOM (the entire browser window is a DOM) is to install the add-on DOM Inspector and use it to investigate what the contents of the DOM looks like. You probably also want, the Element Inspector add-on which is a very useful addition to the DOM Inspector (shift-right-click opens the DOM Inspector to the element clicked). You might also find Stacked Inspector helpful.

Another way to figure out how it is being done is to look at the source code. For the devtools the interface is actually created in the function SH_create within resource:///modules/devtools/framework/toolbox-hosts.js

When placed at the bottom location, the UI is placed as a child of the <notificationbox> which exists for each tab. You can find the <notificationbox> for a tab by using the gBrowser.getNotificationBox( browserForTab ) method. The elements inserted are a <splitter> and an <iframe>. When placed in the other locations within the browser tab those two elements are inserted at locations in the Browser DOM either as children of the <notificationbox>, or as children of its child <hbox> that has class="browserSidebarContainer".

As an example, the following functions will, depending on the [location] parameter, create a panel on the left, right, top, or bottom of the current tab or as a separate window. The default is that the panel is composed of an <iframe> separated from the browser content by a <splitter>. The createInterfacePanel() function is more generic and will accept any element or DOM object as the second parameter which is inserted into the DOM at the appropriate place based on [location] and separated by a form the content. Such Object is expect to be either a Document Fragment or element.

/**
 *   Creates an <iframe> based panel within the current tab,
 *   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.
 * @param location 
 *        Placement of the panel [right|left|top|bottom|window]
 *        The default location is "right".
 * @param 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 400.
 * @param id
 *        The ID to assign to the iframe. Default is
 *        "makyen-interface-panel"
 *        The <splitter> will be assigned the
 *        ID = id + "-splitter"
 * @param chromeUrl
 *        This is the chrome://  URL to use for the contents
 *        of the iframe or the window.
 *        the default is:
 *        "chrome://browser/content/devtools/framework/toolbox.xul"
 * @param 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 by Makyen.
 * Released under the MPL 2.0. http://mozilla.org/MPL/2.0/.
 **/
function createInterfacePanelIframe(location,size,id,chromeUrl,features) {
    //defaults
    size = ( (typeof size !== "number") || size<1) ? 400 : size; 
    id = typeof id !== "string" ? "makyen-interface-panel" : id;
    chromeUrl = typeof chromeUrl !== "string"
        ? "chrome://browser/content/devtools/framework/toolbox.xul"
        : chromeUrl;

    //Create some common variables if they do not exist.
    //  This should work from any Firefox context.
    //  Depending on the context in which the function is being run,
    //  this could be simplified.
    if (typeof window === "undefined") {
        //If there is no window defined, get the most recent.
        var window=Components.classes["@mozilla.org/appshell/window-mediator;1"]
                           .getService(Components.interfaces.nsIWindowMediator)
                           .getMostRecentWindow("navigator:browser");
    }
    if (typeof document === "undefined") {
        //If there is no document defined, get it
        var document = window.content.document;
    }
    if (typeof gBrowser === "undefined") {
        //If there is no gBrowser defined, get it
        var gBrowser = window.gBrowser;
    }

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

    //Create the <iframe> use
    //ownerDocument for the XUL namespace.
    let iframeEl = ownerDocument.createElement("iframe");
    iframeEl.id = id;
    iframeEl.setAttribute("src",chromeUrl);
    iframeEl.setAttribute("height", size.toString());
    iframeEl.setAttribute("width", size.toString());

    //Call createInterfacePanel, pass the size if it is to be a window.
    let splitterEl;
    if(location == "window" ) {
        splitterEl = createInterfacePanel(location, size, size
                                        ,id + "-splitter", chromeUrl, features);
        return [splitterEl, null];
    } else {
        splitterEl = createInterfacePanel(location, iframeEl, iframeEl
                                        ,id + "-splitter", chromeUrl, features);
    }
    return [splitterEl, iframeEl];
}

/**
 * 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.
 *        If features is a string, it is assumed the width is
 *        set in that, or elsewhere (e.g. in the XUL).
 * @param sizeEl
 *        The element that contains attributes of "width" and 
 *        "height". If location=="left"|"right" then the 
 *        "height" attribute is removed prior to the objectEl
 *        being inserted into the DOM.
 *        A spearate reference for the size element in case the
 *        objectEl is a documentFragment containing multiple elements.
 *        However, normal usage is for objectEl === sizeEl 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).
 * @param id
 *        The ID to assign to the <splitter>. The default is:
 *        "makyen-interface-panel-splitter".
 * @param chromeUrl
 *        This is the chrome://  URL to use for the contents
 *        of the window.
 *        the default is:
 *        "chrome://browser/content/devtools/framework/toolbox.xul"
 * @param features
 *        The features string for the window. See:
 *        https://developer.mozilla.org/en-US/docs/Web/API/Window.open
 * returns
 *        if location != "window":
 *           splitterEl, The element for the <splitter>.
 *        if location == "window":
 *           The windowObjectReference returned by window.open().
 *
 * Copyright 2014 by Makyen.
 * Released under the MPL 2.0. http://mozilla.org/MPL/2.0/.
 **/
function createInterfacePanel(location,objectEl,sizeEl,id,chromeUrl,features) {
    //Set location default:
    location = typeof location !== "string" ? "right" : location;
    if(location == "window") {
        if(typeof features !== "string") {
            let width = "";
            let height = "";
            if(typeof objectEl == "number") {
                width = "width=" + objectEl.toString() + ",";
            }
            if(typeof sizeEl == "number") {
                height = "height=" + sizeEl.toString() + ",";
            }
            features = width + height
                       + "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://browser/content/devtools/framework/toolbox.xul"
        : chromeUrl;

    //Create some common variables if they do not exist.
    //  This should work from any Firefox context.
    //  Depending on the context in which the function is being run,
    //  this could be simplified.
    if (typeof window === "undefined") {
        //If there is no window defined, get the most recent.
        var window=Components.classes["@mozilla.org/appshell/window-mediator;1"]
                           .getService(Components.interfaces.nsIWindowMediator)
                           .getMostRecentWindow("navigator:browser");
    }
    if (typeof document === "undefined") {
        //If there is no document defined, get it
        var document = window.content.document;
    }
    if (typeof gBrowser === "undefined") {
        //If there is no gBrowser defined, get it
        var gBrowser = window.gBrowser;
    }

    //Get the current tab & notification box (container for tab UI).
    let 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").contains("browserSidebarContainer")
    ) {
        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 toReturn = null;
    switch(location) {
        case "window"    :
            return window.open(chromeUrl,"_blank",features);
            break;
        case "top"    :
            if(sizeEl) {
                sizeEl.removeAttribute("width");
            }
            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.
            toReturn = notificationBox.insertBefore(docFrag,theChild);
            break;
        case "bottom" :
            if(sizeEl) {
                sizeEl.removeAttribute("width");
            }
            docFrag.appendChild(splitterEl);
            docFrag.appendChild(objectEl);
            //Insert the interface just after theChild.
            toReturn = notificationBox.insertBefore(docFrag,theChild.nextSibling);
            break;
        case "left"   :
            if(sizeEl) {
                sizeEl.removeAttribute("height");
            }
            docFrag.appendChild(objectEl);
            //Splitter is second in this orientaiton.
            docFrag.appendChild(splitterEl);
            //Insert the interface as the first child of theChild.
            toReturn = theChild.insertBefore(docFrag,theChild.firstChild);
            break;
        case "right"  :
        default       :
            //Right orientaiton, the default.
            if(sizeEl) {
                sizeEl.removeAttribute("height");
            }
            docFrag.appendChild(splitterEl);
            docFrag.appendChild(objectEl);
            //Insert the interface as the last child of theChild.
            toReturn = theChild.appendChild(docFrag);
            break;
    }
    return splitterEl;
}

Update:

The code in this answer was significantly enhanced for my answer to "Firefox SDK Add-on with a sidebar on both the right and left at the same time". You are probably much better off using the code contained in that answer rather than the code found here.

这篇关于Firefox扩展,窗口相关的侧边栏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆