Chapter 2

Getting Started

To help you start creating applications as quickly as
possible, this chapter presents two "Hello World" examples that
demonstrate the beginning stages of Mozilla application
development.

The first example is a simple XUL file that is loaded into
the browser window. This example is then expanded on by adding
additional features to the XUL file, such as imported
stylesheets and JavaScript functions. The second "Hello World"
example shows how to turn files like these into packages, which
are the modular, bundled sets of files that fit together to
make Mozilla applications or new modules for the Mozilla
browser.

These examples provide a context for discussing the
development of Mozilla applications. The first example focuses
on creating and editing the basic file types, and the second
focuses on the organization and distribution of applications on
the Mozilla platform.

Simple XUL Example

Like all good "Hello World" applications,
Example 2-1 shows one of the simplest
possible examples of XUL. Although it is small, it demonstrates
some important aspects of XUL programming, including the use of
event handlers to add behavior and the use of a box to
lay out elements properly within the window. This example also
provides a context for discussing more general features of the
language, such as the file format, the namespace, and some XUL
programming conventions.

Use your text editor to save the code in Example 2-1 in a file called hello.xul and
then load the file in Mozilla (you can do this by using File
> Open File from the browser window and browsing to where
you saved the file). You should see a button in the upper-left
corner of the browser window that brings up an alert box when
clicked. Figure 2-1 shows an example of
the alert pop-up window that appears.

Figure 2-1: The first Hello
xFly example

The next few sections describe this sample file in more
detail. The covered topics include the file itself, the syntax
of the markup, XUL namespaces, and the basic layout of a XUL
file.

The xFly Examples

The best way to understand the possible uses of the
Mozilla framework is to look more closely at a number of
various existing applications. This book highlights several
Mozilla development projects, such as ChatZilla and JSLib, as
examples of how some people have already started using
Mozilla's XPFE technologies.

Along with these applications, you'll note the use of the
name "xFly" in many examples in this chapter and elsewhere in
this book. The xFly examples are used throughout Chapter 2 to Chapter
6 to show how to create and package a simple Mozilla
application. An installable version of the complete xFly
application can be found at http://xfly.mozdev.org.

This simple application is useful because it provides a
place to start exploring the new information that you will
learn about in this book. As you read more about XUL, CSS,
JavaScript, and the other parts of Mozilla's development
framework, you can create and edit the xFly files to see how
these technologies work in practice.

Basic XUL Concepts

You have already seen many of XUL's basic features at work.
When you load the example in the previous example, the browser
identifies it as a XUL file, parses the data, creates a new
window and draws the button widget, and executes the function
you've defined when the button is clicked.

These activities are part of the basic and often transparent
interaction between your application files and Mozilla.
However, the format of your XUL files, their syntax and
namespace, the XUL layout, and the windowing system are all
basic to successful XUL programming.

The XUL File Format

A XUL file is a simple text file
that contains proper XML syntax
and has a .xul file extension. Mozilla expects to draw
UI widgets when it encounters a file with a .xul
extension or when it encounters the XUL namespace in other
markup files that it recognizes, including HTML and XML.

The MIME type registered
for XUL files is
application/vnd.mozilla.xul+xml. When editing and using
XUL files locally, you shouldn't need to worry about setting
this on your computer; however, sometimes you may need to set
the MIME type, such as when you host XUL files on a server. Chapter 12 provides additional
information about how you can set the correct file type for
your system.

Conventions

XUL has to follow certain
conventions (as does XHTML or
any other XML-based file) in order to be valid. Mozilla
generates an error when it encounters an invalid XUL file.

The first thing required in a XUL document is the XML
declaration.

<?xml version="1.0"?>

Any comments used to introduce
your file can begin on the line after the declaration. Comments
in XUL follow the same format used in HTML and XML, delimited
by <!-- and -->.

All tag sets must be closed. Empty
tags
are allowed for some elements, such as the
<label> element, that are used without nested
elements or content. Note that a trailing slash at the end of
the tag is required to denote an empty element.

<label value="Getting Started" />

Another thing to remember is
that XUL is case-sensitive. Closing a XUL
<window> tag with </Window>
renders it invalid.

These conventions ensure that the rendering engine can parse
the XUL file successfully and display the elements defined
there. Mozilla does not validate XML files, such as XUL, and it
does not resolve externally parsed entities, but it does check
for document well-formedness.

