Javascript 如何在Firefox中使用XUL创建底部固定面板?

Javascript 如何在Firefox中使用XUL创建底部固定面板?,javascript,firefox-addon,xul,Javascript,Firefox Addon,Xul,对于我的插件,我想创建一个底部停靠的“面板”,以显示信息。类似的例子是Firefox自己的Web控制台面板,可以在Web开发者工具下进行切换 我试图深入研究代码,但无法理解这是如何实现的。有人能给我一个关于如何用XUL创建这个的基本解释,或者给我指出正确的方向吗?它被称为侧栏。我在右边做了一个: 这是一个完整的插件,你可以安装和黑客。非常基本的模板 这是添加侧面板的零件: //START - EDIT BELOW HERE var browser = aDOMWindow.doc

对于我的插件,我想创建一个底部停靠的“面板”,以显示信息。类似的例子是Firefox自己的Web控制台面板,可以在Web开发者工具下进行切换


我试图深入研究代码,但无法理解这是如何实现的。有人能给我一个关于如何用XUL创建这个的基本解释,或者给我指出正确的方向吗?

它被称为侧栏。我在右边做了一个:

这是一个完整的插件,你可以安装和黑客。非常基本的模板

这是添加侧面板的零件:

    //START - EDIT BELOW HERE
    var browser = aDOMWindow.document.querySelector('#browser')
    if (browser) {
        var splitter = aDOMWindow.document.createElement('splitter');
        var propsToSet = {
            id: 'demo-sidebar-with-html_splitter',
            //class: 'sidebar-splitter' //im just copying what mozilla does for their social sidebar splitter //i left it out, but you can leave it in to see how you can style the splitter
        }
        for (var p in propsToSet) {
            splitter.setAttribute(p, propsToSet[p]);
        }

        var sidebar = aDOMWindow.document.createElement('vbox');
        var propsToSet = {
            id: 'demo-sidebar-with-html_sidebar',
            //persist: 'width' //mozilla uses persist width here, i dont know what it does and cant see it how makes a difference so i left it out
        }
        for (var p in propsToSet) {
            sidebar.setAttribute(p, propsToSet[p]);
        }

        var sidebarBrowser = aDOMWindow.document.createElement('browser');
        var propsToSet = {
            id: 'demo-sidebar-with-html_browser',
            type: 'content',
            context: 'contentAreaContextMenu',
            disableglobalhistory: 'true',
            tooltip: 'aHTMLTooltip',
            clickthrough: 'never',
            autoscrollpopup: 'autoscroller',
            flex: '1', //do not remove this
            style: 'min-width: 14em; width: 18em; max-width: 36em;', //you should change these widths to how you want
            src: 'data:text/html,%3Chtml%3E%0A%3Cbody%3E%0A%3Ciframe%20width%3D%22520%22%20height%3D%22390%22%20src%3D%22http%3A%2F%2Fweb2.0calc.com%2Fwidgets%2Fhorizontal%2F%22%20scrolling%3D%22no%22%20style%3D%22border%3A%201px%20solid%20silver%3B%20%22%3E%20%3C%2Fiframe%3E%0A%3Cbr%20%2F%3E%0A%3Ca%20href%3D%22http%3A%2F%2Fweb2.0calc.com%2F%22%3EWeb%202.0%20scientific%20calculator%3C%2Fa%3E%0A%3C%2Fbody%3E%0A%3C%2Fhtml%3E' //or just set this to some url like http://www.bing.com/
        }
        for (var p in propsToSet) {
            sidebarBrowser.setAttribute(p, propsToSet[p]);
        }

        browser.appendChild(splitter);

        sidebar.appendChild(sidebarBrowser);
        browser.appendChild(sidebar);
    }
    //END - EDIT BELOW HERE

