在Firefox非叠加扩展中,如何将文本添加到浏览器工具栏图标?

时间:2014-10-10 12:49:17

标签: javascript firefox firefox-addon-sdk firefox-addon-restartless

如何将文字添加到附加组件的浏览器工具栏按钮?

我对下载管理器按钮在进度条上方显示“ 2h ”文字的方式感兴趣,当时还有2小时的时间来下载所请求的文件(s )。

甚至可以在不使用包含文本的大量预制图像的情况下完成此操作吗?

1 个答案:

答案 0 :(得分:2)

当你有一个已知的工作示例时,一种方法来弄清楚这种类型的东西是如何在DOM中实现的(整个浏览器窗口是一个DOM)是安装add-on DOM Inspector和用它来研究DOM的内容是什么样的。您可能还需要Element Inspector附加组件,它是DOM Inspector的一个非常有用的附加功能(右键单击右键可以打开DOM Inspector到单击的元素)。您可能还会发现Stacked Inspector有帮助。

在这种情况下,下载按钮以<toolbarbutton/>开头。具体做法是:

<toolbarbutton id="downloads-button" 
    class="toolbarbutton-1 chromeclass-toolbar-additional" 
    key="key_openDownloads" oncommand="DownloadsIndicatorView.onCommand(event);"
    ondrop="DownloadsIndicatorView.onDrop(event);"
    ondragover="DownloadsIndicatorView.onDragOver(event);"
    ondragenter="DownloadsIndicatorView.onDragOver(event);"
    label="Downloads" removable="true" cui-areatype="toolbar" 
    tooltip="dynamic-shortcut-tooltip"/>

Download Button prior to downloading

下载开始后,结构将更改为:

<toolbarbutton id="downloads-button" 
    class="toolbarbutton-1 chromeclass-toolbar-additional" 
    key="key_openDownloads" oncommand="DownloadsIndicatorView.onCommand(event);"
    ondrop="DownloadsIndicatorView.onDrop(event);" 
    ondragover="DownloadsIndicatorView.onDragOver(event);" 
    ondragenter="DownloadsIndicatorView.onDragOver(event);" 
    label="Downloads" removable="true" cui-areatype="toolbar"
    tooltip="dynamic-shortcut-tooltip" 
    indicator="true" progress="true" counter="true">
       <stack id="downloads-indicator-anchor" class="toolbarbutton-icon">
           <vbox id="downloads-indicator-progress-area" pack="center">
               <description id="downloads-indicator-counter" value="6h"/>
               <progressmeter id="downloads-indicator-progress" class="plain"
                   min="0" max="100" value="3.484329371737533"/>
           </vbox>
           <vbox id="downloads-indicator-icon"/>
       </stack>
</toolbarbutton>

Download button while downloading

上述结构更改包含在chrome://browser/content/downloads/indicatorOverlay.xul中,它作为叠加层加载到主浏览器文档中。

控制指标的代码位于chrome://browser/content/downloads/indicator.js。实际加载叠加层的代码是ensureOverlayLoaded()中的chrome://browser/content/downloads/downloads.js

不使用XUL叠加层进行更改
鉴于您希望将其作为叠加扩展,您可能不想使用XUL Overlay。因此,您需要遍历按钮所在的所有位置,并对每个位置的结构进行更改。但是,此时您可能正在处理通过CustomizableUI添加的按钮。如果您没有通过打开的窗口运行CustomizableUI,则会浏览它提供给您的节点。有必要这样做,因为许多用户已将您感兴趣的按钮放在自定义托盘中而不是工具栏中。如果是这种情况,尝试使用浏览器窗口document.getElementById()找到document按钮将会失败。要使用CustomizableUI接口运行这些,您可以使用以下内容:

function loadUi() {
    if (window === null || typeof window !== "object") {
        //If you do not already have a window reference, you need to obtain one:
        //  Add a "/" to un-comment the code appropriate for your add-on type.
        /* Add-on SDK:
        var window = require('sdk/window/utils').getMostRecentBrowserWindow();
        //*/
        /* Overlay and bootstrap (from almost any context/scope):
        var window=Components.classes["@mozilla.org/appshell/window-mediator;1"]
                             .getService(Components.interfaces.nsIWindowMediator)
                             .getMostRecentWindow("navigator:browser");
        //*/
    }

    forEachCustomizableUiById("downloads-button", loadIntoButton, window);
}

function forEachCustomizableUiById(buttonId ,func, myWindow) {
    let groupWidgetWrap = myWindow.CustomizableUI.getWidget(buttonId);
    groupWidgetWrap.instances.forEach(function(perWindowUiWidget) {
        //For each button do the load task.
        func(perWindowUiWidget.node);
    });
}