Following the XML specification, Mozilla ignores well-formed
tags that it does not recognize, which can give your
applications extra flexibility, particularly as you begin to
use technologies such as XBL. But it can also make debugging a
little more difficult, as when you create an element named
<botton> and don't see why your XUL button
doesn't have the typical borders or three-dimensional
style.

A good practice to follow when creating XUL files is to use
comments, copious whitespace, indentations (but not tabbed
indentations where you can avoid them), and XUL widgets you are
familiar with.

The XUL Namespace

Like other markup
vocabularies, XUL uses a namespace declaration to define the
particular elements that may be included in a valid file. Example 2-2 shows a sample of the required
namespace declaration. The namespace is an attribute of the
root window element. The lack of any suffix on the XML
namespace declaration (i.e., xmlns:xul) indicates that
XUL is the default namespace for this file.

If you want to include XUL content in documents that use
other types of markup, you need to declare more than one
namespace. Common namespace declarations for getting other
language elements into your code include HTML and RDF, but you
can invent your own as well. If you wanted to put the button
from Example 2-1 into a vanilla XML file,
for example, you could place it into an XML document by using
the xmlns:xul attribute, as shown in Example 2-3.

This file has three types of content: XUL, HTML, and
customized markup called flies. When you use mixed
namespaces, you have to prefix the XUL elements with
xul: to distinguish them from markup in other
namespaces, as with the xul:box and
xul:button shown in Example
2-3.

Basic XUL Layout

Example 2-1 features
some very common XUL elements. In this section, each element is
dissected to show what it does and how it interacts with other
elements. The <window> element is the root of
individual primary XUL documents (in contrast to dialogs that
pop up from windows, which
can use <dialog> as the root, and XUL documents
loaded within other XUL containers, which can use
<page>).

As in HTML, the root element defines the document into which
all elements are drawn, but in XUL, that document is a piece of
an application interface and not a web page. We'll have more to
say about the window and some of its features in the second
example.

A <box> element that
contains a
<button> is inside the window in Example 2-1. Although you can use attributes on
the window element to lay out and position window children,
it's never a bad idea to use the <box> as a
container, particularly when you add new layout to your
document, such as rows of buttons, grids, tabs, or other
elements that need to be arranged precisely within the space of
the window. The box is the basic element for layout in
XUL.

The align attribute on the box specifies that the
children do not stretch and center themselves in the middle of
the available space. If the box was omitted and there were
multiple children of the root window, they would be laid out
vertically by default, one under the other. This setting can be
overridden by adding the orient attribute to
<window> and giving it a value of
"horizontal."

Using XUL Windows

The foundation of an XPFE application is
a window. Each XUL document has to
have at least one XUL <window> element, and it
must be the root of the document-the surrounding, outermost
element in the XML document, set apart from the XML declaration
itself and other processing "preambles." A basic window with no
content looks like this:

Commonly, an application has more than one window, with a
number of dialogs and secondary windows. Each window is also
contained within a
<window> element (though recent additions to the
XUL specification include the dialog and page
elements, which are derived from window and can be
used in its place as root elements in your XUL files).

As your application becomes more complex, you need a way to
keep track of the windows and ensure that they can communicate
with one another. In Mozilla, there is a way to do this by
using
the type
attribute identifier, which allows you to use special
window-opening functions like toOpenWindowByType( ) to
manage particular window types.

NOTE

As with any existing Mozilla functions referred to in this
book, you can look up toOpenWindowByType by using
the LXR web-based source code viewer, described in Appendix A and available at http://lxr.mozilla.org/.

Window features

An id attribute is present on
the <window> element.
Using this
attribute is not necessary to run the windows system, but it is
a good idea to give each window a unique identifier because it
makes nodes easier to find from script (see the DOM method
getElementByID in Chapter
5 for information about how to get elements by identifier).
This is how to set up an ID attribute:

When you load a XUL file that begins in this way, the event
handler attributes onload and onunload carry
out the functions listed as values (startUp( ) and
shutdown( )). In addition, Mozilla provides an
onclose event handler that intercepts the upcoming
window closure to carry out any extra processing you need. The
close event is fired before the unload event, so you
can stop the window from closing in the onclose event
handler if necessary. To stop window closure, the close event
must return false.

