Simple Firefox Customizations: What Can I Change?

Now that we know where to add our XUL changes in a CCK XPI, let's take a look at what we can change. You'll remember from the previous post, we added this line:

and we were able to disable the Options... menuitem. The obvious questions then are, what else can I do and how do I find out what things I can change.

First let's talk about what you can change. It's beyond the scope of this article to go into all the things you can change with XUL. If you want to learn more about XUL, you can check out XULPlanet. For enterprise customization, there are probably two main things we would want to do: disable something or make it go away. We already know how to do disabling, but how would we make the Options... menuitem go away? The answer is the collapsed attribute:

This will make the menuitem go away completely.

OK, so we know how to change the XUL, let's find out what we can change. You'll notice that in order to change the menuitem, we needed to know the ID of the menuitem. So how can we find the ID of what we want to change? For this, we need to understand a little more about how the Firefox UI works. Most of the main Firefox window's UI is contained in a file called browser.xul. By looking through this file, we can find various parts of the UI and use our knowledge of overlays to change them. For instance, looking through that file, we find out that the ID of the toolbar is toolbar-menubar. So if we wanted to make the menu go away, we could simply add:

Note that not only did we need to use the ID, but we had to use the name of the tag (toolbar) as well. You'll notice that the menu is not in browser.xul (you won't find menu_preferences, for instance). This is because the menu is contained in a separate file called browser-menubar.inc. You can consider this file to be a part of browser.xul for our purposes.

If you're having trouble finding some UI in the XUL file, try this. Go to the Mozilla 1.8 Cross-Reference and search on the text you are trying to find. For instance, we'll search on "Error Console." This will return a DTD file that contains the string for the menu item (we want the one that begins with browser). On the same line as the text, you'll see an identifier that usually ends in label. For the error console, it's

By searching on the label, we can find the exact place where it is used in Firefox. In this case, it points us to browser-menubar.inc. We can use the information there to create an overlay that disables or removes the Error Console menuitem.

In the next installment, we'll learn how to customize the default buttons on the toolbar.

Firefox Enterprise Article in Computerworld

Computerworld has an article out today about Firefox in the enterprise that contains some quotes from me. There's also some slashdot discussion, but most of that seems to be from people who don't really understand enterprise requirements.

Unfortunately I didn't respond quickly enough to the request for information, so my stuff is kind of tacked on to the end. Here's the key message I wanted to get across (which wasn't in the article):

The main thing we think has changed at this point is that we (IBM) are working with the Mozilla Community to try to get the community more interested in the enterprise things. In particular, we (the community, as well as IBM) want to help enterprises with customization and deployment of Firefox, as well as work to figure out what can make Firefox better for the enterprise.

I agree with the overall article though. More needs to be done to make Firefox enterprise ready. Hopefully anyone who wants to help with that effort will participate using the various avenues we have created.

Simple Firefox Customizations: Using the CCK XPI

Now that we know the basics of XUL Overlays, we're going to look at using an existing CCK XPI to make our changes. The reason we're using the CCK XPI is because we want to take advantage of code that has already been written for us. We'll start by examining the contents of an XPI created by the CCK Wizard. Note that for this example, we've used the CCK Wizard to create an XPI that has no customization at all. We're just going to add our new modifications.

After creating an XPI using the CCK Wizard, copy unzip that XPI into a directory. You'll see the following files:


chrome/cck.jar
components/cckService.js
defaults/preferences/firefox-cck.js
chrome.manifest
install.rdf
install.js
cck.config

The two files that are important to us are chrome.manifest and cck.jar. Here's that the manifest file looks like:


overlay chrome://browser/content/browser.xul  chrome://cck/content/cck-browser-overlay.xul
style   chrome://global/content/config.xul    chrome://cck/content/cck-config.css
content cck     jar:chrome/cck.jar!/content/cck/

This file defines the overlays we talked about earlier. We are overlaying a file called cck-browser-overlay.xul onto the regular browser XUL file and we are overlaying a new CSS file. We won't modify the manifest right now since it has exactly what we need. Later we'll need to make changes when we want to anything other than the main browser UI.

The next file that is important to us is cck.jar. This is a ZIP file that contains the XUL overlay files. After unzipping this file, you'll see cck-browser-overlay.xul. This is the file where we are going to make our modifications. For now, lets do something similar. Edit the file cck-browser-overlay.xul and add this line before the <stringbundleset> section (we'll get into the specifics of this change in the next installment).

 <menuitem id="menu_preferences" disabled="true"/>

