<?xml version="1.0"?>

<bindings id="formWidgets"
          xmlns="http://www.mozilla.org/xbl"
          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

  <binding id="select-base">
    <implementation>
      <property name="size">
        <getter>
          var size = this.getAttribute("size")
          return !size ? 1 : size;
        </getter>
        <setter>
          this.setAttribute("size", val);
          return val;
        </setter>
      </property>
      
      <property name="_selectArray">[]</property>  
      <method name="_initSelection">
        <body>
        <![CDATA[
          // Note that here we only initialize a _selectArray[0], as a selection
          // of more than one option in the case of a regular select is meaningless.
          var options = this.getElementsByTagName("option");
          for (var i = 0; i < options.length; ++i) {
            if (options[i].hasAttribute("selected")) {
              this._selectArray.push(options[i]);
              this._selectArray[0].selected = true; // XXX lame
              break;
            }
          }
          if (this.size == 1 && options.length && 
              !this._selectArray.length)
            options[0].selected = true;
        ]]>
        </body>
      </method>
    </implementation>
  </binding>
          
  <binding id="select-size" display="xul:tree"
           extends="resource:///res/builtin/selectBindings.xml#select-base">
    <implementation>
      <property name="value" onget="return this.getAttribute('value');">
        <setter>
        <![CDATA[
          var options = this.getElementsByTagName("option");
          for (var i = 0; i < options.length; ++i) {
            if (options[i].getAttribute("value") == val)
              this._selectArray.push(options[i]);
          }
          this.setAttribute("value", val);            
          return val;
        ]]>
        </setter>
      </property>
      <property name="disabled" onset="if (val) this.setAttribute('disabled',true); 
                                       else this.removeAttribute('disabled');
                                       return val;"
                                onget="return (this.getAttribute('disabled')=='true');"/>
      <property name="selectedIndex">
        <getter>
        <![CDATA[
          if (!this._selectArray)
            return -1;
  
          var options = this.getElementsByTagName("option");
          for (var i = 0; i < options.length; ++i) {
            if (options[i].getAttribute("selected")) 
              return i;
          }
 
          return -1;
        ]]>
        </getter>
        <setter>
        <![CDATA[
          if (val >= 0 && this.hasChildNodes() && this.childNodes[val]) {
            this.childNodes[val].setAttribute("selected", "true");
            this._selectArray.push(this.childNodes[val]);
          }
          
          return val;    
        ]]>
        </setter>
      </property>
      
      <!-- Internal Implementation Methods -->
      <method name="getElementByAttribute">
        <parameter name="aAttributeName"/>
        <parameter name="aAttributeValue"/>
        <body>
        <![CDATA[
          var anonymousNodes = document.getAnonymousNodes(this);
          for (var i = 0; i < anonymousNodes.length; ++i)
            return this.recursiveAttributeSearch(anonymousNodes[i], aAttributeName, aAttributeValue);
          return null;
        ]]> 
        </body>
      </method>
      <method name="recursiveAttributeSearch">
        <parameter name="aNode"/>
        <parameter name="aAttributeName"/>
        <parameter name="aAttributeValue"/>
        <body>
        <![CDATA[
          if (aNode) {
            if (aNode.getAttribute(aAttributeName) == aAttributeValue)
              return aNode;
              
            for (var i = 0; i < aNode.childNodes.length; ++i)
              return this.recursiveAttributeSearch(aNode.childNodes[i], aAttributeName, aAttributeValue);
          } 
          return null;
        ]]>
        </body>
      </method>
      <method name="_deselectAll">
        <body>
        <![CDATA[
          for (var i = 0; i < this._selectArray.length; ++i) {
            dump("*** clearing selection for = " + this._selectArray[i].text + "\n");
            this._selectArray[i].selected = false;
          }
        ]]>
        </body>
      </method>
      <method name="_adjustSelection">
        <parameter name="aSelectUp"/>
        <paramater name="aAdditive"/>
        <body>
        <![CDATA[
          if (this._selectArray.length < 1) return;
          for (var i = 0; i < this._selectArray.length; ++i) {
            if (this._selectArray[i] == this.childNodes[this.selectedIndex]) {
              var currItem = this._selectArray[i];
              this._deselectAll();
              var nextItem = aSelectUp ? currItem.previousSibling : currItem.nextSibling;
              if (nextItem) this.selectedIndex = nextItem.index;
              break;
            }
          }
        ]]>
        </body>      
      </method>
	  <constructor action="this._initSelection()"/>
    </implementation>
    <handlers>
      <handler event="mousedown">
      <![CDATA[
        if (event.target.localName != "OPTION")
          return;
          
        for (var i = 0; i < this._selectArray.length; ++i)
          this._selectArray[i].removeAttribute('selected');
        this._selectArray = [event.target];
        event.target.setAttribute("selected", "true");
      ]]>
      </handler>
      <handler event="command" phase="capturing">
      <![CDATA[
        if (event.target.localName == "menuitem") 
          this.selectedItem = event.target;
      ]]>
      </handler>
      <handler event="create">
      <![CDATA[
        if (event.target.parentNode == this && this.selectedItem) {
          // Not ready for auto-setting the active child in hierarchies yet.
          // For now, only do this when the outermost menupopup opens.
          var menuBox = this.boxObject.QueryInterface(Components.interfaces.nsIMenuBoxObject);
          menuBox.activeChild = this.selectedItem;
        }
      ]]>
      </handler>
      
      <!-- Selection Management -->
      <handler event="keypress" keycode="vk_up">
      <![CDATA[
        if (event.target == this)
          this._adjustSelection(true);
        event.preventDefault();
      ]]>
      </handler>
      <handler event="keypress" keycode="vk_down">
      <![CDATA[
        if (event.target == this)
          this._adjustSelection(false);
        event.preventDefault();
      ]]>
      </handler>
      
      
    </handlers>      
  </binding>
 
  <binding id="select" display="xul:menu"
                       extends="resource:///res/builtin/selectBindings.xml#select-base">
    <implementation>
      <property name="value" onget="return this.getAttribute('value');">
        <setter>
        <![CDATA[
          var options = this.getElementsByTagName("option");
          for (var i = 0; i < options.length; ++i) {
            if (options[i].getAttribute("value") == val)
              this._selectArray.push(options[i]);
          }
          this.setAttribute("value", val);            
          return val;
        ]]>
        </setter>
      </property>
      <property name="disabled">
        <getter>
          return this.hasAttribute("disabled");
        </getter>
        <setter>
          if (val == "true") this.setAttribute("disabled", "true");
          else this.removeAttribute("disabled");
          return val;
        </setter>
      </property>
      <property name="selectedIndex">
        <getter>
        <![CDATA[
          if (!this._selectArray)
            return -1;
  
          var options = this.getElementsByTagName("option");
          for (var i = 0; i < options.length; ++i) {
            if (options[i].getAttribute("selected")) 
              return i;
          }
 
          return -1;
        ]]>
        </getter>
        <setter>
        <![CDATA[
          this._selectArray = [];
          
          if (val >= 0 && this.hasChildNodes() && this.childNodes[val]) {
            this.childNodes[val].setAttribute("selected", "true");
            this._selectArray.push(this.childNodes[val]);
             
            var textDisplayNode = this.getElementByAttribute("selectattr", "text");  
            if (textDisplayNode) { 
              var text = this.childNodes[val].text;
              text = text.replace(/\n/g, "");
              textDisplayNode.setAttribute("value", text);
            }
          }
          
          return val;    
        ]]>
        </setter>
      </property>
      
      <!-- Internal Implementation Methods -->
      <method name="getElementByAttribute">
        <parameter name="aAttributeName"/>
        <parameter name="aAttributeValue"/>
        <body>
        <![CDATA[
          var anonymousNodes = document.getAnonymousNodes(this);
          for (var i = 0; i < anonymousNodes.length; ++i)
            return this.recursiveAttributeSearch(anonymousNodes[i], aAttributeName, aAttributeValue);
          return null;
        ]]> 
        </body>
      </method>
      <method name="recursiveAttributeSearch">
        <parameter name="aNode"/>
        <parameter name="aAttributeName"/>
        <parameter name="aAttributeValue"/>
        <body>
        <![CDATA[
          if (aNode) {
            if (aNode.getAttribute(aAttributeName) == aAttributeValue)
              return aNode;
              
            for (var i = 0; i < aNode.childNodes.length; ++i)
              return this.recursiveAttributeSearch(aNode.childNodes[i], aAttributeName, aAttributeValue);
          } 
          return null;
        ]]>
        </body>
      </method>
    </implementation>
    <handlers>
      <handler event="command" phase="capturing">
      <![CDATA[
        if (event.target.localName == "OPTION") 
          this.selectedIndex = event.target.index;
      ]]>
      </handler>
      <handler event="create">
      <![CDATA[
        if (event.target == this && this._selectArray.length) {
          // Not ready for auto-setting the active child in hierarchies yet.
          // For now, only do this when the outermost menupopup opens.
          var boxObject = document.getBoxObjectFor(this);
          var menuBox = boxObject.QueryInterface(Components.interfaces.nsIMenuBoxObject);
          menuBox.activeChild = this._selectArray[0];
        }
      ]]>
      </handler>
      <handler event="mouseover">
      <![CDATA[
        if (event.target.localName == "OPTION") {
          var oldactive = this.getElementByAttribute("menuactive", "true");
          if (oldactive)
            oldactive.removeAttribute("menuactive");
        }
      ]]>
      </handler>
      <handler event="bindingattached" action="this._initSelection()"/>
    </handlers>      
  </binding>
    
  <binding id="option" display="xul:menuitem"
                       extends="resource:///res/builtin/selectBindings.xml#option-base"/>

  <binding id="option-size" display="xul:treerow"
                       extends="resource:///res/builtin/selectBindings.xml#option-base"/>
                         
  <binding id="option-base">
    <implementation>
      <property name="form" readonly="true"/>
      
      <property name="defaultSelected">false</property>
      
      <property name="text" readonly="true">
        <getter>
        <![CDATA[
          var textString = "";
          if (this.hasChildNodes()) {
            for (var i = 0; i < this.childNodes.length; ++i)
              textString += this.childNodes[i].nodeValue;
          }
          return textString;
        ]]>
        </getter>
      </property>
      
      <property name="index" readonly="true">
        <getter>
        <![CDATA[
          var parent = this.parentNode;
          // bail on supporting optgroup at this juncture.
          if (!parent) return -1;
          
          for (var i = 0; i < parent.childNodes.length; ++i) {
            if (parent.childNodes[i] == this) 
              return i;
          }
          return -1;
        ]]>
        </getter>
      </property>
      
      <property name="disabled">
        <getter>
          return this.hasAttribute("disabled");
        </getter>
        <setter>
          if (val) this.setAttribute("disabled", "true");
          else this.removeAttribute("disabled");
        </setter>
      </property>
      
      <property name="label">
        <getter>
          return this.getAttribute("label");
        </getter>
        <setter>
          this.setAttribute("label", val);
          return val;
        </setter>
      </property>
      
      <property name="selected">
        <getter>
          return this.hasAttribute("selected");
        </getter>
        <setter>
          var parent = this.parentNode;
          if (parent)
            parent.selectedIndex = this.index;
          return val;
        </setter>
      </property>
      
      <property name="value">
        <getter>
          return this.getAttribute("value");
        </getter>
        <setter>
          this.setAttribute("value", val);
          return val;
        </setter>
      </property>
      
      <property name="_textNode">
      
      </property>
    </implementation>
  </binding>

</bindings>          