Additional handlers are available for dialog windows. They
are listed and their use is outlined in the section "Application Windows" in Chapter 3.

Window properties

The window declaration is
expanding, but there is still plenty of room for more features.
In addition to the attributes-the event handlers, the
ID, and the namespace that appear within the
<window> tag itself-a XUL window also has all of
the properties of the DOM window object from HTML.
These properties are listed below, along with additional
properties for application specific tasks.

Navigator

Document

window

Parent

Top

Scrollbars

name

ScrollX

ScrollY

ScrollTo

scrollBy

GetSelection

ScrollByLines

ScrollByPages

Size

ToContent

Dump

SetTimeout

SetInterval

Clear

Timeout

ClearInterval

SetResizable

CaptureEvents

Release

Events

RouteEvent

Enable

External

Capture

DisableExternal

Capture

prompt

Open

OpenDialog

Frames

find

self

Screen

History

content

Sidebar

Menubar

Toolbar

Locationbar

Personalbar

Statusbar

Directories

closed

Crypto

pkcs11

Controllers

opener

Status

defaultStatus

Location

innerWidth

InnerHeight

outerWidth

OuterHeight

screenX

ScreenY

pageXOffset

PageYOffset

length

FullScreen

alert

Confirm

focus

Blur

back

Forward

home

Stop

print

MoveTo

moveBy

ResizeTo

resizeBy

Scroll

close

UpdateCommands

escape

Unescape

atob

Btoa

AddEvent

Listener

RemoveEvent

Listener

Dispatch

Event

GetComputed

Style

Special properties of the XUL window object include:

window.content

Using this property is a quick way
to
access the content area of your window, if one exists. This
property is useful only if your window uses one of the
content elements, namely <iframe>,
<browser>, and <editor>. Refer
to the section "Content Panels"
in Chapter 3 for a more
detailed discussion. The content property is linked
only to the frame you have explicitly declared as the primary
area.

<browser type="content-primary" ...>

Subsequently, you can access and manipulate the
content.

window.content.focus( );

window.sizeToContent( )

This property is used to ensure
intrinsic sizing, which is important in XUL application
development, especially in dialog windows. Intrinsic sizing
ensures that the window adapts and morphs to fit the content.
This is preferable to constraining your window with a fixed
width and height when the onload handler anticipates
changeable content, depends on context, or takes input from
another window. The colorpicker in the Mozilla Editor, for
example, uses this function to make sure that the window
displaying the chosen palette shrinks to fit that
palette:

Interaction between windows

The nsIWindowMediator XPCOM component
provides several routines for interacting with different
windows. Though it's a little too early to discuss using a
component like this in the Hello World examples, these routines
include:

Getting the most recent window of a particular type

Enumerating all open windows

Registering and unregistering the window

Updating the window timestamp

Updating the window title

Setting the Z-order position

Chapter 8 provides full
details of how to understand and use XPCOM components.

Window behavior

Mozilla supports the
standard
window.open JavaScript function, which has its origins
in the world of browser scripting and the launching of new
browser windows. Mozilla extends the function to provide some
features for application development. It also provides the
window.openDialog
function
for opening windows in the XPFE scripting environment. The
latter function has become the more commonly used method to
open a new XUL window, although the two are
interchangeable.

The usage of window.open is:

window.open (url, name, features);

window.openDialog extends this functionality with a
new argument list passed to it, which is optional and can be
any number of arguments as needed:

window.openDialog (url, type, features, argument1, argument2);

Here is a list of some of the features of a XUL window
opened using window.openDialog:

close

The window can be created with or without a close
widget.

chrome

The new window has to
be treated as a
window within the chrome context, rather than in the browser
context. It gets its own top-level window. The window itself
is the chrome URL passed to the function, and is not to be
loaded in a browser window.

dependent

The new window belongs
to the calling window on operating systems that support this
behavior. It "floats" on top of the opening window, and you
can still access the parent window. It is minimized with its
parent.

modal

The window will be run
modally. Control is not
given back to the parent window until this window has
closed.

titlebar

The window can be created
with or without a
titlebar.

centerscreen

Open the window centered
on screen.

A comma delimits the features list and the entire list must
be in quotes. The script that handles the new window accesses
the arguments list:

The window created in this example will be modal and use the
message that was passed to it in the variable message.
By default, Mozilla assumes that the chrome feature is
on when you use either window.open or
window.openDialog in a chrome environment, and creates
a new window in the window hierarchy.