Once you've made this change, zip the JAR first and then zip the XPI file. Next, install the XPI.

If everything worked correctly, when you look at the Tools menu, the Options... menuitem should be disabled.

What we've seen in this installment is that by modifying an existing CCK XPI, we can start customizing the Firefox UI. We didn't have to write our own extension from scratch. In our next installment, we'll look at the interesting things we can do in our browser overlay.

Firefox Enterprise Newsgroup

We've recently created a newsgroup/mailing list to talk about Firefox as it relates to enterprise, educational institutions, or other similar ventures. Here's the first post I just put up:

The goal of this newsgroup is to help enterprises, educational institutions and other similar groups embrace Firefox.

When we use the term "enterprise," we in no way mean to limit the focus to large businesses. We want to help anyone from high schools to Fortune 100 companies.

We'll be talking about issues related to things like:

* Customizing the browser for a particular deployment
* Deploying the browser in a specific environment
* Creating custom extensions for your deployment
* Training issues

We have a wiki with some information at:

http://wiki.mozilla.org/Enterprise

There have also been some posts on my blog:

http://www.kaply.com/weblog/category/enterprise/

We look forward to your participation!

You can access the newsgroup multiple ways:

Hopefully we can use this medium to foster some more discussion around Firefox in the enterprise.

Simple Firefox Customizations: The Basics

I get asked a lot of questions about customizing Firefox that are beyond the scope of the CCK. Most of these questions involve how to prevent users from doing certain things or hide certain options in the UI. My typical answer is "you can write an extension for that," but most people don't want to go through the hassle of figuring out how to write an extension for what in most cases is a very simple change.

To try to address these issues, I'm going to do a series where I answer questions related to making simple changes to Firefox that might be needed in an enterprise environment. My goal is that a person with no extension experience at all will be able to make these changes by simply modifying an existing CCK extension.

Before I get into the specific customizations, I'm going to start with a very high level view of how we are going to make these changes.

Let's define some terms in case you don't know them. XUL (pronounced "zool") is Mozilla's XML-based User interface Language. It is used along with JavaScript and CSS to create the user interface in Firefox. Extensions can modify XUL, JavaScript and CSS by overlaying new XUL, JavaScript and CSS that replaces what is built-in to Firefox. Most of our work is going to involve the creation of these overlays. If you want more details, check out XUL Overlays at the Mozilla Developer Center.

There are currently two changes that the CCK makes using XUL overlays - adding a menu item to the Help menu and chanding the icon, link and tool tip for the animated icon (sometimes called the throbber). Both of these involve knowing the ID of the item you want to modify and then writing XUL that either modifies or replaces the existing XUL.

Here's the XUL Overlay for adding the Help menu item:

<menupopup id="menu_HelpPopup">
  <menuseparator insertafter="aboutSeparator"/>
  <menuitem label="Our New Help Item" insertafter="aboutSeparator"
            accesskey="o"
            oncommand="openUILink('http://example.com'), event, false, true);"
            onclick="checkForMiddleClick(this, event);"/>
</menupopup>

In this case, we needed two IDs - the ID of the help menu (menu_HelpPopup) and the id of the item after which we want to insert our menu (aboutSeparator). What this overlay says is "in the menupopup with an ID of menu_HelpPopup, insert a new separator after the exisiting item aboutSeparator, then insert a new menuitem after that old separator as well." Don't worry about the different attributes - we'll cover those later.

We can also use a XUL overlay to replace content. Here's the overlay for the animated icon:

