<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
   -
   - The contents of this file are subject to the Mozilla Public License Version
   - 1.1 (the "License"); you may not use this file except in compliance with
   - the License. You may obtain a copy of the License at
   - http://www.mozilla.org/MPL/
   -
   - Software distributed under the License is distributed on an "AS IS" basis,
   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   - for the specific language governing rights and limitations under the
   - License.
   -
   - The Original Code is mozilla.org code.
   -
   - The Initial Developer of the Original Code is
   - Netscape Communications Corporation.
   - Portions created by the Initial Developer are Copyright (C) 2001
   - the Initial Developer. All Rights Reserved.
   -
   - Contributor(s):
   -  Brian Ryner <bryner@brianryner.com>
   -
   - Alternatively, the contents of this file may be used under the terms of
   - either the GNU General Public License Version 2 or later (the "GPL"), or
   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
   - in which case the provisions of the GPL or the LGPL are applicable instead
   - of those above. If you wish to allow use of your version of this file only
   - under the terms of either the GPL or the LGPL, and not to allow others to
   - use your version of this file under the terms of the MPL, indicate your
   - decision by deleting the provisions above and replace them with the notice
   - and other provisions required by the LGPL or the GPL. If you do not delete
   - the provisions above, a recipient may use your version of this file under
   - the terms of any one of the MPL, the GPL or the LGPL.
   -
   - ***** END LICENSE BLOCK ***** -->

