CustomizableUI.jsm 编辑

This module is only available from Firefox 29 onwards.

The CustomizableUI.jsm JavaScript code module allows you to interact with customizable buttons and items in Firefox's main window UI.

It is available in the Firefox window as the CustomizableUI property on the window. If you want to use it from a JSM or another context without a window reference, you need to import it yourself:

Components.utils.import("resource:///modules/CustomizableUI.jsm");

Introduction

The module is intended for two primary purposes:

  1. Allow adding, moving and removing customizable widgets.
  2. Manage the areas in which these widgets are shown.

Note that it is expressly not really aware about the specific UI used by users to make customizations. This is handled by CustomizeMode.jsm, which interacts with CustomizableUI through a listener mechanism.

Areas

Areas are parts of the user interface in which customizable widgets can be placed. CustomizableUI assumes that each area it is told about is present in every browser window. CustomizableUI is aware of two types of areas: toolbars and the menu panel.

Areas are registered using the registerArea method and unregistered using the unregisterArea method. When a customizable toolbar's XBL binding is constructed (generally, that is when a <toolbar customizable="true"/> node is appended to the document and isn't invisible), the binding will call into CustomizableUI and register the toolbar's node as being one of the concrete instances of its area.

For each area, CustomizableUI keeps track of a list of the widgets they contain, generally refered to as 'placements'. This is analogous to the old currentset attribute. If consumers make a change to the placements in an area, CustomizableUI will update the actual nodes in each area instance for them.

Toolbars generally function the same way they always have. However, they can now be 'overflowable', that is, if there are too many widgets to fit in the toolbar's horizontal space, the excess widgets will be placed in a panel accessible from an anchor (chevron) in the toolbar. In order to register such a toolbar, set the 'overflowable' property to true, and provide the id of the anchor in the 'anchor' property.

Widgets

Widget is the term that CustomizableUI uses for each of the items in a customizable area. Note that these are also abstract cross-window objects; CustomizableUI will manage the actual DOM manipulation involved with adding/moving/removing widgets in all windows for you.

There are three main types of widgets:

  1. 'legacy' XUL widgets, which are the way CustomizableUI represents widgets whose DOM representation is present (or overlaid) into a window;
  2. API-style widgets, which are the new widgets CustomizableUI can create and manage for you. These come in 3 types themselves:
    button
    which are simple toolbar buttons which do something when clicked
    view
    which are toolbar buttons with a 'view' of further options. The view can be shown as its own panel when such a widget is in the toolbar, or as a sliding 'subview' of the menu panel when such a widget is in the menu panel.
    custom
    which are widgets that are custom-created by some JS supplied by the consumer
    For more details, see API-provided widgets.
  3. 'special' widgets: these are the representations of XUL <toolbarseparator>, <toolbarspring> and <toolbarspacer> elements.

CustomizableUI provides APIs to add, move and remove all these different widgets, and mostly abstracts the DOM away from you.

The lifetime of your widget should be identical to the lifetime of the add-on - it's process-global, so if you call createWidget on bootstrap's "startup" and destroyWidget on bootstrap's "shutdown", that's enough.

Listeners

CustomizableUI provides a way to listen for various bits of customization happening. This can be useful if other parts of the code need to react to changes in the customization of the user interface.

In order to use this facility, you should create a plain JS object which defines some of the event handlers defined below. Not all event handler methods need to be defined. CustomizableUI will catch exceptions. Events are dispatched synchronously on the UI thread, so if you can delay any/some of your processing, that is advisable.

The following event handlers are supported:

onWidgetAdded(aWidgetId, aArea, aPosition)
Fired when a widget is added to an area. aWidgetId is the widget that was added, aArea the area it was added to, and aPosition the position in which it was added.
onWidgetMoved(aWidgetId, aArea, aOldPosition, aNewPosition)
Fired when a widget is moved within its area. aWidgetId is the widget that was moved, aArea the area it was moved in, aOldPosition its old position, and aNewPosition its new position.
onWidgetRemoved(aWidgetId, aArea)
Fired when a widget is removed from its area. aWidgetId is the widget that was removed, aArea the area it was removed from.
onWidgetBeforeDOMChange(aNode, aNextNode, aContainer, aIsRemoval)
Fired before a widget's DOM node is acted upon by CustomizableUI (to add, move or remove it). aNode is the DOM node changed, aNextNode the DOM node (if any) before which a widget will be inserted, aContainer the actual DOM container (could be an overflow panel in case of an overflowable toolbar), and aWasRemoval is true iff the action about to happen is the removal of the DOM node.
onWidgetAfterDOMChange(aNode, aNextNode, aContainer, aWasRemoval)
Like onWidgetBeforeDOMChange, but fired after the change to the DOM node of the widget.
onWidgetReset(aNode, aContainer)
Fired after a reset to default placements moves a widget's node to a different location. aNode is the widget's node, aContainer is the area it was moved into (NB: it might already have been there and been moved to a different position!)
onWidgetUndoMove(aNode, aContainer)
Fired after undoing a reset to default placements moves a widget's node to a different location. aNode is the widget's node, aContainer is the area it was moved into (NB: it might already have been there and been moved to a different position!)
onAreaReset(aArea, aContainer)
Fired after a reset to default placements is complete on an area's DOM node. Note that this is fired for each DOM node. aArea is the area that was reset, aContainer the DOM node that was reset.
onAreaNodeUnregistered(aArea, aNode, aReason)
Fired when an area's DOM node is unregistered. aArea is the area for which a node was unregistered, aNode the DOM node which was unregistered, and aReason indicates whether the area as a whole was unregistered (REASON_AREA_UNREGISTERED), or whether a window closed (REASON_WINDOW_CLOSED).
onAreaNodeRegistered(aArea, aNode)
Fired after an area node is first built when it is registered. This is often when the window has opened, but in the case of add-ons, could fire when the node has just been registered with CustomizableUI after an add-on update or disable/enable sequence.
onWidgetCreated(aWidgetId)
Fired when a widget with id aWidgetId has been created, but before it is added to any placements or any DOM nodes have been constructed. Only fired for API-based widgets.
onWidgetAfterCreation(aWidgetId, aArea)
Fired after a widget with id aWidgetId has been created, and has been added to either its default area or the area in which it was placed previously. If the widget has no default area and/or it has never been placed anywhere, aArea may be null. Only fired for API-based widgets.
onWidgetDestroyed(aWidgetId)
Fired when widgets are destroyed. aWidgetId is the widget that is being destroyed. Only fired for API-based widgets.
onWidgetInstanceRemoved(aWidgetId, aDocument)
Fired when a window is unloaded and a widget's instance is destroyed because of this. aWidgetId is the widget whose instance is being destroyed, aDocument the document in which this is happening. Only fired for API-based widgets.
onWidgetDrag(aWidgetId, aArea)
Fired both when and after customize mode drag handling system tries to determine the width and height of widget aWidgetId when dragged to a different area. aArea will be the area the item is dragged to, or undefined after the measurements have been done and the node has been moved back to its 'regular' area.
onCustomizeStart(aWindow)
Fired when opening customize mode in aWindow.
onCustomizeEnd(aWindow)
Fired when exiting customize mode in aWindow.
onWidgetOverflow(aNode, aContainer)
Fired when a widget's DOM node is overflowing its container, a toolbar, and will be displayed in the overflow panel.
onWidgetUnderflow(aNode, aContainer)
Fired when a widget's DOM node is not overflowing its container, a toolbar, anymore.
onWindowOpened(aWindow)
Fired when a new customizable (ie browser) window is opened.
onWindowClosed(aWindow)
Fired when a customizable (ie browser) window is closed.

Method overview

void addListener(aListener);
void removeListener(aListener);
void registerArea(aAreaId, aProperties);
void registerToolbarNode(aToolbar, aExistingChildren);
void registerMenuPanel(aPanel);
void unregisterArea(aAreaId, aDestroyPlacements);
void addWidgetToArea(aWidgetId, aAreaId, [optional] aPosition);
void removeWidgetFromArea(aWidgetId);
void moveWidgetWithinArea(aWidgetId, aPosition);
void ensureWidgetPlacedInWindow(aWidgetId, aWindow);
void beginBatchUpdate();
void endBatchUpdate(aForceDirty);
WidgetGroupWrapper createWidget(aWidgetSpecification);
void destroyWidget(aWidgetId);
WidgetGroupWrapper getWidget(aWidgetId);
Array getUnusedWidgets(aWindow);
Array getWidgetIdsInArea(aAreaId);
Array getWidgetsInArea(aAreaId);
String getAreaType(aAreaId);
DOMElement getCustomizeTargetForArea(aAreaId, aWindow);
void reset();
void undoReset();
void removeExtraToolbar();
Object getPlacementOfWidget(aWidgetId);
bool isWidgetRemovable(aWidgetNodeOrWidgetId);
bool canWidgetMoveToArea(aWidgetId);
void getLocalizedProperty(aWidget, aProp, aFormatArgs, aDef);
void hidePanelForNode(aNode);
bool isSpecialWidget(aWidgetId);
void addPanelCloseListeners(aPanel);
void removePanelCloseListeners(aPanel);
void onWidgetDrag(aWidgetId, aArea);
void notifyStartCustomizing(aWindow);
void notifyEndCustomizing(aWindow);
void dispatchToolboxEvent(aEvent, aDetails, aWindow);
bool isAreaOverflowable(aAreaId);
void setToolbarVisibility(aToolbarId, aIsVisible);
String getPlaceForItem(aElement);
bool isBuiltinToolbar(aToolbarId);

