This tutorial guides you to learning XUL (XML User-interface Language) which is a cross-platform language for describing user interfaces of applications.
This tutorial will demonstrate creating a simple find file user interface, much like that provided by the Macintosh's Sherlock or the find file dialog in Windows. Note that only the user interface will be created and some limited functionality. The actual finding of files will be not be implemented. A blue line will appear to the left of a paragraph where the find file dialog is being modified. You can follow along at these sections.
XUL (pronounced zool and it rhymes with cool) was created to make development of the Mozilla browser easier and faster. It is an XML language so all features available to XML are also available to XUL.
Most applications need to be developed using features of a specific platform making building cross-platform software time-consuming and costly. This may not be important for some, but users may want to use an application on other devices such as handheld devices or set-top boxes.
A number of cross-platform solutions have been developed in the past. Java, for example, has portability as a main selling point. XUL is one such language designed specifically for building portable user interfaces.
It takes a long time to build an application even for only one platform. The time required to compile and debug can be lengthy. With XUL, an interface can be implemented and modified quicky and easily.
XUL has all the advantages of other XML languages. For example XHTML or other XML languages such as MathML or SVG can be inserted within it. Also, text displayed with XUL is easily localizable, which means that it can be translated into other languages with little effort. Style sheets can be applied to modify the appearance of the user interface (much like the skins or themes feature in WinAmp or some window managers).
XUL provides the ability to create most elements found in modern graphical interfaces. It is generic enough that it could be applied to the special needs of certain devices and powerful enough that developers can create sophisticated interfaces with it.
Some elements that can be created are:
The displayed content can be created from the contents of a XUL file or with data from a datasource. In Mozilla, such datasources include a user's mailbox, their bookmarks and search results. The contents of menus, trees and other elements can be populated with this data, or with your own data supplied in an RDF file.
XUL content may be loaded from a local file or a remote site. It may also be packaged into an installer which the user may download and install. This last method gives the application additional privileges, such as reading local files and modifying user preferences.
When loading XUL content from a remote site, you must set up your Web server to send XUL files with the content type 'application/vnd.mozilla.xul+xml'.
You should have an understanding of HTML and at least a basic understanding of XML and CSS. Here are some guidelines to keep in mind:
XUL is supported in Mozilla and browsers based upon it, such as Netscape 6. Due to various changes in XUL syntax over time, you will want to get the latest version for the examples to work properly.
We'll begin by looking at how the XUL file system is organized in Mozilla.
Mozilla is organized in such a way that you can have as many components as you want installed. A typical installation might have the navigator, messenger and editor components. It will also have one component for each installed skin and locale. Each of these components, or packages, is made up of a set of files that describe the user interface for it. For example, the messenger component will have descriptions of the mail messages list window, the composition window and the address book dialogs.
The packages that are provided with Mozilla are located within the chrome directory, which you will find in the directory where you installed Mozilla. The chrome directory is where all the files that describe the user interface used by Mozilla are located.
Each package may have a number of sub-packages. For example, the messenger package contains two sub-packages, the address book package, and the message composition package.
A package can supply its own skin information as part of the package, or it may rely on the default skin.
A user interface is made up of three sets of files, each stored in a separate subdirectory of the chrome directory. These three sets are the content, the skin and the locale. A particular component might provide one or more default skins and locales, but a user can replace them with their own.
Take a look at Mozilla's chrome directory. You should see a bunch of JAR files, one for each installed package. For example, the file messenger.jar describes the user interface for the Messenger component. The file modern.jar describes the Modern skin.
The name of the JAR file might describe what it contains, but you can be sure by viewing its contents. (You can view JAR files with a ZIP utility). Let's use the messenger package as an example. If you extract the files in messenger.jar, you will find that it contains a directory structure like the following:
content
messenger
contents.rdf
messenger.xul
-- other mail XUL and JS files goes here --
addressbook
-- address book files go here --
messengercompose
-- message composition files go here --
.
.
.
This is easily recognizable as a content package, as the top-level directory is called 'content'. For skins, this directory will be called 'skin' and for locales, it will be called 'locale'. Actually, this isn't necessary but you should follow this convention to make your package clearer. Some packages may include a content section, a skin and a locale. In this case, you will find a subdirectory for each type.
The content/messenger directory contains a number of files with xul and js extensions. The XUL files are the ones with the xul extension. The files with js extensions are JavaScript files which contain scripts that handle the functionality of a window. Many XUL files have a script file associated with them.
In the listing above, two files have been shown. There are others of course, but for simplicity they aren't shown. The file messenger.xul is the XUL file that describes the main Messenger window which displays the mail messages list. The main window for a content package should have the same name as the package with a xul extension. Some of the other XUL files are included by messenger.xul or describe separate windows. For example, the file subscribe.xul describes the dialog for subscribing to newsgroups.
The file contents.rdf is found in every package, one for each content, skin and locale in the package. This file is used to describe the contents of the package and will be described in detail later.
Two subdirectories, addressbook and messengercompose, describe additional sections of the Messenger component. They are placed in different directories only to separate them.
The modern.jar and classic.jar files describe the skins provided with Mozilla. Their structure is similar to the content packages. For example, modern.jar:
skin
modern
navigator
contents.rdf
-- navigator skin files go here --
messenger
contents.rdf
-- messenger skin files go here --
editor
contents.rdf
-- editor skin files go here --
communicator
contents.rdf
-- communicator skin files go here --
global
contents.rdf
-- global skin files go here --
.
.
.
Here, five directories exist, one for each package that the skin is applied to. For example, the editor directory describes the skin for the editor component. The global directory contains skin files that are general to all packages. These files will apply to all components. You will usually use this one yourself.
You might notice that there are five contents.rdf files. This way, the skins are applied separately to each component. You could have a different skin for navigator as messenger, but most of the appearance is determined by the global part so you won't see much difference. They are also separate files so that new components can be added and existing components can be removed easily.
A skin is made up of CSS files and a number of images used to define the look of an interface. The images are used for the toolbar buttons. The file messenger.css is used by messenger.xul and contains styles which define the appearance of various parts of the mail interface.
By changing the CSS file, you can adjust the appearance of a window without changing its function. This is how you can create a skin.
The file en-US.jar describes the language information for each component, in this case for US English. Like the skins, each language will contain files that specify text used by the package but for that language.
As usual, a contents.rdf file is provided that lists the packages the locale provides text for. Sundirectories provide the text for each package.
The localized text is stored in two types of files, DTD files, and properties files. The DTD files have a dtd extension and contain entity declarations, one for each text string that is used in a window. For example, the file messenger.dtd contains entity declarations for each menu command. In addition, keyboard shortcuts for each command are also defined, because they may be different for each language. DTD files are used by XUL files so, in general, you will have one per XUL file.
Properties files are similar, but are used by script files. The file messenger.properties contains a few such strings.
This structure allows you to translate Mozilla or a component into a different language by just adding a new locale for that language.
Many of the packages in Mozilla are sub-packages of the communicator package. For example, you'll find the bookmarks window, the history viewer and the preferences dialogs within the communicator package. They are put there because they are general to a number of packages. There is nothing special about them.
There is a special package called toolkit (or global). We saw the global directory earlier for skins. The toolkit.jar contains the corresponding content for it. It contains some global dialogs and definitions. It also defines the default appearance and functionality of the various widgets such as textboxes and buttons. The files located in the global part of a skin archive contains the default look for all of the XUL interface elements. Most skin changes will involve variations of these files.
The structure described above is where the default packages, skins and locales are stored. However, they do not need to be placed there. If you have another package installed, it can be placed anywhere on the disk. The file chrome.rdf in the chrome directory stores the list of installed packages, skins and locales and where they are located.
A user may have multiple skins and locales installed that modify the same package. Only one skin and locale per package is active at any given time. The file chrome/chrome.rdf in the user profile specifies which skins and locales are active.
The following section will describe how to refer to XUL documents and other chrome files.
XUL files can be referenced with a regular HTTP URL just like HTML files (Or any type of URL). However, packages that are installed into Mozilla's chrome system can be referenced with special chrome URLs. Files in the chrome directory will already be installed but you can register your own.
Installed packages have the advantage that they don't have security restrictions placed on them, which is necessary for many applications. Another advantage over other URL types is that they automatically handle mulitple skins and locales.
The basic syntax of a chrome URL is as follows:
chrome://<component>/content/<file.xul>
where <component> is the component name, such as messenger or editor.
Example: chrome://messenger/content/messenger.xul
The example here refers to the messenger window. You could point to a file that is part of a skin by replacing 'content' with 'skin' and changing the filename. Similarly, you can point to a file that is part of a locale by using 'locale' instead of 'content'.
You could think of the chrome URL as a special type of file URL (that is, file:// URLs) where the root directory is the Mozilla chrome directory. However, there is one additional feature. The skin and locale part of the chrome URL maps to the current setting. If the user changes the default skin, the chrome URL does not change, but what it points to changes.
Mozilla is able to figure out which skin current language are currently used and map the appropriate directories into chrome URLs. The file chrome.rdf in the chrome directory and the contents.rdf files are there to tell Mozilla how to do this. That way the user can use any skin or language but the URLs that reference chrome files do not have to be changed. For example, the default navigator.css can be referenced with:
chrome://navigator/skin/navigator.css
If you change the browser skin, the chrome URL does not change, even through the real location of the files used by the skin change.
The chrome system takes the navigator sections of the content, the current skin and the current locale and groups them together to form a user interface. Here are some more examples, this time for messenger:
chrome://messenger/content/messenger.xul
chrome://messenger/content/mime.js
chrome://messenger/skin/icons/images/folder-inbox.jpg
chrome://messenger/locale/messenger.dtd
For subpackages, the same structure can be used. The following URL will refer to the bookmarks window:
chrome://communicator/content/bookmarks/bookmarks.xul
You can enter chrome URLs anywhere normal URLs can be used. You can even enter them directly into the URL bar in a Mozilla browser window. Remember that you can also reference XUL files with regular file URLs also. You might do this to test a file without having to install a package.
You might also see chrome URLs without specified filenames, such as:
chrome://navigator/content/
This type of reference will automatically select an appropriate file from that directory. For content, a file with the name of the package and a xul extension is selected. In the above example, the file navigator.xul is selected.
For a skin, the file package.css is selected; for a locale, the file package.dtd is selected (where package is the name of the package). This is a convenient shorthand syntax.
In this section, we'll see how to put chrome and XUL files into a package and create manifest files for them.
A package is a set of XUL files and scripts that define the functionality of a user interface. Packages may be installed into Mozilla and referenced to with chrome URLs.
A package can contain any files it wants and may be split into subdirectories for different parts of the package. For example, the bookmarks and history viewer are part of the communicator package, but are stored in different sub-directories.
A package can be stored either as a directory or as a JAR archive. Each package will have a manifest file, contents.rdf, that describes the package. This file will be placed inside the JAR file alongside the files that it describes. The file must be named contents.rdf and be a file in RDF (Resource Description Framework) format. We'll learn more about RDF later.
The contents.rdf file describes the contents of a package. It can also be used to describe a skin or locale.
Manifest files are fairly easy to create once you know how. The template below can be used as a starting point.
<?xml version="1.0"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
<RDF:Seq about="urn:mozilla:package:root">
<RDF:li resource="urn:mozilla:package:myapplication"/>
</RDF:Seq>
<RDF:Description about="urn:mozilla:package:myapplication"
chrome:displayName="My Application"
chrome:author="name"
chrome:name="myapplication">
</RDF:Description>
</RDF:RDF>You can use this template and make some minor changes specific to your package. Let's break this down to understand what each piece does.
<?xml version="1.0"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
These three lines should be placed at the top of the contents.rdf file. Because RDF is an XML format, it contains the standard first line that XML files do. Next, we declare the namespaces that are being used, here one for RDF and the other for the chrome system. If you don't understand what this means, don't worry. Just add them at the top of the manifest file.
<RDF:Seq about="urn:mozilla:package:root"> <RDF:li resource="urn:mozilla:package:myapplication"/> </RDF:Seq>
These lines are used to declare what packages, skins and locales are described by the manifest file. In this case, a package is being described (as indicated by the word 'package' in the text). The name of the package here is 'myapplication'. Of course, you would replace this with the name of the package you were creating. For example, the Mozilla mail application has a name of 'messenger'.
The RDF:li tag above is much like the li tag of HTML as it declares an element of a list. Thus, you can declare multiple packages by using multiple RDF:li tags.
For skins, replace the two occurances of 'package' with 'skin'; for locales, replace the two occurances of 'package' with 'locale'. For example, the following specifies a skin:
<RDF:Seq about="urn:mozilla:skin:root"> <RDF:li resource="urn:mozilla:skin:blueswayedshoes"/> </RDF:Seq>
The only differences are the changes of the two occurances of the word 'package' to 'skin' and the change to the skin name 'blueswayedshoes'.
<RDF:Description about="urn:mozilla:package:myapplication"
chrome:displayName="My Application"
chrome:author="name"
chrome:name="myapplication">
</RDF:Description>
This block is used to provide more details of the package, skin or locale. You will need a description for each li that you have. The value of the about attribute should be equal to the resource attribute on the li tag.
The three extra attributes describe extra information about the package:
Let's create a contents.rdf file for the find files dialog we'll be creating. It will need to describe the package. Because there are no sub-packages, skins or locales included, it is fairly similar to the template above.
<?xml version="1.0"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
<RDF:Seq about="urn:mozilla:package:root">
<RDF:li resource="urn:mozilla:package:findfile"/>
</RDF:Seq>
<RDF:Description about="urn:mozilla:package:findfile"
chrome:displayName="Find Files"
chrome:author="Whoever"
chrome:name="findfile">
</RDF:Description>
</RDF:RDF>Here, the component is named 'findfile' which means that we'll be able to refer to it using the following chrome URL:
chrome://findfile/content/findfile.xul
The list of installed packages is stored in the chrome directory in the file chrome.rdf. It will be automatically changed when you install a new package. Like the manifest files, it is an RDF format file. On first inspection, it looks quite different than the manifest files, but if you are familiar with RDF, you should notice that it is actually very similar.
Conveniently, we don't need to edit this file directly. Whenever Mozilla starts up, it checks the chrome directory for a special file called 'installed-chrome.txt'. This file contains a list, in a very simple format, of all the packages, skins and locales that are waiting to be installed. Mozilla scans each entry in the list and installs or updates each one as necessary.
So, to install a new package, all you need to do is add an entry to the file 'installed-chrome.txt' and restart Mozilla. Mozilla also has an installation system called XPInstall which will allow scripts to install packages automatically via JavaScript without having to modify this file manually. XPInstall will be described near the end of the tutorial. However, during development, we can modify the file directly.
The file 'installed-chrome.txt' should be added directly into the chrome directory, if it is not already there. The file contains a list of entries to install, one per line. For example:
content,install,url,resource:/chrome/findfile/content/findfile/ skin,install,url,resource:/chrome/findfile/skin/findfile/
The above will be used to install the findfiles package and also a skin for it. The format of each line is fairly simple. It's just four values separated by commas:
The resource URL is similar to a file URL except that its root is the directory where Mozilla is installed. The resource URL should have only one slash after the colon.
Thus, the line added should point to the directory where the contents.rdf file is located. If you have multiple packages, add a line for each one.
Although Mozilla follows a directory naming convention, you can put the files anywhere you want. For example, the following will install a new package that is located in the directory /main/calculator/.
content,install,path,/main/calculator/
If you are packing your files into a JAR file, you can use a JAR URL to refer to it. It has two parts, separated by an exclamation mark (!). The part before is the URL of the JAR file and the part after is the directory or file within the archive. The example below might refer to the find files dialog:
jar:resource:/chrome/findfile.jar!/content/findfile/
In summary, the following steps are needed to install a package, skin or locale. You do not need to install XUL files, but you will be limited in what scripts will be allowed to do.
We're going to be creating a simple find files utility throughout this tutorial. First, however, we should look at the basic syntax of a XUL file.
A XUL file can be given any name but it really should have a .xul extension. The simplest XUL file has the following structure:
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="findfile-window"
title="Find Files"
orient="horizontal"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
...
</window>A breakdown line by line is necessary:
In order to open a XUL window, there are several methods that can be used. If you are only in the development stage, you can just type the URL (whether a chrome:, file: or other URL type) into the location bar in a Mozilla browser window. The XUL window will appear in the browser window instead of a new window, but this is often sufficient during the early stages of development.
The correct way, of course, is to open the window using JavaScript. No new syntax is necessary as you can use the window.open() function as one can do for HTML documents. However, one additional flag, called 'chrome', is necessary to indicate to the browser that this is a chrome document. This will open without the toolbars, menus and so forth that are present on a normal browser window. The syntax is described below:
window.open(url,windowname,flags);
where the flags contains the flag "chrome".
Example:
window.open("chrome://navigator/content/navigator.xul", "bmarks",
"chrome,width=600,height=300");
Let's begin by creating the basic file for the find file dialog. Create a file called findfile.xul and put it in a new directory somewhere. It doesn't matter where you put it, but the chrome/packages/findfile/findfile/content directory is a suitable place. Add the XUL template shown at the top of this page to the file and save it.
Instead of a file URL, we could use a variant which has its root directory in the Mozilla directory. This is the resource URL. Thus, we could refer to the find files dialog with the following resource URL:
resource://chrome/packages/findfile/findfile/content/findfile.xul
You can use the command-line parameter '-chrome' to specify the XUL file to open when Mozilla starts. If this is not specified, the default window open will open. (Usually the browser window.) For example, we could open the find files dialog with:
mozilla -chrome chrome://findfile/content/findfile.xul
mozilla -chrome resource://chrome/packages/findfile/findfile/content/findfile.xul
If you run this command from a command-line (assuming you have one on your platform), the find files dialog will open by default instead of the Mozilla browser window. Of course, because we haven't put anything in the window, nothing will appear to have happened.
To see the effect though, the following will open the bookmarks window:
mozilla -chrome chrome://communicator/content/bookmarks/bookmarks.xul
In this section, we will look at how to add some simple buttons to a window.
The window we've created so far has nothing in it, so it isn't very interesting yet. In this section, we will add a Find button and a Cancel button. We will also learn a simple way to position them on the window.
Like HTML, XUL has a number of tags that can be used to create user interface elements. The most basic of these is the button tag. This element is used to create simple buttons.
The button element has two main properties associated with it, a label and an image. You need one or the other or both. Thus, a button can have a label only, an image only or both a label and an image. Buttons are commonly used for the buttons on toolbars and for the OK and Cancel buttons in a dialog.
The button tag has the following syntax:
<button
id="identifier"
class="dialog"
label="OK"
image="images/image.jpg"
default="true"
disabled="true"
accesskey="t"/>The attributes are as follows, all of which are optional:
Note that a button supports more attributes than those listed above. They will be discussed later.
By default, buttons will appear on the window with a plain appearance. The text and image will appear inside the button and a raised border drawn around it. In some cases, such as an OK button, this may be what you want. But you may want to have a different border appear around the button. Or you may want the text to highlight when the user moves the mouse over the button. The usual way to do this is much like in HTML by changing the styles of a button using style sheets or scripts.
Some examples of buttons:
Example 2.2.1: Source View<button label="Normal"/> <button label="Disabled" disabled="true"/> <button label="Default" default="true"/>
The examples above will generate the buttons in the image. The
first button is a normal button. The second button is disabled so it appears
greyed out. The third button is the default button and has a thicker border.
The image here is for the modern skin. Other skins will render disabled
and default buttons differently.
We'll start by creating a simple Find button for the find files utility. The example code below shows how to do this:
<button id="find-button" label="Find" default="true"/>
This code creates a simple button with the label Find. This button is specified to be the default button, meaning that the user can press the ENTER key to activate the Find button.
Let's add this code to the file findfile.xul that we created in the previous section. The code needs to be inserted in-between the window tags. The code to add is shown in red below:
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="findfile-window"
title="Find Files"
orient="horizontal"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<button id="find-button" label="Find" default="true"/>
<button id="cancel-button" label="Cancel"/>
</window>You'll notice that the Cancel button was added also. It should not be the default button so this attribute was left off. The window has been given a horizontal orientation so that the two buttons appear beside each other.
If you open the file in Mozilla, you should get something like the image
shown here. Notice that the Find button has appeared with a thicker border.
The effect is caused by the default attribute on the
find button. Later, we'll show how you could override this behavior, although
it's best to leave it as is because this may be the desired effect on some
platforms.
This section describes a way to add labels and images to a window. In addition, we look at how to include elements into groups.
You cannot embed text directly into a XUL file without tags around it and expect it to be displayed. The most basic way to include text in a window is to use the description element. An example is shown below:
Example 2.3.1: Source View<description value="This is some text"/>
The value attribute can be used to specify the text that you wish to have displayed. The text will not wrap, so the text will appear on only one line. This is suitable for short sections of text.
For longer text, you can place content inside the opening and closing description tags. Unlike text specified with the value attribute, the child text will wrap onto multiple lines if necessary. Like HTML, line breaks and extra whitespace are collapsed into a single space. Later we'll find out how to constrain the width of elements so that we can see the wrapping.
Example 2.3.2: Source View<description> This longer section of text is displayed. </description>
A second element, label, can be used in a similar way, except it is intended for labels of controls such as buttons and textboxes. You can use the control attribute to specify which control is associated with the label. When the user clicks the label, that control will be focused. Set the value of the control attribute to the id of the element to be focused.
Example 2.3.3: Source View<label value="Click here:" control="open-button"/> <button id="open-button" label="Open"/>
In the example above, clicking the label will cause the button to be focused.
Like HTML, XUL has an element to display images within a window. This element is appropriately named image. Note that the tag name is different than HTML (image instead of img). You can use the src attribute to specify the URL of the image file. The example below shows this:
<image src="images/banner.jpg"/>
Although you can use this syntax, it would be better to use a style sheet to set the image URL. You can use the list-style-image CSS property to set the URL for the image. Here are some examples:
XUL:
<image id="image1"/>
<image id="search"/>
Style Sheet:
#image1 {
list-style-image="chrome://findfile/skin/banner.jpg";
}
#search {
list-style-image="chrome://findfile/skin/images/search.jpg";
}These images come from within the chrome directory, in the skin for the findfile package. Because images vary by skin, you would usually place images in the skin directory.
XUL has elements that are similar to the HTML form controls.
HTML has an input element which can used for text entry controls (along with other form controls). XUL has a similar element used for straight text entry fields. The element is the textbox element. Without any attributes, the textbox element creates a box in which the user can enter text. Textboxes accept many of the same attributes as HTML input controls. The following are some of them:
The following example shows some textboxes:
Example 2.4.1: Source View<label control="some-text" value="Enter some text"/> <textbox id="some-text"/> <label control="some-password" value="Enter a password"/> <textbox id="some-password" type="password" maxlength="8"/>
The textbox examples above will create text inputs that can only be used for entering one line of text. HTML also has a textarea element for creating a larger text entry area. In XUL, you can use the textbox element for this purpose as well -- two separate elements are not necessary. If you set the multiline attribute to true, the text entry field will display mutliple rows.
For example:
Example 2.4.2: Source View<textbox multiline="true"
value="This is some text that could wrap onto multiple lines."/>Like the HTML textarea, you can use the rows and cols attributes to set the size. This should be set to the number of rows and columns of characters to display.
Let's add a search entry field to the find file dialog. We'll use the textbox element.
<label value="Search for:" control="find-text"/>
<textbox id="find-text"/>
<button id="find-button" label="Find" default="true"/>Add these lines before the buttons we created in the last section. If you open this window, you will see something much like that shown in the image below.
Notice that the label and the text input field have now appeared in the
window. The textbox is fully functional and you can type into it and
select text. Note that the control attribute
has been used so that the textbox is selected when the label is clicked.
Two additional elements are used for creating check boxes and radio buttons. They are variations of buttons. The checkbox is used for options that can be enabled or disabled. Radio buttons can be used for a similar purpose when there are a set of options and only one can be selected at a time. The example below shows some simple checkboxes and radio buttons.
<checkbox id="case-sensitive" checked="true" label="Case sensitive"/> <radio id="orange" checked="false" label="Orange"/> <radio id="violet" checked="true" label="Violet"/> <radio id="yellow" checked="false" label="Yellow"/>
The first line creates a simple checkbox. When the user clicks the checkbox, it switches between checked and unchecked. The checked attribute can be used to indicate the default state. You should set this to either true or false. The label attribute can be used to assign a label that will appear beside the check box. The radio button is similar.
In order to group radio buttons together, you need to use the radiogroup element. Only one of the radio buttons in a radio group can be selected at once. Clicking one with turn off all of the others in the same group. The following example demonstrates this.
Example 2.4.3: Source View<radiogroup> <radio id="orange" checked="false" label="Orange"/> <radio id="violet" checked="true" label="Violet"/> <radio id="yellow" checked="false" label="Yellow"/> </radiogroup>
Check boxes and radio buttons are simply specialized buttons. Remember that buttons are made up of a label and an image. A check box is just a label with an image of a check mark. You can also use many of the same attributes as buttons:
XUL has a number of element types for creating list boxes.
A list box is used to display a number of items in a list. The user may select an item from the list.
XUL provides two types of elements to create lists, a listbox element to create multi-row list boxes, and a menulist element to create drop-down list boxes. They are similar to the HTML select element, which performs both functions, but the XUL elements have additional features.
The simplest list box uses the listbox element for the box itself, and the listitem element for each item. For example, this list box will have four rows, one for each item.
Example 2.5.1: Source View<listbox> <listitem label="Butter Pecan"/> <listitem label="Chocolate Chip"/> <listitem label="Raspberry Ripple"/> <listitem label="Squash Swirl"/> </listbox>
Like with the HTML option element, you can assign a
value for each item using the value attribute. You
can then use the value in a script. The list box will default to a suitable size,
but you can control the size with the rows attribute.
Set it to the number of rows to display in the list box. A scroll bar will appear
that the user can use to display the additional rows.
The following example demonstrates these additional features:
Example 2.5.2: Source View<listbox rows="3"> <listitem label="Butter Pecan" value="bpecan"/> <listitem label="Chocolate Chip" value="chocchip"/> <listitem label="Raspberry Ripple" value="raspripple"/> <listitem label="Squash Swirl" value="squash"/> </listbox>
The example has been changed to display only 3 rows at a time. Values have also been added to each item in the list. List boxes have many additional features which will be described later.
Drop-down lists can be created in HTML using the select element. The user will see a single choice in a textbox and may click the arrow or similar button next to the textbox to make a different selection. The other choices will appear in a pop-up window. XUL has a menulist element which can be used for this purpose. It is made from a textbox and a button beside it. It's name was chosen because it pops up a menu with the choices in it.
Three elements are needed to describe a drop-down box. The first is the menulist element, which creates the textbox with the button beside it. (For non-editable menulists, the textbox will be a button). The second, menupopup, creates the popup window which appears when the button is clicked. The third, menuitem, creates the individual choices.
It's syntax is best described with the example below:
Example 2.5.3: Source View<menulist label="Bus">
<menupopup>
<menuitem label="Car"/>
<menuitem label="Taxi"/>
<menuitem label="Bus" selected="true"/>
<menuitem label="Train"/>
</menupopup>
</menulist>
This menulist will contain four choices, one for each
menuitem element. To show the choices, click the
arrow button on the menulist. When one is selected, it appears as the choice
in the menulist. The selected attribute is used to
indicate the value that is selected by default.
By default, you can only select choices from the list. You cannot enter your own selection by typing it, like you can in some drop-down boxes. A variant of the menulist allows this. Instead of a button for displaying the current selection, a textbox is used so that you can type in the selection. For example, the URL field in Navigator has a drop-down for selecting previously typed URLs, but you can also type them in yourself.
To create an editable menulist, add the editable attribute as follows:
Example 2.5.4: Source View<menulist editable="true">
<menupopup>
<menuitem label="www.mozilla.org"/>
<menuitem label="www.xulplanet.com"/>
<menuitem label="www.dmoz.org"/>
</menupopup>
</menulist>The URL field created here has three pre-populated choices that the user can select or they can enter one of their own by typing it into the field. The text the user enters is not added as a new choice. Because the value attribute was not used in this example, the default value will be blank.
Now that we've added some buttons, let's add some other elements.
In addition to all of the XUL elements that are available, you can also use HTML elements directly within a XUL file, perhaps even placing tables and Java applets in a window. You should avoid using HTML elements in XUL files if you can, but this section will describe how to use them anyway.
To use HTML elements in a XUL file, you must declare your intention by specifying the XHTML namespace; Mozilla can then distinguish the HTML and XUL tags. The attribute below should be added to the window tag of the XUL file or to the outermost HTML element.
xmlns:html="http://www.w3.org/1999/xhtml"
This is a declaration of HTML much like the one we used to declare XUL. This must be entered exactly as shown or it won't work correctly. Note that Mozilla does not actually download this URL, but it does recognize it internally.
Here is an example as it might be added to the find file window:
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="findfile-window"
title="Find Files"
orient="horizontal"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">Noe, you can use HTML tags as you would normally, keeping in mind the following:
You can use any HTML tag although some such as head and body are not really useful. Some examples of using HTML elements are shown below.
<html:img src="banner.jpg"/>
<html:input type="checkbox" value="true"/>
<html:table>
<html:tr>
<html:td>
A simple table
</html:td>
</html:tr>
</html:table>These examples will create an image from the file banner.jpg, a checkbox and a single-cell table. You should always use XUL features if they are available and you probably should not use tables for layout in XUL. (There are XUL elements for doing layout). Notice that the prefix html: was added to the front of each tag. This is so that Mozilla knows that this is an HTML tag and not a XUL one. If you left out the html: part, the browser would think they were XUL elements and they would not display because img, input, table, and so on are not valid XUL tags.
In XUL, you can add labels with the description or label element. You should use these elements when you can. You can also add labels to controls either by using the HTML label element, or you can simply put the text inside another HTML block element (such as p or div) as in the example below.
Example 2.6.1: Source View<html:p> Search for: <html:input id="find-text"/> <button id="okbutton" label="OK"/> </html:p>
This code will cause the text 'Search for:' to be displayed, followed by an input element and an OK button. Notice that the XUL button can appear inside the HTML elements, as it does here. Plain text will only be displayed when placed inside an HTML element that would normally allow you to display text (such as a p tag). Text outside of one will not be displayed, unless the text is inside a XUL element which allows this (the description element, for example). See the examples below.
What follows are some examples of adding HTML elements to windows. In each case, the window and other common information has been left out for simplicitiy.
1. A dialog with a check box
Example 2.6.2: Source View<html:p>
Click the box below to remember this decision.
<html:p>
<html:input id="rtd" type="checkbox"/>
<html:label for="rtd">Remember This Decision</html:label>
</html:p>
</html:p>In this case, one p tag was used to place the text in and another was used to break apart the text into multiple lines.
2. Text outside of HTML blocks
Example 2.6.3: Source View<html:div>
Would you like to save the following documents?
<html:hr/>
</html:div>
Expense Report 1
What I Did Last Summer
<button id="yes" label="Yes"/>
<button id="no" label="No"/>
As can be seen in the image, the text inside the div tag was displayed but the other text (Expense Report 1 and What I Did Last Summer) was not. This is because there is no HTML or XUL element capable of displaying text enclosing it. To have this text appear, you would need to put it inside the div tag, or enclose the text in a description tag.
3. Invalid HTML elements
<html:po>Case 1</html:po> <div>Case 2</div> <html:description value="Case 3"/>
All three of the cases above will not display, each for a different
reason.
Case 1: po is not a valid
HTML tag and Mozilla has no idea what to do with it.
Case 2: div is valid but only
in HTML. To get it to work, you will need to add the html: qualifier.
Case 3: A description element is only
valid in XUL and not in HTML. It should not have the html: qualifier.
In this section, we'll find out how to add some spacing in between the elements we have created.
One of the problems with developing user interfaces is that each user has a different display. Some users may have larger displays with higher resolutions and others may have lower resolutions. In addition, some platforms may have special requirements. If the user interface must support multiple languages, the text for one language might require more room than another.
Applications that need to support multiple platforms and languages usually have their windows laid out with extra blank areas to allow for the varying use of space. Some platforms and user interface toolkits provide components that are smart enough to resize and re-position themselves to fit the needs of the user. (Java uses layout managers for example.)
XUL provides the capability for elements to position and resize automatically. As we've seen, the find files window has appeared in a size that will fit the elements inside it. Each time we add something, the window gets bigger.
XUL uses a layout system called the 'Box Model'. We'll talk more about this in the next section, but it essentially allows you to divide a window into a series of boxes that hold elements. The boxes will be positioned and resized based on specifications that you can define. For now, just know that the window element is a type of box.
Another XUL element that is useful for layout is the spacer. A spacer is very simple and only requires one attribute which will be explained in a moment. The simplest spacer looks like the following:
<spacer flex="1"/>
A spacer is used to put blank space into a window. Its most useful ability is that it can grow or shrink as the user resizes the window. This would be how you would place buttons on the right or bottom of a window and have them stick to that edge no matter what size the window is. As we'll see, you can use a series of spacers to create a number of layout effects.
In this syntax above, the spacer has one attribute, called flex. This is used to define the flexibility of the spacer. In the case above, the spacer has a flex of 1. This makes the spacer element stretchy. If you place a spacer directly inside a window, the spacer will grow in size when the size of the window is changed.
We'll add a spacer to our find file dialog soon. First, let's take a look at what happens when the current dialog is resized.
If you change the size of the find files window, you can see that the elements have remained where they started. None of them have been moved or resized even though the window has more room in it. Let's see what happens when a spacer is added between the text box and the Find button.
By adding a spacer and resizing the window, you can see that the spacer has expanded to fill the space. The buttons have been pushed over. The code to add a spacer is shown below. Insert it just before the Find button.
<spacer flex="1"/>
<button id="find-button" label="Find" default="true"/>XUL lays out elements on a window by calculating suitable widths and heights for the elements and then adding space where they are flexible. Unless you specify information about the width and height of an element, the default size of an element is determined by its contents. You'll notice that the Cancel button in the dialogs has always set its width so that it fits the text inside it. If you create a button with a very long label, the button's default size will be large enough to hold the entire label. Other elements, such as the text box have chosen a suitable default size.
The flex attribute is used to specify whether and element can change size to fit the box (in this case, the window) containing it. We've already seen the flex attribute applied to spacers, but it can be applied to any element. For example, you might want the Find button to resize instead.
As you can see in the image, placing a flex attribute on the Find button causes it to resize when the window does. A spacer is really nothing special. It could really be considered a hidden button. It works much the same way as a button except it does not draw on screen.
You may have noticed something about the image above. Not only did the Find button grow in size but some space has appeared between the main label and the button. This is the spacer that we put in earlier; it has been resized also. If you look closely enough, you should notice that the change in size has been divided equally between the spacer and the button. The spacer has received half of the free space and the button has received the other half.
The reason we're seeing this effect is that both the spacer and the Find button have a flex attribute. Because both are flexible, both the button and the spacer resize equally.
What if you want one element to grow twice as large an another? You can use a higher number as the value of the flex attribute. The values of the flex element are a ratio. If one element has a flex of 1 and the next has a flex of 2, the second one will grow at twice the rate of the first. In effect, a flex of 2 says that this element has a flex that is two times larger than elements that have a flex of one.
The flex attribute only hints as to what the size ratio between elements should be. For various reasons, including explicit sizes set on elements or special requirements of certain widgets, the flexibility may not be honored exactly.
The flex attribute can be placed on any element, incuding HTML elements. However, it only has any meaning when placed on an element directly inside a box. We'll look at boxes in a later section. This means that even though you can place a flex on an HTML element, it will have no effect if that element is inside a non-box element.
Let's see some examples:
Example 1:
<button label="Find" flex="1"/>
<button label="Cancel" flex="1"/>
Example 2:
<button label="Find" flex="1"/>
<button label="Cancel" flex="10"/>
Example 3:
<button label="Find" flex="2"/>
<button label="Replace"/>
<button label="Cancel" flex="4"/>
Example 4:
<button label="Find" flex="2"/>
<button label="Replace" flex="2"/>
<button label="Cancel" flex="3"/>
Example 5:
<html:div>
<button label="Find" flex="2"/>
<button label="Replace" flex="2"/>
</html:div>
Example 6:
<button label="Find" flex="145"/>
<button label="Replace" flex="145"/>
Specifying a flex value of 0 has the same effect as leaving the flex attribute out entirely. It means that the element is not flexible at all.
You may have noticed that when you resize the find file dialog vertically, the buttons resize themselves to fit the height of the window. This is because all of the buttons have an implied vertical flex given to them by the window. In the next section we'll talk about changing this.
You may sometimes see a flex value specified as a percentage. This has no special meaning and is treated as if the percent sign was not there.
In this section, we will look at some additional features of buttons.
You can add an image to a button by specifying a URL in the image attribute. The image is loaded from the URL, which can be a relative or absolute URL, and then the image is displayed on the button.
The button below will have both a label and the image 'happy.png'. The image will appear to the left of the label. You can change this position by using two other attributes. This will be explained in a moment.
Example 2.8.1: Source View<button label="Help" image="happy.png"/>
Another way to specify the image by using the CSS list-style-image style property on the button. This is designed to allow the 'skin' (in this case, the appearance of the image) to be changed without changing the XUL file. An example is shown below.
Example 2.8.2: Source View<button id="find-button"
label="Find" default="true" style="list-style-image: url('happy.png')"/>In this case, the image 'find.png' is displayed on the button. The style attribute functions similar to its HTML counterpart. In general, it can be used on all XUL elements. Note that you really should put the style declarations in a separate style sheet.
By default, the image on a button will appear to the left of the text label. There are two attributes that can be used to control this position.
The dir attribute controls the direction of the image and text. By setting this attribute to the value rtl, which stands for right-to-left, the image will be placed on the right side of the text. By using the value ltr, or leaving the attribute out entirely, the image will be placed on the left side of the text.
The orient attribute can be used to place the image above or below the text. The default value is horizontal which is used to place the image on the left or right. You can also use the value vertical to place the image above or below. In this case, the dir attribute controls the placement above or below. The same values are used, where ltr means place the image above the text, and rtl means place the image below the text.
Example 2.8.3: Source View<button label="Left" image="happy.png"/> <button label="Right" image="happy.png" dir="rtl"/> <button label="Above" image="happy.png" orient="vertical"/> <button label="Below" image="happy.png" orient="vertical" dir="rtl"/>
The example here shows all four types of alignment of buttons. Note that the two attributes are not specified when the default value can be used.
Buttons can have arbitrary markup contained inside them; it will be rendered inside the button. You probably wouldn't use this very often, but you might use it when creating custom elements.
For example, the following will create a button where two of the words are purple:
Example 2.8.4: Source View<button> <description value="This is a"/> <description value="rather strange" style="color: purple;"/> <description value="button"/> </button>
Any XUL element may be placed inside the button. HTML elements will be ignored unless you wrap them inside a description element. If you specify the label attribute on the button, it will override any content placed inside the button.
You can place a menupopup inside the button to cause a menu to drop down when the button is pressed, much like the menulist. However, in this case you must set the type attribute to the value menu.
Example 2.8.5: Source View<button type="menu" label="Device">
<menupopup>
<menuitem label="Printer"/>
<menuitem label="Mouse"/>
<menuitem label="Keyboard"/>
</menupopup>
</button>In this example, the user may click the button to pop up a menu containing three items. Note that selecting one of these menu items doesn't change the label on the button, unlike a menulist. This type of button is intended as a menu, with a script attached to each item which performs a task. We'll see more on menus later.
You can also set the type attribute to the value
menu-button. This also creates a button with a menu,
but the appearance will be different. The image to the right shows the difference.
The left one is a 'menu' and the second one is a 'menu-button'. It has an arrow
indicating the presence of a menu. For the 'menu', the user may click anywhere on
the button to show the menu. For the 'menu-button', the user must click the arrow
to show the menu.
In this section, we'll look at how XUL handles layout.
The main form of layout in XUL is called the 'Box Model'. This model allows you to divide a window into a series of boxes. Elements inside of a box will orient themselves horizontally or vertically. By combining a series of boxes, spacers and elements with flex attributes, you can control the layout of a window.
Although a box is the fundamental part of XUL element layout, it follows a few very simple rules. A box can lay out its children in one of two orientations, either horizontally or vertically. A horizontal box lines up its elements horizontally and a vertical box orients its elements vertically. You can think of a box as one row or one column from an HTML table. Various attributes placed on the child elements in addition to some CSS style properties control the exact position and size of the children.
The basic syntax of a box is as follows:
<hbox> ... </hbox> <vbox> ... </vbox>
The hbox element is used to create a horizontally oriented box. Each element placed in the hbox will be placed horizontally in a row. The vbox element is used to create a vertically oriented box. Added elements will be placed underneath each other in a column.
There is also a generic box element which defaults to horizontal orientation, meaning that it is equivalent to the hbox. However, you can use the orient attribute to control the orientation of the box. You can set this attribute to the value horizontal to create a horizontal box and vertical to create a vertical box.
Thus, the two lines below are equivalent:
<vbox> <box orient="vertical">
The following example shows how to place three buttons vertically.
Example 3.1.1: Source View<vbox> <button id="yes" label="Yes"/> <button id="no" label="No"/> <button id="maybe" label="Maybe"/> </vbox>
The three buttons here are oriented vertcally as was indicated by the box.
To change the buttons so that they are oriented horizontally, all you need to
do is change the vbox element to a
hbox element.
You can add as many elements as you want inside a box, including other boxes. In the case of a horizontal box, each additional element will be placed to the right of the previous one. The elements will not wrap at all so the more elements you add, the wider the window will be. Similarly, each element added to a vertical box will be placed underneath the previous one. The example below shows a simple login prompt:
Example 3.1.2: Source View<vbox>
<hbox>
<label control="login" value="Login:"/>
<textbox id="login"/>
</hbox>
<hbox>
<label control="pass" value="Password:"/>
<textbox id="pass"/>
</hbox>
<button id="ok" label="OK"/>
<button id="cancel" label="Cancel"/>
</vbox>
Here four elements have been oriented vertically, two inner
hbox tags and two
button elements. Notice that only the
elements that are direct descendants of the box are oriented vertcally.
The labels and textboxes are inside the inner hbox
elements, so they are oriented according to those boxes, which are horizontal.
You can see in the image that each label and textbox is oriented horizontally.
If you look closely at the image of the login dialog, you can see that the two textboxes are not aligned with each other horizontally. It would probably be better if they were. In order to do this we need to add some additional boxes.
Example 3.1.3: Source View<vbox>
<hbox>
<vbox>
<label control="login" value="Login:"/>
<label control="pass" value="Password:"/>
</vbox>
<vbox>
<textbox id="login"/>
<textbox id="pass"/>
</vbox>
</hbox>
<button id="ok" label="OK"/>
<button id="cancel" label="Cancel"/>
</vbox>
Notice how the text boxes are now aligned with each other. To do this, we
needed to add boxes inside of the main box. The two labels and textboxes
are all placed inside a horizontal box. Then, the labels are placed inside
another box, this time a vertical one, as are the textboxes. This inner
box is what makes the elements orient vertically. The horizontal box is
needed as we want the labels vbox and the inputs vbox to be placed horizontally
with each other. If this box was removed, both textboxes would appear below
both of the labels.
The issue now is that the 'Password' label is too high. We should really use the grid element here to fix this which we'll learn about in a later section.
Let's add some boxes to the find files dialog. A vertical box will be added around all of the elements, and a horizontal box with be added around the textbox and the buttons. The result will be that the buttons will appear below the textbox.
<vbox flex="1"> <description> Enter your search criteria below and select the Find button to begin the search. </description> <hbox> <label value="Search for:" control="find-text"/> <textbox id="find-text"/> </hbox> <hbox> <spacer flex="1"/> <button id="find-button" label="Find" default="true"/> <button id="cancel-button" label="Cancel"/> </hbox> </vbox>
The vertical box causes the main text, the box with the textbox and the box with the buttons to orient vertically. The inner boxes orient their elements horizontally. As you see in the image below, the label and text input are placed side by side. The spacer and two buttons are also placed horizontally in their box. Notice how the spacer causes the buttons to appear on the right side, because it is flexible.
Here we'll look at controlling the position and size of an element.
So far, we know how to position elements either horizontally or vertically inside a box. We will often need more control over the position and size of elements within the box. For this, we first need to look at how a box works.
The position of an element is determined by the layout style of its container. For example, the position of a button in a horizontal box is to the right of the previous button, if any. The size of an element is determined by two factors, the size that the element wants to be and the size you specify. The size that an element wants to be is determined by what is in the element. For example, a button's width is determined by the amount of text inside the button.
An element will generally be as large as it needs to be to hold its contents, and no larger. Some elements, such as textboxes have a default size, which will be used. A box will be large enough to hold the elements inside the box. A horizontal box with three buttons in it will be as wide as the three buttons, plus a small amount of padding.
In the image below, the first two buttons have been given a suitable size to hold their text. The third button is larger because it contains more content. The width of the box containing the buttons is the total width of the buttons plus the padding between them. The height of the buttons is a suitable size to hold the text.
You may need to have more control over the size of an element in a window. There are a number of features that allow you to control the size of an element. The quick way is to simply add the width and height attributes on an element, much like you might do on an HTML img tag. An example is shown below:
Example 3.2.1: Source View<button label="OK" width="100" height="40"/>
However, it is not recommended that you do this. It is not very portable and may not fit in with some themes. A better way is to use style properties, which work similarly to style sheets in HTML. The following CSS properties can be used.
By setting either of the two properties, the element will be created with that width and height. If you specify only one size property, the other is calculated as needed. The size of these style properties should be specified as a number followed by a unit.
The sizes are fairly easy to calculate for non-flexible elements. They simply obey their specified widths and heights, and if the size wasn't specified, the element's default size is just large enough to fit the contents. For flexible elements, the calculation is slightly trickier.
Flexible elements are those that have a flex attribute set to a value greater than 0. Recall that flexible elements grow and shrink to fit the available space. Their default size is still calculated the same as for inflexible elements. The following example demonstrates this:
Example 3.2.2: Source View<box> <button label="Yes" flex="1"/> <button label="No"/> <button label="I really don't know one way or the other"/> </box>
The window will initially appear like in the image earlier. The first two buttons will be sized at a suitable default width and the third button will be larger because it has a longer label. The first button is made flexible and all three elements have been placed inside a box. The width of the box will be set to the initial total width of all three buttons (around 430 pixels in the image).
If you increase the width of the window, elements are checked to see whether they are flexible to fill the blank space that would appear. The button is the only flexible element, but it will not grow wider. This is because the box that the button is inside is not flexible. An inflexible element never changes size even when space is available, so the button can't grow either. Thus, the button won't get wider.
The solution is to make the box flexible also. Then, when you make the window wider, extra space will be available, so the box will grow to fill the extra space. Because the box is larger, more extra space will be created inside it, and the flexible button inside it will grow to fit the available space. This process repeats for as many nested boxes as necessary.
You may want to allow a element to be flexible but constrain the size so that it cannot be larger than a certain size. Or, you may want to set a minimum size. You can set this by using the CSS properties listed below.
These properties are only useful for flexible elements. By setting a maximum height, for example, a stretchy button will only grow to a certain maximum height. You will still be able to resize the window beyond that point but the button will stop growing in size. The box the button is inside will also continue to grow, unless you set a maximum height on the box also.
If two buttons are equally flexible, normally both will share the amount of extra space. If one button has a maximum width, the second will still continue to grow and take all of the remaining space.
If a box has a maximum width or height, the children cannot grow larger than that maximum size. If a box has a minimum width or height, the children cannot shrink smaller than that minimum size. Here are some examples of setting widths and heights:
<button label="1" style="width: 100px;"/> <button label="2" style="width: 100em; height: 10px;"/> <button label="3" flex="1" style="min-width: 50px;"/> <button label="4" flex="1" style="min-height: 2ex; max-height: 100px"/> <textbox flex="1" style="max-width: 10em;"/> <html style="max-width: 50px">This is some boring but simple wrapping text.</html>
Example 1: the first button will be displayed with a width of
100 pixels (px means pixels). You need to add the unit or the width will be
ignored.
Example 2: the second button will be displayed with a height
of ten pixels and a width of 100 ems (an em is the size of a character in the
current font).
Example 3: the third button is flexible so it will grow based
on the size of the box the button is in. However, the button will never shrink
to be less than 50 pixels. Other flexible components such as spacers will
absorb the remaining space, breaking the flex ratio.
Example 4: the fourth button is flexible and will never have
a height that is smaller than 2 ex (an ex is usually the height of the letter
x in the current font) or larger than 100 pixels.
Example 5: the text input is flexible but will never grow to
be larger than 10 ems. You will often want to use ems when specifying sizes
with text in them. This unit is useful for textboxes so that the font can
change and the textboxes would always be a suitable size, even if the font
is very large.
Example 6: the description element
is constrained to have a maximum width of 50 pixels. The text inside will wrap
to the next line, after fifty pixels.
Let's add some of these styles to the find files dialog. We'll make it so that the textbox will resize to fit the entire window.
<textbox id="find-text" flex="1" style="min-width: 15em;"/>Here, the text input has been made flexible. This way, it will grow if the user changes the size of the dialog. This is useful if the user wants to enter a long string of text. Also, a minimum width of 15 ems has been set so that the text box will always show at least 15 characters. If the user resizes the dialog to be very small, the text input will not shrink past 15 ems. It will be drawn as if it extends past the edge of the window. Notice in the image below that the text input has grown to extend to the full size of the window.
Let's say you have a box with two child elements, both of which are not flexible, but the box is flexible. For example:
Example 3.2.3: Source View<box flex="1"> <button label="Happy"/> <button label="Sad"/> </box>
If you resize the window, the box will stretch to fit the window size. The buttons are not flexible, so they will not change their widths. The result is extra space that will appear on the right side of the window, inside the box. You may wish, however, for the extra space to appear on the left side instead, so that the buttons stay right aligned in the window.
You could accomplish this by placing a spacer inside the box, but that gets messy when you have to do it numerous times. A better way is to use an additional attribute pack on the box. This attribute indicates how to pack the child elements inside the box. For horizontally oriented boxes, it controls the horizonal positioning of the children. For vertically oriented boxes, it controls the vertical positioning of the children. You can use the following values:
The pack attribute applies to the box containing the elements to be packed, not to the elements themselves.
We can change the earlier example to center the elements as follows:
Example 3.2.4: Source View<box flex="1" pack="center"> <button label="Happy"/> <button label="Sad"/> </box>
Now, when the window is resized, the buttons center themselves horizontally. Compare this behavior to that of the previous example.
If you resize the window in the Happy-Sad example above horizontally, the box will grow in width. If you resize the window vertically however, you will note that the buttons grow in height. This is because the flexibility is assumed by default in the other direction.
You can control this behavior with the align attribute. For horizontal boxes, it controls the position of the children vertically. For vertical boxes, it controls the position of the children horizontally. The possible values are similar to the pack.
As with the pack attribute, the align attribute applies to the box containing the elements to be aligned, not to the elements themselves.
For example, the first box below will have its children stretch, because that is the default. The second box has an align attribute, so its children will be placed centered.
Example 3.2.5: Source View<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window id="yesno" title="Question" orient="horizontal"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<hbox>
<button label="Yes"/>
<button label="No"/>
</hbox>
<hbox align="center">
<button label="Maybe"/>
<button label="Perhaps"/>
</hbox>
</window>
You can also use the style properties -moz-box-pack and -moz-box-align instead of specifying attributes.
You could potentially create a button element that contains a label that is larger than the maximum width of the button. Of course, a solution would be to increase the size of the button. However, buttons (and other elements with a label) have a special attribute called crop that allows you to specify how the text may be cropped if it is too big.
If the text is cropped, an ellipsis (...) will appear on the button where the text was taken out. Four possible values are valid:
This attribute is really only useful when a dialog has been designed to be useful at any size. The crop attribute can also be used with the description element and other elements that use the label attribute for labels. The following shows this attribute in use:
Example 3.2.6: Source View<button label="Push Me Please!" crop="right" flex="1"/>
Notice how the text on the button has had the right side of it cropped
after the window is made smaller.
We've seen a lot of features of the box model. Here, we'll find out some more details with some examples.
The style properties such as min-width and max-height can be applied to any element. We've added them to buttons and textboxes, but we can also add them to spacers or boxes. In addition, the flex attribute can be applied to any element.
Example 3.3.1: Source View<hbox flex="1"> <button label="Left" style="min-width: 100px;" flex="1"/> <spacer flex="1"/> <button label="Right" style="min-width: 100px;" flex="1"/> </hbox>
In the example above, all three elements will resize themselves as they are all flexible. The two buttons indicate a minimum width of 100 pixels. The buttons will never be smaller than this size but they may grow larger. Here the window should appear just over 200 pixels wide. That's enough for the two buttons. Because all three elements are flexible, but they don't need any more room, the flexibility adds no extra space.
As shown in the image above, there are two buttons which expand vertically to fit their container, which in this case is the hbox. The align attribute controls this behavior on a horizontal box. You can also prevent this strecthing by placing a maximum height on the elements or, better, on the box itself. If a box has a maximum height, the elements inside it are constrained by this. However, the problem with this is that you need to know how big the element will be beforehand. The following shows the example with a align attribute set.
Example 3.3.2: Source View<hbox flex="1" align="top"> <button label="Left" style="min-width: 100px;" flex="1"/> <spacer flex="1"/> <button label="Right" style="min-width: 100px;" flex="1"/> </hbox>
To achieve complicated layouts, you will generally need to add nested boxes, specify minimum and maximum sizes on some elements, and make certain elements flexible. The best interface is one that can be displayed at various sizes without problems. The box model may be difficult to understand without trying various various things out for yourself.
The following is an outline of both types of boxes:
You can put boxes anywhere in a XUL file, including inside an HTML element such as a table. However, the layout will be partly controlled by the HTML element. That means that the flex might not work exactly as you want it. Remember that flexibility only has meaning for elements that are directly inside a box or an element that is a type of box.
1. Using Spacers
Example 3.3.3: Source View<hbox> <button label="One"/> <spacer style="width: 5px"/> <button label="Two"/> </hbox>
Here, a spacer is used as a separator between the two buttons, by setting an explicit width of 5 pixels. You could also set margins (using the CSS margin property).
2. Centering Buttons
Example 3.3.4: Source View<hbox pack="center" align="center" flex="1"> <button label="Look at Me!"/> <button label="Push Me!"/> </hbox>
This example contains a horizontal box with two buttons in it, contained inside a flexible box. The box has the pack attribute which is used to center the buttons horizontally. The align attribute aligns the buttons vertically. The result is that the buttons will be centered in the box in both directions. This example will work with a vertical box as well, although the second button will be underneath the first one, instead of beside it.
3. A Find Text Dialog
Example 3.3.5: Source View<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window id="findtext" title="Find Text" orient="horizontal"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<vbox flex="3">
<label control="t1" value="Search Text:"/>
<textbox id="t1" style="min-width: 100px;" flex="1"/>
</vbox>
<vbox style="min-width: 150px;" flex="1" align="start">
<checkbox id="c1" label="Ignore Case"/>
<spacer flex="1" style="max-height: 30px;"/>
<button label="Find"/>
</vbox>
</window>Here, two vertical boxes are created, one for the textbox and the other for the check box and button. The left box has a flexiblity that is 3 times greater than the right one so it will always receive 3 times as much of the extra space when the window size is increased. The right box enforces a minimum width of 150 pixels.
The textbox is flexible so it will resize as the window resizes. The textbox also enforces a minimum width of 100 pixels. The check box appears in the right box along with its label. Just below the check box is a spacer. The spacer will grow and shrink but not exceed 30 pixels. The result is that the check box and the Find button will be spaced apart from each other by some space of no more than 30 pixels.
The second box has an alignment of start. This causes the child elements to be aligned on the left edge. If this was not specified, the default would be stretch, which would make the child elements stretch horizontally. Because we don't want the Find button to change size, we need to set an alignment.
This section describes a way to include elements into groups.
HTML provides an element, fieldset which can be used to group elements together. A border is typically drawn around the elements to show that they are related. An example would be a group of check boxes. XUL provides an equivalent element, groupbox which can be used for a similar purpose.
As its name implies, the groupbox is a type of box. That means that the elements inside it align themselves according to the rules of boxes. There are two differences between groupboxes and regular boxes:
Because groupboxes are types of boxes, you can use the same attributes such as orient and flex. You can put whatever elements you want inside the box, although typically they will be related in some way.
The label across the top of the groupbox can be created by using the caption element. It works much like the HTML legend element. A single caption element placed as the first child is sufficient.
The example below shows a simple groupbox:
Example 3.4.1: Source View<groupbox> <caption label="Answer"/> <description value="Banana"/> <description value="Tangerine"/> <description value="Phone Booth"/> <description value="Kiwi"/> </groupbox>
This will cause four pieces of text to be displayed surrounded by a box with
the label Answer. Note that the groupbox has a vertical orientation by default
which is necesssary to have the text elements stack in a single column.
You can also add child elements inside the caption element to create a more complex caption. For example, Mozilla's Font preferences panel uses a drop-down menu as a caption. Although any content can be used, usually you would use a checkbox or dropdown menu.
Example 3.4.2: Source View<groupbox flex="1">
<caption>
<checkbox label="Enable Backups"/>
</caption>
<hbox>
<label control="dir" value="Directory:"/>
<textbox id="dir" flex="1"/>
</hbox>
<checkbox label="Compress archived files"/>
</groupbox>
In this example, a checkbox has been used as a caption. We might use a script
to enable and disable the contents of the groupbox when the checkbox is checked
and unchecked. The groupbox contains a horizontal box with a label and textbox.
Both the textbox and groupbox have been made flexible so the textbox expands when
the window is expanded. The additional checkbox appears below the textbox because
of the vertical orientation of the groupbox. We'll add a groupbox to the find
files dialog in the next section.
You can use the radiogroup element to group radio elements together. The radiogroup is a type of box. You can put any element you want inside it, and apart from its special handling of radio buttons, it works like any other box.
Any radio buttons placed inside the radio group will be grouped together, even if they are inside nested boxes. This could be used to add extra elements within the structure, such as in the following example:
Example 3.4.3: Source View<radiogroup>
<radio id="no" value="no" label="No Number"/>
<radio id="random" value="random" label="Random Number"/>
<hbox>
<radio id="specify" value="specify" label="Specify Number:"/>
<textbox id="specificnumber"/>
</hbox>
</radiogroup>We'll conclude the discussion of boxes by adding some boxes to the find files dialog.
We'll add some more elements to the find files dialog now. First, we'll add the capability to search for other information such as the file size and date.
<hbox>
<menulist id="searchtype">
<menupopup>
<menuitem label="Name"/>
<menuitem label="Size"/>
<menuitem label="Date Modified"/>
</menupopup>
</menulist>
<spacer style="width: 10px;"/>
<menulist id="searchmode">
<menupopup>
<menuitem label="Is"/>
<menuitem label="Is Not"/>
</menupopup>
</menulist>
<spacer style="width: 10px;"/>
<textbox id="find-text" flex="1" style="min-width: 15em;"/>
</hbox>Two drop down boxes have been added to the dialog. A spacer has been added in-between each element to separate them. These spacers have been given an explicit width of 10 pixels each. You'll notice that if the window is resized, the textbox grows but the other components do not. You'll also notice that the label was removed.
If you resize the window vertically, the elements do not change size. This is because they are inside horizontal boxes. In might be more appropriate if the Find and Cancel buttons always stayed along the bottom of the window. This is easy to do by adding a spacer in-between the two horizontal boxes.
<spacer style="height: 10px"/> <hbox> <menulist id="searchtype"> <menupopup> <menuitem label="Name"/> <menuitem label="Size"/> <menuitem label="Date Modified"/> </menupopup> </menulist> <spacer style="width: 10px;"/> <menulist id="searchmode"> <menupopup> <menuitem label="Is"/> <menuitem label="Is Not"/> </menupopup> </menulist> <spacer style="width: 10px;"/> <textbox id="find-text" flex="1" style="min-width: 15em;"/> </hbox> <spacer style="height: 10px" flex="1"/> <hbox>
Now when the dialog is resized, the two buttons will move so that they are always along the bottom of the dialog. The first spacer adds extra spacing in-between the title label and the search criteria elements.
It might look nicer if there was a border around the search criteria. There are two ways to do this. We could use the CSS border property or we could use the groupbox element. This first method would require that we set the style on the box itself. We'll use the latter method, however. A groupbox has the advantage that it draws a box with a nice beveled look, suitable for the current theme.
Let's change the box into a groupbox:
<groupbox orient="horizontal"> <caption label="Search Criteria"/> <menulist id="searchtype"> . . . <spacer style="width: 10px;"/> <textbox id="find-text" flex="1" style="min-width: 15em;"/> </groupbox>
There are other cosmetic problems as well. We could also have the groupbox grow so that it extends vertically to the bottom of the box. Also, we could modify some of the margins so that the elements are positioned better.
We'll see more examples of the box model and some of its features as we continue to add elements throughout the tutorial.
In this section, we'll look at creating progress meters.
A progress meter is a bar that indicates how much of a task has been completed. You typically see it when downloading files or when performing a lengthy operation. XUL has a progress meter element which can be used to create these. There are two types of progress meters: determinate and undeterminate.
Determinate progress meters are used when you know the length of time that an operation will take. The progress meter will fill up and, once full, the operation should be finished. This can be used for the download file dialog as the size of the file is known.
Undeterminate progress meters are used when you do not know the length of time of an operation. In Mozilla, the progress meter will look like a spinning barber pole, and will animate like one.
Determinate progress meter:
Undeterminate progress meter:
The progress meter has the following syntax:
<progressmeter
id="identifier"
mode="determined"
value="0%"/>The attributes are as follows:
Let's add a progress meter to our find file dialog. We would normally put an undeterministic progress meter as we don't know how many files we'll be searching or how long the search will take. However, we'll add a normal one for now as an animating one can be distracting during development. The progress meter would normally only appear while the search is taking place. We'll add a script later to turn it on and off.
<hbox>
<progressmeter value="50%" style="margin: 4px;"/>
<spacer flex="1"/>
The value has been set to 50% so that we can see the meter on the window. A margin has been set to 4 pixels so that it is separated from the edge of the window. As was stated earlier, we only want the progress bar to be displayed while the search was occuring. A script will show and hide it as necessary.
Now, let's find out to add scroll bars to a window.
A scroll bar is typically used so that a user can move around in a large document. You can also use it when you need to ask for a value that falls within a certain range. Scroll bars can be created in a number of ways. In XUL, one can be created using the scrollbar tag. Some elements, such as text boxes, will also add scroll bars as necessary when the content inside is too large.
First, we'll discuss creating a stand-alone scroll bar. The user will set the value by adjusting the scroll bar. You probably won't use this too often. A scroll bar is made up of several parts, the slider, which is the main part of the scroll bar with the adjustable box, and the two arrow buttons on the end. A scroll bar creates all of these elements automatically.