Popup Content (Context Menus and Tooltips)
- Feature Owners
- Dave Hyatt
(Content Model Work, Arbitrary XUL Popups)
- Chris Saari (Popup Menus and Context Menus)
- Mike Pinkerton (Tooltips, Making Things Suck Less)
- Chris Saari (Popup Menus and Context Menus)
The XUL language provides a way for developers to declare that a XUL subtree is popup content, meaning that the content is displayed in its own window when a certain event occurs (e.g., a right mouse click to bring up a context menu, or a left click to bring up a popup color picker on a toolbar).
There are two kinds of popup content: menus and windows.
Popup menus use the native menus on each platform and are
described using menu
and
menuitem
elements (See
Menus and Menu Bars for details).
Popup windows can contain arbitrary XUL, and are
full-fledged XUL windows, declared using the
window
tag (See Windows
and Dialogs for details).
Popup content is placed inside a
popup
tag, which prevents it
from being displayed in the main document. The popup tag
always has an identifier attached to it (using the
id
attribute) that is used when
attaching the popup content to a UI element.
<popup id="replyMenu"> <menu> <menuitem name="Reply to Sender"> <menuitem name="Reply to All"> </menu> </popup>
There are three different ways of automatically attaching
a popup to content. All three methods involve setting
attributes on the content node that should have the popup
content attached to it. The attributes are
popup
,
context
, and
tooltip
. The value of one of
these attributes is the id
of
the popup element that should be used to build the popup
content.
<titledbutton value="Reply" popup="replyMenu"/>
The popup
attribute is used
to attach popup content that will be invoked on a
"left mouse down". The
context
attribute is used to
attach popup content that will be invoked on a context menu
event (with the cross-platform abstraction being taken care
of for you). The tooltip
attribute is used to attach popup content that will be
invoked after a time-delay hover over the node that has the
popup content attached. (Note that tooltips may only be used
with popup window content and never with popup menu
content.)
By default the popup content appears with its top left
point located directly underneath the point at which the
user's mouse goes down (on tooltips the content is displaced
by the height of the mouse cursor). This placement can be
controlled using the
popupanchor
and
popupalign
attributes.
The popupanchor
and
popupalign
attributes have four
possible values: topleft, topright, bottomleft and
bottomright. The popupanchor
attribute can be used to specify that the popup content
should come up anchored to one of the four corners of the
content object (e.g., the button popping up the content). If
omitted, no anchoring occurs. Instead the popup content
comes up directly underneath the mouse event coordinates.
This point (either directly under the mouse or attached to
one of the four corners) is called the originating
point.
The popupalign
attribute can
be used to specify which corner of the popup content is tied
to the originating point. If omitted, the default is
topleft. The example below shows how to create the
traditional buttons with attached left mouse menus that
exist in the 4.x Communicator product.
<titledbutton value="Reply" popup="replyMenu" popupanchor="bottomleft"/>
On Windows 98, anchored menus will animate (unless the
property is turned off) to the opposite corner of the value
specified in the popupalign
attribute. In the above example, since the attribute is
omitted, the default is topleft, and the menu will therefore
animate to the bottomright corner.
The popup content can have attached event handlers just
as regular content might. In these event handlers, the
element that the popup was invoked upon can be retrieved by
examining the popupNode
property of the document. This property is set only when the
popup is currently open.
<popup id="toolbarContextMenu"> <menu> ... <menuitem name="Delete" onclick="mailNewsCore.deleteButton(document.popupNode)"> ... </menu> </popup>
A similar property,
tooltipNode
, is set for the
element that has a tooltip displayed over it.
Arbitrary XUL windows that are created as popups have
their own document, and any namespaces must be declared
again on the new window tag. Style sheets, however, are
inherited from the parent document. A popup XUL window is
linked to the parent window that spawned it using the
opener
property, and thus can
get back to the originating document to invoke functions or
to examine data.
Arbitrary XUL popups can be closed or repositioned just
as normal windows can using the methods of the
window
object. The most
relevant method is
window.close()
, which can be
used to discard the popup.
<popup id="justifierPopup"> <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" width="40" height="100"> <titledbutton id="left" onclick="opener.setJustification('left'); window.close();"/> <titledbutton id="center" onclick="opener.setJustification('center'); window.close();"/> <titledbutton id="right" onclick="opener.setJustification('right'); window.close();"/> </window> </popup> ... <titledbutton popup="justifierPopup" popupanchor="bottomleft"/> ...
Popup content can also be created in response to any
event (and not just the predefined
popup
,
context
and
tooltip
events. There are two
new methods on the window
object that allow popup content to be instantiated
programmatically.
createPopup
takes six
arguments: the DOM element to attach the popup to, the DOM
element that represents the popup content, the x screen
coordinate of the popup, the y screen coordinate of the
popup, the popup type (context, popup, or tooltip), and the
popup alignment (topleft, bottomright, bottomleft,
topright).
The createAnchoredPopup
method can be used to create popup content at a specific
anchor point on a content object. It takes five arguments:
the element to attach the popup to, the popup content
element, the anchor position for the content (topleft,
bottomright, bottomleft, topright), the popup type, and the
popup alignment.
Using these methods, fine-grained control of popup instantiation is possible, e.g., a popup can be brought up after a time-delay or in response to keyboard events.
Popups can also be built dynamically or be modified just
prior to being displayed. The
create
and
destroy
events are fired on a
popup element just prior to it being displayed and just
after it has lost the focus, respectively. Event listeners
can be attached using the
oncreate
and
ondestroy
attributes or by
using the DOM addEventListener
function.
Due to how
the menubar and dynamic menus are implemented on MacOS, the
ondestroy
handler is not
guaranteed to be called at any particular time. On MacOS
only, it will be called at one of the following times:
- just before the next menu is to be displayed (which could be hours after the menu actually leaves the screen or when a different menubar is active)
- when the app quits
The window associated with this menubar may be long gone by the time the handler is executed. Do not put anything time-critical or anything that relies on a window being present in this handler.
Tooltips
Tooltips are basically timed xul popups. You have full control over the appearance of these popups, or you may use a combination of JS and a standard "template" tooltip to get up and running quickly.
The easy way:
<!-- this popup is in globaloverlay.xul. you don't need to duplicate it it is included here as an example. --> <popupset> <popup id="aTooltip" oncreate="return FillInTooltip(document.tooltipNode);"> <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" width="200" height="20" style="border: thin solid black"> <titledbutton id = "replaceMe" align="left" class="borderless paneltitle"/> </window> </popup> </popupset> ... <toolbar tooltip="aTooltip"> <titledbutton tooltiptext="Tip for Button One"/> <titledbutton tooltiptext="Tip for Button Two"/> <titledbutton tooltiptext="Tip for Button Three"/> </toolbar> ...
The tooltiptext
attribute
specifies the text displayed in the tooltip for this item.
If you need more control over the tooltip for a particular
button, you can specify the
tooltip
attribute directly on
that item and set its id to a different popup where the new
content lives.
You can use the JS convenience routine
FillInTooltip()
(available from
globaloverlay.js) anywhere you want as long as you have one
node within the popup whose name is "replaceMe". This way
you keep the convenience of only having to specify the
tooltip text on the button but can use any popup you
like.
To prevent tooltips from showing up based on content,
return false from the oncreate
event handler. Actually, this is true for any xul popup, but
most useful for tooltips.
Tooltips will automatically time out after 5 seconds or
so and go away on their own. If you have a lot of
information in your tooltip and would prefer that it didn't,
set the noautohide
attribute to
true on the tooltip's
<popup>
tag. Tooltips
will also go away when the mouse leaves the Gecko frame
corresponding to the DOM node that was the event target that
spawned the tip.
Known Issues
- HTML Elements - Popups can only be attached to XUL elements right now and not to HTML elements.
- Anchoring - Don't try to use the popupanchor attribute yet. It will cause the popups to not even show up at all. Also, the createAnchoredPopup method doesn't do anything yet.
-
Arbitrary XUL Popup Issues
- The destruct event doesn't fire when an arbitrary XUL popup is closed.