Making Mozilla Work for You

The second "Hello World" sample,
shown in Example 2-4, adds some important
application features and begins to take advantage of the
resources that Mozilla provides for you. This section goes over
the ways you can import stylesheets and Mozilla scripts to make
your XUL more sophisticated and modular. It also prepares you
to make an actual application.

You can see this example in action by saving the code in Example 2-4 to a file, hello2.xul, and
then launching Mozilla and selecting File > Open File from
the browser. This displays the example as content in the
Mozilla browser, as shown in Figure
2-2.

The difference between Example 2-4 and
the first example is the addition of new elements, including
the script element that brings in Mozilla JavaScript
functions for use, additional box layout properties, inline
style rules and processing instructions to import stylesheets,
and the DOCTYPE declaration, which we describe later
in this chapter in the section "The xFly
DTD."

These extras make your XUL file work more like an
application by giving you access to services and features that
already exist in Mozilla. They can also help you organize your
own work into reusable parts, such as application stylesheets,
widgets, and script libraries, as described later in this
chapter in the section "Creating a
Package."

Figure 2-2: The second Hello
xFly example loaded in the browser

Importing Resources from Mozilla

The code in Example 2-4 uses scripts
and styles that are already
defined in Mozilla. As you'll see in examples in this book
and in the Mozilla source
code, the global.css stylesheet is where many basic
styles
are defined for XUL widgets. Most XUL widgets have some
inherent style, as you can see in Example
2-1, where the button has a button-like look without any
explicit style rules or stylesheet imports.

As the XPFE has evolved, XUL widgets
have used XBL internally to define some of these inherent looks
and behaviors, which has taken some of the responsibility away
from global.css and other CSS files. But this stylesheet
still contains important rules for displaying basic XUL
widgets. It's usually a good idea to import this main
stylesheet into your application, as described here, and see
what it gets you in terms of presentation. If you load Example 2-4 with and without the global.css
line, you can see the way that the rules in the stylesheet
provide styles for the widgets in the XUL.

Similarly, scripts like globalOverlay.js,
tasksOverlay.js, and dialogOverlay.js, imported
in Example 2-4, provide basic functions
you can use in your applications.

Loading stylesheets

In the second line of Example 2-4, the
stylesheet declaration uses a
chrome:// URL to refer to and load the global.css
file. The style rules in that file give the button widget its
"widgetness." You can use the stylesheet
processing instruction to load Mozilla stylesheets like
global.css, navigator.css,
and toolbar.css, or you can use it to load your own
application stylesheet. In both cases, the chrome:// URL
allows you to refer to packaged files in a flexible way.

Also note the use of an inline style in Example 2-4. The style property on the
label widget gives you a place to define CSS rules
directly on widgets. In this case, the label is given a bold
font so that it shows up better in the window. You could also
define this style rule in an external stylesheet and make that
stylesheet part of the package for your application, as we do
later in this chapter in the section "Separating the Files."

Accessing script in XUL

To access a script in XUL, use the script element
and a URL value for its src attribute:

All functions in dialogOverlay.js are imported into
the scope of the XUL file and can be called directly, as
CenterWindowOnScreen( ) is in the onload
event handler for the XUL window. Note that the functions
contained in an imported JavaScript file are not broadcast in
any particular way (though you can see them if you use the
JavaScript Debugger). You may need to look around in the source
code or see how other applications import files to find the
functions you need, but the routines you want to use in your
application code are probably already available in Mozilla.[*]

Displaying XUL Files as Chrome

Figure 2-2 shows the XUL file
in Example 2-4 loaded into the browser's
main content area. The example features a label widget
and an image, both situated within a vbox
that lays them out properly in the available space. These
widgets make up the chrome of your application, the Mozilla
user interface that can refer to itself and its resources with
the special chrome:// URL.

This example is starting to show off some of the nice
features of XPFE programming, but it still isn't an application
yet. Among other things, you probably don't want your code to
live inside the browser window forever. As it grows, you may
also want to divide it into sensible parts-a XUL file, a
separate stylesheet, and a script file, for example. The rest
of this chapter explains how to organize and package the code
in Example 2-4 and launch it as a
standalone window by using the -chrome option when
launching Mozilla.

