text: (function() {
  
     var lang = YAHOO.lang, Event = YAHOO.util.Event, Dom = YAHOO.util.Dom;
  
  /**
   * Basic string field (equivalent to the input type "text")
   * @class inputEx.StringField
   * @extends inputEx.Field
   * @constructor
   * @param {Object} options Added options:
   * <ul>
   *	  <li>regexp: regular expression used to validate (otherwise it always validate)</li>
   *   <li>size: size attribute of the input</li>
   *   <li>maxLength: maximum size of the string field (no message display, uses the maxlength html attribute)</li>
   *   <li>minLength: minimum size of the string field (will display an error message if shorter)</li>
   *   <li>typeInvite: string displayed when the field is empty</li>
   *   <li>readonly: set the field as readonly</li>
   * </ul>
   */
  inputEx.StringField = function(options) {
     inputEx.StringField.superclass.constructor.call(this, options);
  
  	  if(this.options.typeInvite) {
  	     this.updateTypeInvite();
  	  }
  };
  
  lang.extend(inputEx.StringField, inputEx.Field, {
     /**
      * Set the default values of the options
      * @param {Object} options Options object as passed to the constructor
      */
  	setOptions: function(options) {
  	   inputEx.StringField.superclass.setOptions.call(this, options);
  
  	   this.options.regexp = options.regexp;
  	   this.options.size = options.size;
  	   this.options.maxLength = options.maxLength;
  	   this.options.minLength = options.minLength;
  	   this.options.typeInvite = options.typeInvite;
  	   this.options.readonly = options.readonly;
  	   this.options.disabled = options.disabled;
  	   this.options.autocomplete = lang.isUndefined(options.autocomplete) ?
  	                                  inputEx.browserAutocomplete :
  	                                  (options.autocomplete === false || options.autocomplete === "off") ? false : true;
  	   this.options.trim = (options.trim === true) ? true : false;
     },
  
  
     /**
      * Render an 'INPUT' DOM node
      */
     renderComponent: function() {
  
        // This element wraps the input node in a float: none div
        this.wrapEl = inputEx.cn('div', {className: 'inputEx-StringField-wrapper'});
  
        // Attributes of the input field
        var attributes = {};
        attributes.type = 'text';
        attributes.id = this.divEl.id?this.divEl.id+'-field':YAHOO.util.Dom.generateId();
        if(this.options.size) { attributes.size = this.options.size; }
        if(this.options.name) { attributes.name = this.options.name; }
        if(this.options.readonly) { attributes.readonly = 'readonly'; }
        if (this.options.disabled) { attributes.disabled = 'disabled'; }
  
        if(this.options.maxLength) { attributes.maxLength = this.options.maxLength; }
        attributes.autocomplete = this.options.autocomplete ? 'on' : 'off';
  
        // Create the node
        this.el = inputEx.cn('input', attributes);
  
        // Append it to the main element
        this.wrapEl.appendChild(this.el);
        this.fieldContainer.appendChild(this.wrapEl);
     },
  
  	/**
  	 * Set the name of the field (or hidden field)
  	 */
  	setFieldName: function(name) {
  		this.el.name = name;
  	},
  
     /**
      * Register the change, focus and blur events
      */
     initEvents: function() {
  	   Event.addListener(this.el, "change", this.onChange, this, true);
  
         if (YAHOO.env.ua.ie){ // refer to inputEx-95
              var field = this.el;
              new YAHOO.util.KeyListener(this.el, {keys:[13]}, {fn:function(){
                  field.blur();
                  field.focus();
              }}).enable();
         }
  
  	   Event.addFocusListener(this.el, this.onFocus, this, true);
  		Event.addBlurListener(this.el, this.onBlur, this, true);
  	   Event.addListener(this.el, "keypress", this.onKeyPress, this, true);
  	   Event.addListener(this.el, "keyup", this.onKeyUp, this, true);
     },
  
     /**
      * Return the string value
      * @param {String} The string value
      */
     getValue: function() {
        
        var value;
        
        value = (this.options.typeInvite && this.el.value == this.options.typeInvite) ? '' : this.el.value;
        
        if (this.options.trim) {
           v2 = YAHOO.lang.trim(value);
           if (v2 != value) {           // для апдейта поля на форме экрана
              this.setValue(v2, false);
           }
           value = v2;
        }
        
  	   return value;
     },
  
     /**
      * Function to set the value
      * @param {String} value The new value
      * @param {boolean} [sendUpdatedEvt] (optional) Wether this setValue should fire the updatedEvt or not (default is true, pass false to NOT send the event)
      */
     setValue: function(value, sendUpdatedEvt) {
  		// + check : if Null or Undefined we put '' in the stringField
  	  this.el.value = ( lang.isNull(value) || lang.isUndefined(value) ) ? '' : value;
  
        // call parent class method to set style and fire updatedEvt
        inputEx.StringField.superclass.setValue.call(this, value, sendUpdatedEvt);
     },
  
     /**
      * Uses the optional regexp to validate the field value
      */
     validate: function() {
        var val = this.getValue();
  
        // empty field
        if (val === '') {
           // validate only if not required
           return !this.options.required;
        }
  
        // Check regex matching and minLength (both used in password field...)
        var result = true;
  
        // if we are using a regular expression
        if( this.options.regexp ) {
  	      result = result && val.match(this.options.regexp);
        }
        if( this.options.minLength ) {
  	      result = result && val.length >= this.options.minLength;
        }
        return result;
     },
  
     /**
      * Disable the field
      */
     disable: function() {
        this.el.disabled = true;
     },
  
     /**
      * Enable the field
      */
     enable: function() {
        this.el.disabled = false;
     },
  
     /**
      * Check if the field is disabled
      */
     isDisabled: function() {
        return this.el.disabled;
     },
  
     /**
      * Set the focus to this field
      */
     focus: function() {
        // Can't use lang.isFunction because IE >= 6 would say focus is not a function (IE says it's an object) !!
        if(!!this.el && !lang.isUndefined(this.el.focus) ) {
           this.el.focus();
        }
     },
  
  	/**
      * Add the minLength string message handling
      */
  	getStateString: function(state) {
  	   if(state == inputEx.stateInvalid && this.options.minLength && this.el.value.length < this.options.minLength) {
  	      return inputEx.messages.stringTooShort[0]+this.options.minLength+inputEx.messages.stringTooShort[1];
        }
  	   return inputEx.StringField.superclass.getStateString.call(this, state);
  	},
  
     /**
      * Display the type invite after setting the class
      */
     setClassFromState: function() {
  	   inputEx.StringField.superclass.setClassFromState.call(this);
  
  	   // display/mask typeInvite
  	   if(this.options.typeInvite) {
  	      this.updateTypeInvite();
        }
  	},
  
  	updateTypeInvite: function() {
  
  	   // field not focused
        if (!Dom.hasClass(this.divEl, "inputEx-focused")) {
  
           // show type invite if field is empty
           if(this.isEmpty()) {
  	         Dom.addClass(this.divEl, "inputEx-typeInvite");
  	         this.el.value = this.options.typeInvite;
  
  	      // important for setValue to work with typeInvite
           } else {
              Dom.removeClass(this.divEl, "inputEx-typeInvite");
           }
  
        // field focused : remove type invite
        } else {
  	      if(Dom.hasClass(this.divEl,"inputEx-typeInvite")) {
  	         // remove text
  	         this.el.value = "";
  
  	         // remove the "empty" state and class
  	         this.previousState = null;
  	         Dom.removeClass(this.divEl,"inputEx-typeInvite");
           }
        }
  	},
  
  	/**
  	 * Clear the typeInvite when the field gains focus
  	 */
  	onFocus: function(e) {
  	   inputEx.StringField.superclass.onFocus.call(this,e);
  
  	   if(this.options.typeInvite) {
           this.updateTypeInvite();
        }
  	},
  
  	onKeyPress: function(e) {
  	   // override me
  	},
  
     onKeyUp: function(e) {
        // override me
        //
        //   example :
        //
        //   lang.later(0, this, this.setClassFromState);
        //
        //     -> Set style immediatly when typing in the field
        //     -> Call setClassFromState escaping the stack (after the event has been fully treated, because the value has to be updated)
     }
  
  });
  
  
  inputEx.messages.stringTooShort = ["This field should contain at least "," numbers or characters"];
  
  // Register this class as "string" type
  inputEx.registerType("string", inputEx.StringField, [
      { type: 'string', label: 'Type invite', name: 'typeInvite', value: ''},
      { type: 'integer', label: 'Size', name: 'size', value: 20},
      { type: 'integer', label: 'Min. length', name: 'minLength', value: 0}
  ]);
  
  })();
  