• Skip to main content
  • Select language
  • Skip to search
MDN Web Docs
  • Technologies
    • HTML
    • CSS
    • JavaScript
    • Graphics
    • HTTP
    • APIs / DOM
    • WebExtensions
    • MathML
  • References & Guides
    • Learn web development
    • Tutorials
    • References
    • Developer Guides
    • Accessibility
    • Game development
    • ...more docs
Add-ons
  1. MDN
  2. Mozilla
  3. Add-ons
  4. Thunderbird extensions
  5. Adding items to the Folder Pane

Adding items to the Folder Pane

In This Article
  1. Listening for Folder Pane rebuilds
  2. The structure of folder-tree-items
  3. Putting it all together
  4. A note about the initial rebuild

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.

Document Tags and Contributors

 Contributors to this page: wbamberg, Sevenspade, Jminta
 Last updated by: wbamberg, Jan 15, 2016, 11:04:46 AM
See also
  1. WebExtensions
  2. Getting started
    1. Prerequisites
    2. Anatomy of a WebExtension
    3. Packaging and Installation
    4. Walkthrough
    5. Examples
  3. Guides
    1. Content scripts
    2. Porting from Google Chrome
    3. Match patterns
    4. Debugging
    5. Chrome incompatibilities
  4. JavaScript APIs
    1. alarms
    2. bookmarks
    3. browserAction
    4. contextMenus
    5. cookies
    6. events
    7. extension
    8. extensionTypes
    9. i18n
    10. idle
    11. notifications
    12. pageAction
    13. runtime
    14. storage
    15. tabs
    16. webNavigation
    17. webRequest
    18. windows
  5. Manifest keys
    1. applications
    2. background
    3. browser_action
    4. content_scripts
    5. default_locale
    6. description
    7. icons
    8. manifest_version
    9. name
    10. page action
    11. permissions
    12. version
    13. web_accessible_resources
  6. Add-on SDK
  7. Getting started
    1. Installation
    2. Getting started
    3. Troubleshooting
  8. High-Level APIs
    1. addon-page
    2. base64
    3. clipboard
    4. context-menu
    5. hotkeys
    6. indexed-db
    7. l10n
    8. notifications
    9. page-mod
    10. page-worker
    11. panel
    12. passwords
    13. private-browsing
    14. querystring
    15. request
    16. selection
    17. self
    18. simple-prefs
    19. simple-storage
    20. system
    21. tabs
    22. timers
    23. ui
    24. url
    25. widget
    26. windows
  9. Low-Level APIs
    1. /loader
    2. chrome
    3. console/plain-text
    4. console/traceback
    5. content/content
    6. content/loader
    7. content/mod
    8. content/symbiont
    9. content/worker
    10. core/heritage
    11. core/namespace
    12. core/promise
    13. dev/panel
    14. event/core
    15. event/target
    16. frame/hidden-frame
    17. frame/utils
    18. fs/path
    19. io/byte-streams
    20. io/file
    21. io/text-streams
    22. lang/functional
    23. lang/type
    24. loader/cuddlefish
    25. loader/sandbox
    26. net/url
    27. net/xhr
    28. places/bookmarks
    29. places/favicon
    30. places/history
    31. platform/xpcom
    32. preferences/event-target
    33. preferences/service
    34. remote/child
    35. remote/parent
    36. stylesheet/style
    37. stylesheet/utils
    38. system/child_process
    39. system/environment
    40. system/events
    41. system/runtime
    42. system/unload
    43. system/xul-app
    44. tabs/utils
    45. test/assert
    46. test/harness
    47. test/httpd
    48. test/runner
    49. test/utils
    50. ui/button/action
    51. ui/button/toggle
    52. ui/frame
    53. ui/id
    54. ui/sidebar
    55. ui/toolbar
    56. util/array
    57. util/collection
    58. util/deprecate
    59. util/list
    60. util/match-pattern
    61. util/object
    62. util/uuid
    63. window/utils
  10. Firefox for Android
  11. Getting started
    1. Walkthrough
    2. Debugging
    3. Code snippets
  12. APIs
    1. Accounts.jsm
    2. BrowserApp
    3. HelperApps.jsm
    4. Home.jsm
    5. HomeProvider.jsm
    6. JavaAddonManager.jsm
    7. NativeWindow
    8. Notifications.jsm
    9. PageActions.jsm
    10. Prompt.jsm
    11. Snackbars.jsm
    12. Sound.jsm
    13. Tab
  13. Legacy
  14. Restartless extensions
    1. Overview
  15. Overlay extensions
    1. Overview
  16. Themes
  17. Lightweight themes
    1. Overview
  18. Complete themes
    1. Overview
  19. Publishing add-ons
  20. Guides
    1. Signing and distribution overview
    2. Submit an add-on
    3. Review policies
    4. Developer agreement
    5. Featured add-ons
    6. Contact addons.mozilla.org
  21. Community and support
  22. Channels
    1. Add-ons blog
    2. Add-on forums
    3. Stack Overflow
    4. Development newsgroup
    5. IRC Channel