Launching a XUL file by using the chrome switch requires
that you register your application in the chrome registry so
that Mozilla sees and recognizes it. The "Registering a Package" section later in this
chapter provides more information about the chrome environment
and how to register this sample application.

Although this example hasn't been registered yet, we want to
give you a preview of what it will look like when launched in a
standalone window so you can compare it with how the same XUL
file looks when loaded into the browser window. When you do
launch the example by using the -chrome option (as
described later in this chapter in the section "Launching the Application"), you will see the
window displayed in Figure 2-3.

Figure 2-3: The second Hello
xFly example launched in its own window

Using the -chrome option tells Mozilla to display
the specified file (in this case, the code from Example 2-4) as a standalone application rather
than as content within a browser window. The file itself is the
same regardless of how it is loaded, but the results differ
depending on what you tell Mozilla to do with the file.

Displaying a XUL file in its own chrome window makes it more
independent and breaks the link to the browser content area
that is present when you use the File > Open File... method.
Launching standalone windows, accompanied by the JavaScript
window.openDialog function explained later in this
chapter, opens up much more flexible window display options for
your application.

Creating a Package

The previous two main sections
introduced the concept of chrome and the prospect of creating
standalone application windows. The next step is to make the
example into an actual package-a modularized collection of
files that can be installed in Mozilla as a new
application.

In the earlier section "Making Mozilla Work
for You," you added features and complexity to your XUL
file. In this section, you pull those features into separate
files-a CSS file, JS file, and a DTD file-register these files
together, and make them installable as a single package.

Only when you have packaged your work will your files have
access to Mozilla files, such as CSS and scripts, be accessible
from the special chrome:// type URLs, be able to accept
new themes, and be able
to get to the XPCOM objects in which much of the application
for Mozilla is defined.

Tools are available that help set up the files that form the
basis of a new package. Appendix
B provides information about XULKit, which is a collection
of scripts that automates part of the package creation process.
It is recommended that you try to set up your own package by
hand first to understand how packages are put together before
using the XULKit scripts.

Architecture of a Chrome Package

The architecture of the
Mozilla XPFE is
component- or layer-based. One of the primary aims of the
design was the separation of each different component of an
application, namely content, functionality, and layout. This
design results in greater modularization, making it easy to
create and change a UI-to change skins for your application,
for example, update the language in which the user interface is
presented, or bring in new script elements.

When a package is modularized like it can be in Mozilla,
design determinations can be left to the designer, language in
the user interface can be left to writers, and the application
framework itself can be handled by software developers (though
the programmer handles all of these in many small- to
medium-sized projects). The next several sections provide more
detail about each component and its content and file types. The
way basic packages fit components together can be the basis for
your own application development.

A package is a group of directories and related files that
make up a Mozilla application. A small, typical package may
include a single XUL file, a script file (currently JavaScript,
with implementations for Perl, Python, Ruby, and other
languages being developed), and a CSS file. However, a single
package might include dozens of these files, and may also
include XBL files, Image File Types (PNG, JPG, GIF), DTD, HTML,
and RDF files. Each has an important role to play in the
application.

Package Components

As you will discover, each
component in a package is independent. It is possible for your
application to exist with just one or two of these components.
Yet they all tie together when necessary to create a full
featured application, and they are all at your disposal to take
advantage of.

Chrome content

The content is
the XUL and XBL data, contained in one or more files.
This content is pulled in at runtime from files, overlays, and
bindings, for display in the window system. The cross-platform
implementation ensures consistency in the native system, and
fits into the "write once, run anywhere" model. The XUL defines
a single set of UI elements for all platforms. The XUL parser
is much less tolerant than many HTML parsers; in fact, it's
completely intolerant. However, it needs to be because every
element in XUL impacts others and affects the layout of the
UI-especially in the context of the Box Model, which Chapter 3 describes in detail.

The widget set consists of simple widgets that display by
drawing themselves absolutely in their allotted space, and of
more complex widgets that act as containers, draw on top of
others, or
accept input. A <label> widget is an example of
the former, while <stack> is of the latter, more
complex group. If the parser does not find an element in the
content files, it fails to load and returns an error. Errors
vary by type. An XML syntax error, for example, displays in the
window in place of the expected content. It gives you the file
the error originated in, along with the line number and column
number.

