Posted on February 3, 2010 in Uncategorized by adamNo Comments »

I expect that the majority of plugins that people create are going to be around adding custom functionality or formats, but sometimes you will want to tie Se-IDE to you service. (Much like Sauce Labs does with Sauce IDE.) Typically that tie-in needs some sort of credentials.

There are two different ways to do this. First, you could just store things as a preference and be done with it, but that has a bit of a problem around it. Namely, it gets stored in the clear in your profile’s prefs.js file and (depending on your permissions regime on disk), anyone could read it and get your credentials. This is not quite ideal.

The better way to store your credentials is through Firefox’s Login Manager.

Again, Preflight doesn’t have need for a password right now, but if it did, here is how you would protect it.

Add a new overlay to selenium-common.xul in the chrome.manifest

overlay chrome://selenium-ide/content/selenium-ide-common.xul chrome://preflight/content/overlays/preflightCommonOverlay.xul

And in the overlay, add a js file that is going to have out secure password manipulation code.

<overlay id="common_overlay" xmlns="">
  <script type="application/x-javascript" src="chrome://preflight/content/js/secure.js"/>

Here is the contents of secure.js. I’ll explain them afterwards.

var passwordManager = Components.classes[";1"].
var nsLoginInfo = new Components.Constructor(";1",
                      Components.interfaces.nsILoginInfo, "init");
function storeUsernameAndKey(username, key) {
    var logins = passwordManager.findLogins({}, "chrome://preflight", null, 'Username and API Key');
    if (logins.length == 0) {
        var extLoginInfo = new nsLoginInfo('chrome://preflight',
                               null, 'Username and Password',
                               username, key, "", "");
    } else {
        var extLoginInfo = new nsLoginInfo('chrome://preflight',
                               null, 'Username and Password',
                               username, key, "", "");
        passwordManager.modifyLogin(logins[0], extLoginInfo);
function retrievePreflightUsername() {
    var logins = passwordManager.findLogins({}, "chrome://preflight", null, 'Username and Password');
    if (logins.length == 1) {
        return logins[0].username;
    } else {
        return "";
function retrievePreflightPassword() {
    var logins = passwordManager.findLogins({}, "chrome://preflight", null, 'Username and Password');
    if (logins.length == 1) {
        return logins[0].password;
    } else {
        return "";

This is almost straight copy-and-paste from the Mozilla docs, but with an additional layer of wrapping added. The part that you will want to change is the chrome url. It should be the url for your plugin.

The reason why I wrapped things like this is that it allows us to do things like

var u = retrievePreflightUsername()

from anywhere in your addon’s js. (This works because we included secure.js at a very high level in the app.)

Some things to be aware of when using this

  • This does not protect your credentials from other plugins. They can just as easily make the same calls as you did and get the information. All it does it protect it from prying eyes on disk.
  • This method of dealing with password was introduced in Firefox 3.0. As a result, if you are using this you need to set the minVersion in install.rdf appropriately.
Posted on February 2, 2010 in Uncategorized by adamNo Comments »

The world is full of people who don’t read English, so it makes sense that your application should cater to more of the world than just them. Firefox provides a means to display these other languages through its use of locales.

There are a couple of ways to play with locales, but the easiest way is the Quick Locale Switcher plugin.

Se-IDE currently ships with support for four locales

  • en-US – US English
  • fr-FR – France french (as compared to Canadian french)
  • ja-JP – Japanese
  • pt-BR – Brazilian portuguese

The reason I list these here is that, like most things, you need to make a chrome.manifest change for each locale you support. And since the plugin your custom plugin supports those four, yours should too.

locale preflight en-US chrome/locale/en-US/
locale preflight fr-FR chrome/locale/fr-FR/
locale preflight ja-JP chrome/locale/ja-JP/
locale preflight pt-BR chrome/locale/pt-BR/

Now, Firefox knows where to look for its language strings.

Believe it or not, if you have been following this series you are already used to making use of the localization framework. Recall that we have been putting the following line in our .xul files?

<!DOCTYPE prefwindow SYSTEM "chrome://preflight/locale/options.dtd">

Through a bit of internal magic, the ‘locale’ part of that gets switched into whichever locale you have selected so in my ‘normal’ case the url is really chrome://preflight/chrome/locale/en-US/options.dtd. With that url loading in the overlay we can now pull locale specific strings from it.

Right now, it only has one string in it.

<!ENTITY performpreflight "Perform preflight checks">

To reference that string you use the entity name preceded by a & as shown in this snippet of overlay.

<hbox align="center">
  <label control="name" value="&performpreflight;"/>
  <checkbox preference="pref_perform" id="perform" />

Ideally, every string that is presented to the user in your overlays would be handled like this. A good way to test this is through a technique I call LOUD which I will let you research on your own a bit.

But referencing DTDs in xul is only half of the L10N story as far as our plugins go. Plugins are a combination of XUL and JS.

The way you localize the JS is very similar to the XUL only instead of using .dtd files you use a .properties file. Now my Preflight Checks plugin is still too simple to have JS that displays something to the user, so I can’t really make use of this. But essentially, this is what you need to know…

  • Property files have the syntax of key=value
  • In your overlay, use the stringbundle element to inject it into the DOM

    <stringbundle id="options.strings" src="chrome://preflight/locale/" />
  • Get a reference to the bundle from the DOM and then extract the string

    var strbundle = document.getElementById("options.strings");
    var nofilesfound=strbundle.getString("notFoundAlert");

That’s it. It can be a bit of a pain when creating screens to now have to put text into multiple files when working, but it is an absolute pain to have to find all your strings after the fact, so just get in the habit of writing L10N clean code from the start.

Oh, and here are two links that you will want to have handy when doing this step are

« Previous Page