<button id="navigator-throbber" oncommand="openUILink('http://example.com')" onclick="checkForMiddleClick(this, event);" tooltiptext="TOOLTIP" disabled="false"/>
  

In this case, we needed the id of the existing animated icon (navigator-throbber) and we used our XUL to actually change the animated icon. We changed it from being disabled, we added tooltip text, and we added functionality when it is clicked.

Now that you have a very basic sense of how XUL overlays work, next we're going to take a look at where in an existing CCK XPI our new overlays are going to be placed.

One Year of Operator

It's been one year since I released Operator and I wanted to take the opportunity to thank everyone who is using it and has had good things to say about it. I haven't advanced the technology as much as I wanted to over the past year but hopefully this next year we'll see much more, especially with the inclusion of a microformats API in Firefox 3.

And now for something completely different.

If you use Operator on amazon.com, you might notice that the "Tagspaces" item is available, but when you pop it down, you get a lot of stuff that says "ref=tag_dpp_cust_itdp_t." This is because amazon (like a lot of other sites - any drupal site comes to mind) is not following the rel-tag spec. To attempt to work around this problem, I've added a hidden preference to Operator called "extensions.operator.allowInvalidTags." If you add this preference via about:config and set it to true, Operator will display the text content of the tag and use it, instead of the proper tag value. Note that although this makes some things work on amazon.com, they still is completely clueless about how to use rel-tag - checkout their Firefox tag page and take a look at the Tagspaces menu with the hidden preference turned on. You'll get things like "See all 226 tags" and "See all 25 customers." Great job amazon! Go read the spec!

And for everyone else that has screwed up tags, please go read the spec. If you don't like the spec, that's fine, but please don't add rel="tag" to anything that is an invalid tag.

Operator 0.9 beta available

I'm making available a beta of Operator 0.9, which has support for Firefox 3 and uses the built-in Firefox 3 microformats support.

The primary focus of this release has been performance, and I believe it shows. Sites like the Samsonite Store Locator are MUCH faster. Note that if you want to improve performance even more, you should remove the adr microformat from your toolbar. I've done this for new installs of Operator in the future. Since most pages with adrs have them in hCards, I've moved all the functionality that was for adrs into the hCard submenus.

Other changes include support for whether or not hidden microformats are displayed. You can try this out on the Samsonite website. Note that this functionality doesn't work on Firefox 3 because it required a change to the core Microformats support which hasn't made it into Firefox 3 yet.

Other small changes are the addition of searching for tags on amazon.com products, as well as searching for addresses on MapQuest.

One thing that is NOT in this release is modifications to support the new RDFa spec. We're still waiting for some stuff to be finalized for that.

Enjoy!

Operator and Page Load Performance

One of the biggest complaints about Operator is that it affects performance when loading pages and switching tabs. I've been spending the past few weeks analyzing these problems and I think I have them mostly solved. Note that page load vs. tab switching are actually two different problems; tab switching has to do with how fast I process the microformat data, whereas page load has to do with listening to DOM events. So here's what I learned:

  • My method for removing duplicate microformats was unnecessarily expensive. I was sorting in every case, and also duplicating and chopping up arrays. I went back to the way I originally wrote it and it works much better.
  • The adr microformat is a real pain because it doesn't have the concept of default text to display in the UI like other microformats. This meant that any page that has a lot of adr microformats was very expensive because of all the work I do computing what the address could be. To solve this in the future, adr will not be on the toolbar by default.
    Incidentally, the only reason I added adr in the first place was because I wanted to handle the edge case of multiple addresses in one hCard. I have since added support for actions to function on multiple items in a microformat, so the next release will move mapping back to hCard where it belongs with a submenu if there are multiple addresses.
  • Some pages have lots of hidden microformats they show and hide based on interaction with the page. This can cause some performance issues. I think that by default, microformats should not be visible in Operator if they don't show up on the page. So a page can have a thousand hidden microformats and it won't affect performance. There will be an option to show all microformats.
  • You have to be very careful not to add event listeners too early or you will get WAY too many messages. I was adding my DOM event listeners too soon so I was getting all DOM events during page load. Bad idea. Listeners should be added on each individual pageshow event, not DOMContentLoaded, and you should not try to be smart and add listeners recursively. Just add them to each target for each pageshow event.
  • While we're on the subject of DOMContentLoaded vs. pageshow, if you have an extension that updates the UI based on page content, you have to manage the interaction between these messages very carefully. The problem is that there are cases where you get just pageshow, just DOMContentLoaded, or both. Here's the scoop: DOMContentLoaded happens on the first load of a page as long as it is not from back/forward cache. pageshow happens with the load of any page including from the back/forward cache and it happens after DOMContentLoaded. The case where DOMContentLoaded happens without pageshow is the display of error messages like when you put in a bad URL. So the trick is to disable your UI on DOMContentLoaded and do interesting stuff on pageshow.
  • My testing shows that a pageshow event for a page containing frames doesn't happen until all the child frames have received their pageshow. Because of that, I can wait to process the microformats on the page until I have received the pageshow event for the main content document since I am going to recurse into the child frames anyway. If I am wrong, someone please correct me.