Built as a complementary
description language to XUL, XBL allows you to create your own
widgets or add new behavior to existing XUL widgets. You may
attach scripting and create (anonymous) content in a single
binding or in many. With a little imagination, you can extend
the content available to you infinitely by adding your own
styling and behavior with XBL.

Chrome appearance

Loading up a XUL file with
no styles attached
to the XUL
elements will render the UI as a plain, disproportioned group
of widgets. While plain text on a web page can be effective for
simply relaying information, the situation is not analogous in
user interfaces.

Mozilla user interfaces without style are not very usable.
Even to achieve the traditional plain gray interface that so
many applications use, you must use CSS to style the Mozilla
front end, and subtle effects, such as color grades or 3D
button effects, often make even the most basic interface look
and work better.

Themes and the ability to customize
the look of
an application are becoming more prominent. Mozilla developers
realized this prominence during the design phase of Mozilla,
and it's reflected in the architecture: the appearance of the
interface is almost entirely separate from the structural
representation in the content.

Chrome behavior

Mozilla currently supports
only JavaScript as the bridge
between the UI and the application code. JavaScript is the glue
that binds the UI and the back end functionality, which is
almost entirely written in C++.

Much of the infrastructure is in place for
the support of other programming
languages, however, and Python and Perl are currently being
proposed as the next languages to fit into the framework.
Currently, you will see JavaScript associated with XUL content
via the following declaration:

<script type="application/x-javascript" src="xfly.js" />

type replaces the now deprecated language
attribute and expects a MIME type for its value. As Mozilla
matures and support for other languages arrives, this value may
become interchangeable-which fits in with the philosophy,
common in open source projects, of there being More Than One
Way To Do It. Note that the behavior component of a Mozilla
application usually sits in the content subdirectory of
a package, as described later in the section "Directory Structure."

Chrome locale

Localization is
the modification of software to meet the language of a location
and the adaptation of resources, such as user interface and
documentation, for that region. Widgets such as menu items,
buttons, window titlebars, and alert dialogs commonly need to
be localized. Beyond these widgets, there can be other
localizable content in an application, from HTML pages to
install packages.

The formats used by Mozilla are:

DTD (.dtd) files, which contain entities that host
the strings to be included in your XUL content.

Property files (.properties), which contain string
bundles that are accessed by dynamic content in JavaScript
and C++ files or, theoretically, any language.

HTML files for certain pages installed with the
application-e.g., About Mozilla.

RDF files.

Directory Structure

Files can be organized in many
different ways. If your application is small-say a single
window with a simple structure that needs to be available only
in one language-then having all your files in one directory may
be easier. As the size of an application goes over a certain
threshold, however, logically grouping your files into
subdirectories is a good practice to make the files more
accessible.

Most applications use a directory structure that mirrors the
package component descriptions described earlier: XUL and
JavaScript
in a content subdirectory, CSS and images in a
skin subdirectory,
and DTDs and
other resources for localizing the interface in a locale
subdirectory. Figure 2-4
shows this
common grouping.

Figure 2-4: A sample package
layout in the directory system

These three different directories usually contain the
following type of files:

content

The content directory is
the home for the XUL files that contain the widgets to be
drawn for you application. It is
common
practice to also place files related to behavior, namely
JavaScript files, in this directory.

locale

This directory contains
the files
that contain localized
strings for your package. Most files are DTD files that
contain the entities referenced in XUL files. There is a
subdirectory for each language, and the naming convention is
code-region, such as en-US.

skin

The term "skin" is an
internal name
for a theme. The
skin directory contains all CSS files and images that
contribute to the appearance of the windows. This is a good
place to put the application images-in their own
subdirectory.

The xFly application directory
structure

The structure of the directories in which
an application is
defined (whether those directories are in the filesystem or
subdirectories in an archive such as a JAR file) is an
important part of that application's design and relationship to
Mozilla. Use the following steps to make your xFly package
self-contained, registerable, and adaptable.

On your computer, go to the directory where you have
installed Mozilla and create a new directory underneath the
chrome directory called "xfly."

All Mozilla applications live in the chrome
directory.

Under that directory, create the three new directories,
content, locale, and skin, as shown in
Figure 2-5. The locale directory
will have the default 'en-US' language pack structure.

Figure 2-5: xFly package
directory structure

Package Manifests

