<?xml version="1.0"?>

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

  <binding id="radiogroup">
    <resources>
      <stylesheet src="chrome://global/skin/radio.css"/>
    </resources>

    <implementation>
      <property name="value" onset="this.setAttribute('value',val); return val;"
                            onget="return this.getAttribute('value');"/>
      <property name="disabled">
        <getter>
        <![CDATA[
            var v = this.getAttribute('disabled');
            return v=='true';
        ]]>
        </getter>
        <setter>
        <![CDATA[
          this.setAttribute('disabled', 'true');
          var groupElements = this.getElementsByAttribute( "group", this.id );
          for( var i = 0; i < groupElements.length; i++ ) {
            if (val)
              groupElements[i].setAttribute("disabled","true");
            else
              groupElements[i].removeAttribute("disabled");
          }
          if (!val)
            this.removeAttribute('disabled');
          return val;
        ]]>
        </setter>
      </property>
      
      <property name="selectedItem">
        <getter>
        <![CDATA[
          this.disabled = this.disabled; // this strange line is to fire the setter for the disabled property
          var groupElements = this.getElementsByAttribute( "group", this.id );
          for( var i = 0; i < groupElements.length; i++ ) {
            if( groupElements[i].checked || 
                groupElements[i].getAttribute( "checked" ) == "true" ) {
              return groupElements[i];
            }
          }
          return null;
        ]]>
        </getter>
        <setter>
        <![CDATA[
          if (this.getAttribute("focused") == "true") 
            val.setAttribute("focused", "true");
          this.value = val.value;

          val.checked = true;
          
          // uncheck all other group nodes
          var groupElements = this.getElementsByAttribute( "group", this.id );
          for( var i = 0; i < groupElements.length; i++ ) {
            if( groupElements[i] != val ) {
              groupElements[i].checked = false;
              groupElements[i].removeAttribute("focused");
            }
          }
          return val;
        ]]>
        </setter>        
      </property>
      
      <property name="focusedItem">
        <getter>
        <![CDATA[
          var groupElements = this.getElementsByAttribute( "group", this.id );
          for( var i = 0; i < groupElements.length; i++ ) {
            if( groupElements[i].getAttribute( "focused" ) == "true" ) {
              return groupElements[i];
            }
          }
          return null;
        ]]>
        </getter>
        <setter>
        <![CDATA[
          if (val) val.setAttribute("focused", "true");
          
          // unfocus all other group nodes
          var groupElements = this.getElementsByAttribute( "group", this.id );
          for( var i = 0; i < groupElements.length; i++ ) {
            if( groupElements[i] != val ) {
                groupElements[i].removeAttribute("focused");
            }
          }
          return val;
        ]]>
        </setter>
      </property>
      
      <method name="checkAdjacentElement">
        <parameter name="aNextFlag"/>
        <body>
        <![CDATA[
          var currentElement = this.focusedItem;
          var groupElements = this.getElementsByAttribute( "group", this.id );
          var index;
          for (var i = 0; i < groupElements.length; i++ ) {
            if (groupElements[i] != currentElement) 
              continue;
            if (aNextFlag) {
              index = (i + 1) % groupElements.length;
              this.selectedItem = groupElements[index];
              break;
            }
            else {              
              index = i > 0 ? i - 1 : groupElements.length - 1;
              this.selectedItem = groupElements[index];
              break;
            }
          }
          this.selectedItem.command();
        ]]>
        </body>
      </method>
    </implementation>
    
    <handlers>
      <handler event="click" button="0">
        <![CDATA[
            if (event.target.localName == "radio" && !event.target.disabled)
              this.selectedItem = event.target;

         ]]>
      </handler>

      <handler event="mousedown" button="0">
        <![CDATA[
            if (event.target.localName == "radio" && !event.target.disabled)
              this.focusedItem = event.target;

         ]]>
      </handler>
     
      <!-- keyboard navigation -->
      <!-- Here's how keyboard navigation works in radio groups on Windows:
           The group takes 'focus'
           The user is then free to navigate around inside the group
           using the arrow keys. Accessing previous or following radio buttons
           is done solely through the arrow keys and not the tab button. Tab
           takes you to the next widget in the tab order -->
      <handler event="keypress" key=" ">
         this.selectedItem = this.focusedItem;
      </handler>
      <handler event="keypress" keycode="VK_UP">
        this.checkAdjacentElement(false);
      </handler>
      <handler event="keypress" keycode="VK_LEFT">
        this.checkAdjacentElement(false);
      </handler>
      <handler event="keypress" keycode="VK_DOWN">
        this.checkAdjacentElement(true);
      </handler>
      <handler event="keypress" keycode="VK_RIGHT">
        this.checkAdjacentElement(true);
      </handler>

      <!-- set a focused attribute on the selected item when the group
           receives focus so that we can style it as if it were focused even though
           it is not (Windows platform behaviour is for the group to receive focus,
           not the item -->
      <handler event="focus">
        if (event.target == this) {
          this.setAttribute("focused", "true");
          if (this.focusedItem == null) this.focusedItem = this.selectedItem;
        }
      </handler>
      <handler event="blur">
        this.removeAttribute("focused");
        this.focusedItem = null;
      </handler>
    </handlers>
  </binding>

  <binding id="radio" extends="chrome://global/content/bindings/checkbox.xml#checkbox-baseline">
    <resources>
      <stylesheet src="chrome://global/skin/radio.css"/>
    </resources>

    <implementation>
      <property name="value" onset="this.setAttribute('value',val); return val;"
                            onget="return this.getAttribute('value');"/>
      <property name="group" onset="this.setAttribute('group',val); return val;"
                            onget="return this.getAttribute('group');"/>
    </implementation>
  </binding>
  

</bindings>