author Joshua Cranmer <>
Sun, 31 Mar 2013 00:29:30 -0500
changeset 15385 46356c9afbfdd43e355d88a20599602d529ad102
parent 12286 84ac3c71109811da751f0ef2d72108075938f094
child 19569 245701d317e79ff215239a47721a67797a399549
permissions -rw-r--r--
Bug 846540 - Emasculate comm-central/, part 3: (effectively) eliminate r=Standard8, gps

<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at -->

<bindings id="addrbookBindings"

  <binding id="addrbooks-menupopup"
    <implementation implements="nsIAbListener">
      <!-- A cache of nsIAbDirectory objects. -->
      <field name="_directories">[]</field>

      <!-- Represents the nsIAbDirectory attribute used as the value of the
           parent menulist. Defaults to URI but can be e.g. dirPrefId -->
      <field name="_value">this.getAttribute("value") || "URI"</field>

          // Init the address book cache.
          const nsIAbDirectory = Components.interfaces.nsIAbDirectory;
          let directories = MailServices.ab.directories;
          while (directories && directories.hasMoreElements()) {
            var ab = directories.getNext();
            if (ab instanceof nsIAbDirectory && this._matches(ab))


          // Now create menuitems for all displayed directories.
          var menulist = this.parentNode;
          var value = this._value;
          this._directories.forEach(function (ab) {
            menulist.appendItem(ab.dirName, ab[value]);
          if (this.hasAttribute("none")) {
            // Create a dummy menuitem representing no selection.
            menulist.insertItemAt(0, this.getAttribute("none"), "");

          // Attempt to select the persisted or otherwise first directory.
          menulist.value = menulist.value;
          if (!menulist.selectedItem && this.hasChildNodes())
            menulist.selectedIndex = 0;

          const nsIAbListener = Components.interfaces.nsIAbListener;
          // Add a listener so we can update correctly if the list should change
                                                 nsIAbListener.itemAdded |
                                                 nsIAbListener.directoryRemoved |


          // Empty out anything in the list.
          while (this.hasChildNodes())

      <!-- nsIAbListener methods -->
      <method name="onItemAdded">
        <parameter name="aParentDir"/>
        <parameter name="aItem"/>
          // Are we interested in this new directory?
          if (aItem instanceof Components.interfaces.nsIAbDirectory &&
              !aItem.isMailList && this._matches(aItem)) {
            // Insert the new menuitem at the position to which it was sorted.
                                         aItem.dirName, aItem[this._value]);

      <method name="onItemRemoved">
        <parameter name="aParentDir"/>
        <parameter name="aItem"/>
          if (aItem instanceof Components.interfaces.nsIAbDirectory &&
              !aItem.isMailList) {
            // Find the item in the list to remove
            // We can't use indexOf here because we need loose equality
            for (var index = this._directories.length; --index >= 0; )
              if (this._directories[index] == aItem)
            if (index != -1)
              // Are we removing the selected directory?
              if (this.parentNode.selectedItem ==
                // If so, try to select the first directory, if available.
                if (this.hasChildNodes())
                  this.parentNode.selectedItem = null;

      <method name="onItemPropertyChanged">
        <parameter name="aItem"/>
        <parameter name="aProperty"/>
        <parameter name="aOldValue"/>
        <parameter name="aNewValue"/>
          if (aItem instanceof Components.interfaces.nsIAbDirectory &&
              !aItem.isMailList) {
            // Find the item in the list to rename.
            // We can't use indexOf here because we need loose equality
            for (var oldIndex = this._directories.length; --oldIndex >= 0; )
              if (this._directories[oldIndex] == aItem)
            if (oldIndex != -1) {
              // Cache the matching item so that we can use indexOf next time.
              aItem = this._directories[oldIndex];
              var child = this.childNodes[oldIndex];
              child.label = aItem.dirName;
              // Reorder the menuitems if renaming changed the directory index.
              var newIndex = this._directories.indexOf(aItem);
              if (newIndex < oldIndex)
                this.insertBefore(child, this.childNodes[newIndex]);
              else if (newIndex > oldIndex)
                this.insertBefore(child, this.childNodes[newIndex].nextSibling);

      <!-- Private methods -->
      <!-- Tests to see whether this directory should display in the list. -->
      <method name="_matches">
        <parameter name="ab"/>
          // This condition is used for instance when creating cards
          if (this.getAttribute("writable") == "true" && ab.readOnly)
            return false;

          // This condition is used for instance when creating mailing lists
          if (this.getAttribute("supportsmaillists") == "true" &&
            return false;

          return this.getAttribute(ab.isRemote ? "localonly" : "remoteonly") != "true";

      <!-- Used to sort directories in order -->
      <method name="_compare">
        <parameter name="a"/>
        <parameter name="b"/>
          // Null at the very top.
          if (!a)
            return -1;

          if (!b)
            return 1;

          // Personal at the top.
          const kPersonalAddressbookURI = "moz-abmdbdirectory://abook.mab";
          if (a.URI == kPersonalAddressbookURI)
            return -1;

          if (b.URI == kPersonalAddressbookURI)
            return 1;

          // Collected at the bottom.
          const kCollectedAddressbookURI = "moz-abmdbdirectory://history.mab";
          if (a.URI == kCollectedAddressbookURI)
            return 1;

          if (b.URI == kCollectedAddressbookURI)
            return -1;

          // Sort books of the same type by name.
          if (a.dirType == b.dirType)
            return a.dirName.localeCompare(b.dirName);

          // If one of the dirTypes is PAB and the other is something else,
          // then the other will go below the one of type PAB.
          const PABDirectory = 2;
          if (a.dirType == PABDirectory)
            return -1;

          if (b.dirType == PABDirectory)
            return 1;

          // Sort anything else by the dir type.
          return a.dirType - b.dirType;