Methods

addListener()

Add a listener object that will get fired for various events regarding customization.

Parameters
aListener
the listener object to add

removeListener()

Remove a listener added with addListener.

Parameters
aListener
the listener object to remove

registerArea()

Register a customizable area with CustomizableUI.

Parameters
aAreaId
The name of the area to register. Can only contain alphanumeric characters, dashes (-) and underscores (_).
aProperties
The properties of the area. The following properties are recognized:
PropertyDescription
typeThe type of area. Either TYPE_TOOLBAR (default) or TYPE_MENU_PANEL.
anchorFor a menu panel or overflowable toolbar, the anchoring node for the panel.
legacySet to true if you want CustomizableUI to automatically migrate the currentset attribute.
overflowableSet to true if your toolbar is overflowable. This requires an anchor, and only has an effect for toolbars.
defaultPlacementsAn array of widget IDs making up the default contents of the area.
defaultCollapsed(INTERNAL ONLY) Only applied to TYPE_TOOLBAR areas. Set to true if the toolbar should be collapsed by default. Defaults to true. Set to null to ensure that reset/inDefaultState don't care about the toolbar's collapsed state.

registerToolbarNode()

Register a concrete node for a registered area. This method is automatically called from any toolbar in the main browser window that has its customizable attribute set to true. There should normally be no need to call it yourself.

