In addition to the extension files already created, we need to create an install manifest and sev-eral configuration files for correctly registering our extension package in the chrome r
Trang 1function siteLedsPageLoaded() { var ledElement = document.getElementById(‘siteleds-statusbar-panel’);
if (gSiteLedsLastRequest.status == 200) { var prevContent = gSiteLedsLastContent;
gSiteLedsLastContent = gSiteLedsLastRequest.responseText;
if ((prevContent != null) && (prevContent != gSiteLedsLastContent)) { ledElement.setAttribute(‘sitestate’, ‘modified’);
} else { ledElement.setAttribute(‘sitestate’, ‘ok’);
setTimeout(siteLedsCheckPage, 900000);
} } else { ledElement.setAttribute(‘sitestate’, ‘error’);
setTimeout(siteLedsCheckPage, 900000);
} } window.addEventListener(“load”, siteLedsCheckPage, false);
Making the Extension Localizable
As mentioned in the previous chapter, XUL documents shouldn’t contain any literal strings that are presented to the user Instead, you should define all such strings in a separate file and make your XUL document reference them This allows the extension to be easily translated to
a different language All you need to do is to provide an additional file with the translated strings
Currently, our XUL element looks like this:
<statusbarpanel class=”statusbarpanel-iconic”
id=”siteleds-statusbar-panel”/>
tooltiptext=”SiteLeds Status Icon”
sitestate=”unknown”
insertbefore=”statusbar-display”/>
As you can see, the “SiteLeds Status Icon”string is in English If we want to translate our extension into a different language, we will need to modify the XUL file and provide two different versions of our extension What if the extension is translated into a dozen languages? Luckily, there is a better way First, we define all the strings in a separate DTD file DTD files
are usually used to define the structure of XML elements, but they can also contain entities,
which are XML variables that define common strings and allow them to be reused Let’s define our string as an XML entity in the siteledsOverlay.dtd file:
<!ENTITY siteLeds.tooltip “SiteLeds Status Icon”>
We need to modify our XUL element accordingly:
<statusbarpanel class=”statusbarpanel-iconic”
id=”siteleds-statusbar-panel”/>
tooltiptext=”&siteLeds.tooltip;”
sitestate=”unknown”
Trang 2We have replaced the literal string “SiteLeds Status Icon”with an XML entity reference
“&siteLeds.tooltip;”
The Final XUL File
We have created the CSS style sheet, the needed JavaScript functions, and a string table DTD file How can we specify that our XUL document should use all these files? Look at the final version of our siteledsOverlay.xul document:
<?xml version=”1.0”?>
<?xml-stylesheet href=”chrome://siteleds/skin/siteledsOverlay.css”
type=”text/css”?>
<!DOCTYPE overlay SYSTEM “chrome://siteleds/locale/siteledsOverlay.dtd”>
<overlay id=”siteleds-overlay”
xmlns=”http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul”>
<script type=”application/x-javascript”
src=”chrome://siteleds/content/siteledsOverlay.js”/>
<statusbar id=”status-bar”>
<statusbarpanel class=”statusbarpanel-iconic”
id=”siteleds-statusbar-panel”
tooltiptext=”&siteLeds.tooltip;”
sitestate=”unknown”
insertbefore=”statusbar-display”/>
</statusbar>
</overlay>
An explanation of what’s been added follows:
1 The xml-stylesheetXML instruction associates the siteledsOverlay.css style sheet with our XUL document Please note that we are using chrome URLs, meaning that the extension package needs to be properly installed and registered before we can test our extension You will see how this is done in the following sections
2 The DOCTYPEdeclaration associates an external DTD file named siteledsOverlay.dtd with our XUL document
3 The scriptelement specifies that the document should import and use the siteledsOverlay.js JavaScript file
Packaging the Extension
This section explains where the files we have created in the previous sections should be located and how they should be packaged to create an installable extension file
In addition to the extension files already created, we need to create an install manifest and sev-eral configuration files for correctly registering our extension package in the chrome registry
Trang 3Extension Directory Structure
In the “Introduction to Chrome” section, you saw that the chrome package has three logical parts: content, skin, and locale During the development process, the physical directory struc-ture of our extension will follow this logical partition The top-level directory in the extension directory tree will contain the install manifest file named install.rdf (more on this shortly) and a directory named chrome The chrome directory contains three subdirectories:
content: Contains XUL documents and JavaScript files.
skin: Contains one or more skin sets, each in a separate subdirectory A skin is any
num-ber of CSS style sheet files and images Our extension contains only one skin located in the subdirectory named classic
locale: Contains one or more locale sets, each containing a different translation of the
user interface and located in a separate subdirectory The string tables are located in DTD files (for strings used in XML documents) and Property files (for strings used in JavaScript programs) Our extension initially contains only English strings located in a subdirectory named en-US
Figure 17-5 shows this directory structure
F IGURE 17-5: The extension directory structure
The directory structure described in this section is only a suggestion Arranging your files in this directory hierarchy during development is convenient and allows easy packaging of your extension at the later stages, but as you see in the following sections, the extension mechanism doesn’t assume anything about the locations of your chrome directories You can change the locations of these directories and their names, as long as your manifest files are adjusted to reflect these changes
Creating Old-Style Chrome Manifest Files
If we merely package together all the files we have created, Firefox has no way of knowing how
to register them in the chrome registry We need to provide additional files called chrome
mani-fests that describe the package contents There are two styles of chrome manifest The old-style
siteleds chrome content locale skin en-US classic
Trang 4files, used in Firefox versions prior to 1.1, are RDF files called contents.rdf The new-style manifest mechanism introduced in Firefox 1.1 greatly simplifies matters by requiring a single plain-text chrome manifest file This section covers the old-style manifests, and the new mani-fest is described in the following sections
Each directory that contains a chrome package part, in our case content,skin/classic, and locale/en-US, must contain a file named contents.rdf Each contents.rdf file describes the contents of the package directory and is used during the extension installation for register-ing the package in the chrome registry, so the files can be accessed usregister-ing chrome URLs
The following examples use the name siteleds to denote our package When creating a new extension, give it a unique name and replace all the occurrences of siteleds with the name of your extension
The contents.rdf file is an XML document with a special syntax Look at the contents.rdf located in our content directory:
<?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:siteleds”/>
</RDF:Seq>
<RDF:Description about=”urn:mozilla:package:siteleds”
chrome:displayName=”SiteLeds”
chrome:author=”Alex Sirota”
chrome:name=”siteleds”
chrome:extension=”true”/>
<RDF:Seq about=”urn:mozilla:overlays”>
<RDF:li resource=”chrome://browser/content/browser.xul”/>
</RDF:Seq>
<RDF:Seq about=”chrome://browser/content/browser.xul”>
<RDF:li>chrome://siteleds/content/siteledsOverlay.xul</RDF:li>
</RDF:Seq>
</RDF:RDF>
Now look more closely at the different parts of this file:
The following lines introduce a new package named siteleds that should be merged into the chrome registry:
<RDF:Seq about=”urn:mozilla:package:root”>
<RDF:li resource=”urn:mozilla:package:siteleds”/>
Trang 5Next, we describe the new package and its attributes:
<RDF:Description about=”urn:mozilla:package:siteleds”
chrome:displayName=”SiteLeds”
chrome:author=”Alex Sirota”
chrome:name=”siteleds”
chrome:extension=”true”/>
Now we specify that we are interested in overlaying the main browser user interface doc-ument browser.xul:
<RDF:Seq about=”urn:mozilla:overlays”>
<RDF:li resource=”chrome://browser/content/browser.xul”/>
</RDF:Seq>
Finally, we specify which document will overlay the browser UI, in our case, siteledsOverlay.xul:
<RDF:Seq about=”chrome://browser/content/browser.xul”>
<RDF:li>chrome://siteleds/content/siteledsOverlay.xul</RDF:li>
</RDF:Seq>
The manifest file located in the skin directory,skin/classic/contents.rdf, is simpler because it doesn’t contain any overlay information:
<?xml version=”1.0”?>
<RDF:RDF xmlns:chrome=”http://www.mozilla.org/rdf/chrome#”
xmlns:RDF=”http://www.w3.org/1999/02/22-rdf-syntax-ns#”>
<RDF:Seq about=”urn:mozilla:skin:root”>
<RDF:li resource=”urn:mozilla:skin:classic/1.0” />
</RDF:Seq>
<RDF:Description about=”urn:mozilla:skin:classic/1.0”>
<chrome:packages>
<RDF:Seq about=”urn:mozilla:skin:classic/1.0:packages”>
<RDF:li resource=”urn:mozilla:skin:classic/1.0:siteleds”/>
</RDF:Seq>
</chrome:packages>
</RDF:Description>
</RDF:RDF>
Here, we are specifying that our siteledspackage includes a skin part that should be regis-tered in the chrome registry
Finally, here is the locale contents.rdffile, located in the locale/en-USdirectory:
<?xml version=”1.0”?>
<RDF:RDF xmlns:chrome=”http://www.mozilla.org/rdf/chrome#”
xmlns:RDF=”http://www.w3.org/1999/02/22-rdf-syntax-ns#”>
Trang 6<RDF:Seq about=”urn:mozilla:locale:root”>
<RDF:li resource=”urn:mozilla:locale:en-US”/>
</RDF:Seq>
<RDF:Description about=”urn:mozilla:locale:en-US”
chrome:author=”Alex Sirota”
chrome:displayName=”English(US)”
chrome:name=”en-US”>
<chrome:packages>
<RDF:Seq about=”urn:mozilla:locale:en-US:packages”>
<RDF:li resource=”urn:mozilla:locale:en-US:siteleds”/>
</RDF:Seq>
</chrome:packages>
</RDF:Description>
</RDF:RDF>
This contents.rdffile specifies that our siteledspackage contains an English (en-US) locale information
Packaging the Chrome Files
When all your chrome files — XUL documents, JavaScript scripts, CSS style sheets, and so
on — are ready, and you have created all the needed chrome manifest files, you should package the contents of the chrome directory, which typically contains three subdirectories (content, skin and locale), into a single ZIP archive You should give this ZIP archive the same name as your extension package (in our case, siteleds) and a jar extension Figure 17-6 shows the con-tents of our siteleds.jar archive
F IGURE 17-6: The contents of the siteleds.jar file
content
contents.rdf siteledsOverlay.js siteledsOverlay.xul
locale
skin
en-US
contents.rdf siteledsOverlay.dtd
classic
contents.rdf siteledsOverlay.css state-error.png state-modified.png state-ok.png state-unknown.png
Trang 7Creating the Install Manifest
The install manifest is a file that contains various information about the extension — its name, author, version number, what versions of Firefox it is compatible with, and so on This file is called install.rdf, and it is located in the root directory of the extension directory tree
The following code listing shows the SiteLeds install.rdf file:
<?xml version=”1.0”?>
<RDF xmlns=”http://www.w3.org/1999/02/22-rdf-syntax-ns#”
xmlns:em=”http://www.mozilla.org/2004/em-rdf#”>
<Description about=”urn:mozilla:install-manifest”>
<em:id>{E1B2492D-E6AC-4221-A433-C143E3A1C71E}</em:id>
<em:version>0.1</em:version>
<em:name>SiteLeds</em:name>
<em:description>Site Status Monitor</em:description>
<em:creator>Alex Sirota</em:creator>
<em:homepageURL>http://www.iosart.com/firefox/siteleds</em:homepageURL>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>0.9</em:minVersion>
<em:maxVersion>1.1</em:maxVersion>
</Description>
</em:targetApplication>
<em:file>
<Description about=”urn:mozilla:extension:file:siteleds.jar”>
<em:package>content/</em:package>
<em:skin>skin/classic/</em:skin>
<em:locale>locale/en-US/</em:locale>
</Description>
</em:file>
</Description>
</RDF>
Take a closer look at the various parts of this file:
The em:idproperty specifies the extension Globally Unique Identifier (GUID) GUID
is a 128-bit number that uniquely identifies the extension You should generate this unique number for every new extension you create There are several utilities that can generate a GUID for you On Windows, there is a guidgen utility that is available for download from the Microsoft site On UNIX, there is a similar utility called uuidgen There are also a number of websites that can be used to generate a GUID If you have an IRC client installed, you can generate a GUID by visiting the #botbotchannel on the irc.mozilla.orgserver and typing botbot uuid:
Trang 8The em:versionproperty specifies the version of your extension The version should
be in Firefox Version Format (FVF): major.minor.release.build[+] Only the major part
of the version number is mandatory, so 2, 1.1, 3.4.5, and 7.0.1.20050313 are all valid ver-sion numbers:
<em:version>0.1</em:version>
The em:namespecifies the name of the extension for being displayed in the user interface:
<em:name>SiteLeds</em:name>
The em:description,em:creator, and em:homepageURLproperties are optional and specify the extension description, its author, and home page This information will
be displayed in the Extension Manager dialog after the extension is installed:
<em:description>Site Status Monitor</em:description>
<em:creator>Alex Sirota</em:creator>
<em:homepageURL>http://www.iosart.com/firefox/siteleds</em:homepageURL>
The em:targetApplicationproperty specifies the application the extension is intended for and the range of versions of this application it is compatible with The tar-get application is specified using its GUID For example, SiteLeds is compatible with Firefox versions 0.9 to 1.1:
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>0.9</em:minVersion>
<em:maxVersion>1.1</em:maxVersion>
</Description>
</em:targetApplication>
The em:fileproperty specifies the jar file that contains the extension chrome files and the various parts of the chrome package (content/skin/locale) For example, the SiteLeds chrome files are packaged into a siteleds.jar file, which contains content, skin/classic, and locale/en-USsubdirectories:
<em:file>
<Description about=”urn:mozilla:extension:file:siteleds.jar”>
<em:package>content/</em:package>
<em:skin>skin/classic/</em:skin>
<em:locale>locale/en-US/</em:locale>
</Description>
</em:file>
The em:fileproperty isn’t needed when using the new-style plain-text chrome
manifestchrome manifest
Creating a New-Style Chrome Manifest File
In Firefox 1.1, there is a much simpler chrome manifest mechanism All the information needed to describe the chrome contained in an extension package is specified in a single plain-text file named chrome.manifest and located in the root directory of the extension tree When using the new manifest, you no longer need to create the contents.rdf files or specify the em:fileproperty in the install.rdf install manifest
Trang 9The SiteLeds chrome.manifestfile contains only four lines:
content siteleds jar:chrome/siteleds.jar!/content/
locale siteleds en-US jar:chrome/siteleds.jar!/locale/en-US/
skin siteleds classic/1.0 jar:chrome/siteleds.jar!/skin/classic/
overlay chrome://browser/content/browser.xul @ta chrome://siteleds/content/siteledsOverlay.xul The file structure is very simple and straightforward:
Content package:
content <package name> <path to files>
Locale package:
locale <package name> <locale name> <path to files>
Skin package:
skin <package name> <skin name> <path to files>
XUL overlay:
overlay <chrome://file to overlay> <chrome://overlay file>
Creating the Extension Installation Package
After creating the chrome JAR archive and the install.rdf install manifest, you can finally create the extension package that can be installed into Firefox This package file will have an XPI extension, but just like the chrome JAR file, it is actually a regular ZIP archive
Create a ZIP archive that contains the install.rdf file and the chrome directory at its root, and give it an XPI extension The chrome subdirectory contains the chrome JAR file If you are using the new-style chrome manifests, there should also be a chrome.manifest file at the top-most level of the XPI archive
Preferably, give your XPI file a meaningful name, one that includes the extension name and its version Figure 17-7 shows the contents of the SiteLeds_0.1.xpi archive
F IGURE 17-7: The contents of the SiteLeds XPI package
SiteLeds_0.1xpi
install.rdf chrome.manifest (*)
(*) Present only when using new style chrome manifests (Firefox 1.1 and later)
Trang 10Later in this chapter, you will see how to automate the packaging process If you want to pack-age the extension manually, you can do the following:
1 Create a directory named build somewhere on your hard disk.
2 Copy the install.rdf file into this directory.
3 If using new-style chrome manifests, copy the chrome.manifest file into this directory.
4 Create a subdirectory named chrome under the build directory.
5 Copy the siteleds.jar file you created earlier into the newly created chrome directory.
6 Go to the build directory and zip up the install.rdf, chrome.manifest, and the chrome
directory into the SiteLeds_0.1.xpi file
Once your extension XPI package is ready, you can install it into Firefox and give it a try
There are several ways to install a local XPI file into Firefox You can open it using File ➪ Open File , or just drag your XPI file and drop it into the Firefox window
Testing and Debugging Your Extension
As with any other program, there is a good chance that you will initially run into some prob-lems with your extension Things might work differently from what you were expecting or not work at all There are several mechanisms you can use to troubleshoot your extension and help you find and fix those annoying bugs
Some bugs in your extension, its packaging, or its chrome registration may break your browser and make it either partially or completely unusable You can usually solve these problems by starting Firefox in safe mode (by using the -safe-mode command-line switch, for example) and uninstalling the extension, or by creating a new user profile
If you see an error dialog saying “Chrome Registration Failed” when trying to install your exten-sion, verify that the content of your manifest files is correct and that you have packaged all the needed files using the correct directory structure Also, pressing the View Details button in this dialog can provide useful clues about the problem For example, you can see whether the prob-lem was in the content, skin, or locale part of your extension’s chrome
Preferences Settings
Several preferences settings in Firefox can assist you with the debugging process:
javascript.options.showInConsole: Setting this preference to trueinstructs Firefox to show errors that originate in chrome files in the JavaScript Console For example, a JavaScript function might be silently failing inside your extension, and, with-out seeing the error message, it may be very hard to pinpoint the problem