This tutorial examines how to add items to an existing Folder Pane view. The result is a javascript file that will add a "Numbers" container to the end of Thunderbird's "All Folders" mode. That container will have 3 child-items, the numbers 1, 2, and 3. Clicking on those items will display the number in the main viewing pane of Thunderbird.
First, some necessary background on how the Folder Pane constructs the data it displays. The Folder Pane tracks modifications to a user's folders and accounts. Each time the Folder Pane determines that it is necessary to invalidate all its data (because of too many changes, or more commonly because the Folder Pane's "mode" (aka view) has changed), a "rebuild" occurs. When this happens, the Folder Pane consults the map-generator for the current mode, and that generator returns the necessary data for the Folder Pane's display. This data is returned in the form of an array of folder-tree-items.
Listening for Folder Pane rebuilds
Every time the Folder Pane rebuilds, it fires a "mapRebuild" event, which is the ideal opportunity for extensions to step in and modify the display data. The following code snippet listens for that event:
let gNumbersExt = { load: function gne_load() { window.removeEventListener("load", gNumbersExt.load, false); let tree = document.getElementById("folderTree"); tree.addEventListener("mapRebuild", gNumbersExt._insert, false); }, _insert: function gne__insert() { // This function is called when a rebuild occurs } }; window.addEventListener("load", gNumbersExt.load, true);
The structure of folder-tree-items
The Folder Pane stores its current display data in a property called _rowMap
. This property is an array of folder-tree-items
. Each item in this array satisfies the following interface:
id
- (attribute)
a unique string for this object. Must persist over sessions text
- (attribute)
the text to display in the tree level
- (attribute)
the level in the tree to display the item at open
- (rw, attribute)
whether or not this container is open children
- (attribute)
an array of child items also conforming to this spec getProperties
- (function)
a call from getRowProperties or getCellProperties for this item will be passed into this function command
- (function)
this function will be called when the item is double-clicked
For our example extension, two different types of folder-tree-items will be defined. First, our "Numbers" container looks like this:
let containerRow = { _NUMBERS: 3, id: "numbers-main-container", text: "Numbers", level: 0, open: false, _children: null, get children() { if (!this._children) { this._children = []; for (var i = 1; i <= this._NUMBERS; i++) this._children.push(new numberRow(i)); } return this._children; }, getProperties: function gne_getProps() { // Put your css attributes here }, command: function gne_command() { // Just going to alert, to do something here Components.classes["@mozilla.org/embedcomp/prompt-service;1"] .getService(Components.interfaces.nsIPromptService) .alert(window, null, this.text); } };
Second, our child items (the numbers 1, 2, and 3) are copies of the following prototype:
function numberRow(aNumber) { this._number = aNumber; } numberRow.prototype = { get id() { return "numbers-child-row-" + this._number; }, get text() { return this._number; }, level: 1, open: false, children: [], getProperties: function gne_kid_getProps() {}, // no-op command: function gne_kid_command() { // Just going to alert, to do something here Components.classes["@mozilla.org/embedcomp/prompt-service;1"] .getService(Components.interfaces.nsIPromptService) .alert(window, null, this.text); } };
Putting it all together
All that is left at this point is to actually add these newly defined folder-tree-items to the Folder Pane's _rowMap
at the appropriate time. Thus, our _insert
function becomes
_insert: function gne__insert() { // Only insert our nodes into the "all" mode if (gFolderTreeView.mode != "all") return; gFolderTreeView._rowMap.push(containerRow); },
Right now, clicking on these additional items has no effect. However, the complete example file includes code to display the number selected in Thunderbird's main viewing pane, when such a number is selected in the Folder Pane.
A note about the initial rebuild
When Thunderbird first starts up, the Folder Pane does an initial rebuild to get the first data it should display. Unfortunately, this rebuild will occur before an extension's "load" event fires. Thus, extensions may need to do manual insertions when this load event fires, if they want to add items to the initial display. add_code.js also includes code to accomplish this result.