Well that's what I've learned so far. There should be an Operator release soon that addresses all these issues.

Microformats and Web Services Redux

Earlier I made a comment about how I wished there was a better way to connect microformats to web services. I'd like to elaborate on that comment and see if I could get some discussion going around the subject. First let me summarize the problem. (Note that throughout this post I will use the term microformat, but all these problems hold true for RDF as well)

The problem is that there is no standard way (that I've found) to interact with various web services that deal with the types of data involved in microformats. Note that in some cases there are standard data interchange formats (like vCard and iCal), but the web services do not always accept these formats.

The way Operator solves this problem through the use of user scripts that implement actions. What these actions do is take the microformat and use the data to construct a URL (or even a POST request) that connects to the appropriate web service. For instance, if I want to add my hCard to to the Yahoo! address book, the URL might look something like this:

http://address.yahoo.com/?ln=Kaply&fn=Michael&co=IBM
&e=nospam@example.com&pu=http://www.kaply.com/weblog/&A=C

In this case, the user script has taken apart the microformat and then constructed a URL that emulates adding a Yahoo! Contact. In doing this, lots of code was involved because the Yahoo! Add Contact does not map completely to the data that was in the microformat (you can see that code in yahoo.js). (Folks might ask why I'm not using Yahoo! APIs - that's mainly because I don't want to mess with authentication keys and stuff - this is a web interface, so I'd rather just redirect to websites)

The problem with this code is that in order to express the mapping from a microformat to Yahoo!, I require a large chunk of code.

For Firefox 3, I want to provide some UI that connects microformat to web services, but I want that to be extendable by third parties. I want it to be similar to how feed readers work in Firefox 2 (see registerContentHandler). While my action architecture works in the context of Operator, I do not believe that it is robust enough to be a part of Firefox 3. So what I'm trying to find is some better way to describe the mapping between microformats and web services or possibly to create a new standard around interacting with these web services. It might be as simple as just encouraging all of the vendors to accept the upload of vCard and iCal. I don't know. Here are some thoughts I (and others) have had.

Encourage people to support the submission of vCard and iCal in a standard way

The obvious thing to do here would be for services to allow the submission of vCards and iCals directly to their web services as a way to provide information to the services. 30 Boxes currently allows this, but unfortunately the iCal must be physically located on a web site, so I can't send it to them. Other services that accept vCards use a POST mechanism that is difficult to emulate because it relies on lots of private data during the POST submission.

Server Data Broker

Setup up a web service that would essentially act as a data broker. Data could be given to this server in a standard way, and then the server would turn that data into a URL that could be used to redirect to the appropriate web service. In this way, the logic to turn the microformat data into a URL would be done on the server. The client would give some common data source to the server, telling the service where it wanted the data to be sent and the server would simply send the client a redirect URL.

OpenAction similar to OpenSearch

S. Sriram had an interesting thought in reply to my previous post. He thought about using something similar to OpenSearch where web services can have an XML description file that describes how to interact with their services and then we could use that file to determine how to map the microformat data to the web service.

Those are just a few ideas we've come up with. I'd love to hear any other ideas you might have...

Ajax Experience Trip Report

Thought I'd take a minute to post about Ajax Experience.

Before I talk about the conference, I want to talk a little bit about some really cool technology that was in the Seaport Hotel. It's called Seaportal. Seaportal is a machine running Windows XP Embedded that provides web surfing, office applications and free Voice over IP. It uses OpenOffice for the office applications and Internet Explorer for the web surfing. I was curious about the mix of open source and non-open source, so I contacted the IT department. The answer was what I expected. They picked OpenOffice because it saved them money on licensing, and they picked IE because it was a part of the embedded stack that came from their vendor They didn't want to add extra software to the stack, which makes perfect sense. The IE also came pretty well customized by the vendor, although they did have to work to figure out how to do more customization with the registry.

All in all, I was VERY impressed by their solution and found myself using it a lot to avoid turning on my laptop when I needed something quick. My only complaints would be that using IE 6 is REALLY painful and that they need to be more current with adding interesting plug ins and things. For instance, I couldn't watch TV shows from abc.com because it uses some proprietary plug ins.

If you stay in Boston, stay at the Seaport and request a room with Seaportal to check it out. Now on to the conference...

Started out the conference on Wednesday by attending "State of Ajax" by Ben Galbraith and Dion Almaer. Good talk. Awesome pie chart about where web developers spend their time that I wish I could find to show you. (Their State of Ajax talk is not on the Ajax Experience slides page.) I disagreed with their assessment of JavaScript tools. There is more to life than Firebug.

Next up was Kevin Survance from MapQuest. This keynote was awesome. Kevin is an excellent speaker and he gave a great picture of what MapQuest is doing to reinvent themselves. He talked about the new MapQuest which is in beta right now. I find it funny that despite the popularity of Google Maps, the term MapQuest is embedded in our culture similar to Kleenex. On a side note, I talked to a couple MapQuest developers about microformats and I'm hoping they'll put them on the site. I'm planning to do an Operator action for the new MapQuest beta.

From there I went to the Aptana IDE presentation. This presentation was disappointing. The presenter just wasn't the right guy to do this, and there was actually too much demo and not enough slides.

After lunch I went to the Google Gears talk, and it was interesting, but there really wasn't much that I couldn't have gotten from reading documentation on the web, so I went over to catch the tail end of Accessibility and Internationalization with Dojo. Good presentation, but it was folks on my team, so what did I expect.

After lunch I went to "iPhone and iPod Touch Web Development" which was a horribly named presentation, because it was basically a plug for Aptana. This session should have been simply combined into the other Aptana presentation.

Skipped the next round, but caught the Silverlight presentation later that afternoon. What impressed me most about the Silverlight stuff was the tooling. Microsoft really has the tooling down.

Thursday I started with "Introduction to jQuery" by John Resig. This was great. I finally "get" jQuery and hope to start messing around with it soon. Really showed off how useful Firebug was for jQuery development.

The "Ask the Ajax Experts" panel was interesting, but everyone involved in this session needs to learn a little bit about how a panel works. Basically with the VERY long answers and the number of questions that Ben and Dion asked, there really wasn't much time to get questions from the audience.

Next up was my session on the Ajax Toolkit Framework. I thought it went well, although I need more content for my presentation. I was 20 minutes short.

After my presentation, I skipped out to meet with a friend over at IBM Research.

Friday morning I didn't have a lot of time before my flight, but I caught Aza Raskin from Humanized talking about the ZIA or Zen Internet Application. This was a really interesting presentation that really got me thinking about the best way to do microformat UI. I'm still thinking.

Other interesting notes were meeting Mark Finkle in person and getting to see the qooxdoo folks again.

Next time I'll plan less stuff on the side and go to more sessions.