text: COMPONENT('rawinput', 'type:text', function(self, config, cls) {
  
  	var customvalidator;
  	var input;
  
  	self.validate = function(value) {
  
  		if ((!config.required || config.disabled) && !self.forcedvalidation())
  			return true;
  
  		if (customvalidator)
  			return customvalidator(value);
  
  		if (self.type === 'date')
  			return value instanceof Date && !isNaN(value.getTime());
  
  		if (value == null)
  			value = '';
  		else
  			value = value.toString();
  
  		if (config.minlength && value.length < config.minlength)
  			return false;
  
  		switch (self.type) {
  			case 'email':
  				return value.isEmail();
  			case 'phone':
  				return value.isPhone();
  			case 'url':
  				return value.isURL();
  			case 'zip':
  				return (/^\d{5}(?:[-\s]\d{4})?$/).test(value);
  			case 'currency':
  			case 'number':
  				value = value.parseFloat();
  				if ((config.minvalue != null && value < config.minvalue) || (config.maxvalue != null && value > config.maxvalue))
  					return false;
  				return config.minvalue == null ? value > 0 : true;
  		}
  
  		return value.length > 0;
  	};
  
  	self.formatter(function(path, value) {
  		if (value) {
  			switch (config.type) {
  				case 'lower':
  					return (value + '').toLowerCase();
  				case 'upper':
  					return (value + '').toUpperCase();
  				case 'phone':
  					return (value + '').replace(/\s/g, '');
  				case 'email':
  					return (value + '').toLowerCase();
  				case 'date':
  					return value.format(config.format || 'yyyy-MM-dd');
  				case 'time':
  					return value.format(config.format || 'HH:mm');
  				case 'number':
  					return config.format ? value.format(config.format) : value;
  			}
  		}
  
  		return value;
  	});
  
  	self.parser(function(path, value) {
  		if (value) {
  			var tmp;
  			switch (config.type) {
  				case 'date':
  					tmp = self.get();
  					if (tmp)
  						tmp = tmp.format('HH:mm');
  					else
  						tmp = '';
  					return value + (tmp ? (' ' + tmp) : '');
  				case 'lower':
  				case 'email':
  					value = value.toLowerCase();
  					break;
  				case 'upper':
  					value = value.toUpperCase();
  					break;
  				case 'phone':
  					value = value.replace(/\s/g, '');
  					break;
  				case 'time':
  					tmp = value.split(':');
  					var dt = self.get();
  					if (dt == null)
  						dt = new Date();
  					dt.setHours(+(tmp[0] || '0'));
  					dt.setMinutes(+(tmp[1] || '0'));
  					dt.setSeconds(+(tmp[2] || '0'));
  					value = dt;
  					break;
  			}
  		}
  		return value ? config.spaces === false ? value.replace(/\s/g, '') : value : value;
  	});
  
  	self.make = function() {
  		self.aclass(cls);
  		var attr = [];
  		config.type && attr.attr('type', config.type === 'password' ? 'password' : 'text');
  		config.maxlength && attr.attr('maxlength', config.maxlength);
  		config.placeholder && attr.attr('placeholder', config.placeholder);
  		config.autofocus && attr.push('autofocus');
  
  		if (config.autofill) {
  			attr.attr('autocomplete', 'on');
  			attr.attr('name', self.path);
  		} else {
  			attr.attr('name', Date.now() + '');
  			attr.attr('autocomplete', 'new-password');
  		}
  
  		self.append('<input data-jc-bind="" {0} />'.format(attr.join(' ')));
  
  		var $input = self.find('input');
  		input = $input[0];
  
  		config.enter && $input.on('keydown', function(e) {
  			if (e.which === 13)
  				self.SEEX(config.enter, input.value, self);
  		});
  
  		$input.on('focus', function() {
  
  			var el = $(this);
  
  			if (config.disabled) {
  				el.blur();
  				return;
  			}
  
  			self.aclass(cls + '-focused');
  			config.autocomplete && self.EXEC(config.autocomplete, self, el.parent());
  
  			if (config.autosource) {
  				var opt = {};
  				opt.element = self.element;
  				opt.search = GET(self.makepath(config.autosource));
  				opt.callback = function(value) {
  					var val = typeof(value) === 'string' ? value : value[config.autovalue];
  					if (config.autoexec) {
  						self.EXEC(config.autoexec, value, function(val) {
  							self.set(val, 2);
  							self.change();
  							self.bindvalue();
  						});
  					} else {
  						self.set(val, 2);
  						self.change();
  						self.bindvalue();
  					}
  				};
  				SETTER('autocomplete/show', opt);
  			}
  		}).on('blur', function() {
  			self.rclass(cls + '-focused');
  		});
  
  	};
  
  	self.configure = function(key, value) {
  		switch (key) {
  			case 'disabled':
  				self.tclass('ui-disabled', !!value);
  				input.prop('readonly', !!value);
  				self.reset();
  				break;
  			case 'readonly':
  				input.prop('readonly', !!value);
  				self.reset();
  				break;
  			case 'required':
  				self.tclass(cls + '-required', !!value);
  				self.reset();
  				break;
  			case 'type':
  				self.type = value;
  				break;
  			case 'validate':
  				customvalidator = value ? (/\(|=|>|<|\+|-|\)/).test(value) ? FN('value=>' + value) : (function(path) { path = self.makepath(path); return function(value) { return GET(path)(value); }; })(value) : null;
  				break;
  			case 'monospace':
  				self.tclass(cls + '-monospace', !!value);
  				break;
  		}
  	};
  
  	self.preparevalue = function(value) {
  
  		if (self.type === 'number' && (config.minvalue != null || config.maxvalue != null)) {
  			var tmp = typeof(value) === 'string' ? +value.replace(',', '.') : value;
  			if (config.minvalue > tmp)
  				value = config.minvalue;
  			if (config.maxvalue < tmp)
  				value = config.maxvalue;
  		}
  
  		return value;
  	};
  
  	self.getterin = self.getter;
  	self.getter = function(value, realtime, nobind) {
  		self.getterin(self.preparevalue(value), realtime, nobind);
  	};
  
  	self.setter = function(value) {
  		input.value = value == null ? '' : (value + '');
  	};
  
  	self.state = function(type) {
  		if (type) {
  			var invalid = config.required ? self.isInvalid() : self.forcedvalidation() ? self.isInvalid() : false;
  			if (invalid === self.$oldstate)
  				return;
  			self.$oldstate = invalid;
  			self.tclass(cls + '-invalid', invalid);
  		}
  	};
  
  	self.forcedvalidation = function() {
  
  		if (!config.forcevalidation)
  			return false;
  
  		if (self.type === 'number')
  			return false;
  
  		var val = self.get();
  		return (self.type === 'phone' || self.type === 'email') && (val != null && (typeof(val) === 'string' && val.length !== 0));
  	};
  
  });