The Lurker
Mozilla and feature bloat
This Mozilla screenshot is funny. Getting the content area down to about 15% of the browser window is quite an achievement.
Yesterday I managed to create a XUL template which actually generated content. (Practically all my past efforts have resulted in tree widgets with no content, and for some reason XUL template errors are sent to the logger — which is disabled in non-debug Mozilla builds, and therefore unavailable to normal content developers — rather than somewhere useful, like the Javascript console.) I noticed there was a full moon last night, though, so it probably won't work next week.
Anyway, a few notes to myself in case I ever want to try this again:
- There are several pages, at mozilla.org and xulplanet.com, which claim to explain how to create XPI (installable Mozilla packages). However, only one of them is readable and accurate. (My compliments and thanks go to Ian Oeschger.)
- The <content> element binds to the variable named in its uri attribute the RDF resource referred to in the ref attribute of the element to which the datasource is bound. In other words, although in one sense the ref attribute indicates where in the RDF graph the template starts, it's the variable set up by this element which makes it possible for the other conditions to refer to that resource. (It can also bind to descendants of the datasource element which have an id attribute; literally until I added that last sentence I didn't understand what that feature did, but now it occurs to me that this must be how recursive templates like bookmarks menus work.)
- As far as I could tell this is not mentioned in the documentation, but reading the source code reveals that the <triple> element's subject and object attributes can refer either to an explicit RDF resource or node (respectively) or a variable, but the predicate must be an explicitly named resource. (This wasn't an issue I had a problem with; I just thought it was interesting that the doc didn't mention it, even though it's spelled out in a source code comment.)
- The best way to test this code is to disable XUL caching and install the code as a chrome package. After the first install, disable the registerChrome() call in install.js to stop Mozilla adding the package to the chrome list every time the code changes.
I was looking for a way to make the cookie permission dialog come up a bit faster. I have a little over 1500 domains listed in cookperm.txt (because I habitually deny cookies to every site I visit, unless it turns out they're needed), and it takes several seconds of heavy CPU use between clicking the menu item to open the window and having it actually appear. Unfortunately it turned out that most of the time was spent iterating through the nsIPermissionManager's list of permissions. I also hoped to be able to display the window before the permissions were loaded, and to display a progress meter while you wait, but the permission manager doesn't expose the number of permissions that exist, throwing that idea out the window (and I don't think it would update the display until loading was completed anyway).
I was also surprised when I noticed that the code which checks for a stored permission runs through that entire permission list linearly for each cookie check. It's getting late, so I may have read the code wrong, but I think it does that multiple times (for host.blah.example.com, then blah.example.com, and so on) for each cookie. Maybe they didn't expect cookie blacklists to get too long, or maybe with today's CPU speeds a naive algorithm is good enough.
Anyway, back to RDF. Since I had a reasonably large pile of data, I thought it would be useful to finally try to get my head around XUL templates. Mozilla's cookie manager doesn't use XUL templates — it provides an implementation of nsITreeView instead, which I'll get back to in a minute. Mozilla is pretty easy to develop for — in just a few lines of code I could run through the permission manager's enumerator and create an in-memory RDF datasource from it. After a few false starts, and with the help of the W3C's RDF Validator to get my head around what RDF looks like again, I managed to populate a XUL tree with permissions. Of course, this was no better than Mozilla's existing cookie permission dialog, but I was pretty pleased to have finally got a XUL template to work.
I mentioned earlier that occasionally I deny cookies to a site, then discover that the site does not function without cookies. (In the worst cases, some sites check for cookie support by setting a cookie and redirecting to the same page — causing an infinite redirection loop if the browser rejects cookies.) The Cookie Manager menu includes a "Unblock cookies from this site" item, but it only unblocks the domain the page was served from (which may not be the exact same domain the denied cookie was intended for). In these cases, I need to go to the cookie manager dialog and find the other domains. Unfortunately the domains are displayed in alphabetical order, so www.example.com and example.com aren't really that close to each other.
So the feature I really wanted to implement, the reason I got started on this in the first place, is a simple filter (that is, a text box that says "only show domains matching this string"). To do this with a template, I needed to have an assertion in the datasource on all permissions which matched the filter. Unfortunately, my RDF implementation (which added and removed a hell of a lot of assertions when the filter string is changed) was terribly slow. Perhaps it would have been more efficient to generate the filter assertions on-the-fly rather than adding them to the in-memory datasource, but that looked like a lot more work than going back to the nsITreeView implementation.
Adding the filter to the tree view took perhaps twenty lines of code and less than an hour; the RDF implementation would have taken much longer, required considerably more code, and been more error-prone. And the filter now works almost instantaneously.
(Another undocumented quirk I discovered reading the source: when calling
the tree object model's rowCountChanged()
method, the count
value is positive when notifying the tree that rows have been added, and
negative when rows have been deleted.)
So after spending about a day and a half playing with the code, I successfully created a XUL template, I proved to myself that a feature I find useful was easy to implement, and I found myself left with a desire to rewrite the permission manager service from scratch. Two out of three ain't bad.
Related topics: Web
All timestamps are Melbourne time.