<?xml version="1.0"?>

<!-- ***** BEGIN LICENSE BLOCK *****
   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
   -
   - The contents of this file are subject to the Mozilla Public License Version
   - 1.1 (the "License"); you may not use this file except in compliance with
   - the License. You may obtain a copy of the License at
   - http://www.mozilla.org/MPL/
   -
   - Software distributed under the License is distributed on an "AS IS" basis,
   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   - for the specific language governing rights and limitations under the
   - License.
   -
   - The Original Code is Mozilla 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>
   -
   - 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 ***** -->


<!--
  This file contains xforms input, secret and textarea controls implementation
  for XUL. All controls are inherited from interface bindings realized in
  xforms-input.xml.
-->

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


  <!-- INPUT: base widget for input: <default>, textarea: <default> and
              secret: <default> controls.

    Binding assumes getControlElement returns object that has properties
    required by 'xformswidget-input-base' binding plus 'editor' property to
    get nsIEditor for embedded editor. You shouldn't use this binding if xforms
    input element isn't supposed to have an editor.
  -->
  <binding id="xformswidget-input-base"
           extends="chrome://xforms/content/input.xml#xformswidget-input-base">

    <implementation implements="nsIXFormsNSEditableElement">

      <property name="editor" readonly="true"
                onget="return this.control.editor;"/>

      <method name="getControlElement">
        <body>
          var control = this.ownerDocument.
              getAnonymousElementByAttribute(this, 'anonid', 'control');

          return {
            control: control,

            __proto__: control.inputField,

            set readonly(val) {
              if (val)
                this.control.setAttribute("readonly", val);
              else
                this.control.removeAttribute("readonly");
            }
          };
        </body>
      </method>
    </implementation>

    <handlers>
      <handler event="focus" phase="capturing">
        if (event.originalTarget == this.control) {
          this.dispatchDOMUIEvent("DOMFocusIn");
        }
      </handler>

      <handler event="blur" phase="capturing">
        if (event.originalTarget == this.control) {
          this.updateInstanceData();
          this.dispatchDOMUIEvent("DOMFocusOut");
        }
      </handler>

      <handler event="input">
        if (event.originalTarget == this.control) {
          this.updateInstanceData(true);
        }
      </handler>
    </handlers>
  </binding>


  <!-- INPUT: <DEFAULT> -->
  <binding id="xformswidget-input"
           extends="#xformswidget-input-base">
    <content>
      <children includes="label"/>
      <xul:textbox class="xf-value" anonid="control" flex="1"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>

    <handlers>
      <handler event="keypress" keycode="VK_RETURN">
        if (event.originalTarget == this.control) {
          this.dispatchDOMUIEvent("DOMActivate");
        }
      </handler>
    </handlers>
  </binding>


  <!-- INPUT: BOOLEAN -->
  <binding id="xformswidget-input-boolean"
           extends="chrome://xforms/content/input.xml#xformswidget-input-boolean-base">
    <content>
      <children includes="label"/>
      <xul:checkbox anonid="control" class="xf-value"
                    xbl:inherits="tabindex"/>
      <children/>
    </content>

    <implementation>
      <method name="getControlElement">
        <body>
          return {
            __proto__: this.ownerDocument.
              getAnonymousElementByAttribute(this, 'anonid', 'control'),

            get value() {
              return this.checked;
            },
            set value(val) {
              this.checked = val;
            },
            set readonly(val) {
              this.disabled = val;
            }
          };
        </body>
      </method>
    </implementation>

    <handlers>
      <handler event="command">
        if (event.originalTarget == this.control)
          this.updateInstanceData(true);
      </handler>

      <handler event="focus" phase="capturing">
        if (event.originalTarget == this.control) {
          this.dispatchDOMUIEvent("DOMFocusIn");
        }
      </handler>

      <handler event="blur" phase="capturing">
        if (event.originalTarget == this.control) {
          this.updateInstanceData();
          this.dispatchDOMUIEvent("DOMFocusOut");
        }
      </handler>
    </handlers>
  </binding>


  <!-- INPUT: <DATE> -->
  <binding id="xformswidget-input-date"
           extends="#xformswidget-input-base">

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

    <content>
      <children includes="label"/>
      <xul:hbox class="-moz-menulist-container" flex="1">
        <html:input anonid="control" flex="1"
                    class="-moz-menulist-textfield"
                    allowevents="true"
                    xbl:inherits="tabindex"/>
        <xul:dropmarker mozType:dropmarker="true" anonid="dropmarker"
                        xbl:inherits="disabled"/>
      </xul:hbox>
      <xul:popup anonid="popup" ignorekeys="true">
        <xul:box mozType:calendar="true" anonid="picker"
                 internaltabhandling="true"/>
      </xul:popup>
      <children/>
    </content>

    <implementation implements="nsIXFormsComboboxUIWidget, nsIAccessibleProvider">
    <!-- nsIXFormsComboboxUIWidget -->
      <property name="open">
        <getter>
          return this._isPickerVisible;
        </getter>
        <setter>
          if (val)
            this.showPicker();
          else
            this.hidePicker();
        </setter>
      </property>

    <!-- nsIAccessibleProvider -->
      <property name="accessibleType" readonly="true">
        <getter>
          return Components.interfaces.nsIAccessibleProvider.XFormsInputDate;
        </getter>
      </property>

      <method name="getControlElement">
        <body>
          return this.ownerDocument.
            getAnonymousElementByAttribute(this, 'anonid', 'control');
        </body>
      </method>

      <constructor>
        var pickerChangeHandler = {
          inputControl: this,
          handleEvent: function(aEvent) {
            if (aEvent.originalTarget == this.inputControl.picker) {
              this.inputControl.control.value = this.inputControl.picker.value;
              this.inputControl.hidePicker();
            }
          }
        };
        this.picker.addEventListener("change", pickerChangeHandler, false);
      </constructor>

      <method name="showPicker">
        <body>
          this.popup.showPopup(this.dropmarker, -1, -1, "popup",
                               "bottomleft", "topleft");
          this._isPickerVisible = true;
        </body>
      </method>

      <method name="hidePicker">
        <body>
          this.popup.hidePopup();
          this._isPickerVisible = false;

          this.ownerDocument.defaultView.setTimeout(
            function(control) { control.focus(); }, 0, this.control);
        </body>
      </method>

      <method name="togglePicker">
        <body>
          if (!this._isPickerVisible)
            this.showPicker();
          else
            this.hidePicker();
        </body>
      </method>

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

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

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

      <field name="_isPickerVisible">false</field>
    </implementation>

    <handlers>
      <handler event="command">
        if (event.originalTarget == this.dropmarker)
          this.showPicker();
      </handler>

      <handler event="popupshowing">
        this.picker.value = this.control.value;
      </handler>

      <handler event="popupshown">
        this.ownerDocument.defaultView.setTimeout(
          function(picker) { picker.focus();} , 0, this.picker);
      </handler>

      <handler event="keypress">
      <![CDATA[
        if (event.keyCode == event.DOM_VK_F4) {
          this.togglePicker();
        } else if (event.keyCode == event.DOM_VK_ESCAPE) {
          this.hidePicker();
        } else if (event.altKey && (event.keyCode == event.DOM_VK_DOWN ||
                   event.keyCode == event.DOM_VK_UP)) {
          this.togglePicker();
          event.preventDefault();
        }
      ]]>
      </handler>
    </handlers>
  </binding>


  <!-- INPUT: <DATE, APPEARANCE='FULL'> -->
  <binding id="xformswidget-input-date-full"
           extends="chrome://xforms/content/input.xml#xformswidget-input-date-calendar-base">
    <content>
      <children includes="label"/>
      <xul:box mozType:calendar="true" anonid="control"/>
      <children/>
    </content>

    <implementation>
      <method name="getControlElement">
        <body>
          return this.ownerDocument.
            getAnonymousElementByAttribute(this, "anonid", "control");
        </body>
      </method>

      <constructor>
        var changeHandler = {
          inputControl: this,
          handleEvent: function() {
            this.inputControl.updateInstanceData(false);
          }
        };
        this.addEventListener("change", changeHandler, false);
      </constructor>
    </implementation>
  </binding>


  <!-- INPUT: <NUMBER> -->
  <binding id="xformswidget-input-number-base"
           extends="#xformswidget-input-base">

    <implementation>
      <constructor>
        var changeHandler = {
          xfcontrol: this,
          handleEvent: function(aEvent) {
            if (aEvent.currentTarget == aEvent.originalTarget) {
              this.xfcontrol.updateInstanceData(true);
            }
          }
        };
        this.control.control.addEventListener("change", changeHandler, false);
      </constructor>
    </implementation>
  </binding>


  <!-- INPUT: type="xsd:integer" -->
  <binding id="xformswidget-input-integer"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="Number.MIN_VALUE" max="Number.MAX_VALUE"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

  <!-- INPUT: type="xsd:nonPositiveInteger" -->
  <binding id="xformswidget-input-nonPositiveInteger"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="Number.MIN_VALUE" max="0"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

  <!-- INPUT: type="xsd:negativeInteger" -->
  <binding id="xformswidget-input-negativeInteger"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="Number.MIN_VALUE" max="-1"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

  <!-- INPUT: type="xsd:long" -->
  <binding id="xformswidget-input-long"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="-9223372036854775807" max="9223372036854775807"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

  <!-- INPUT: type="xsd:int" -->
  <binding id="xformswidget-input-int"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="-2147483647" max="2147483647"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

  <!-- INPUT: type="xsd:short" -->
  <binding id="xformswidget-input-short"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="-32767" max="32767"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

  <!-- INPUT: type="xsd:byte" -->
  <binding id="xformswidget-input-byte"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="-127" max="127"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

  <!-- INPUT: type="xsd:nonNegativeInteger" -->
  <binding id="xformswidget-input-nonNegativeInteger"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="0" max="Number.MAX_VALUE"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>


  <!-- INPUT: type="xsd:unsignedLong" -->
  <binding id="xformswidget-input-unsignedLong"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="0" max="18446744073709551615"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

  <!-- INPUT: type="xsd:unsignedInt" -->
  <binding id="xformswidget-input-unsignedInt"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="0" max="4294967295"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

  <!-- INPUT: type="xsd:unsignedShort" -->
  <binding id="xformswidget-input-unsignedShort"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="0" max="65535"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

  <!-- INPUT: type="xsd:unsignedByte" -->
  <binding id="xformswidget-input-unsignedByte"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="0" max="255"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

  <!-- INPUT: type="xsd:positiveInteger" -->
  <binding id="xformswidget-input-positiveInteger"
           extends="#xformswidget-input-number-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="number" class="xf-value" anonid="control" flex="1"
                   min="1" max="Number.MAX_VALUE"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>


  <!-- SECRET: <DEFAULT> -->
  <binding id="xformswidget-secret"
           extends="#xformswidget-input-base">
    <content>
      <children includes="label"/>
      <xul:textbox type="password" anonid="control" flex="1"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>

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

    <handlers>
      <handler event="keypress" keycode="VK_RETURN">
        if (event.originalTarget == this.control) {
          this.dispatchDOMUIEvent("DOMActivate");
        }
      </handler>
    </handlers>
  </binding>


  <!-- TEXTAREA: <DEFAULT> -->
  <binding id="xformswidget-textarea"
           extends="#xformswidget-input-base">
    <content>
      <children includes="label"/>
      <xul:textbox multiline="true" class="xf-value"
                   anonid="control" flex="1"
                   xbl:inherits="tabindex"/>
      <children/>
    </content>
  </binding>

</bindings>