Now that you have created the
directories
for your package, you must tell Mozilla about them. All Mozilla
packages must include manifests that describe their contents
and make it possible to register them with Mozilla. A manifest
is an RDF file (or series of RDF files) that sits within the
package and interacts with Mozilla's chrome directory.
RDF files are XML files that describe data in a
machine-readable form.

Each xFly package subdirectory needs its own manifest file.
Mozilla uses these files (in each case, called
contents.rdf) when registering the application. These
files are listed in Examples 2-5, 2-6, and 2-7. Create these
files in your xFly content, skin, and
locale subdirectories, respectively.

In the content manifest in Example 2-5,
note the chrome:name, chrome:author, and the
other metadata that the manifest provides to Mozilla. This
information can be used by others to identify what your
application is and who wrote it. For example, the name, author,
and short description information for each browser theme you
have installed is viewable by going to Preferences and
selecting Appearance > Themes.

In Example 2-6, which describes
the skin for
xFly only, note that new skin resources for the Classic theme
are all that is supplied, as indicated in the RDF:Seq,
which lists only classic as affected by this new
package.

In Example 2-7, which shows the third
kind of manifest, for new locale information, the English
language pack (en-US) is augmented with the
localizable resources in the xFly package named there. The
RDF:Seq structure
in a manifest
states, "to the package listed here (i.e., the en-US
language pack), add the following."

Manifests are detailed in Chapter
6. For now, it's enough to see that each manifest describes
the subdirectory in which it is located, and that the contents
of those subdirectories make up the package collectively.

The content describes the content of the xFly package, the
XUL, and the JavaScript. The skin describes the theme of xFly,
or the CSS and images used to lay out the XUL. The third part
describes the locale, or the strings in the UI that can be
localized or adapted for various languages or locales.

Separating the Files

Once you have a subdirectory structure set up
in accordance with the package component structure of your
application, you can pull the pieces of your XUL file out into
their own files and modularize your application. These separate
files-the basic XUL file and separate CSS, JS, and DTD
files-are registered as a single package and can then be
launched as a standalone application.

Though the files contain the information you've already seen
in the "Hello World" sample shown in Example
2-4, their interaction demonstrates how packages can work
together in Mozilla. Each step taken to separate the different
components requires editing the base XUL file.

The xFly CSS file

The inline style rule
on the label widget can go almost unadulterated into a separate
text file called xfly.css. Save the code in Example 2-8 in the chrome/xfly/skin/
directory.

Example 2-8: The contents of
the xfly.css file

#xlabel { font-weight: bold; }
window { background-color: white; }

Using style rules from an external file is different because
you have to specify some way for the style rule to associate
itself with the appropriate tags in the XUL file. CSS provides
a rich collection of selectors, which bind style data to
elements. In this case, where you have two separate elements
that need to pick up rules, the id attribute on the
XUL element is used to bind a unique element to an external
style rule and the other style rule is bound by referring to
the XUL element directly. Example 2-8
includes the selectors for the two elements, and Example 2-9 shows the updated XUL that uses
xfly.css.

Note the extra stylesheet import statement at the top and
the use of the new id attribute on the label. When you
register the new files in your package with Mozilla, the
xfly directory in that stylesheet processing instruction
will point into your application directory structure (at the
skin subdirectory, and at a file named after the
directory itself, xfly.css). The label will pick up the
style information in the file that was previously defined
directly in its style attribute.

The xFly script file

The next step is to take
the scripting portion, as simple as it is, out of the XUL file
and put it into an external JavaScript file. Example 2-10 shows a XUL file that gets a function
for the button from an external script file, given here as
xfly.js.

Note that the function greet( ) is used to name the
action that is performed when the button is clicked. The
greet( ) function is now defined in the xfly.js
file that the XUL file picks up with the script import
statement:

Example 2-11 contains all of the code
needed for the xfly.js file. Example 2-11The contents of the xfly.js file

function greet( ) {
alert("Hello World");
}

Save xfly.js in the content subdirectory of
the xFly application (chrome/xfly/content/). The script
import statement above uses the chrome:// URL to locate
scripts from directories that were registered with Mozilla.

The xFly DTD

The final step in a basic
application setup
is to generalize parts of the interface that are written in a
particular language, such as English. When you create a
locale subdirectory for your package and place a DTD
file that contains the English strings in the user interface,
you can refer to and load that DTD just as you do with the CSS
and script files.