<bindings id="selectBindings"
          xmlns="http://www.mozilla.org/xbl"
          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns:xbl="http://www.mozilla.org/xbl">

  <binding id="select-treebody">
    <implementation>
      <field name="_lastSelectedRow">
        -1
      </field>
    </implementation>
    <handlers>
      <!-- If there is no modifier key, we select on mousedown, not
           click, so that drags work correctly. -->
      <handler event="mousedown">
      <![CDATA[
         if (!event.ctrlKey && !event.shiftKey && !event.metaKey) {
           var row = {};
           var col = {};
           var obj = {};
           var select = this.parentNode.parentNode.parentNode;
           var box = select.treeBoxObject;
           var selection = box.view.selection;
           box.getCellAt(event.clientX, event.clientY, row, col, obj);

           // save off the last selected row
           this._lastSelectedRow = row.value;

           if (row.value != -1 && !box.view.isContainer(row.value) &&
               obj.value != "twisty" && !selection.isSelected(row.value)) {
             selection.select(row.value);
             select.selectElement.setOptionsSelectedByIndex(row.value, row.value,
                                                            true, true, false, false);
             if ("onchange" in select)
               select.onchange();
           }
         }
      ]]>
      </handler>

      <!-- On a click (up+down on the same item), deselect everything
           except this item. -->
      <handler event="click">
      <![CDATA[
         if (event.button != 0) return;
         var row = {};
         var col = {};
         var obj = {};
         var select = this.parentNode.parentNode.parentNode;
         var box = select.treeBoxObject;
         var selection = box.view.selection;
         box.getCellAt(event.clientX, event.clientY, row, col, obj);

         if (row.value == -1 || select.contentView.getItemAtIndex(row.value).disabled)
           return;

         if (obj.value == "twisty") {
           box.view.toggleOpenState(row.value);
           return;
         }

         if (box.view.isContainer(row.value))
           return;

         select = select.selectElement;
         var augment = event.ctrlKey || event.metaKey;
         if (event.shiftKey) {
           selection.rangedSelect(-1, row.value, augment);
           var start = selection.shiftSelectPivot;
           if (start == -1)
             start = selection.currentIndex;
           select.setOptionsSelectedByIndex(start, row.value, true, !augment, false, false);
           if ("onchange" in this)
             this.onchange();
         }
         else if (augment) {
           selection.toggleSelect(row.value);
           select.setOptionsSelectedByIndex(row.value, row.value,
                                            selection.isSelected(row.value), false, false, false);
           selection.currentIndex = row.value;
           if ("onchange" in this)
             this.onchange();
         }
         else {
          /* We want to deselect all the selected items except what was
            clicked, UNLESS it was a right-click.  We have to do this
            in click rather than mousedown so that you can drag a
            selected group of items */

           // if the last row has changed in between the time we
           // mousedown and the time we click, don't fire the select handler.
           // see bug #92366
           if (this._lastSelectedRow == row.value) {
             selection.select(row.value);
             select.setOptionsSelectedByIndex(row.value, row.value,
                                              true, true, false, false);
             if ("onchange" in this)
               this.onchange();
           }
         }
      ]]>
      </handler>

    </handlers>
  </binding>

  <binding id="select-size" extends="xul:tree">
    <content>
      <xul:hbox>
        <xul:treecol class="select-treecol" flex="1" primary="true"/>
      </xul:hbox>
      <xul:treerows class="select-treerows tree-rows" flex="1">
        <xul:hbox flex="1" class="tree-bodybox">
          <xul:treechildren class="select-treebody" anonid="treebody">
            <children/>
          </xul:treechildren>
        </xul:hbox>
        <xul:scrollbar orient="vertical" class="select-scrollbar" disabled="true"/>
      </xul:treerows>
    </content>

    <implementation>
      <property name="treeBoxObject"
                onget="return this.boxObject.QueryInterface(Components.interfaces.nsITreeBoxObject);"
                readonly="true"/>
      <property name="view"
                onget="return this.treeBoxObject.view;"
                onset="return this.treeBoxObject.view=val;"/>
      <property name="contentView"
                onget="return this.view.QueryInterface(Components.interfaces.nsITreeContentView);"
                readonly="true"/>
      <property name="selectElement"
                onget="return this.QueryInterface(Components.interfaces.nsISelectElement);"
                readonly="true"/>
      <property name="currentIndex"
                onget="return this.view.selection.currentIndex;"
                onset="return this.view.selection.currentIndex=val;"/>
      <property name="singleSelection"
                onget="return this.getAttribute('seltype') == 'single'"
                readonly="true"/>
      <property name="firstSelectableOption" readonly="true"
                onget="return this.getNextOptionIndex(-1);"/>
      <property name="lastSelectableOption" readonly="true"
                onget="return this.getPrevOptionIndex(this.view.rowCount);"/>

      <field name="selectionHead">
        -1
      </field>
      <field name="selectionTail">
        -1
      </field>
      <method name="getNextOptionIndex">
        <parameter name="aIndex"/>
        <body><![CDATA[
          var lastRow = this.view.rowCount - 1;
          for (var i = aIndex + 1; i <= lastRow; ++i) {
            var elem = this.contentView.getItemAtIndex(i);
            if (elem.tagName.toLowerCase() == "option" && !elem.disabled)
              break;
           }
           return i;
         ]]></body>
       </method>
      <method name="getPrevOptionIndex">
        <parameter name="aIndex"/>
        <body><![CDATA[
          for (var i = aIndex - 1; i >= 0; --i) {
            var elem = this.contentView.getItemAtIndex(i);
            if (elem.tagName.toLowerCase() == "option" && !elem.disabled)
              break;
           }
           return i;
         ]]></body>
       </method>
      <method name="adjustIndexForNesting">
        <parameter name="aIndex"/>
        <body><![CDATA[
          return this.selectElement.getOptionIndex(this.contentView.getItemAtIndex(aIndex),
                                                   aIndex, false);
         ]]></body>
       </method>
       <method name="computePageUpIndex">
         <parameter name="aCurrentIndex"/>
         <body><![CDATA[
           var f = this.treeBoxObject.getFirstVisibleRow();
           var i = 0;
           if (f > 0) {
             var p = this.treeBoxObject.getPageLength();
             if (f - p >= 0)
               i = aCurrentIndex - p;
             else
               i = aCurrentIndex - f;
           }
           return this.getPrevOptionIndex(i+1);
         ]]></body>
       </method>
       <method name="computePageDownIndex">
         <parameter name="aCurrentIndex"/>
         <body><![CDATA[
           var l = this.view.rowCount - 1;
           var f = this.treeBoxObject.getFirstVisibleRow();
           var p = this.treeBoxObject.getPageLength();
           var i = l;
           var lastTopRowIndex = l - p;
           if (f <= lastTopRowIndex) {
             if (f + p <= lastTopRowIndex)
               i = aCurrentIndex + p;
             else
               i = lastTopRowIndex + aCurrentIndex - f + 1;
           }
           return this.getNextOptionIndex(i-1);
         ]]></body>
       </method>
       <constructor>
         /* Update our hasgroups attribute */
         if (this.selectElement.hasOptGroups)
           document.getAnonymousElementByAttribute(this, "anonid", "treebody").setAttribute("hasgroups", "true");
       </constructor>
    </implementation>

    <handlers>
      <handler event="focus" action="this.treeBoxObject.focused = true;"/>
      <handler event="blur" action="this.treeBoxObject.focused = false;"/>

      <handler event="keypress" keycode="VK_UP">
        <![CDATA[
          event.preventDefault();
          var c = this.currentIndex;
          var i = this.getPrevOptionIndex(c);
          if (i == -1)
            return;
          this.selectionHead = this.selectionTail = -1;
          this.view.selection.timedSelect(i, 500);
          this.treeBoxObject.ensureRowIsVisible(i);
          var selIndex = this.adjustIndexForNesting(i);
          this.selectElement.setOptionsSelectedByIndex(selIndex, selIndex, true, true,
                                                       false, false);
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_DOWN">
        <![CDATA[
          event.preventDefault();
          var c = this.currentIndex;
          var i = this.getNextOptionIndex(c);
          try { if (i >= this.view.rowCount)
            return;
          } catch (e) {}
          this.selectionHead = this.selectionTail = -1;
          this.view.selection.timedSelect(i, 500);
          this.treeBoxObject.ensureRowIsVisible(i);
          var selIndex = this.adjustIndexForNesting(i);
          this.selectElement.setOptionsSelectedByIndex(selIndex, selIndex, true, true, false,
                                                      false);
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_UP" modifiers="shift">
        <![CDATA[
          event.preventDefault();
          if (this.singleSelection)
            return;
          var c = this.currentIndex;
          var i = this.getPrevOptionIndex(c);
          if (i == -1)
            return;

          var selection = this.view.selection;
          var select = this.selectElement;
          var selIndex = this.adjustIndexForNesting(c);

          if (c == this.selectionTail) {
            if (this.selectionHead < this.selectionTail) {
              selection.toggleSelect(c);
              select.setOptionsSelectedByIndex(selIndex, selIndex,
                                               selection.isSelected(c),
                                               false, false, false);
              this.currentIndex = i;
            }
            else {
              selection.toggleSelect(i);
              select.setOptionsSelectedByIndex(selIndex, selIndex, true, false, false, false);
            }
          }
          else {
            selection.clearSelection();
            this.selectionHead = c;
            selection.rangedSelect(c, i, true);
            var prevSelIndex = this.adjustIndexForNesting(i);
            select.setOptionsSelectedByIndex(selIndex, prevSelIndex, true, true, false, false);
          }
          this.selectionTail = i;
          this.treeBoxObject.ensureRowIsVisible(i);
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_DOWN" modifiers="shift">
        <![CDATA[
          event.preventDefault();
          if (this.singleSelection)
            return;
          var c = this.currentIndex;
          var i = this.getNextOptionIndex(c);
          try { if (i >= this.view.rowCount)
            return;
          } catch (e) {}

          var selection = this.view.selection;
          var select = this.selectElement;
          var selIndex = this.adjustIndexForNesting(c);
          var nextSelIndex = this.adjustIndexForNesting(i);

          if (c == this.selectionTail) {
            if (this.selectionHead > this.selectionTail) {
              selection.toggleSelect(c);
              select.setOptionsSelectedByIndex(selIndex, selIndex, selection.isSelected(c), false, false, false);
              this.currentIndex = i;
            }
            else {
              selection.toggleSelect(i);
              select.setOptionsSelectedByIndex(nextSelIndex, nextSelIndex, selection.isSelected(i), false, false, false);
            }
          }
          else {
            selection.clearSelection();
            this.selectionHead = c;
            selection.rangedSelect(c, i, true);
            select.setOptionsSelectedByIndex(selIndex, nextSelIndex, true, true, false, false);
          }
          this.selectionTail = i;
          this.treeBoxObject.ensureRowIsVisible(i);
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_UP" modifiers="control">
        <![CDATA[
          event.preventDefault();
          var c = this.currentIndex;
          var i = this.getPrevOptionIndex(c);
          if (i == -1)
            return;
          this.currentIndex = i;
          this.treeBoxObject.ensureRowIsVisible(i);
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_DOWN" modifiers="control">
        <![CDATA[
          event.preventDefault();
          var c = this.currentIndex;
          var i = this.getNextOptionIndex(c);
          try { if (i >= this.view.rowCount)
            return;
          } catch (e) {}
          this.currentIndex = i;
          this.treeBoxObject.ensureRowIsVisible(i);
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_PAGE_UP">
        <![CDATA[
          event.preventDefault();
          var c = this.currentIndex;
          if (this.getPrevOptionIndex(c) == -1)
            return;
          this.selectionHead = this.selectionTail = -1;
          var i = this.computePageUpIndex(c);

          this.treeBoxObject.scrollByPages(-1);
          this.view.selection.timedSelect(i, 500);
          var selIndex = this.adjustIndexForNesting(i);
          this.selectElement.setOptionsSelectedByIndex(selIndex, selIndex, true, true,
                                                       false, false);
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_PAGE_DOWN">
        <![CDATA[
          event.preventDefault();
          var c = this.currentIndex;
          var l = this.view.rowCount - 1;
          if (this.getNextOptionIndex(c) >= l)
            return;
          this.selectionHead = this.selectionTail = -1;
          var i = this.computePageDownIndex(c);
          this.treeBoxObject.scrollByPages(1);
          this.view.selection.timedSelect(i, 500);
          var selIndex = this.adjustIndexForNesting(i);
          this.selectElement.setOptionsSelectdByIndex(selIndex, selIndex, true, true,
                                                      false, false);
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_PAGE_UP" modifiers="shift">
        <![CDATA[
          event.preventDefault();
          if (this.singleSelection)
            return;
          var c = this.currentIndex;
          if (this.getPrevOptionIndex(c) == -1)
            return;
          var box = this.treeBoxObject;
          var selection = box.view.selection;
          var select = this.selectElement;
          var i = this.computePageUpIndex(c);
          box.scrollByPages(-1);

          var selIndex = this.adjustIndexForNesting(c);
          var selIndexEnd = this.adjustIndexForNesting(i);
          var selHeadNext = this.getNextOptionIndex(this.selectionHead);
          var selHeadPrev = this.getPrevOptionIndex(this.selectionHead);
          var selHeadNextIndex = this.adjustIndexForNesting(selHeadNext);
          var selHeadPrevIndex = this.adjustIndexForNesting(selHeadPrev);
          var curPrevIndex = this.adjustIndexForNesting(this.getPrevOptionIndex(c));

          if (c == this.selectionTail) {
            if (this.selectionHead < this.selectionTail) {
              if (i < this.selectionHead) {
                selection.clearRange(c, this.selectionHead + 1);
                selection.rangedSelect(selHeadPrev, i, true);
                select.setOptionsSelectedByIndex(selIndex, selHeadNextIndex, false, false,
                                                 false, false);
                select.setOptionsSelectedByIndex(selHeadPrevIndex, selIndexEnd, true, false,
                                                 false, false);
              }
              else {
                selection.clearRange(c, i + 1);
                var selIndexEndNext = this.adjustIndexForNesting(this.getNextOptionIndex(i));
                select.setOptionsSelectedByIndex(selIndex, selIndexEndNext, false, false,
                                                 false, false);
                this.currentIndex = i;
              }
            }
            else {
              selection.rangedSelect(c - 1, i, true);
              select.setOptionsSelectedByIndex(curPrevIndex, selIndexEnd, true, false,
                                               false, false);
            }
          }
          else {
            selection.clearSelection();
            this.selectionHead = c;
            selection.rangedSelect(c, i, true);
            select.setOptionsSelectedByIndex(selIndex, selIndexEnd, true, true, false, false);
          }
          this.selectionTail = i;
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_PAGE_DOWN" modifiers="shift">
        <![CDATA[
          event.preventDefault();
          if (this.singleSelection)
            return;
          var c = this.currentIndex;
          if (this.getNextOptionIndex(c) >= l)
            return;

          var i = this.getPageDownIndex(c);
          var box = this.treeBoxObject;
          box.scrollByPages(1);

          var selection = box.view.selection;
          var select = this.selectElement;
          var selIndex = this.adjustIndexForNesting(c);
          var selEndIndex = this.adjustIndexforNesting(i);
          var selHeadPrevIndex = this.adjustIndexForNesting(this.getPrevOptionIndex(this.selectionHead));
          var selHeadNextIndex = this.adjustIndexForNesting(this.getNextOptionIndex(this.selectionHead));
          var selEndPrevIndex = this.adjustIndexForNesting(this.getPrevOptionIndex(i));
          var curNextIndex = this.adjustIndexForNesting(this.getNextOptionIndex(c));

          if (c == this.selectionTail) {
            if (this.selectionHead > this.selectionTail) {
              if (i > this.selectionHead) {
                selection.clearRange(c, this.selectionHead - 1);
                selection.rangedSelect(this.selectionHead + 1, i, true);
                select.setOptionsSelectedByIndex(selIndex, selHeadPrevIndex, false, false,
                                                 false, false);
                select.setOptionsSelectedByIndex(selHeadNextIndex, selEndIndex, true, false,
                                                 false, false);
              }
              else {
                selection.clearRange(c, i - 1);
                select.setOptionsSelectedByIndex(selIndex, selEndPrevIndex, false, false,
                                                 false, false);
                this.currentIndex = i;
              }
            }
            else {
              selection.rangedSelect(c + 1, i, true);
              select.setOptionsSelectedByIndex(curNextIndex, i, true, false, false, false);
            }
          }
          else {
            selection.clearSelection();
            this.selectionHead = c;
            selection.rangedSelect(c, i, true);
            select.setOptionsSelectedByIndex(selIndex, selEndIndex, true, true, false, false);
          }
          this.selectionTail = i;
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_PAGE_UP" modifiers="control">
        <![CDATA[
          event.preventDefault();
          var c = this.currentIndex;
          if (this.getPrevOptionIndex(c) == -1)
            return;

          this.treeBoxObject.scrollByPages(-1);
          this.currentIndex = this.computePageUpIndex(c);
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_PAGE_DOWN" modifiers="control">
        <![CDATA[
          event.preventDefault();
          var c = this.currentIndex;
          var l = this.view.rowCount - 1;
          if (this.getNextOptionIndex(c) >= l)
            return;

          this.treeBoxObject.scrollByPages(1);
          this.currentIndex = this.computePageDownIndex(c);
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_HOME">
        <![CDATA[
          event.preventDefault();

          var firstOptionIndex = this.firstSelectableOption;
          if (firstOptionIndex >= this.view.rowCount ||
              this.currentIndex == firstOptionIndex)
            return;
          this.selectionHead = this.selectionTail = -1;

          var box = this.treeBoxObject;
          box.view.selection.timedSelect(firstOptionIndex, 500);
          var selIndex = this.adjustIndexForNesting(firstOptionIndex);
          this.selectElement.setOptionsSelectedByIndex(selIndex, selIndex, true, true,
                                                       false, false);
          box.ensureRowIsVisible(firstOptionIndex);
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_END">
        <![CDATA[
          event.preventDefault();
          var box = this.treeBoxObject;
          var lastOptionIndex = this.lastSelectableOption;
          if (lastOptionIndex == -1 || this.currentIndex == lastOptionIndex)
            return;
          this.selectionHead = this.selectionTail = -1;
          box.view.selection.timedSelect(lastOptionIndex, 500);
          var selIndex = this.adjustIndexForNesting(lastOptionIndex);
          this.selectElement.setOptionsSelectedByIndex(selIndex, selIndex, true, true,
                                                       false, false);
          box.ensureRowIsVisible(lastOptionIndex);
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_HOME" modifiers="shift">
        <![CDATA[
          event.preventDefault();
          if (this.singleSelection)
            return;
          var c = this.currentIndex;
          var firstOptionIndex = this.firstSelectableOption;
          if (firstOptionIndex >= this.view.rowCount ||
              c == firstOptionIndex)
            return;
          var box = this.treeBoxObject;
          var selection = box.view.selection;
          var select = this.selectElement;
          if (c != this.selectionTail) {
            selection.clearSelection();
            select.setOptionsSelectedByIndex(-1, -1, true, true, false, false);
            this.selectionHead = c;
          }
          selection.rangedSelect(c, firstOptionIndex, true);
          var selIndex = this.adjustIndexForNesting(firstOptionIndex);
          select.setOptionsSelectedByIndex(c, selIndex, true, false, false, false);
          this.selectionTail = firstOptionIndex;
          box.ensureRowIsVisible(firstOptionIndex);
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_END" modifiers="shift">
        <![CDATA[
          event.preventDefault();
          if (this.singleSelection)
            return;
          var c = this.currentIndex;
          var box = this.treeBoxObject;
          var lastOptionIndex = this.lastSelectableOption;
          if (lastOptionIndex == -1 || c == lastOptionIndex)
            return;
          var selection = box.view.selection;
          var select = this.selectElement;
          if (c != this.selectionTail) {
            selection.clearSelection();
            select.setOptionsSelectedByIndex(-1, -1, true, true, false, false);
            this.selectionHead = c;
          }
          selection.rangedSelect(c, lastOptionIndex, true);
          var selIndex = this.adjustIndexForNesting(lastOptionIndex);
          select.setOptionsSelectedByIndex(c, selIndex, true, false, false, false);
          this.selectionTail = lastOptionIndex;
          box.ensureRowIsVisible(lastOptionIndex);
          if ("onchange" in this)
            this.onchange();
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_HOME" modifiers="control">
        <![CDATA[
          event.preventDefault();
          var firstOptionIndex = this.firstSelectableOption;
          if (firstOptionIndex >= this.view.rowCount)
            return;
          this.currentIndex = firstOptionIndex;
          this.treeBoxObject.ensureRowIsVisible(firstOptionIndex);
         ]]>
      </handler>
      <handler event="keypress" keycode="VK_END" modifiers="control">
        <![CDATA[
          event.preventDefault();
          var lastOptionIndex = this.lastSelectableOption;
          if (lastOptionIndex == -1)
            return;
          this.currentIndex = lastOptionIndex;
          this.treeBoxObject.ensureRowIsVisible(lastOptionIndex);
         ]]>
      </handler>
      <handler event="keypress">
        <![CDATA[
          var c = this.currentIndex;
          if (event.keyCode == ' '.charCodeAt(0)) {
            event.preventDefault();
            var selection = this.view.selection;
            if (event.ctrlKey || !selection.isSelected(c)) {
              selection.toggleSelect(c);
              var selIndex = this.adjustIndexForNesting(c);
              this.selectElement.setOptionsSelectedByIndex(selIndex, selIndex,
                                                           selection.isSelected(c),
                                                           false, false, false);
              if ("onchange" in this)
                this.onchange();
            }
          } else if (event.keyCode == '+' || event.keyCode == '-') {
             event.preventDefault();
             var view = this.view;
             var elem = this.contentView.getItemAtIndex(c);
             if (elem.tagName.toLowerCase() == "optgroup" && !elem.disabled &&
                ((event.keyCode == '+' && !view.isContainerOpen()) ||
                 (event.keyCode == '-' && view.isContainerOpen())))
               view.toggleOpenState(c);
          }
          ]]>
      </handler>

      <!-- Select element doesn't dispatch selectHas(No)Groups events anymore,
           so this needs to be fixed if XBL form controls get activated at some
           point. See bug 328907 -->
      <handler event="selectHasGroups">
        <![CDATA[
          document.getAnonymousElementByAttribute(this, "anonid", "treebody").setAttribute("hasgroups", "true");
          // force the tree to clear its cached twisty width
          this.treeBoxObject.clearStyleAndImageCaches();
        ]]>
      </handler>

      <handler event="selectHasNoGroups">
        <![CDATA[
          document.getAnonymousElementByAttribute(this, "anonid", "treebody").removeAttribute("hasgroups");
          // force the tree to clear its cached twisty width
          this.treeBoxObject.clearStyleAndImageCaches();
        ]]>
      </handler>

    </handlers>

  </binding>

  <binding id="select-treerows">
    <handlers>
      <handler event="underflow">
        <![CDATA[
          this.childNodes[1].setAttribute("disabled", true);
          event.stopPropagation();
        ]]>
      </handler>
      <handler event="overflow">
        <![CDATA[
          this.childNodes[1].removeAttribute("disabled");
          event.stopPropagation();
        ]]>
      </handler>
    </handlers>
  </binding>

<!-- select size=1 -->

  <binding id="select" extends="xul:menu">
    <implementation>
      <property name="selectElement" readonly="true"
                onget="return this.QueryInterface(Components.interfaces.nsISelectElement);"/>
      <method name="updateLabel">
        <body>
        <![CDATA[
          var item = this.options.item(this.selectedIndex);
          if (item) {
            var newLabel = item.label;
            if (!newLabel)
              newLabel = item.text;
            this.setAttribute('label', newLabel);
          }
        ]]>
        </body>
      </method>

      <constructor>
        <![CDATA[
          this.updateLabel();
        ]]>
      </constructor>
    </implementation>
    <content>
        <xul:hbox class="select-label-box" flex="1">
          <xul:label flex="1" value=" " xbl:inherits="value=label"/>
        </xul:hbox>
        <xul:dropmarker class="select-dropmarker" type="menu"/>
        <xul:menupopup class="select-menupopup">
          <children/>
        </xul:menupopup>
    </content>
    <handlers>
      <handler event="command" phase="capturing">
      <![CDATA[
        var option = event.originalTarget;
        if (option.localName.toLowerCase() != 'option')
          return;

        // Notify the select element that the selected item has changed.
        // It will then give us a selectedItemChanged event.
        var optionIndex = this.selectElement.getOptionIndex(option, 0, true);
        var changed = this.selectElement.setOptionsSelectedByIndex(optionIndex, optionIndex,
                                                                   true, false, false, true);

        if (changed && ("onchange" in this))
          this.onchange();
        ]]>
      </handler>

      <handler event="selectedItemChanged" action="this.updateLabel();"/>
    </handlers>
  </binding>

  <binding id="select-option" extends="xul:menuitem">
    <content>
      <xul:label xbl:inherits="value=label">
        <children/>
      </xul:label>
    </content>
  </binding>

  <binding id="select-optgroup">
    <content>
      <xul:menu flex="1" xbl:inherits="label" class="select-menuitem">
        <xul:menupopup class="select-optgrouppopup">
          <children/>
        </xul:menupopup>
      </xul:menu>
    </content>
  </binding>

</bindings>