可以将其复制粘贴到scratchpad运行,但要从scrathpad运行,您必须首先将
var browser=aDomWindow.document.querySelector(“#browser”)
替换为
var browser=Services.wm.getMostRecentWindow('navigator:browser').document.querySelector('#browser')
它被称为侧栏。我在右边做了一个:

这是一个完整的插件,你可以安装和黑客。非常基本的模板

这是添加侧面板的零件:

    //START - EDIT BELOW HERE
    var browser = aDOMWindow.document.querySelector('#browser')
    if (browser) {
        var splitter = aDOMWindow.document.createElement('splitter');
        var propsToSet = {
            id: 'demo-sidebar-with-html_splitter',
            //class: 'sidebar-splitter' //im just copying what mozilla does for their social sidebar splitter //i left it out, but you can leave it in to see how you can style the splitter
        }
        for (var p in propsToSet) {
            splitter.setAttribute(p, propsToSet[p]);
        }

        var sidebar = aDOMWindow.document.createElement('vbox');
        var propsToSet = {
            id: 'demo-sidebar-with-html_sidebar',
            //persist: 'width' //mozilla uses persist width here, i dont know what it does and cant see it how makes a difference so i left it out
        }
        for (var p in propsToSet) {
            sidebar.setAttribute(p, propsToSet[p]);
        }

        var sidebarBrowser = aDOMWindow.document.createElement('browser');
        var propsToSet = {
            id: 'demo-sidebar-with-html_browser',
            type: 'content',
            context: 'contentAreaContextMenu',
            disableglobalhistory: 'true',
            tooltip: 'aHTMLTooltip',
            clickthrough: 'never',
            autoscrollpopup: 'autoscroller',
            flex: '1', //do not remove this
            style: 'min-width: 14em; width: 18em; max-width: 36em;', //you should change these widths to how you want
            src: 'data:text/html,%3Chtml%3E%0A%3Cbody%3E%0A%3Ciframe%20width%3D%22520%22%20height%3D%22390%22%20src%3D%22http%3A%2F%2Fweb2.0calc.com%2Fwidgets%2Fhorizontal%2F%22%20scrolling%3D%22no%22%20style%3D%22border%3A%201px%20solid%20silver%3B%20%22%3E%20%3C%2Fiframe%3E%0A%3Cbr%20%2F%3E%0A%3Ca%20href%3D%22http%3A%2F%2Fweb2.0calc.com%2F%22%3EWeb%202.0%20scientific%20calculator%3C%2Fa%3E%0A%3C%2Fbody%3E%0A%3C%2Fhtml%3E' //or just set this to some url like http://www.bing.com/
        }
        for (var p in propsToSet) {
            sidebarBrowser.setAttribute(p, propsToSet[p]);
        }

        browser.appendChild(splitter);

        sidebar.appendChild(sidebarBrowser);
        browser.appendChild(sidebar);
    }
    //END - EDIT BELOW HERE
可以将其复制粘贴到scratchpad运行,但要从scrathpad运行,您必须首先将
var browser=aDomWindow.document.querySelector(“#browser”)
替换为
var browser=Services.wm.getMostRecentWindow('navigator:browser').document.querySelector('#browser')
Web控制台不是一个浏览器。在Fireox中只有一个侧栏,它可以位于浏览器内容的左侧或右侧。侧边栏是UI的固定部分,即使您更改了选项卡。它通常用于内容、历史记录、书签或其他此类信息,这些信息不会因您正在查看的选项卡而改变

对于调查类似的内容,如果您还没有安装,我建议使用附加组件

Web控制台包含在其所在选项卡下的
内的

iframe的XUL是:

首先是一个
,然后在包含它的选项卡的
之后插入

通过调用
gDevToolsBrowser.selecttoolscommand(gBrowser,“webconsole”)打开web控制台

gDevToolsBrowser
chrome://browser/content/browser.js
resource:///modules/devtools/gDevTools.jsm

它们实际上是在
SH_create
函数
resource:///modules/devtools/framework/toolbox-hosts.js

所有这些
chrome://
resource://
URL都应该在Firefox中工作。Firefox安装中有大量文件打包在三个文件cales omni.ja中。这些文件位于/omni.ja、/browser/omni.ja和/webart/omni.ja中。omni.ja文件只是zip格式的文件,扩展名已重命名。为了方便访问这些文件,我经常将它们解压缩到目录中(在Firefox安装目录树之外)。我发现,当我想弄清楚事情是如何完成的时候,这使得搜索和操作文件变得更加容易

如果您只是在寻找将创建一个类似用于web控制台的框的代码,那么其复杂性取决于您操作的上下文。以下内容几乎可以在任何地方使用:

/**
 *   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;
}
/**
*在当前选项卡中创建基于的面板,
*或打开一个窗口,用作用户界面框。
*如果它不是窗口,则与当前
*浏览器选项卡。
*@param位置
*面板的放置[右|左|上|下|窗]
*默认位置为“右”。
*@param大小
*宽度(如果在左侧或右侧)。顶部或底部的高度。
*如果location=“window”,则宽度和高度均为,除非
*特征是一个字符串。
*默认值为400。
*@param-id
*要分配给iframe的ID。默认为
*“makyen接口面板”
*将为
*ID=ID+“-拆分器”
*@param chromeUrl
*这是用于内容的chrome://URL
*iframe或窗口的。
*默认值为:
*        "chrome://browser/content/devtools/framework/toolbox.xul"
*@param功能
*窗口的功能字符串。见:
*        https://developer.mozilla.org/en-US/docs/Web/API/Window.open
*返回[splitterEl,iframeEl]
*和的要素
*
*Makyen版权所有2014。
*在MPL2.0下发布。http://mozilla.org/MPL/2.0/.
**/
函数CreateInterfacePanelFrame(位置、大小、id、色度、特征){
//默认值
大小=((大小类型!=“数字”)| | sizeWeb控制台不是一个。在Fireox中只有一个侧栏,它可以位于浏览器内容的左侧或右侧。侧栏是UI的一个固定部分,即使您更改了选项卡。它通常用于内容、历史记录、书签或其他此类信息,这些信息不会因您正在查看的选项卡而改变

对于调查类似的内容,如果您还没有安装,我建议使用附加组件

Web控制台包含在其所在选项卡下的
内的

iframe的XUL是:

首先是一个
,然后在包含它的选项卡的
之后插入

通过调用
gDevToolsBrowser.selectToolCommand(gBrowser,“webconsole”);

gDevToolsBrowser
chrome://browser/content/browser.js
resource:///modules/devtools/gDevTools.jsm

它们实际上是在
SH_create
函数
resource:///modules/devtools/framework/toolbox-hosts.js

所有这些
ch