<!-- ***** 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 XForms support.
   -
   - The Initial Developer of the Original Code is
   - Alexander Surkov.
   - Portions created by the Initial Developer are Copyright (C) 2006
   - the Initial Developer. All Rights Reserved.
   -
   - Contributor(s):
   -  Alexander Surkov <surkov@dc.baikal.ru>
   -  Merle Sterling <msterlin@us.ibm.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 GPL or the LGPL. 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 ***** -->

<!DOCTYPE bindings [
<!ENTITY % xformsDTD SYSTEM "chrome://xforms/locale/xforms.dtd">
  %xformsDTD;
]>

<bindings id="widgetsBindingsForXUL"
          xmlns="http://www.mozilla.org/xbl"
          xmlns:xbl="http://www.mozilla.org/xbl"
          xmlns:html="http://www.w3.org/1999/xhtml"
          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns:mozType="http://www.mozilla.org/projects/xforms/2005/type">


<!--
  The file contains auxiliary controls implementations for XUL context. The
  controls are inherited from bindings defined in 'widgets.xml' file.
-->


<!-- CALENDAR WIDGETS -->

  <!-- COMPACT CALENDAR -->
  <binding id="calendar-compact"
           extends="chrome://xforms/content/widgets.xml#calendar-compact-base">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:grid role="grid">
        <xul:columns>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
        </xul:columns>
        <xul:rows anonid="dayContainer"/>
      </xul:grid>
    </content>

    <implementation>
    <!-- interface -->

      <!-- Set type and label for the day control element -->
      <method name="setDayControl">
        <parameter name="aControl"/>
        <parameter name="aType"/>
        <parameter name="aLabel"/>
        <body>
          aControl.setAttribute("label", aLabel);
          aControl.setAttribute("class", aType);
        </body>
      </method>

      <!-- Select day control element -->
      <method name="selectDayControl">
        <parameter name="aControl"/>
        <body>
          if (aControl)
            aControl.setAttribute("checked", "true");
        </body>
      </method>

      <!-- Unselect day control element -->
      <method name="unselectDayControl">
        <parameter name="aControl"/>
        <body>
          if (aControl)
            aControl.removeAttribute("checked");
        </body>
      </method>

      <!-- Return true if node is control element for a day -->
      <method name="isDayControl">
        <parameter name="aNode"/>
        <body>
          if (aNode.localName != "toolbarbutton" ||
              aNode.namespaceURI != this.XUL_NS)
            return false;
          return true;
        </body>
      </method>

      <method name="buildUIInternal">
        <body>
          <![CDATA[
          var dayOfWeekNames = this.getDaysOfWeekNames();

          var row = document.createElementNS(this.XUL_NS, "row");

          // create days of a week names
          var header, description;
          for (var i = 0; i < 7; i++) {
            description = this.ownerDocument.createElementNS(this.XUL_NS,
                                                             "description");
            description.setAttribute("value", dayOfWeekNames[i]);
            description.setAttribute("class", "header");
            description.setAttribute("role", "columnheader");
            row.appendChild(description);
          }
          this.dayContainer.appendChild(row);

          // create days
          var cell;
          for (var i = 0; i < 6; i++) {
            row = document.createElementNS(this.XUL_NS, "row");

            for (var y = 0; y < 7; y++) {
              var button  = this.ownerDocument.createElementNS(this.XUL_NS,
                                                               "toolbarbutton");
              button.setAttribute("tabindex", "-1");
              button.setAttribute("role", "gridcell");
              this._dayElements.push(button);
              row.appendChild(button);
            }
            this.dayContainer.appendChild(row);
          }
        ]]>
        </body>
      </method>

      <method name="buildUI">
        <body>
          this.buildUIInternal();
        </body>
      </method>

      <property name="XHTML_NS" readonly="true"
                onget="return 'http://www.w3.org/1999/xhtml';"/>

      <property name="XUL_NS" readonly="true"
                onget="return 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';"/>

      <!-- Return container of controls for days -->
      <property name="dayContainer" readonly="true">
        <getter>
          if (!this._dayContainer)
            this._dayContainer = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "dayContainer");
          return this._dayContainer;
        </getter>
      </property>
      <field name="_dayContainer">null</field>
    </implementation>

    <handlers>
      <handler event="command">
        var target = event.originalTarget;
        if (this.isDayControl(target))
          this.processAction(target.getAttribute("class"),
                             target.getAttribute('label'));
      </handler>

      <handler event="keypress" phase="capturing">
      <![CDATA[
        // Stop event propagation to prevent event processing of
        // button binding, i.e. to prevent default behaviour of button
        // that is to advance/rewind focus on arrow keys.
        if (event.originalTarget.namespaceURI == this.XUL_NS &&
            event.originalTarget.localName == "toolbarbutton") {
          switch (event.keyCode) {
            case event.DOM_VK_UP:
            case event.DOM_VK_DOWN:
            case event.DOM_VK_LEFT:
            case event.DOM_VK_RIGHT:
              event.stopPropagation();
              break;
          }
        }
      ]]>
      </handler>
    </handlers>
  </binding>


  <!-- FULL CALENDAR -->
  <binding id="calendar-full" extends="#calendar-compact">
    <content orient="vertical">
      <xul:hbox mozType:monthyearbox="true" anonid="monthyear"/>
      <!-- calendar days container-->
      <xul:grid role="grid">
        <xul:columns>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
          <xul:column flex="1"/>
        </xul:columns>
        <xul:rows anonid="dayContainer"/>
      </xul:grid>
    </content>

    <implementation>
    <!-- interface -->
      <!-- Update UI -->
      <method name="refresh">
        <parameter name="aCurrentDay"/>
        <parameter name="aDaysRefreshOnly"/>
        <body>
          this.refreshInternal(aCurrentDay, aDaysRefreshOnly);

          this.monthyearBox.month = this.month - 1;
          this.monthyearBox.year = this.year;
        </body>
      </method>

    <!-- private -->
      <constructor>
        var handler = {
          handleEvent: function handleEvent(aEvent) {
            this.widget.setDate(this.monthyear.year, this.monthyear.month + 1);
          },
          widget: this,
          monthyear: this.monthyearBox
        };
        this.monthyearBox.addEventListener("change", handler, false);
      </constructor>

      <property name="monthyearBox" readonly="true">
        <getter>
          if (!this._monthyearBox) {
            this._monthyearBox = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "monthyear");
          }
          return this._monthyearBox;
        </getter>
      </property>
      <field name="_monthyearBox">null</field>
    </implementation>

    <handlers>
      <handler event="keypress" keycode="VK_TAB">
        if (!this.hasAttribute("internaltabhandling"))
          return;

        event.preventDefault();

        if (this.monthyearBox.isMonthFocused())
          this.monthyearBox.focusYear();
        else if (this.monthyearBox.isYearFocused())
          this.focus();
        else
          this.monthyearBox.focusMonth();
      </handler>

      <handler event="keypress" keycode="VK_TAB" modifiers="shift">
        if (!this.hasAttribute("internaltabhandling"))
          return;

        event.preventDefault();

        if (this.monthyearBox.isMonthFocused())
          this.focus();
        else if (this.monthyearBox.isYearFocused())
          this.monthyearBox.focusMonth();
        else
          this.monthyearBox.focusYear();
      </handler>
    </handlers>
  </binding>


  <!-- DROPMARKER -->
  <binding id="dropmarker" extends="xul:button">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:image class="dropmarker-icon"/>
    </content>

    <implementation implements="nsIAccessibleProvider">
      <property name="accessibleType" readonly="true">
        <getter>
          return Components.interfaces.nsIAccessibleProvider.XFormsDropmarkerWidget;
        </getter>
      </property>
    </implementation>
  </binding>

  <!-- SPINBUTTONS
       Copied from \mozilla\toolkit\content\widgets\spinbuttons.xml.
       The spinbuttons widget may be used as anonymous content in
       either xul or xhtml bindngs.
  -->
  <binding id="spinbuttons"
           extends="chrome://global/content/bindings/general.xml#basecontrol">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:vbox class="spinbuttons-box" flex="1">
        <xul:button anonid="increaseButton" type="repeat" flex="1"
                    class="spinbuttons-button spinbuttons-up"
                    xbl:inherits="disabled,disabled=increasedisabled"/>
        <xul:button anonid="decreaseButton" type="repeat" flex="1"
                    class="spinbuttons-button spinbuttons-down"
                    xbl:inherits="disabled,disabled=decreasedisabled"/>
      </xul:vbox>
    </content>

    <implementation>
      <property name="_increaseButton" readonly="true">
        <getter>
          return document.getAnonymousElementByAttribute(this, "anonid", "increaseButton");
        </getter>
      </property>
      <property name="_decreaseButton" readonly="true">
        <getter>
          return document.getAnonymousElementByAttribute(this, "anonid", "decreaseButton");
        </getter>
      </property>

      <property name="increaseDisabled"
                onget="return this._increaseButton.getAttribute('disabled');"
                onset="if (val) this._increaseButton.setAttribute('disabled', 'true');
                       else this._increaseButton.removeAttribute('disabled'); return val;"/>
      <property name="decreaseDisabled"
                onget="return this._decreaseButton.getAttribute('disabled');"
                onset="if (val) this._decreaseButton.setAttribute('disabled', 'true');
                       else this._decreaseButton.removeAttribute('disabled'); return val;"/>

    </implementation>

    <handlers>
      <handler event="mousedown">
        <![CDATA[
          // on the Mac, the native theme draws the spinbutton as a single widget
          // so a state attribute is set based on where the mouse button was pressed
          if (event.originalTarget == this._increaseButton)
            this.setAttribute("state", "up");
          else if (event.originalTarget == this._decreaseButton)
            this.setAttribute("state", "down");
        ]]>
      </handler>
      
      <handler event="mouseup">
        this.removeAttribute("state");
      </handler>
      <handler event="mouseout">
        this.removeAttribute("state");
      </handler>

      <handler event="command">
        <![CDATA[
        var eventname;
        if (event.originalTarget == this._increaseButton)
          eventname = "up";
        else if (event.originalTarget == this._decreaseButton)
          eventname = "down";

        var evt = document.createEvent("Events");
        evt.initEvent(eventname, true, true);
        var cancel = this.dispatchEvent(evt);
        if (this.hasAttribute("on" + eventname)) {
          var fn = new Function("event", this.getAttribute("on" + eventname));
          if (fn.call(this, event) == false)
            cancel = true;
        }

        return !cancel;
        ]]>
      </handler>

    </handlers>
  </binding>

  <!-- NUMBERBOX
       Copied from \mozilla\toolkit\content\widgets\numberbox.xml with minor
       modifications. The numberbox widget may be used as anonymous content in
       either xul or xhtml bindngs.
  -->
  <binding id="numberbox"
           extends="chrome://global/content/bindings/textbox.xml#textbox">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:hbox class="textbox-input-box numberbox-input-box" flex="1" xbl:inherits="context">
        <html:input class="numberbox-input textbox-input" flex="1" anonid="input"
                    xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,tabindex,accesskey"/>
      </xul:hbox>
      <xul:spinbuttons anonid="buttons" xbl:inherits="disabled,hidden=hidespinbuttons"
                       onup="this.parentNode._modifyUp();"
                       ondown="this.parentNode._modifyDown();"/>
    </content>

    <implementation>
      <field name="_valueEntered">false</field>
      <field name="_spinButtons">null</field>
      <field name="_value">0</field>
      <field name="decimalSymbol">"."</field>

      <property name="spinButtons" readonly="true">
        <getter>
          <![CDATA[
            if (!this._spinButtons)
              this._spinButtons = document.getAnonymousElementByAttribute(this, "anonid", "buttons");
            return this._spinButtons;
          ]]>
        </getter>
      </property>

      <property name="value">
        <getter>
          if (this._valueEntered) {
            var newval = this.inputField.value;
            newval = newval.replace(this.decimalSymbol, ".");
            this._validateValue(newval, false);
          }
          return this._value;
        </getter>
        <setter>
          return this._validateValue(val, false);
        </setter>
      </property>

      <property name="wrapAround">
        <getter>
        <![CDATA[
          return (this.getAttribute('wraparound') == 'true')
        ]]>
        </getter>
        <setter>
        <![CDATA[
          if (val)
            this.setAttribute('wraparound', 'true');
          else
            this.removeAttribute('wraparound');
          this._enableDisableButtons();
          return val;
        ]]>
        </setter>
      </property>

      <property name="min">
        <getter>
          var min = this.getAttribute("min");
          return min ? Number(min) : 0;
        </getter>
        <setter>
        <![CDATA[
          if (typeof val == "number") {
            this.setAttribute("min", val);
            if (this.value <= val)
              this._validateValue(val, false);
          }
          return val;
        ]]>
        </setter>
      </property>

      <property name="max">
        <getter>
          var max = this.getAttribute("max");
          return max ? Number(max) : Infinity;
        </getter>
        <setter>
        <![CDATA[
          if (typeof val != "number")
            return val;
          var min = this.min;
          if (val <= min)
            val = min;
          this.setAttribute("max", val);
          if (this.value >= val)
            this._validateValue(val, false);
          return val;
        ]]>
        </setter>
      </property>

      <property name="decimalPlaces">
        <getter>
          var places = this.getAttribute("decimalplaces");
          return places ? Number(places) : 0;
        </getter>
        <setter>
          if (typeof val == "number") {
            this.setAttribute("decimalplaces", val);
            this._validateValue(this.value, false);
          }
          return val;
        </setter>
      </property>

      <property name="increment">
        <getter>
          var increment = this.getAttribute("increment");
          return increment ? Number(increment) : 1;
        </getter>
        <setter>
        <![CDATA[
          if (typeof val == "number")
            this.setAttribute("increment", val);
        ]]>
        </setter>
      </property>

      <method name="decrease">
        <body>
          return this._validateValue(this.value - this.increment, true);
        </body>
      </method>

      <method name="increase">
        <body>
          return this._validateValue(this.value + this.increment, true);
        </body>
      </method>

      <method name="_modifyUp">
        <body>
          <![CDATA[
            if (this.disabled || this.readOnly)
              return;

            var oldval = this.value;
            var newval = this.increase();
            this.inputField.select();
            if (oldval != newval) {
              this._fireChange();
              this._fireSpinEvent("spinup");
            }
          ]]>
        </body>
      </method>
      <method name="_modifyDown">
        <body>
          <![CDATA[
            if (this.disabled || this.readOnly)
              return;

            var oldval = this.value;
            var newval = this.decrease();
            this.inputField.select();
            if (oldval != newval) {
              this._fireChange();
              this._fireSpinEvent("spindown");
            }
          ]]>
        </body>
      </method>

      <method name="_enableDisableButtons">
        <body>
          <![CDATA[
            var buttons = this.spinButtons;
            if (this.disabled || this.readOnly) {
              buttons.disabled = true;
            }
            else {
              buttons.decreaseDisabled = (this.value <= this.min);
              buttons.increaseDisabled = (this.value >= this.max);
            }
          ]]>
        </body>
      </method>

      <!-- Adust the value as necessary so that it remains between the current
           values of the min and max attributes.

           aValue: Value to be validated.
           aIsIncDec: Value being changed due to increment/decrement from
           spinbuttons or keypress (as opposed to direct entry)?
      -->
      <method name="_validateValue">
        <parameter name="aValue"/>
        <parameter name="aIsIncDec"/>
        <body>
          <![CDATA[
            aValue = Number(aValue) || 0;

            var min = this.min;
            var max = this.max;

            // If the min and max attributes are finite values and
            // the wraparound attribute is true, we allow a value at
            // the maximum to wraparound to the minimum on increment
            // events and a value at the minimum to wraparound to the
            // maximum on decrement events.
            var wrapAround = this.wrapAround &&
                             min != -Infinity && max != Infinity;
            if (aValue <= min)
              aValue = (aIsIncDec && wrapAround ? max : min);
            else if (aValue >= max)
              aValue = (aIsIncDec && wrapAround ? min : max);

            // Round the value to specified number of decimal places.
            var places = this.decimalPlaces;
            if (places != Infinity)
              aValue = aValue.toFixed(places);

            this._valueEntered = false;
            this._value = Number(aValue);

            // Localization: use the correct decimal symbol.
            this.inputField.value = aValue.replace(/\./, this.decimalSymbol);

            if (!wrapAround)
              this._enableDisableButtons();

            return aValue;
          ]]>
        </body>
      </method>

      <!-- Fire change event. -->
      <method name="_fireChange">
        <body>
          var evt = document.createEvent("Events");
          evt.initEvent("change", true, true);
          this.dispatchEvent(evt);
        </body>
      </method>

      <!-- Fire spinup or spindown event. -->
      <method name="_fireSpinEvent">
        <parameter name="eventname"/>
        <body>
          var evt = document.createEvent("Events");
          evt.initEvent(eventname, true, false);
          this.dispatchEvent(evt);
        </body>
      </method>

      <constructor><![CDATA[
        if (this.max < this.min)
          this.max = this.min;

        var dsymbol = (Number(5.4)).toLocaleString().match(/\D/);
        if (dsymbol != null)
          this.decimalSymbol = dsymbol[0];

        var value = this.inputField.value || 0;
        this._validateValue(value, false);
      ]]></constructor>

    </implementation>

    <handlers>
      <handler event="input">
        this._valueEntered = true;
      </handler>

      <handler event="keypress">
        <![CDATA[
          if (!event.ctrlKey && !event.metaKey && !event.altKey && event.charCode) {
            if (event.charCode == this.decimalSymbol.charCodeAt(0) &&
                this.decimalPlaces &&
                String(this.inputField.value).indexOf(this.decimalSymbol) == -1)
              return;

            // charCode 45 == '-'
            if (event.charCode == 45 && this.min < 0)
              return;

            // charCode 48-57 == numbers 0-9.
            if (event.charCode < 48 || event.charCode > 57)
              event.preventDefault();
          }
        ]]>
      </handler>

      <handler event="keypress" keycode="VK_UP" phase="capturing">
        this._modifyUp();
      </handler>

      <handler event="keypress" keycode="VK_DOWN" phase="capturing">
        this._modifyDown();
      </handler>

      <handler event="change">
        if (event.originalTarget == this.inputField) {
          var newval = this.inputField.value;
          newval = newval.replace(this.decimalSymbol, ".");
          this._validateValue(newval, false);
        }
      </handler>
    </handlers>
  </binding>


  <!-- MONTHBOX -->
  <binding id="monthbox"
           extends="chrome://global/content/bindings/textbox.xml#textbox">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:hbox class="textbox-input-box numberbox-input-box" flex="1"
                xbl:inherits="context">
        <html:input class="numberbox-input textbox-input" flex="1"
                    anonid="input" readonly="true"
                    xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,tabindex,accesskey"/>
      </xul:hbox>
      <xul:spinbuttons anonid="buttons"
                       xbl:inherits="disabled,hidden=hidespinbuttons"
                       onup="this.parentNode._modifyUp();"
                       ondown="this.parentNode._modifyDown();"/>
    </content>

    <implementation>
      <property name="value"
                onget="return this.monthValues[this.inputField.value];">
        <setter>
        <![CDATA[
          if (val < 0)
            val = 11;
          else if (val > 11)
            val = 0;

          if (!this.monthNames.length) {
            for (var month = 0; month < 12; month++) {
              var loc = new Date(1970, month).toLocaleFormat("%B");
              this.monthNames.push(loc);
              this.monthValues[loc] = month;
            }
          }

          this.inputField.value = this.monthNames[val];
        ]]>
        </setter>
      </property>

      <method name="_modifyUp">
        <body>
          this.value++;
          this.fireEvent("change");
          this.fireEvent("spinup");
        </body>
      </method>

      <method name="_modifyDown">
        <body>
          this.value--;
          this.fireEvent("change");
          this.fireEvent("spindown");
        </body>
      </method>

      <method name="fireEvent">
        <parameter name="aName"/>
        <body>
          var evt = document.createEvent("Events");
          evt.initEvent(aName, true, false);
          this.dispatchEvent(evt);
        </body>
      </method>

      <constructor>
        if (this.value == undefined)
          this.value = 0;
      </constructor>

      <field name="monthNames">new Array()</field>
      <field name="monthValues">new Object()</field>
    </implementation>

    <handlers>
      <handler event="keydown" keycode="VK_UP">
        this._modifyUp();
      </handler>
      <handler event="keypress" keycode="VK_DOWN">
        this._modifyDown();
      </handler>
    </handlers>
  </binding>


  <binding id="monthyearbox">
    <content>
      <xul:textbox type="month" anonid="month" size="10" flex="1"/>
      <xul:textbox type="number" anonid="year" size="4"/>
    </content>

    <implementation>
    <!-- interface -->
      <property name="year"
                onget="return this.yearField.value;"
                onset="this.yearField.value = val;"/>

      <property name="month"
                onget="return this.monthField.value;"
                onset="this.monthField.value = val;"/>

      <method name="focusMonth">
        <body>
          this.monthField.focus();
        </body>
      </method>

      <method name="focusYear">
        <body>
          this.yearField.focus();
        </body>
      </method>

      <method name="isMonthFocused">
        <body>
          return this.getFocusedElement() == this.monthField;
        </body>
      </method>

      <method name="isYearFocused">
        <body>
          return this.getFocusedElement() == this.yearField;
        </body>
      </method>

    <!-- private -->
      <method name="getFocusedElement">
        <body>
          var focused = this.ownerDocument.commandDispatcher.focusedElement;
          if (!focused)
            return;

          var binding = this.ownerDocument.getBindingParent(focused);
          return binding;
        </body>
      </method>

      <constructor>
        var handler = {
          handleEvent: function handleEvent(aEvent) {
            if (aEvent.type == "spinup") {
              if (this.widget.month == 0)
                this.widget.year++;
            } else if (this.widget.month == 11) {
              this.widget.year--;
            }
          },
          widget: this
        };
        this.monthField.addEventListener("spinup", handler, false);
        this.monthField.addEventListener("spindown", handler, false);
      </constructor>

      <property name="monthField" readonly="true">
        <getter>
          if (!this._monthField)
            this._monthField = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "month");
          return this._monthField;
        </getter>
      </property>
      <field name="_monthField">null</field>

      <property name="yearField" readonly="true">
        <getter>
          if (!this._yearField)
            this._yearField = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "year");
          return this._yearField;
        </getter>
      </property>
      <field name="_yearField">null</field>
    </implementation>
  </binding>

  <!-- DATETIME RANGE-->
  <binding id="range-datetime"
           extends="chrome://xforms/content/widgets.xml#datetime">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:label value="" anonid="minLabel"/>
      <xul:box class="range-box">
        <xul:label control="yearSpin" value="&xforms.date.year.label;"/>
        <xul:textbox type="number" size="3" anonid="yearSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="monthSpin" value="&xforms.date.month.label;"/>
        <xul:textbox type="number" size="1" anonid="monthSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="daySpin" value="&xforms.date.day.label;"/>
        <xul:textbox type="number" size="1" anonid="daySpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="hoursSpin" value="&xforms.time.hours.label;"/>
        <xul:textbox type="number" size="1" anonid="hoursSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="minutesSpin" value="&xforms.time.minutes.label;"/>
        <xul:textbox type="number" size="1" anonid="minutesSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="secondsSpin" value="&xforms.time.seconds.label;"/>
        <xul:textbox type="number" size="1" anonid="secondsSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:label value="" anonid="maxLabel"/>
    </content>

    <implementation>
      <method name="updateLabels">
        <body>
        <![CDATA[
          this.minLabel.value = this.start + this._startSeparator;
          this.maxLabel.value = this._endSeparator + this.end;
        ]]>
        </body>
      </method>

      <method name="updateValue">
        <body>
        <![CDATA[
          var year = this.yearSpin.value.toString();
          year = this.formatValue(year, 4);

          var month = this.monthSpin.value.toString();
          month = this.formatValue(month, 2);

          var day = this.daySpin.value.toString();
          day = this.formatValue(day, 2);

          var hours = this.hoursSpin.value.toString();
          hours = this.formatValue(hours, 2);

          var minutes = this.minutesSpin.value.toString();
          minutes = this.formatValue(minutes, 2);

          var seconds = this.secondsSpin.value.toString();
          seconds = this.formatValue(seconds, 2);

          var value = year + "-" + month + "-" + day + "T" +
                      hours + ":" + minutes + ":" + seconds;

          this.setAttribute("value", value);
        ]]>
        </body>
      </method>

      <method name="updateFields">
        <body>
        <![CDATA[
          var value = this.value;
          
          // Date
          this.yearSpin.value = this.getYear(value);
          this.monthSpin.value = this.getMonth(value);
          this.daySpin.value = this.getDay(value);
      
          // Time
          this.hoursSpin.value = this.getHours(value);
          this.minutesSpin.value = this.getMinutes(value);
          this.secondsSpin.value = this.getSeconds(value);
        ]]>
        </body>
      </method>

      <method name="setSpinbuttonMinMax">
        <body>
        <![CDATA[
          // Date
          // Year
          this.yearSpin.min = this.getYearMin();
          this.yearSpin.max = this.getYearMax();
          // Month
          this.monthSpin.min = this.getMonthMin();
          this.monthSpin.max = this.getMonthMax();
          // Day
          this.daySpin.min = this.getDayMin();
          this.daySpin.max = this.getDayMax();

          // Time
          // Hours
          this.hoursSpin.min = this.getHoursMin();
          this.hoursSpin.max = this.getHoursMax();
          // Minutes
          this.minutesSpin.min = this.getMinutesMin();
          this.minutesSpin.max = this.getMinutesMax();
          // Seconds
          this.secondsSpin.min = this.getSecondsMin();
          this.secondsSpin.max = this.getSecondsMax();
        ]]>
        </body>
      </method>

      <method name="isInRange">
        <parameter name="aValue"/>
        <body>
        <![CDATA[
          var startDate = this.getDate(this.start);
          var endDate = this.getDate(this.end);
          var currentDate = this.getDate(aValue);
          return startDate <= currentDate && currentDate <= endDate;
        ]]>
        </body>
      </method>

      <!-- Private -->
      <property name="minLabel" readonly="true">
        <getter>
          if (!this._minLabel) {
            this._minLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "minLabel");
          }
          return this._minLabel;
        </getter>
      </property>
      <field name="_minLabel">null</field>

      <property name="yearSpin" readonly="true">
        <getter>
          if (!this._yearSpin) {
            this._yearSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "yearSpin");
          }
          return this._yearSpin;
        </getter>
      </property>
      <field name="_yearSpin">null</field>

      <property name="monthSpin" readonly="true">
        <getter>
          if (!this._monthSpin) {
            this._monthSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "monthSpin");
          }
          return this._monthSpin;
        </getter>
      </property>
      <field name="_monthSpin">null</field>

      <property name="daySpin" readonly="true">
        <getter>
          if (!this._daySpin) {
            this._daySpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "daySpin");
          }
          return this._daySpin;
        </getter>
      </property>
      <field name="_daySpin">null</field>

      <property name="hoursSpin" readonly="true">
        <getter>
          if (!this._hoursSpin) {
            this._hoursSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "hoursSpin");
          }
          return this._hoursSpin;
        </getter>
      </property>
      <field name="_hoursSpin">null</field>

      <property name="minutesSpin" readonly="true">
        <getter>
          if (!this._minutesSpin) {
            this._minutesSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "minutesSpin");
          }
          return this._minutesSpin;
        </getter>
      </property>
      <field name="_minutesSpin">null</field>

      <property name="secondsSpin" readonly="true">
        <getter>
          if (!this._secondsSpin) {
            this._secondsSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "secondsSpin");
          }
          return this._secondsSpin;
        </getter>
      </property>
      <field name="_secondsSpin">null</field>

      <property name="maxLabel" readonly="true">
        <getter>
          if (!this._maxLabel) {
            this._maxLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "maxLabel");
          }
          return this._maxLabel;
        </getter>
      </property>
      <field name="_maxLabel">null</field>
    </implementation>
  </binding>

  <!-- DATE RANGE-->
  <binding id="range-date"
           extends="chrome://xforms/content/widgets.xml#date">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:label value="" anonid="minLabel"/>
      <xul:box class="range-box">
        <xul:label control="yearSpin" value="&xforms.date.year.label;"/>
        <xul:textbox type="number" size="3" anonid="yearSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="monthSpin" value="&xforms.date.month.label;"/>
        <xul:textbox type="number" size="1" anonid="monthSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="daySpin" value="&xforms.date.day.label;"/>
        <xul:textbox type="number" size="1" anonid="daySpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:label value="" anonid="maxLabel"/>
    </content>

    <implementation>
      <method name="updateLabels">
        <body>
        <![CDATA[
          this.minLabel.value = this.start + this._startSeparator;
          this.maxLabel.value = this._endSeparator + this.end;
        ]]>
        </body>
      </method>

      <method name="updateValue">
        <body>
        <![CDATA[
          var year = this.yearSpin.value.toString();
          year = this.formatValue(year, 4);

          var month = this.monthSpin.value.toString();
          month = this.formatValue(month, 2);

          var day = this.daySpin.value.toString();
          day = this.formatValue(day, 2);

          var value = year + "-" + month + "-" + day;
          this.setAttribute("value", value);
        ]]>
        </body>
      </method>

      <method name="updateFields">
        <body>
        <![CDATA[
          var value = this.value;
          
          this.yearSpin.value = this.getYear(value);
          this.monthSpin.value = this.getMonth(value);
          this.daySpin.value = this.getDay(value);
        ]]>
        </body>
      </method>

      <method name="setSpinbuttonMinMax">
        <body>
        <![CDATA[
          // Year
          this.yearSpin.min = this.getYearMin();
          this.yearSpin.max = this.getYearMax();
          // Month
          this.monthSpin.min = this.getMonthMin();
          this.monthSpin.max = this.getMonthMax();
          // Day
          this.daySpin.min = this.getDayMin();
          this.daySpin.max = this.getDayMax();
        ]]>
        </body>
      </method>

      <method name="isInRange">
        <parameter name="aValue"/>
        <body>
        <![CDATA[
          var startDate = this.getDate(this.start);
          var endDate = this.getDate(this.end);
          var currentDate = this.getDate(aValue);
          return startDate <= currentDate && currentDate <= endDate;
        ]]>
        </body>
      </method>

      <!-- Private -->
      <property name="minLabel" readonly="true">
        <getter>
          if (!this._minLabel) {
            this._minLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "minLabel");
          }
          return this._minLabel;
        </getter>
      </property>
      <field name="_minLabel">null</field>

      <property name="yearSpin" readonly="true">
        <getter>
          if (!this._yearSpin) {
            this._yearSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "yearSpin");
          }
          return this._yearSpin;
        </getter>
      </property>
      <field name="_yearSpin">null</field>

      <property name="monthSpin" readonly="true">
        <getter>
          if (!this._monthSpin) {
            this._monthSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "monthSpin");
          }
          return this._monthSpin;
        </getter>
      </property>
      <field name="_monthSpin">null</field>

      <property name="daySpin" readonly="true">
        <getter>
          if (!this._daySpin) {
            this._daySpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "daySpin");
          }
          return this._daySpin;
        </getter>
      </property>
      <field name="_daySpin">null</field>

      <property name="maxLabel" readonly="true">
        <getter>
          if (!this._maxLabel) {
            this._maxLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "maxLabel");
          }
          return this._maxLabel;
        </getter>
      </property>
      <field name="_maxLabel">null</field>
    </implementation>
  </binding>

  <!-- TIME RANGE-->
  <binding id="range-time"
           extends="chrome://xforms/content/widgets.xml#time">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:label value="" anonid="minLabel"/>
      <xul:box class="range-box">
        <xul:label control="hoursSpin" value="&xforms.time.hours.label;"/>
        <xul:textbox type="number" size="1" anonid="hoursSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="minutesSpin" value="&xforms.time.minutes.label;"/>
        <xul:textbox type="number" size="1" anonid="minutesSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="secondsSpin" value="&xforms.time.seconds.label;"/>
        <xul:textbox type="number" size="1" anonid="secondsSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:label value="" anonid="maxLabel"/>
    </content>

    <implementation>
      <method name="updateLabels">
        <body>
        <![CDATA[
          this.minLabel.value = this.start + this._startSeparator;
          this.maxLabel.value = this._endSeparator + this.end;
        ]]>
        </body>
      </method>

      <method name="updateValue">
        <body>
        <![CDATA[
          var hours = this.hoursSpin.value.toString();
          hours = this.formatValue(hours, 2);

          var minutes = this.minutesSpin.value.toString();
          minutes = this.formatValue(minutes, 2);

          var seconds = this.secondsSpin.value.toString();
          seconds = this.formatValue(seconds, 2);

          var value = hours + ":" + minutes + ":" + seconds;

          this.setAttribute("value", value);
        ]]>
        </body>
      </method>

      <method name="updateFields">
        <body>
        <![CDATA[
          var value = this.value;
          
          this.hoursSpin.value = this.getHours(value);
          this.minutesSpin.value = this.getMinutes(value);
          this.secondsSpin.value = this.getSeconds(value);
        ]]>
        </body>
      </method>

      <method name="setSpinbuttonMinMax">
        <body>
        <![CDATA[
          // Hours
          this.hoursSpin.min = this.getHoursMin();
          this.hoursSpin.max = this.getHoursMax();
          // Minutes
          this.minutesSpin.min = this.getMinutesMin();
          this.minutesSpin.max = this.getMinutesMax();
          // Seconds
          this.secondsSpin.min = this.getSecondsMin();
          this.secondsSpin.max = this.getSecondsMax();
        ]]>
        </body>
      </method>

      <method name="isInRange">
        <parameter name="aValue"/>
        <body>
        <![CDATA[
          var startTime = this.getDate(this.start);
          var endTime = this.getDate(this.end);
          var currentTime = this.getDate(aValue);
          return startTime <= currentTime && currentTime <= endTime;
        ]]>
        </body>
      </method>

      <!-- Private -->
      <property name="minLabel" readonly="true">
        <getter>
          if (!this._minLabel) {
            this._minLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "minLabel");
          }
          return this._minLabel;
        </getter>
      </property>
      <field name="_minLabel">null</field>

      <property name="hoursSpin" readonly="true">
        <getter>
          if (!this._hoursSpin) {
            this._hoursSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "hoursSpin");
          }
          return this._hoursSpin;
        </getter>
      </property>
      <field name="_hoursSpin">null</field>

      <property name="minutesSpin" readonly="true">
        <getter>
          if (!this._minutesSpin) {
            this._minutesSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "minutesSpin");
          }
          return this._minutesSpin;
        </getter>
      </property>
      <field name="_minutesSpin">null</field>

      <property name="secondsSpin" readonly="true">
        <getter>
          if (!this._secondsSpin) {
            this._secondsSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "secondsSpin");
          }
          return this._secondsSpin;
        </getter>
      </property>
      <field name="_secondsSpin">null</field>

      <property name="maxLabel" readonly="true">
        <getter>
          if (!this._maxLabel) {
            this._maxLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "maxLabel");
          }
          return this._maxLabel;
        </getter>
      </property>
      <field name="_maxLabel">null</field>
    </implementation>
  </binding>


  <!-- NUMERIC SPIN RANGE-->
  <binding id="range-numeric-spin"
           extends="chrome://xforms/content/widgets.xml#range">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:label value="" anonid="minLabel"/>
      <xul:box class="range-box">
        <xul:label control="spinValue" value="" anonid="spinLabel"/>
        <xul:textbox type="number" size="1" anonid="spinValue"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:label value="" anonid="maxLabel"/>
    </content>

    <implementation>
      <method name="updateLabels">
        <body>
        <![CDATA[
          this.minLabel.value = this.start + this._startSeparator;
          this.maxLabel.value = this._endSeparator + this.end;
        ]]>
        </body>
      </method>

      <method name="updateFields">
        <body>
        <![CDATA[
          this.spinValue.value = this.getNumericValue(this.value);
        ]]>
        </body>
      </method>

      <method name="setSpinbuttonMinMax">
        <body>
        <![CDATA[
          this.spinValue.min = this.getNumericValue(this.start);
          this.spinValue.max = this.getNumericValue(this.end);
        ]]>
        </body>
      </method>

      <method name="isInRange">
        <parameter name="aValue"/>
        <body>
        <![CDATA[
          return this.start <= aValue && aValue <= this.end;
        ]]>
        </body>
      </method>

      <method name="getNumericValue">
        <parameter name="aValue"/>
        <body>
        <![CDATA[
          return parseFloat(aValue);
        ]]>
        </body>
      </method>

      <!-- Private -->
      <property name="minLabel" readonly="true">
        <getter>
          if (!this._minLabel) {
            this._minLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "minLabel");
          }
          return this._minLabel;
        </getter>
      </property>
      <field name="_minLabel">null</field>

      <property name="spinLabel" readonly="true">
        <getter>
          if (!this._spinLabel) {
            this._spinLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "spinLabel");
          }
          return this._spinLabel;
        </getter>
      </property>
      <field name="_spinLabel">null</field>

      <property name="spinValue" readonly="true">
        <getter>
          if (!this._spinValue) {
            this._spinValue = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "spinValue");
          }
          return this._spinValue;
        </getter>
      </property>
      <field name="_spinValue">null</field>

      <property name="maxLabel" readonly="true">
        <getter>
          if (!this._maxLabel) {
            this._maxLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "maxLabel");
          }
          return this._maxLabel;
        </getter>
      </property>
      <field name="_maxLabel">null</field>
    </implementation>
  </binding>

  <!-- GDAY RANGE-->
  <binding id="range-gday"
           extends="#range-numeric-spin">

    <implementation>
      <field name="_daySpinLabel">&xforms.date.day.label.field;</field>

      <method name="updateValue">
        <body>
        <![CDATA[
          var value = this.spinValue.value.toString();
          value = this.formatValue(value, 2);

          this.setAttribute("value", value);
        ]]>
        </body>
      </method>

      <!-- private -->
      <constructor>
        this.spinLabel.value = this._daySpinLabel;
      </constructor>
    </implementation>
  </binding>

  <!-- GMONTH RANGE-->
  <binding id="range-gmonth"
           extends="#range-numeric-spin">

    <implementation>
      <field name="_monthSpinLabel">&xforms.date.month.label.field;</field>

      <method name="updateValue">
        <body>
        <![CDATA[
          var value = this.spinValue.value.toString();
          value = this.formatValue(value, 2);

          this.setAttribute("value", value);
        ]]>
        </body>
      </method>

      <!-- private -->
      <constructor>
        this.spinLabel.value = this._monthSpinLabel;
      </constructor>
    </implementation>
  </binding>

  <!-- GYEAR RANGE-->
  <binding id="range-gyear"
           extends="#range-numeric-spin">

    <implementation>
      <field name="_yearSpinLabel">&xforms.date.year.label.field;</field>

      <method name="updateValue">
        <body>
        <![CDATA[
          var value = this.spinValue.value.toString();
          value = this.formatValue(value, 4);

          this.setAttribute("value", value);
        ]]>
        </body>
      </method>

      <!-- private -->
      <constructor>
        this.spinLabel.value = this._yearSpinLabel;
        this.spinValue.size = 3;
      </constructor>
    </implementation>
  </binding>

  <!-- GMONTHDAY RANGE-->
  <binding id="range-gmonthday"
           extends="chrome://xforms/content/widgets.xml#gmonthday">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:label value="" anonid="minLabel"/>
      <xul:box class="range-box">
        <xul:label control="monthSpin" value="&xforms.date.month.label;"/>
        <xul:textbox type="number" size="1" anonid="monthSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="daySpin" value="&xforms.date.day.label;"/>
        <xul:textbox type="number" size="1" anonid="daySpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:label value="" anonid="maxLabel"/>
    </content>

    <implementation>
      <method name="updateLabels">
        <body>
        <![CDATA[
          this.minLabel.value = this.start + this._startSeparator;
          this.maxLabel.value = this._endSeparator + this.end;
        ]]>
        </body>
      </method>

      <method name="updateValue">
        <body>
        <![CDATA[
          // Month
          var month = this.monthSpin.value.toString();
          month = this.formatValue(month, 2);
          // Day
          var day = this.daySpin.value.toString();
          day = this.formatValue(day, 2);

          var value = month + "-" + day;
          this.setAttribute("value", value);
        ]]>
        </body>
      </method>

      <method name="updateFields">
        <body>
        <![CDATA[
          var value = this.value;

          this.monthSpin.value = this.getMonth(value);
          this.daySpin.value = this.getDay(value);
        ]]>
        </body>
      </method>

      <method name="setSpinbuttonMinMax">
        <body>
        <![CDATA[
          // Month
          this.monthSpin.min = this.getMonthMin();
          this.monthSpin.max = this.getMonthMax();
          // Day
          this.daySpin.min = this.getDayMin();
          this.daySpin.max = this.getDayMax();
        ]]>
        </body>
      </method>

      <method name="isInRange">
        <parameter name="aValue"/>
        <body>
        <![CDATA[
          // Use JS Date objects to determine if the current gMonthDay
          // falls between the start and end gMonthDay.
          var startDate = this.getDate(this.start);
          var endDate = this.getDate(this.end);
          var currentDate = this.getDate(aValue);
          return startDate <= currentDate && currentDate <= endDate;
        ]]>
        </body>
      </method>

      <!-- Private -->
      <property name="minLabel" readonly="true">
        <getter>
          if (!this._minLabel) {
            this._minLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "minLabel");
          }
          return this._minLabel;
        </getter>
      </property>
      <field name="_minLabel">null</field>

      <property name="monthSpin" readonly="true">
        <getter>
          if (!this._monthSpin) {
            this._monthSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "monthSpin");
          }
          return this._monthSpin;
        </getter>
      </property>
      <field name="_monthSpin">null</field>

      <property name="daySpin" readonly="true">
        <getter>
          if (!this._daySpin) {
            this._daySpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "daySpin");
          }
          return this._daySpin;
        </getter>
      </property>
      <field name="_daySpin">null</field>

      <property name="maxLabel" readonly="true">
        <getter>
          if (!this._maxLabel) {
            this._maxLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "maxLabel");
          }
          return this._maxLabel;
        </getter>
      </property>
      <field name="_maxLabel">null</field>
    </implementation>
  </binding>


  <!-- GYEARMONTH RANGE-->
  <binding id="range-gyearmonth"
           extends="chrome://xforms/content/widgets.xml#gyearmonth">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:label value="" anonid="minLabel"/>
      <xul:box class="range-box">
        <xul:label control="yearSpin" value="&xforms.date.year.label;"/>
        <xul:textbox type="number" size="3" anonid="yearSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="monthSpin" value="&xforms.date.month.label;"/>
        <xul:textbox type="number" size="1" anonid="monthSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:label value="" anonid="maxLabel"/>
    </content>

    <implementation>
      <method name="updateLabels">
        <body>
        <![CDATA[
          this.minLabel.value = this.start + this._startSeparator;
          this.maxLabel.value = this._endSeparator + this.end;
        ]]>
        </body>
      </method>

      <method name="updateValue">
        <body>
        <![CDATA[
          // Year
          var year = this.yearSpin.value.toString();
          year = this.formatValue(year, 4);
          // Month
          var month = this.monthSpin.value.toString();
          month = this.formatValue(month, 2);

          var value = year + "-" + month;
          this.setAttribute("value", value);
        ]]>
        </body>
      </method>

      <method name="updateFields">
        <body>
        <![CDATA[
          var value = this.value;

          this.yearSpin.value = this.getYear(value);
          this.monthSpin.value = this.getMonth(value);
        ]]>
        </body>
      </method>

      <method name="setSpinbuttonMinMax">
        <body>
        <![CDATA[
          // Year
          this.yearSpin.min = this.getYearMin();
          this.yearSpin.max = this.getYearMax();
          // Month
          this.monthSpin.min = this.getMonthMin();
          this.monthSpin.max = this.getMonthMax();
        ]]>
        </body>
      </method>

      <method name="isInRange">
        <parameter name="aValue"/>
        <body>
        <![CDATA[
          // Use JS Date objects to determine if the current gYearMonth
          // falls between the start and end gYearMonth.
          var startDate = this.getDate(this.start);
          var endDate = this.getDate(this.end);
          var currentDate = this.getDate(aValue);
          return startDate <= currentDate && currentDate <= endDate;
        ]]>
        </body>
      </method>

      <!-- Private -->
      <property name="minLabel" readonly="true">
        <getter>
          if (!this._minLabel) {
            this._minLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "minLabel");
          }
          return this._minLabel;
        </getter>
      </property>
      <field name="_minLabel">null</field>

      <property name="yearSpin" readonly="true">
        <getter>
          if (!this._yearSpin) {
            this._yearSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "yearSpin");
          }
          return this._yearSpin;
        </getter>
      </property>
      <field name="_yearSpin">null</field>

      <property name="monthSpin" readonly="true">
        <getter>
          if (!this._monthSpin) {
            this._monthSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "monthSpin");
          }
          return this._monthSpin;
        </getter>
      </property>
      <field name="_monthSpin">null</field>

      <property name="maxLabel" readonly="true">
        <getter>
          if (!this._maxLabel) {
            this._maxLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "maxLabel");
          }
          return this._maxLabel;
        </getter>
      </property>
      <field name="_maxLabel">null</field>
    </implementation>
  </binding>

  <!-- YEARMONTHDURATION RANGE-->
  <binding id="range-yearmonthduration"
           extends="chrome://xforms/content/widgets.xml#yearmonthduration">
    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:label value="" anonid="minLabel"/>
      <xul:box class="range-box">
        <xul:label control="yearSpin" value="&xforms.date.year.label;"/>
        <xul:textbox type="number" size="1" anonid="yearSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="monthSpin" value="&xforms.date.month.label;"/>
        <xul:textbox type="number" size="1" anonid="monthSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:label value="" anonid="maxLabel"/>
    </content>

    <implementation>
      <method name="updateLabels">
        <body>
        <![CDATA[
          this.minLabel.value = this.start + this._startSeparator;
          this.maxLabel.value = this._endSeparator + this.end;
        ]]>
        </body>
      </method>

      <method name="updateValue">
        <body>
        <![CDATA[
          var years = this.yearSpin.value.toString();
          var months = this.monthSpin.value.toString();

          var duration = "P" + years + "Y" + months + "M";

          this.setAttribute("value", duration);
        ]]>
        </body>
      </method>

      <method name="updateFields">
        <body>
        <![CDATA[
          var value = this.value;
          var years = this.getYears(value);
          var months = this.getMonths(value);

          this.yearSpin.value = years;
          this.monthSpin.value = months;
        ]]>
        </body>
      </method>

      <method name="setSpinbuttonMinMax">
        <body>
        <![CDATA[
          // Years
          this.yearSpin.min = this.getYearsMin();
          this.yearSpin.max = this.getYearsMax();
          // Months
          this.monthSpin.min = this.getMonthsMin();
          this.monthSpin.max = this.getMonthsMax();
        ]]>
        </body>
      </method>

      <method name="isInRange">
        <parameter name="aValue"/>
        <body>
        <![CDATA[
          var startMonths = this.getDurationMonths(this.start);
          var endMonths = this.getDurationMonths(this.end);
          var currentMonths = this.getDurationMonths(aValue);

          return startMonths <= currentMonths && currentMonths <= endMonths;
        ]]>
        </body>
      </method>

      <!-- Private -->
      <property name="minLabel" readonly="true">
        <getter>
          if (!this._minLabel) {
            this._minLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "minLabel");
          }
          return this._minLabel;
        </getter>
      </property>
      <field name="_minLabel">null</field>

      <property name="yearSpin" readonly="true">
        <getter>
          if (!this._yearSpin) {
            this._yearSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "yearSpin");
          }
          return this._yearSpin;
        </getter>
      </property>
      <field name="_yearSpin">null</field>

      <property name="monthSpin" readonly="true">
        <getter>
          if (!this._monthSpin) {
            this._monthSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "monthSpin");
          }
          return this._monthSpin;
        </getter>
      </property>
      <field name="_monthSpin">null</field>

      <property name="maxLabel" readonly="true">
        <getter>
          if (!this._maxLabel) {
            this._maxLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "maxLabel");
          }
          return this._maxLabel;
        </getter>
      </property>
      <field name="_maxLabel">null</field>
    </implementation>
  </binding>

  <!-- DAYTIMEDURATION RANGE-->
  <binding id="range-daytimeduration"
           extends="chrome://xforms/content/widgets.xml#daytimeduration">

    <resources>
      <stylesheet src="chrome://xforms/skin/widgets-xul.css"/>
    </resources>

    <content>
      <xul:label value="" anonid="minLabel"/>
      <xul:box class="range-box">
        <xul:label control="daySpin" value="&xforms.date.day.label;"/>
        <xul:textbox type="number" size="1" anonid="daySpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="hoursSpin" value="&xforms.time.hours.label;"/>
        <xul:textbox type="number" size="1" anonid="hoursSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="minutesSpin" value="&xforms.time.minutes.label;"/>
        <xul:textbox type="number" size="1" anonid="minutesSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:box class="range-box">
        <xul:label control="secondsSpin" value="&xforms.time.seconds.label;"/>
        <xul:textbox type="number" size="1" anonid="secondsSpin"
                     xbl:inherits="tabindex=mozType:tabindex"/>
      </xul:box>
      <xul:label value="" anonid="maxLabel"/>
    </content>

    <implementation>
      <method name="updateLabels">
        <body>
        <![CDATA[
          this.minLabel.value = this.start + this._startSeparator;
          this.maxLabel.value = this._endSeparator + this.end;
        ]]>
        </body>
      </method>

      <method name="updateValue">
        <body>
        <![CDATA[
          var days = this.daySpin.value.toString();
          var hours = this.hoursSpin.value.toString();
          var minutes = this.minutesSpin.value.toString();
          var seconds = this.secondsSpin.value.toString();

          var duration = "P" + days + "DT" + hours + "H" +
                         minutes + "M" + seconds + "S";

          this.setAttribute("value", duration);
        ]]>
        </body>
      </method>

      <method name="updateFields">
        <body>
        <![CDATA[
          var value = this.value;

          this.daySpin.value = this.getDays(value);
          this.hoursSpin.value = this.getHours(value);
          this.minutesSpin.value = this.getMinutes(value);
          this.secondsSpin.value = this.getSeconds(value);
        ]]>
        </body>
      </method>

      <method name="setSpinbuttonMinMax">
        <body>
        <![CDATA[
          var start = this.start;
          var end = this.end;
          var value = this.value;

          // Days
          var startDays = this.getDays(start);
          var endDays = this.getDays(end);
          var currentDays = this.getDays(value);

          // Hours
          var startHours = this.getHours(start);
          var endHours = this.getHours(end);
          var currentHours = this.getHours(value);

          // Minutes
          var startMinutes = this.getMinutes(start);
          var endMinutes = this.getMinutes(end);
          var currentMinutes = this.getMinutes(value);

          // Seconds
          var startSeconds = this.getSeconds(start);
          var endSeconds = this.getSeconds(end);

          // Calculated min/max values for each spinbutton.
          var minHours = 0;
          var maxHours = 0;
          var minMinutes = 0;
          var maxMinutes = 0;
          var minSeconds = 0;
          var maxSeconds = 0;

          // Min and Max for the hours spinbutton depends on the day range.
          if (endDays == startDays) {
            // Range is less than one full day but the days of the start
            // and end are the same.
            // Example: start=P0DT23H59M59S, end=P1DT20H10M25S
            // OR
            // The range is greater than or equal to 1 day but less than
            // 2 days and the start and end days are the same.
            // Example: start=P1DT0H0M0S, end=P1DT23H59M259S

            // Hours range between the start and end hours.
            minHours = startHours;
            maxHours = endHours;

            // Min and Max minutes depends on the current hours.
            if (currentHours == startHours) {
              if (startHours == endHours) {
                // This is a simple range of minutes and seconds. Min minutes
                // is the minutes of the start duration and max minutes is
                // the minutes of the end duration.
                // Example: start=0DT0H1M0S, end=0DT0H30M30S
                minMinutes = startMinutes;
                maxMinutes = endMinutes;
              } else {
                // Min minutes is the minutes of the start duration. Max minutes
                // is the maximum number of minutes in an hour.
                minMinutes = startMinutes;
                maxMinutes = 59;
              }

              // Seconds depends on the current minutes.
              if (currentMinutes == startMinutes) {
                if (startMinutes == endMinutes) {
                  // Simple range of seconds only so min seconds is the seconds
                  // of the start duration and max seconds is the seconds of the
                  // end duration.
                  // Example: start=0DT0H0M10S, end=0DT0H0M20S
                  minSeconds = startSeconds;
                  maxSeconds = endSeconds;
                } else {
                  // Current minutes is the start minutes of the start day and
                  // start hour. Seconds can range from the start seconds to the
                  // maximum number of seconds in a minute.
                  minSeconds = startSeconds;
                  maxSeconds = 59;
                }
              } else if (currentMinutes == endMinutes) {
                // Current minutes is the end minutes of the start day and
                // start hour. Seconds can range from 0 to the number of
                // seconds in the end duration.
                minSeconds = 0;
                maxSeconds = endSeconds;
              } else {
                // Current minutes is between the start and end minutes of
                // the start day/start hour.
                minSeconds = 0;
                maxSeconds = 59;
              }
            } else if (currentHours == endHours) {
              // Current hours value is equal to the end hours. The min minutes
              // is minimum number of minutes in an hour and the max minutes
              // is the minutes of the end duration. The min seconds is the
              // minimum number of seconds in a minute and the max seconds is
              // the seconds of the end duration.
              // Example: start=P1DT0H0M0S, end=P1DT1H59M59S
              minMinutes = 0;
              maxMinutes = endMinutes;
              minSeconds = 0;
              maxSeconds = endSeconds;
            } else {
              // Current hours value is between the start and end hours values
              // of the same day. Minutes and seconds can range between their
              // miminimum and maximum values.
              // Example: start=P1DT0H0M0S, end=P1DT10H59M59S
              minMinutes = 0;
              maxMinutes = 59;
              minSeconds = 0;
              maxSeconds = 59;
            }
          } else if (endDays - startDays == 1) {
            // Range is less than one full day but the days of the start
            // and end are different.
            // Example: start=P0D23H59M59S, end=P1D20H30M10S
            // OR
            // The range is greater than or equal to 1 day but less than
            // 2 days and the start and end days are different.
            // Example: start=P0D0H0M0S, end=P1D23H10M10S
            // Example: start=P0D0H0M0S, end=P1D0H0M0S

            // Hours, minutes, and seconds depend on the current day.
            if (currentDays == startDays) {
              // Current day value is equal to the start day.
              // The min hour is the start hours and the max hours is the
              // maximum number of hours in a day.
              minHours = startHours;
              maxHours = 23;
              // Minutes can range between the minutes of the start duration
              // and the maximum number of minutes in an hour.
              minMinutes = startMinutes;
              maxMinutes = 59;
              // Seconds can range between the seconds of the start duration
              // and the maximum number of seconds in a minute.
              minSeconds = startSeconds;
              maxSeconds = 59;
            } else if (currentDays == endDays) {
              // Current day value is equal to the end day.
              // The min hour is the minimum number of hours in a day and the
              // max hours is the hours of the end duration.
              minHours = 0;
              maxHours = endHours;

              // Minutes and seconds depend on the current hours.
              if (currentHours >= endHours) {
                // Current hour is the end hour of the end day.
                minMinutes = 0;
                maxMinutes = endMinutes;

                if (currentMinutes >= endMinutes) {
                  // Current minutes is greater than or equal to the end
                  // minutes of the end day. Seconds can range between the
                  // minimum number of seconds in a minute to the seconds of
                  // the end duration.
                  minSeconds = 0;
                  maxSeconds = endSeconds;
                } else {
                  // Current minutes is between the start and end minutes of
                  // the current hour. Seconds range between their minimum and
                  // maximum values.
                  minSeconds = 0;
                  maxSeconds = 59;
                }
              } else {
                // Current hours is between the start and end hours of the
                // end day. Minutes and seconds can range between their
                // minimum and maximum values.
                minMinutes = 0;
                maxMinutes = 59;
                minSeconds = 0;
                maxSeconds = 59;
              }
            }
          } else {
            // Range is more than one full day.
            // Example: start= P1DT10H59M59S, end=P3DT23H30M10S
            // Example: start= P1DT0H0M0S, end=P3DT0H0M0S

            if (currentDays == startDays) {
              // Min hours is the start hours and max hours is the maximum
              // number of hours in a day.
              // on the end hours.
              minHours = startHours;
              maxHours = 23;

              // Minutes depends on the current hour.
              if (currentHours == startHours) {
                // Current hours is equal to the start hours. Minutes range
                // from the start minutes to the maximum number of minutes
                // in an hour.
                minMinutes = startMinutes;
                maxMinutes = 59;

                // Seconds depends on the current minutes.
                if (currentMinutes == startMinutes) {
                  // Current minutes is equal to the start minutes. Seconds
                  // range from the start seconds to the maximum number of
                  // seconds in a minute.
                  minSeconds = startSeconds;
                  maxSeconds = 59;
                } else {
                  // Current minutes is between the start and end minutes of
                  // the current hour.  Seconds range between their minimum
                  // and maximum values.
                  minSeconds = 0;
                  maxSeconds = 59;
                }
              } else {
                // Current hours is between the start and end hours of the
                // current day. Minutes and seconds range between their minimum
                // and maximum values.
                minMinutes = 0;
                maxMinutes = 59;
                minSeconds = 0;
                maxSeconds = 59;
              }
            } else if (currentDays == endDays) {
              // Current day is equal to the end day.
              // Hours range between the minimum number of hours in a day and
              // the hours of the end duration.
              minHours = 0;
              maxHours = endHours;

              // Minutes depend on the current hour.
              if (currentHours == endHours) {
                // Current hour is equal to the end hour. Minutes range between
                // the minimum number of minutes in an hour and the minutes of
                // the end duration.
                minMinutes = 0;
                maxMinutes = endMinutes;

                // Seconds depends on the current minutes.
                if (currentMinutes >= endMinutes) {
                  // Current minutes is greater than or equal to the end
                  // minutes of the end day. Seconds range between the minimum
                  // number of seconds in a minute and the seconds of the end
                  // duration.
                  minSeconds = 0;
                  maxSeconds = endSeconds;
                } else {
                  // Current minutes is between the start and end minutes of
                  // the current hour. Seconds range between their minimum and
                  // maximum values.
                  minSeconds = 0;
                  maxSeconds = 59;
                }
              } else {
                // Current hours is between the start and end hours of the
                // end day. Minutes and seconds range between their minimum
                // and maximum values.
                minMinutes = 0;
                maxMinutes = 59;
                minSeconds = 0;
                maxSeconds = 59;
              }
            } else {
              // Current day falls between the start and end days. Hours,
              // minutes, and seconds all range between their minimum and
              // maximum values.
              minHours = 0;
              maxHours = 23;
              minMinutes = 0;
              maxMinutes = 59;
              minSeconds = 0;
              maxSeconds = 59;
            }
          }

          // Set the min and max for the days, hours, minutes,
          // and seconds spinbuttons.
          this.daySpin.min = startDays;
          this.daySpin.max = endDays;
          this.hoursSpin.min = minHours;
          this.hoursSpin.max = maxHours;
          this.minutesSpin.min = minMinutes;
          this.minutesSpin.max = maxMinutes;
          this.secondsSpin.min = minSeconds;
          this.secondsSpin.max = maxSeconds;
        ]]>
        </body>
      </method>

      <method name="isInRange">
        <parameter name="aValue"/>
        <body>
        <![CDATA[
          var startSeconds = this.getDurationSeconds(this.start);
          var endSeconds = this.getDurationSeconds(this.end);
          var currentSeconds = this.getDurationSeconds(aValue);

          return startSeconds <= currentSeconds && currentSeconds <= endSeconds;
        ]]>
        </body>
      </method>

      <!-- Private -->
      <property name="minLabel" readonly="true">
        <getter>
          if (!this._minLabel) {
            this._minLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "minLabel");
          }
          return this._minLabel;
        </getter>
      </property>
      <field name="_minLabel">null</field>

      <property name="daySpin" readonly="true">
        <getter>
          if (!this._daySpin) {
            this._daySpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "daySpin");
          }
          return this._daySpin;
        </getter>
      </property>
      <field name="_daySpin">null</field>

      <property name="hoursSpin" readonly="true">
        <getter>
          if (!this._hoursSpin) {
            this._hoursSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "hoursSpin");
          }
          return this._hoursSpin;
        </getter>
      </property>
      <field name="_hoursSpin">null</field>

      <property name="minutesSpin" readonly="true">
        <getter>
          if (!this._minutesSpin) {
            this._minutesSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "minutesSpin");
          }
          return this._minutesSpin;
        </getter>
      </property>
      <field name="_minutesSpin">null</field>

      <property name="secondsSpin" readonly="true">
        <getter>
          if (!this._secondsSpin) {
            this._secondsSpin = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "secondsSpin");
          }
          return this._secondsSpin;
        </getter>
      </property>
      <field name="_secondsSpin">null</field>

      <property name="maxLabel" readonly="true">
        <getter>
          if (!this._maxLabel) {
            this._maxLabel = this.ownerDocument.
              getAnonymousElementByAttribute(this, "anonid", "maxLabel");
          }
          return this._maxLabel;
        </getter>
      </property>
      <field name="_maxLabel">null</field>
    </implementation>
  </binding>

</bindings>