function loadIntoButton(buttonElement) {
    //Make whatever changes to the button you want to here.
    //You may need to save some information about the original state
    //  of the button.
}

显然,卸载只是加载的反向:

function unloadUi() {
    if (window === null || typeof window !== "object") {
        //If you do not already have a window reference, you need to obtain one:
        //  Add a "/" to un-comment the code appropriate for your add-on type.
        /* Add-on SDK:
        var window = require('sdk/window/utils').getMostRecentBrowserWindow();
        //*/
        /* Overlay and bootstrap (from almost any context/scope):
        var window=Components.classes["@mozilla.org/appshell/window-mediator;1"]
                             .getService(Components.interfaces.nsIWindowMediator)
                             .getMostRecentWindow("navigator:browser");
        //*/
    }

    forEachCustomizableUiById("downloads-button", unloadFromButton, window);
}

function unloadFromButton(buttonElement) {
    //Return the button to its original state
}

在将按钮更改为下载状态的特定实例中,您可以执行以下操作:

function loadIntoButton(buttonElement) {
    buttonElement.setAttribute("indicator","true");
    buttonElement.setAttribute("progress","true");
    buttonElement.setAttribute("counter","true");
    let additional = ''
       + '<stack id="downloads-indicator-anchor" class="toolbarbutton-icon">'
       + '    <vbox id="downloads-indicator-progress-area" pack="center">'
       + '        <description id="downloads-indicator-counter" value="6h"/>'
       + '        <progressmeter id="downloads-indicator-progress" class="plain"'
       + '            min="0" max="100" value="3.484329371737533"/>'
       + '    </vbox>'
       + '    <vbox id="downloads-indicator-icon"/>'
       + '</stack>';
    buttonElement.insertAdjacentHTML("beforeend",additional);
}

function unloadFromButton(buttonElement) {
    buttonElement.removeAttribute("indicator","true");
    buttonElement.removeAttribute("progress","true");
    buttonElement.removeAttribute("counter","true");
    buttonElement.removeChild(buttonElement.getElementsByTagName("stack")[0]);
}

我还没有机会测试上面的代码,所以可能存在一些问题。

从头开始创建复杂的CustomizableUI小部件:
如果你想要从头开始创建更复杂的东西,那么你应该使用CustomizableUI并创建一个custom小部件。 CustomizableUI.jsm page at MDN"simple" example of a complex widget,即:

CustomizableUI.createWidget({ 
    //Must run createWidget before windowListener.register because the register
    //  function needs the button added first.
        id: 'navigator-throbber',
        type: 'custom',
        defaultArea: CustomizableUI.AREA_NAVBAR,
        onBuild: function(aDocument) {
            var toolbaritem = aDocument.createElementNS(
                'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul',
                'toolbaritem');
            var image = aDocument.createElementNS(
                'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul',
                'image');
            var props = {
                id: 'navigator-throbber',
                title: 'Activity Indicator',
                align: 'center',
                pack: 'center',
                mousethrough: 'always',
                removable: 'true',
                sdkstylewidget: 'true',
                overflows: false
            };
            for (var p in props) {
                toolbaritem.setAttribute(p, props[p]);
            }

            toolbaritem.appendChild(image);
            return toolbaritem;
        }
    });

作为一个更复杂的示例,Noitidart提供了浏览器用于自定义窗口小部件的代码摘要,该窗口小部件用于缩放控件和编辑控件。它可以在这个要点上找到:https://gist.github.com/Noitidart/10902477








Firefox下载按钮的自定义CSS和XML绑定: 要完全实现您自己的下载按钮版本,您还需要Mozilla使用的CSS和自定义XML绑定。

下载按钮的CSS(来自chrome://browser/content/browser.css

#downloads-button {
  -moz-binding: url("chrome://browser/content/downloads/download.xml#download-toolbarbutton");
}

/*** Visibility of downloads indicator controls ***/

/* Bug 924050: If we've loaded the indicator, for now we hide it in the menu panel,
   and just show the icon. This is a hack to side-step very weird layout bugs that
   seem to be caused by the indicator stack interacting with the menu panel. */
#downloads-button[indicator]:not([cui-areatype="menu-panel"]) > image.toolbarbutton-icon,
#downloads-button[indicator][cui-areatype="menu-panel"] > #downloads-indicator-anchor {
  display: none;
}

toolbarpaletteitem[place="palette"] > #downloads-button[indicator] > image.toolbarbutton-icon {
  display: -moz-box;
}

toolbarpaletteitem[place="palette"] > #downloads-button[indicator] > stack.toolbarbutton-icon {
  display: none;
}

#downloads-button:-moz-any([progress], [counter], [paused]) #downloads-indicator-icon,
#downloads-button:not(:-moz-any([progress], [counter], [paused]))
                                                   #downloads-indicator-progress-area
{
  visibility: hidden;
}