For example, to localize the text of the label and button
elements in the "hello xFly" example, you can use a special
syntax to tell Mozilla to use an entity rather than a string.
Because that entity is defined in xfly.dtd and located
in the locale subdirectory, it can easily be swapped for an
entity from a different language pack when the user switches
languages in Mozilla.

Once again, the external file you create can be very simple.
Example 2-12 contains the code needed for
the xfly.dtd file, which you create and save in the
locale subdirectory. Example 2-12The contents of the xfly.dtd file

The updated XUL file that uses this external DTD, then,
appears in Example 2-13. Once you have
made the final changes in the XUL to refer to the external
files you've created, save the code in Example
2-13 as xfly.xul in the chrome/xfly/content/
directory. Example 2-13XUL using an
external DTD file

Like the CSS and script file imports, the updated
DOCTYPE definition at the top of the file tells
Mozilla to load additional entities as part of the xFly
package. Those entities-the English strings that display in the
user interface-are defined so they can be localized or
internationalized without affecting the application's
structure.

All three of these imports use the chrome:// URL to
refer to resources that are internal to the xFly package. These
type of URLs can also refer to resources elsewhere in Mozilla,
such as image resources, strings that have already been defined
in entities, and functions from scripts such as
centerWindowOnScreen( ).

When you finish setting things up in the package
directories, you should have a structure that looks like the
tree structure in Example 2-14. Example
2-14Tree structure of a completed
sample xFly package

Registering a Package

Registering packages in Mozilla
can
be confusing at first, so don't worry about understanding
everything at this point. Later chapters provide more detailed
information about packaging and registration, and you can
always copy the examples given here to install your own
application. In general, to make your package registerable,
create manifests that describe your package in terms that
Mozilla can understand.

Although it's customary to make registration a part of the
installation process by using the XPInstall API and
installation
scripts, you need a simple way to register the xFly application
so you can see your work and test it as it develops. For this
purpose, hacking the installed-chrome.txt file living
in Mozilla's
chrome directory will do.

The installed-chrome.txt file is a list of packages
and package parts that Mozilla should find and register on
start up. When you add entries to this file, you point to your
package and tell Mozilla to register that package when it
starts up.

Append the entries in Example 2-15 to
the bottom of the installed-chrome.txt file in the main
chrome directory. Example 2-15Additions
to the installed-chrome.txt file

When Mozilla starts up, it looks for the package manifests,
reads them, and registers the xFly package.

When others install your application and use it on their
machines (but do not use the hack to
installed-chrome.txt), you can provide them with a
JavaScript installation file that downloads and registers your
package from a web page. See Chapter
6 for more information about these installation files and
the XPInstall technology they are based upon.

Launching the Application

Once your package is registered, you can use these startup
options to access your package directly.

Windows launch

In the Mozilla install directory, launch xFly at
the
command prompt with:

mozilla -chrome chrome://xfly/content/

You can also launch xFly from a shortcut on your desktop by
right-clicking on the existing Mozilla icon and selecting
Properties. In the Target area of the Properties box, add the
following text at the end of the line:

Unix launch

Macintosh launch

Start xFly by creating a text file on your desktop
with the following content:

-chrome chrome://xfly/content/

You can either drag this text file onto your Mozilla icon to
launch the application or set the text file's creator type to
MOZZ. If you change the creator type, you should be
able to double-click on the text file to launch Mozilla.

Once you register your application, you are free to continue
developing it in the various component subdirectories and
relaunching it as it progresses. You can add new XUL files in
the content directory, for example, that are invoked
from buttons using window.openDialog( ) event
handlers.

You can add new widgets to xfly.xul, add new styles
to xfly.css that apply to the XUL, add new functions to
xfly.js, or use existing functions in the Mozilla source
code that you can find new ways to use in your own
application.

The steps described in this chapter-creating a basic XUL
file, adding features, displaying that XUL file as a standalone
window, organizing the code into separate files and a package
structure, and registering and launching that package-are the
basic building blocks of all Mozilla applications. When you get
a feel for what's going on here, you'll be able to quickly
understand and use the topics described in the rest of the
book.

[Back] Unfortunately, no good reference exists for the
functions defined in the various scripts files you can import.
The functions and their locations within the files continue to
change, so finding and using the right ones is sometimes a
matter of luck, sometimes a matter of whom you know, and often
a matter of testing, determination, and patience.