Note that ideally, you should register your toolbar using registerArea before any of the toolbars have their XBL bindings constructed (which will happen when they're added to the DOM and are not hidden). If you don't, and your toolbar has a defaultset attribute, CustomizableUI will register it automatically. If your toolbar does not have a defaultset attribute, the node will be saved for processing when you call registerArea. Note that CustomizableUI won't restore state in the area, allow the user to customize it in customize mode, or otherwise deal with it, until the area has been registered.

registerMenuPanel()

Register the menu panel node. This method should not be called by anyone apart from the built-in PanelUI.

Parameters
aPanel
the panel DOM node being registered.

unregisterArea()

Unregister a customizable area. The inverse of registerArea.

Unregistering an area will remove all the (removable) widgets in the area, which will return to the panel, and destroy all other traces of the area within CustomizableUI. Note that this means the contents of the area's DOM nodes will be moved to the panel or removed, but the area's DOM node(s) themselves will stay.

Furthermore, by default the placements of the area will be kept in the saved state (!) and restored if you re-register the area at a later point. This is useful for add-ons that get disabled and then re-enabled (e.g., when they update).

You can override this last behavior (and destroy the placements information in the saved state) by passing true for aDestroyPlacements.

Parameters
aName
the name of the area to unregister.
aDestroyPlacements
whether to destroy the placements information for the area, too.

addWidgetToArea()

Add a widget to an area.

If the area to which you try to add is not known to CustomizableUI, this will throw.

If the area to which you try to add has not yet been restored from its legacy state (currentset attribute), this will postpone the addition.

If the area to which you try to add is the same as the area in which the widget is currently placed, this will do the same as moveWidgetWithinArea.

If the widget cannot be removed from its original location, this will no-op.

Otherwise, this will fire an onWidgetAdded notification, and an onWidgetBeforeDOMChange and onWidgetAfterDOMChange notification for each window CustomizableUI knows about.

Parameters
aWidgetId
the ID of the widget to add
aAreaId
the ID of the area to add the widget to
[optional] aPosition
the position at which to add the widget. If you do not pass a position, the widget will be added to the end of the area.

removeWidgetFromArea()

Remove a widget from its area.

If the widget cannot be removed from its area, or is not in any area, this will no-op.

Otherwise, this will fire an onWidgetRemoved notification, and an onWidgetBeforeDOMChange and onWidgetAfterDOMChange notification for each window CustomizableUI knows about.

Parameters
aWidgetId
the ID of the widget to remove

moveWidgetWithinArea()

Move a widget within an area.

If the widget is not in any area, or if the widget is already at the indicated position, this will no-op.

Otherwise, this will move the widget and fire an onWidgetMoved notification, and an onWidgetBeforeDOMChange and onWidgetAfterDOMChange notification for each window CustomizableUI knows about.

Parameters
aWidgetId
the ID of the widget to move
aPosition
the position to move the widget to. Negative values or values greater than the number of widgets will be interpreted to mean moving the widget to respectively the first or last position.

ensureWidgetPlacedInWindow()

Ensure a XUL-based widget created in a window after areas were initialized moves to its correct position. This is roughly equivalent to manually looking up the position and using insertItem in the old API, but a lot less work for consumers. Always prefer this over using toolbar.insertItem() (which might no-op because it delegates to addWidgetToArea) or, worse, moving items in the DOM yourself.

NB: why is this API per-window, you wonder? Because if you need this, presumably you yourself need to create the widget in all the windows and need to loop through them anyway, and there's no point in attempting to do this for all windows if the widget hasn't been created yet in those windows.

Parameters
aWidgetId
the ID of the widget that was just created
aWindow
the window in which you want to ensure it was added.

beginBatchUpdate()

Start a batch update of items. During a batch update, the customization state is not saved to the user's preferences file, in order to reduce (possibly sync) IO.

Calls to begin/endBatchUpdate may be nested.

Callers should ensure that NO MATTER WHAT HAPPENS they call endBatchUpdate once for each call to beginBatchUpdate, even if there are exceptions in the code in the batch update. Otherwise, for the duration of the Firefox session, customization state is never saved. Typically, you would do this using a try...finally block wrapped around your insertion code.

endBatchUpdate()

End a batch update. See the documentation for beginBatchUpdate above.

State is not saved if we believe it is identical to the last known saved state. State is only ever saved when all batch updates have finished (that is, there has been 1 endBatchUpdate call for eachbeginBatchUpdate call). If any of the endBatchUpdate calls pass aForceDirty=true, we will flush to the prefs file.

Parameters
aForceDirty
force CustomizableUI to flush to the prefs file when all batch updates have finished.

createWidget()

Create a widget.

To create a widget, you should pass an object with its desired properties. For a list of supported properties, see API-provided widgets.

Parameters
aProperties
the specification for the widget
Return value

A wrapper around the created widget.

Note: if your extension is compatible with versions of Firefox below 29, i.e. before CustomizableUI was introduced, then you have to make sure that in case of running on newer browsers, XUL overlay does not contain description of the button that you are creating with createWidget() method. Otherwise, conflicting static XUL overlay button and dynamic CustomizableUI buttons might cause the created button to be unstable or create a double button. To avoid that, update your Chrome Manifest file with links to two different versions of XUL overlay, using Manifest Flags. Note: unlike button described with XUL overlay, widget-button created via createWidget() method cannot have references to other overlay elements transferred directly as parameters. For example, if there is a need to create a button with dynamically assignable tooltip, the node for static tooltip should be deleted as soon as the widget will be created, and node-reference to popup tooltip element has to be added. For that, this function has to be used (see more here):

onCreated: function(node)
{
         node.removeAttribute("tooltiptext");
         node.tooltip = "[reference to popup tooltip element, described in XUL overlay, or created in any other way]";
},

destroyWidget()

Destroy a widget

If the widget is part of the default placements in an area, this will remove it from there. It will also remove any DOM instances. However, it will keep the widget in the placements for whatever area it was in at the time. You can remove it from there yourself by calling CustomizableUI.removeWidgetFromArea(aWidgetId).

Parameters
aWidgetId
the ID of the widget to destroy

getWidget()

Get a wrapper object with information about the widget.

Parameters
aWidgetId
the ID of the widget whose information you need
Return value

A wrapper around the widget as described above, or null if the widget is known not to exist (any more). NB: non-null return is no guarantee the widget exists because we cannot know in advance if an XUL widget exists or not.

getUnusedWidgets()

Get an array of widget wrappers for all the widgets which are currently not in any area (so which are in the palette).

Parameters
aWindowPalette
the palette (and by extension, the window) in which CustomizableUI should look. This matters because of course XUL-provided widgets could be available in some windows but not others, and likewise API-provided widgets might not exist in a private window (because of the showInPrivateBrowsing property).
Return value

An array of widget wrappers.

getWidgetIdsInArea()

Get an array of all the widget IDs placed in an area. This is roughly equivalent to fetching the currentset attribute and splitting by commas in the legacy APIs. Modifying the array will not affect CustomizableUI.

NB: will throw if called too early (before placements have been fetched) or if the area is not currently known to CustomizableUI.

Parameters
aArea
the ID of the area whose placements you want to obtain.
Return value

An array containing the widget IDs that are in the area.

getWidgetsInArea()

Get an array of widget wrappers for all the widgets in an area. This is the same as calling getWidgetIdsInArea and .map()-ing the result through CustomizableUI.getWidget. Careful: this means that if there are IDs in there which don't have corresponding DOM nodes (like in the old-style currentset attribute), there might be nulls in this array, or items for which wrapper.forWindow(win) will return null.

NB: will throw if called too early (before placements have been fetched) or if the area is not currently known to CustomizableUI.

Parameters
aArea
the ID of the area whose widgets you want to obtain.
Return value

An array containing the widget wrappers and/or null values for the widget IDs placed in an area.

getAreaType()

Check what kind of area (toolbar or menu panel) an area is. This is useful if you have a widget that needs to behave differently depending on its location. Note that widget wrappers have a convenience getter property (areaType) for this purpose.

Parameters
aArea
the ID of the area whose type you want to know
Return value

TYPE_TOOLBAR or TYPE_MENU_PANEL depending on the area, null if the area is unknown.

getCustomizeTargetForArea()

Obtain the DOM node that is the customization target for an area in a specific window.

Areas can have a customization target that does not correspond to the node itself. In particular, toolbars that have a customizationtarget attribute set will have their customization target set to that node. This means widgets will end up in the customization target, not in the DOM node with the ID that corresponds to the area ID. This is useful because it lets you have fixed content in a toolbar (e.g. the panel menu item in the navbar) and have all the customizable widgets use the customization target.

Using this API yourself is discouraged; you should generally not need to be asking for the DOM container node used for a particular area. In particular, if you're wanting to check it in relation to a widget's node, your DOM node might not be a direct child of the customize target in a window if, for instance, the window is in customization mode, or if this is an overflowable toolbar and the widget has been overflowed.

Parameters
aArea
the ID of the area whose customize target you want to have
aWindow
the window where you want to fetch the DOM node.
Return value

The customize target DOM node for aArea in aWindow

reset()

Reset the customization state back to its default.

This is the nuclear option. You should never call this except if the user explicitly requests it. Firefox does this when the user clicks the "Restore Defaults" button in customize mode.

undoReset()

Undoes a previous reset, restoring the state of the UI to the state prior to the reset. This can only be called immediately after reset(). If any of the UI is changed after calling reset(), then undoReset will be a no-op.

removeExtraToolbar()

Remove a custom toolbar added in a previous version of Firefox or using an add-on. NB: only works on the customizable toolbars generated by the toolbox itself. Intended for use from CustomizeMode, not by other consumers.

Parameters
aToolbarId
the ID of the toolbar to remove

getPlacementOfWidget()

Get the placement of a widget. This is by far the best way to obtain information about what the state of your widget is. The internals of this call are cheap (no DOM necessary) and you will know where the user has put your widget.

Parameters
aWidgetId
the ID of the widget whose placement you want to know
Return value

A JS Object of the form:

{
  area: "somearea", // The ID of the area where the widget is placed
  position: 42      // the index in the placements array corresponding to your widget
}

OR null if the widget is not placed anywhere (that is, it is in the palette).

isWidgetRemovable()

Check if a widget can be removed from the area it's in.

Note that if you're wanting to move the widget somewhere, you should generally be checking canWidgetMoveToArea, because that will return true if the widget is already in the area where you want to move it (!).

NB: oh, also, this method might lie if the widget in question is a XUL-provided widget and there are no windows open, because it can obviously not check anything in this case. It will return true. You will be able to move the widget elsewhere. However, once the user reopens a window, the widget will move back to its 'proper' area automagically.

Parameters
aWidgetId
the widget ID or DOM node to check
Return value

true if the widget can be removed from its area, false otherwise.

canWidgetMoveToArea()

Check if a widget can be moved to a particular area. Like isWidgetRemovable but better, because it'll return true if the widget is already in the right area.

Parameters
aWidgetId
the widget ID or DOM node you want to move somewhere
aArea
the area ID you want to move it to.
Return value

true if this is possible, false if it is not. The same caveats as for isWidgetRemovable apply, however, if no windows are open.

getLocalizedProperty()

Get a localized property off a (widget) object.

NB: this is unlikely to be useful unless you're in Firefox code, because this code uses the builtin widget stringbundle, and can't be told to use add-on-provided strings. It's mainly here as convenience for custom builtin widgets that build their own DOM but use the same stringbundle as the other builtin widgets.

Parameters
aWidget
the object whose property we should use to fetch a localizable string
aProp
the property on the object to use for the fetching
aFormatArgs
(optional) any extra arguments to use for a formatted string
aDef
(optional) the default to return if we don't find the string in the stringbundle
Return value

The localized string, or aDef if the string isn't in the bundle.

If aDef is not provided, and if aProp exists on aWidget, we'll return that, otherwise we'll return the empty string

hidePanelForNode()

Given a node, walk up to the first panel in its ancestor chain, and close it.

Parameters
aNode
a node whose panel should be closed

isSpecialWidget()

Check if a widget is a "special" widget: a spring, spacer or separator.

Parameters
aWidgetId
the widget ID to check.
Return value

true if the widget is 'special', false otherwise.

addPanelCloseListeners()

Add listeners to a panel that will close it. For use from the menu panel and overflowable toolbar implementations, unlikely to be useful for consumers.

Parameters
aPanel
the panel to which listeners should be attached.

removePanelCloseListeners()

Remove close listeners that have been added to a panel with addPanelCloseListeners. For use from the menu panel and overflowable toolbar implementations, unlikely to be useful for consumers.

Parameters
aPanel
the panel from which listeners should be removed.

onWidgetDrag()

Notify listeners a widget is about to be dragged to an area. For use from Customize Mode only, do not use otherwise.

Parameters
aWidgetId
the ID of the widget that is being dragged to an area.
aArea
the ID of the area to which the widget is being dragged.

notifyStartCustomizing()

Notify listeners that a window is entering customize mode. For use from Customize Mode only, do not use otherwise.

Parameters
aWindow
the window entering customize mode

notifyEndCustomizing()

Notify listeners that a window is exiting customize mode. For use from Customize Mode only, do not use otherwise.

Parameters
aWindow
the window exiting customize mode

dispatchToolboxEvent()

Notify toolbox(es) of a particular event. If you don't pass aWindow, all toolboxes will be notified. For use from Customize Mode only, do not use otherwise.

Parameters
aEvent
the name of the event to send.
aDetails
optional, the details of the event.
aWindow
optional, the window in which to send the event.

isAreaOverflowable()

Check whether an area is overflowable.

Parameters
aAreaId
the ID of an area to check for overflowable-ness
Return value

true if the area is overflowable, false otherwise

setToolbarVisibility()

Set a toolbar's visibility state in all windows.

Parameters
aToolbarId
the ID of the toolbar whose visibility should be adjusted
aIsVisible
whether the toolbar should be visible

getPlaceForItem()

Obtain a string indicating the place of an element. This is intended for use from customize mode. You should generally use getPlacementOfWidget instead, which is cheaper because it does not use the DOM.

Parameters
aElement
the DOM node whose place we need to check
Return value
  • "toolbar" if the node is in a toolbar,
  • "panel" if it is in the menu panel,
  • "palette" if it is in the (visible!) customization palette,
  • undefined otherwise.

isBuiltinToolbar()

Check if a toolbar is builtin or not.

Parameters
aToolbarId
the ID of the toolbar you want to check
Return value

true if the toolbar is builtin, false otherwise.

Properties

For readability, the properties are split according to purpose:

Dynamic getters

AttributeTypeDescription
areasArrayAlways returns an up to date Array of all the area IDs that are currently registered with CustomizableUI.
inDefaultStatebool

Whether we're in a default state. Note that non-removable non-default widgets and non-existing widgets are not taken into account in determining whether we're in the default state.

NB: this is a property with a getter. The getter is NOT cheap, because it does smart things with non-removable non-default items, non-existent items, and so forth. Please don't call unless necessary.

canUndoResetboolWhether the "Restore Defaults" operation can be reverted. This is only true after "Restore Defaults" has been performed and no other UI changes happen after the "Restore Defaults" operation.

Area constants

AttributeTypeDescription
AREA_NAVBARString"nav-bar", a constant reference to the ID of the navigation toolbar.
AREA_TABSTRIPString"TabsToolbar", a constant reference to the ID of the tabstrip toolbar.
AREA_MENUBARString"toolbar-menubar", a constant reference to the ID of the menubar's toolbar.
AREA_BOOKMARKSString"PersonalToolbar", a constant reference to the ID of the bookmarks toolbar.
AREA_ADDONBAR DeprecatedString"addon-bar", a constant reference to the ID of the add-on toolbar shim. Do not use, this will be removed as soon as reasonably possible.
AREA_PANELString"PanelUI-contents", a constant reference to the ID of the menu panel.
TYPE_TOOLBARString"toolbar", a constant indicating the area is a toolbar.
TYPE_MENU_PANELString"menu-panel", a constant indicating the area is a menu panel.

Widget constants

PROVIDER_XULString"xul", a constant indicating an XUL-type provider.
PROVIDER_APIString"api", a constant indicating an API-type provider.
PROVIDER_SPECIALString"special", a constant indicating dynamic (special) widgets: spring, spacer, and separator.
SOURCE_BUILTINString"builtin", a constant indicating the widget is built-in.
SOURCE_EXTERNALString"external", a constant indicating the widget is externally provided (e.g., by add-ons or other items not part of the builtin widget set).
WIDE_PANEL_CLASSString"panel-wide-item", the class used to distinguish items that span the entire menu panel.
PANEL_COLUMN_COUNTNumber3, the (constant) number of columns in the menu panel.

Examples

CreateWidget - Button Type

This is likely the code you need for your widget. Only rare need a type:custom widget.

CustomizableUI.createWidget({
    id: 'id_of_my_widget_within_customizableui_AND_dom',
    defaultArea: CustomizableUI.AREA_NAVBAR,
    label: 'My Widget',
    // type: 'button', //we don't need to type this, the default type is button
    tooltiptext: 'This is my widget created with CUI.jsm',
    onCommand: function(aEvent) {
        var thisDOMWindow = aEvent.target.ownerDocument.defaultView; //this is the browser (xul) window
        var thisWindowsSelectedTabsWindow = thisDOMWindow.gBrowser.selectedTab.linkedBrowser.contentWindow; //this is the html window of the currently selected tab
        thisWindowsSelectedTabsWindow.alert('alert from html window of selected tab');
        thisDOMWindow.alert('alert from xul window');
    }
});

Giving the button an icon non-style sheet method

The style sheet method (below) is one way to add an icon. The other way is to watch for when your widget is dropped into an area, and give an appropriate icon. This way is simpler because you don't have to maintain a style sheet.

    var myWidgetListener = {
        onWidgetAdded: function(aWidgetId, aArea, aPosition) {
            console.log('a widget moved to an area, arguments:', arguments);
            if (aWidgetId != 'noida') {
                return
            }
            console.log('my widget moved');

            var useIcon;
            if (aArea == CustomizableUI.AREA_PANEL) {
                useIcon = 'chrome://branding/content/icon32.png';
            } else {
                useIcon = 'chrome://branding/content/icon16.png';
            }

            var myInstances = CustomizableUI.getWidget('noida').instances;
            for (var i=0; i<myInstances.length; i++) {
                myInstances[i].node.setAttribute('image', useIcon);
            }

        },
        onWidgetDestroyed: function(aWidgetId) {
            console.log('a widget destroyed so removing listener, arguments:', arguments);
            if (aWidgetId != 'noida') {
                return
            }
            console.log('my widget destoryed');
            CustomizableUI.removeListener(myWidgetListener);
        }
    }
    CustomizableUI.addListener(myWidgetListener);
    CustomizableUI.createWidget({
        id: 'noida',
        defaultArea: CustomizableUI.AREA_NAVBAR,
        label: 'My Widget',
        tooltiptext: 'This is my widget created with CUI.jsm'
    });

It is important we add the listener before creating the element, because otherwise, the icon will not be set as the buttons are added, then we register the listener. So if we register listener first, then it catches the initial adds. When the button is in the panel area, it needs a 32x32 icon, and when in other places it needs a 16x16 icon. One issue with this method, is that when the icon is removed to the "customize toolbox" (when you right click and say customize and it opens that tab), it doesn't give it the 32x32 icon it needs (i have to figure out how and update the docs, its probably onWidgetRemoved or something)

Giving the button an icon via style sheet method

The above code creates your widget with click functionality. However it will not have an icon. We have to register a style sheet for that. This example here uses nsIStyleSheetService to do so. This is a complete example that can be copied and pasted into scratchpad:

//start - use CustomizableUI.jsm to create the widget
Cu.import('resource:///modules/CustomizableUI.jsm');
CustomizableUI.createWidget({
    id: 'id_of_my_widget_within_customizableui_AND_dom',
    defaultArea: CustomizableUI.AREA_NAVBAR,
    label: 'My Widget',
    // type: 'button', //we don't need to type this, the default type is button
    tooltiptext: 'This is my widget created with CUI.jsm',
    onCommand: function(aEvent) {
        var thisDOMWindow = aEvent.target.ownerDocument.defaultView; //this is the browser (xul) window
        var thisWindowsSelectedTabsWindow = thisDOMWindow.gBrowser.selectedTab.linkedBrowser.contentWindow; //this is the html window of the currently selected tab
        thisWindowsSelectedTabsWindow.alert('alert from html window of selected tab');
        thisDOMWindow.alert('alert from xul window');
    }
});
//end - use CustomizableUI.jsm to create the widget

//start - use style sheet service to style our widget to give it an icon
Cu.import('resource://gre/modules/Services.jsm');
var sss = Cc['@mozilla.org/content/style-sheet-service;1'].getService(Ci.nsIStyleSheetService);

var css = '';
css += '@-moz-document url("chrome://browser/content/browser.xul") {';
css += '    #id_of_my_widget_within_customizableui_AND_dom {';
css += '        list-style-image: url("chrome://branding/content/icon16.png")'; //a 16px x 16px icon for when in toolbar
css += '    }';
css += '    #id_of_my_widget_within_customizableui_AND_dom[cui-areatype="menu-panel"],';
css += '        toolbarpaletteitem[place="palette"] > #id_of_my_widget_within_customizableui_AND_dom {';
css += '        list-style-image: url("chrome://branding/content/icon32.png");'; //a 32px x 32px icon for when in toolbar
css += '    }';
css += '}';

var cssEnc = encodeURIComponent(css);
var newURIParam = {
    aURL: 'data:text/css,' + cssEnc,
    aOriginCharset: null,
    aBaseURI: null
}
var cssUri = Services.io.newURI(newURIParam.aURL, newURIParam.aOriginCharset, newURIParam.aBaseURI); //store this in a global var so you can call it when removing the widget
sss.loadAndRegisterSheet(cssUri, sss.AUTHOR_SHEET);

/**************/
// When you want to remove this widget run this code:
// sss.unregisterSheet(cssUri, sss.AUTHOR_SHEET); //remove the style sheet we applied
// CustomizableUI.destroyWidget('id_of_my_widget_within_customizableui_AND_dom'); //remove the widget
/**************/

CreateWidget - Custom Type - Simple

This shows a simple example of how to make a widget with type custom. This example creates a simple button; type custom should not be used for such a simple widget. If this is your need see the example above CreateWidget - Button Type. Note: the DOM node you construct should have the same ID as the id property described above, so that CustomizableUI can find the node again later.

CustomizableUI.createWidget({
    id: 'navigator-throbber', //id in cui.jsm // SHOULD match id of that in dom (Line #11)
    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');
        image.setAttribute('src', 'chrome://branding/content/icon16.png');

        var props = {
            id: 'navigator-throbber', //id in dom // SHOULD match id of that in cui.jsm (Line #2)
            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;
    }
});

When you want to remove this widget run this code:

CustomizableUI.destroyWidget('navigator-throbber-id-within-CustomizableUI-object');

Custom Type - Involved

The browser uses type custom for its zoom controls and edit controls in the Panel. The code is more advanced. It can be found summarized at this gist: https://gist.github.com/Noitidart/10902477

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

词条统计

浏览:144 次

字数:61739

最后编辑:7年前

编辑次数:0 次

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文