我正在为Firefox编写扩展程序,我需要将此扩展程序的UI放在侧边栏上,我关注了一些mozilla教程,但是侧边栏与一个窗口无关。
我需要一个像UI这样的侧边栏,它会保存同一个窗口中的导航数据,并且需要它只与那个窗口相关,就像firebug一样。
到目前为止我所做的只是创建一个菜单和一个项目,我需要点击这个项目来切换我的侧边栏。
我看了一下firebug源代码,我没有在它的XUL中发现任何侧边栏的叠加,脚本对我来说很复杂,所以我不知道他们如何将他们的UI添加到窗口。
我能读到的任何想法或消息来源吗?
答案 0 :(得分:1)
在谈论补充工具栏时,需要注意术语。 Mozilla在Firefox中使用的特定术语,用于" Sidebar"指的是位于UI侧面的内容框。边栏(如果打开)是UI的常量部分,其显示独立于所选选项卡。只提供一个可以选择在左侧或右侧。它通常用于不会从标签更改为标签的内容(例如书签或历史记录)。
用于Firefox devtools的UI(以及FireBug使用的展示位置)是当前标签中的子面板。它仅在调用它的选项卡中显示。它在<iframe>
内实施。它也可以作为一个单独的窗口打开。
当你有一个已知的工作示例时,一种方法来弄清楚这种类型的东西是如何在DOM中实现的(整个浏览器窗口是一个DOM)是安装add-on DOM Inspector和用它来研究DOM的内容是什么样的。您可能还需要Element Inspector附加组件,它是DOM Inspector的一个非常有用的附加功能(右键单击右键可以打开DOM Inspector到单击的元素)。您可能还会发现Stacked Inspector有帮助。
了解它是如何完成的另一种方法是查看源代码。对于devtools,接口实际上是在SH_create
resource:///modules/devtools/framework/toolbox-hosts.js
中创建的
当放置在底部位置时,UI将作为每个选项卡存在的<notificationbox>
的子项放置。您可以使用<notificationbox>
方法找到标签的gBrowser.getNotificationBox( browserForTab )
。插入的元素是<splitter>
和<iframe>
。当放置在浏览器选项卡中的其他位置时,这两个元素将作为<notificationbox>
的子项插入到浏览器DOM中的位置,或者作为其子<hbox>
的子项class="browserSidebarContainer"
插入
作为示例,以下函数将根据[location]参数在当前选项卡的左侧,右侧,顶部或底部创建一个面板,或者作为单独的窗口创建。默认情况下,该面板由<iframe>
组成,<splitter>
与浏览器内容分开/**
* 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;
}
。 createInterfacePanel()函数更通用,并且将接受任何元素或DOM对象作为第二个参数,该参数根据[location]在适当的位置插入DOM,并由表单内容分隔。此类对象应为Document Fragment或element。
{{1}}
我对#34; Firefox SDK Add-on with a sidebar on both the right and left at the same time&#34;的回答显着增强了此答案中的代码。使用该答案中包含的代码而不是此处的代码可能会好得多。