I hate to say that I'm not real impressed with the state of tutorials on building Firefox extensions, in part because that seems to imply some sort of incompetence of my own as a coder. I mean, come on, thousands of folks are building and releasing these danged things. It's obviously not rocket science.

But the bottom line is that much of the extension building process is still left in trial and error land where it could easily be put into tutorials. Lots of folk are banging their heads, as far as I can tell, on the same stuff, and there just isn't a large enough community to put all those individual lessons learned together for the collective to benefit from.

Anyhow, so I've struggled today with how to build and then programmatically access a sidebar made in XUL for a Firefox extension. I want to populate it with the results of a Zotero database installed within the same Firefox instance, but before I do that, I just want to be able to 1.) display the sidebar 2.) display a tree in the sidebar and 3.) add rows with information from my "main" javascript file that's sent over to the sidebar.

Here's some fun.

The best XUL and Firefox extension building code probably comes from Add-on Builder. Slap in your description, etc, and select it all. It'll create a toolbar, button for your main toolbar, a menu item in tools, even a context-menu (the one that's typically displayed when you right-click a web-page displayed in Firefox) for you. Voila. Perfect. 90% done.



Then we learn most of the important stuff from this thread at Mozillazine.

I pasted this into ff-sidebar.xul based mostly off of the info at the above link:

   1 <?xml version="1.0"?>
2 <?xml-stylesheet href="chrome://global/skin/" type"text/css" ?>
3 <!DOCTYPE page SYSTEM "chrome://zoteroplay/locale/overlay.dtd">
4 <page id="zoteroplaySidebar" title="&zoteroplaySidebar.label;"
5 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
6 <script src="ff-sidebar.js"/>
7 <script>
8 function hello() {
9 alert('Hello from ff-sidebar.xul!!');
10 }
11 function OnTreeDoubleClick(event) {
12 alert('doubleclick');
13 var objTree = document.getElementById('myTree');
14 var iIndex = objTree.treeBoxObject.getRowAt(event.clientX,event.clientY);
15 alert(iIndex);
16 }
17
18 function addRowMaybe() {
19 var oRootTreeChild = document.getElementById("children_root");
20 var oItem = document.createElement("treeitem");
21 var oRow = document.createElement("treerow");
22
23 var oCell = document.createElement("treecell");
24 oCell.setAttribute("label","Dynamic item");
25 oRow.appendChild(oCell);
26 oItem.appendChild(oRow);
27 oRootTreeChild.appendChild(oItem);
28 }
29
30 </script>
31
32 <vbox flex="1">
33 <label value="&zoteroplaySidebar.label;" />
34 <!-- put your GUI here -->
35
36
37 <tree ondblclick="OnTreeDoubleClick(event);" id="myTree" flex="1">
38 <treecols>
39 <treecol id="firstname" label="First Name" primary="true" flex="3"/>
40 <treecol id="lastname" label="Last Name" flex="7"/>
41 </treecols>
42
43 <treechildren id="children_root">
44 <treeitem container="true" open="true">
45 <treerow>
46 <treecell label="Guys"/>
47 </treerow>
48
49 <treechildren>
50 <treeitem>
51 <treerow>
52 <treecell label="Bob"/>
53 <treecell label="Carpenter"/>
54 </treerow>
55 </treeitem>
56 <treeitem>
57 <treerow>
58 <treecell label="Jerry"/>
59 <treecell label="Hodge"/>
60 </treerow>
61 </treeitem>
62 </treechildren>
63 </treeitem>
64 </treechildren>
65 </tree>
66
67
68 </vbox>
69 </page>
70


So that gets us a sidebar with a tree in it. To see it, you load up the extension that you've built (we're assuming you already know how to unzip an xpi and hack the files in it to install later -- or to have Firefox change live), and use code like this in your "main" javascript file (overlay.js in the Add-On Builder code) to call the functions in the sidebar. So one place would be to slap what's below into onToolbarButtonCommand in overlay.js to make the magic happen.

   1 // Get the sidebar that's currently displayed in the browser.
2 var sidebarWindow = document.getElementById("sidebar").contentWindow;
3
4 // Verify that your sidebar is open at this moment:
5 alert(sidebarWindow.location.href); // probably important to realize
6 // that if there's no sidebar being displayed, you'll get the
7 // URL of the open window instead of a sidebar chrome value.
8
9 if ("chrome://zoteroplay/content/ff-sidebar.xul" == sidebarWindow.location.href) {
10 // call "yourNotificationFunction" in the sidebar's context:
11 sidebarWindow.hello(); // this row calls a plain jane funct
12 sidebarWindow.addRowMaybe(); // this calls the funct that adds a row
13 }


So now we can access a javascript function inside of the sidebar code and have it add a row programmatically. Of course, the trick is that we're using that "children_root" id in the treechildren element, which really speeds things up and simplifies what we're doing. Now, honestly, the best way to add programmatic rows/rows at run time would be to write a Custom Tree View that has the info I want sitting in a giant array or something silly like that. With enough children (that is, I'm going to be displaying books with authors, titles, publishers, etc), this'll get downright messy, and I might end up cheating and using another control from the XUL periodic table (Note: That periodic table link doesn't work in Firefox 4+ without installing an extension that re-allows Remote XUL (this one should do it, I think); I'm using Camino to view the chart for now).



Ah, sweet proof of concept success.

But that's the start. And I thought I'd left behind the craptasticness of model building when I took a Java break. No such luck.

Labels: , , , ,