/* Hacks for toolbar full and text modes, until bug 573329 removes them */

toolbar[mode="text"] > #downloads-button {
  display: -moz-box;
  -moz-box-orient: vertical;
  -moz-box-pack: center;
}

toolbar[mode="text"] > #downloads-button > .toolbarbutton-text {
  -moz-box-ordinal-group: 1;
}

toolbar[mode="text"] > #downloads-button > .toolbarbutton-icon {
  display: -moz-box;
  -moz-box-ordinal-group: 2;
  visibility: collapse;
}

自定义下载按钮XML绑定(来自chrome://browser/content/downloads/download.xml):

<?xml version="1.0"?>
<!-- -*- Mode: HTML; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- -->
<!-- vim: set ts=2 et sw=2 tw=80: -->

<!-- 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/. -->

<!DOCTYPE bindings SYSTEM "chrome://browser/locale/downloads/downloads.dtd">

<bindings id="downloadBindings"
          xmlns="http://www.mozilla.org/xbl"
          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns:xbl="http://www.mozilla.org/xbl">

  <binding id="download"
           extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
    <content orient="horizontal"
             align="center"
             onclick="DownloadsView.onDownloadClick(event);">
      <xul:image class="downloadTypeIcon"
                 validate="always"
                 xbl:inherits="src=image"/>
      <xul:image class="downloadTypeIcon blockedIcon"/>
      <xul:vbox pack="center"
                flex="1"
                class="downloadContainer"
                style="width: &downloadDetails.width;">
        <!-- We're letting localizers put a min-width in here primarily
             because of the downloads summary at the bottom of the list of
             download items. An element in the summary has the same min-width
             on a description, and we don't want the panel to change size if the
             summary isn't being displayed, so we ensure that items share the
             same minimum width.
             -->
        <xul:description class="downloadTarget"
                         crop="center"
                         style="min-width: &downloadsSummary.minWidth2;"
                         xbl:inherits="value=target,tooltiptext=target"/>
        <xul:progressmeter anonid="progressmeter"
                           class="downloadProgress"
                           min="0"
                           max="100"
                           xbl:inherits="mode=progressmode,value=progress"/>
        <xul:description class="downloadDetails"
                         crop="end"
                         xbl:inherits="value=status,tooltiptext=statusTip"/>
      </xul:vbox>
      <xul:stack>
        <xul:button class="downloadButton downloadCancel"
                    tooltiptext="&cmd.cancel.label;"
                    oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_cancel');"/>
        <xul:button class="downloadButton downloadRetry"
                    tooltiptext="&cmd.retry.label;"
                    oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_retry');"/>
        <xul:button class="downloadButton downloadShow"
                    tooltiptext="&cmd.show.label;"
                    oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_show');"/>
      </xul:stack>
    </content>
  </binding>

  <binding id="download-full-ui"
           extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
    <resources>
      <stylesheet src="chrome://browser/content/downloads/download.css"/>
    </resources>

    <content orient="horizontal" align="center">
      <xul:image class="downloadTypeIcon"
                 validate="always"
                 xbl:inherits="src=image"/>
      <xul:image class="downloadTypeIcon blockedIcon"/>
      <xul:vbox pack="center" flex="1">
        <xul:description class="downloadTarget"
                         crop="center"
                         xbl:inherits="value=displayName,tooltiptext=displayName"/>
        <xul:progressmeter anonid="progressmeter"
                           class="downloadProgress"
                           min="0"
                           max="100"
                           xbl:inherits="mode=progressmode,value=progress"/>
        <xul:description class="downloadDetails"
                         style="width: &downloadDetails.width;"
                         crop="end"
                         xbl:inherits="value=status,tooltiptext=statusTip"/>
      </xul:vbox>

      <xul:button class="downloadButton downloadCancel"
                  tooltiptext="&cmd.cancel.label;"
                  oncommand="goDoCommand('downloadsCmd_cancel')"/>
      <xul:button class="downloadButton downloadRetry"
                  tooltiptext="&cmd.retry.label;"
                  oncommand="goDoCommand('downloadsCmd_retry')"/>
      <xul:button class="downloadButton downloadShow"
                  tooltiptext="&cmd.show.label;"
                  oncommand="goDoCommand('downloadsCmd_show')"/>

    </content>
  </binding>

  <binding id="download-toolbarbutton"
           extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
    <content>
      <children />
      <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
      <xul:label class="toolbarbutton-text" crop="right" flex="1"
                 xbl:inherits="value=label,accesskey,crop,wrap"/>
      <xul:label class="toolbarbutton-multiline-text" flex="1"
                 xbl:inherits="xbl:text=label,accesskey,wrap"/>
    </content>
  </binding>
</bindings>