Location: PHPKode > scripts > WebWidgets > webwidgets/FormControls.lib.php
<?php
/************************************************************
 * Part of WebWidgets library
 * Contain classes for making input fields.
 * **********************************************************
 *	Version 0.8  09.10.02
 * **********************************************************
 * License: GPL - http://www.fsf.org/copyleft/gpl.txt
 * **********************************************************
 * Contain classes:
 *
 * FormControl - abstract class.
 * TextField	
 * TextArea		
 * Hidden
 * Password
 * Radio
 * CheckBox
 * Option
 * Select
 * Submit
 * Reset
 * FileField - produce field to upload file
 * InputImage
 * Button
 * **********************************************************
 * Author: Dmitry Levashov (hide@address.com , hide@address.com)
 * *********************************************************/


/************************************************************
 * Abstract class form elements widgets
 * Declare common interface for access to form elements
 ***********************************************************/
class FormControl extends WebWidget
{
	/**
	 * Field label, used in error message
	 * @param string
	 */
	var $Label;		
	/**
	 * Error message
	 * @param string
	 */
	var $ErrMsg = 'Incorrect value'; 

	/**
	 * Constructor
	 * @param	string	tag name
	 * @param	string	name of form field
	 * @param	string	value of field
	 * @param	string	label of field
	 * @param	array		tags attributes
	 * @access public
	 */
	function FormControl($tag, $name, $val='', $label='', $attr='')
	{
		$this->Id = WebWidget::_makeId();
		$this->Tag = strtolower($tag);
		if ($attr) $this->setAttr($attr);
		if ($name) $this->setAttr('name', $name);
		if ($val) $this->setAttr('value', $val);
		$this->Label = $label;
	} // end func constructor

	
	/**
	 * Overloaded method from parent class.
	 * For "name" atribute check is it array element name. 
	 * If so, call _getRealName method to parse name
	 * @param	string/array	attribute name / array of attributes
	 * @param	string			attribute value
	 * @access public
	 */
	function setAttr($attr, $val='')
	{
		if (!$attr) return;
		
		if (!is_array($attr)) {
			if ('name' == $attr)	$this->Attr['name'] = $this->_getRealName($val);
			else	$this->Attr[$attr] = $val;
		} else {
			foreach ($attr as $k=>$v) {
				if ('name' == $k)	$this->Attr['name'] = $this->_getRealName($v);
				else	$this->Attr[$k] = $v;
			}
		}
	} // end func setAttr

	/**
	 * Set form element value
	 */
	function setValue($value) { $this->Attr['value'] = $value; } // end func setValue
	
	/**
	 * Return value, which user input in form field.
	 * If flag $struct is true, return whole structure, 
	 * according to the full element name (see _fetFullName()). 
	 * If - false, return name-value pair
	 * @param	bool	flag
	 * @access public
	 * @return array
	 */
		
	function getValue($struct = true) 
	{ 
		return $this->_getStruct($this->Attr['value'], $struct); 
	} // end func getValue


	/**
	 * Returns attributes as string
	 * @access private
	 * @return	string
	 */
	function _attr2str()
	{
		foreach ($this->Attr as $k=>$v) {
			if ($k != 'name' || !$this->Groups)  
				$str .= ' ' . $k . '="' . htmlspecialchars($v) . '"';
			else 
				$str .= ' ' .$k . '="'.$this->_getFullName() . '"';
		}
		return $str;
	} // end func _attr2str

	/**
	 * If field name is name of array element, parse name and 
	 * put part in $Groups array. Return field name
	 * @access private
	 * @param string	
	 * @return string
	 */
	function _getRealName($name)
	{
		if (preg_match_all('/([^\[\]]+)|\[()\]/i', $name,$m)) {
			$rname = array_pop($m[1]);
			$this->Groups = $m[1];
			return $rname;
		}
		return htmlspecialchars($name);
	} // end func _getRealName
		
	/**
	 * If array $Groups is not empty, build name of field as array element name
	 * @access private
	 * @return string
	 */
	function _getFullName()
	{
		$str = $this->Groups[0];
		if (sizeof($this->Groups) > 1)
			$str .= '[' . implode('][', array_slice($this->Groups, 1)) . ']';
		return $str.'['.$this->Attr['name'].']';
	} // end func _getFullName

	/**
	 * Fetch field value from _GET or _POST, passed by reference.
	 * @param	array		_POST or _GET or part of it
	 * @access private
	 * @return array
	 */
	function &_fetch(&$source)
	{
		if ($this->Groups) {
			for ($i=0; $i<sizeof($this->Groups); $i++) {
				$source = &$source[$this->Groups[$i]];
			}
		}
		return ($this->Attr['name']) ? $source[$this->Attr['name']] : $source;
	} // end func &_fetch
	
	/**
	 * Validate input value, return true or false
	 * @access private
	 * @return bool
	 */
	function _valid() { return true; } // end func _valid

	/**
	 * Build array for getValue method and put element value in it
	 *	@param	mix	element value
	 *	@param	bool	build whole array?
	 * @access private
	 */
	function _getStruct($val, $struct=true)
	{
		if (!$this->Groups || !$struct)
			return array($this->Attr['name'] => $val);

		$res[$this->Groups[0]] = array();
		$data = &$res[$this->Groups[0]];
		for ($i=1; $i<sizeof($this->Groups); $i++) {
			$data[$this->Groups[$i]] = array();
			$data = &$data[$this->Groups[$i]];
		}
		if (!$this->Attr['name'])			
			$data = $val;
		else
			$data[$this->Attr['name']] = $val;
		return $res;

	} // end func _getStruct
	
	/**
	 * Build Html output
	 * @access private
	 */
	function _createView()
	{
		$this->View = '<' . $this->Tag . $this->_attr2str() . " />\n";
	} // end func _createView
			
} // end class FormControl


/***********************************************************
 * produce text field
 ***********************************************************/

class TextField extends FormControl 
{
	/**
	 * Type of data in field
	 * @param string
	 */
	var $DType = 'str';	
	/**
	 * Param for validate field. Min & max field value (string lenth)
	 * @param array
	 */
	var $Range;				
	/**
	 * RegExp for validate filed
	 * @param string
	 */
	var $Reg;			
	/**
	 * name of callback function to validate field
	 * @param 	string
	 */
	var $Callback;	
		
	/**
	 * Constructor
	 * @param	string	name of the field
	 * @param	string	value of the field
	 * @param	string	label of the field
	 * @param	array		attributes
	 * @param	string	data type
	 * @access public
	 */
	function TextField($name, $val='', $label='', $attr='', $dtype='str')
	{	
		parent::FormControl('input', $name, $val, $label, $attr);
		$this->Attr['type'] = 'text';
		$this->DType = $dtype;
	} // end func conctructor
	
	/**
	 * Set min & max value (string lenth) of field
	 * @param 	int	min value
	 * @param	int	max value
	 * @access 	public
	 */
	function setRange($min=0, $max=0) 
	{
		if ($min) $this->Range['min'] = $min;
		if ($max) $this->Range['max'] = $max;
	} // end func setRange
	
	/**
	 * Set RegExp for validate field
	 * @param	string	regexp
	 * @access 	public
	 */
	function setReg($reg) { $this->Reg = $reg; } // end func setReg
	
	/**
	 * Set callback function for validate field
	 * @param	string	callback function name
	 * @access 	public
	 */
	function setCallback($callback) { $this->CallBack = $callback; } // end func setCallback
	
	/**
	 * Fetch value from _GET or _POST, passed by reference, if form was submitted.
	 * If element contains incorrect value, put into $err array pair 
	 * of element label and error message
	 * @param	array
	 * @param	array		array of error messages
	 * @access 	private
	 */
	function _complite(&$source, &$err) 
	{	
		$this->Attr['value'] = $this->_clean($this->_fetch($source));
		
		if (!$this->_valid())
			$err[($this->Label) ? $this->Label : $this->Attr['name']] = $this->ErrMsg;
	} // end func _complite
	
	/**
	 * "Clean" user input
	 * @param	string 	user input data
	 * @return	string	"clean data"
	 * @access 	private
	 */
	function	_clean($data)
	{
		if ('int' == $this->DataType) {
			return intval($data);
		} elseif ('double' == $this->DataType) {
			return doubleval($data);
		} else {
			return trim($data);
		}
	} // end func _clean
	
	/**
	 * Validate field value
	 * @return 	bool	coorect value or not
	 * @access 	private
	 */
	function _valid()
	{
		if ($this->Reg) {
			return preg_match($this->Reg, $this->Attr['value']);
		} elseif ($this->CallBack) {
			return $this->Callback($this->Attr['value']);
		} elseif ($this->Range) {
			$val = ('str' == $this->DType) ? strlen($this->Attr['value']) : $this->Attr['value'];
			if ($this->Range['min'] && $val < $this->Range['min']) return false;
			if ($this->Range['max'] && $val > $this->Range['max']) return false;
		}
		return true;
	} // end func _valid

} // end class TextField

/*********************************************************
 * produce textarea field
 ********************************************************/
class TextArea extends FormControl
{
	/**
	 * Param for validate field. Min & max string lenth
	 * @param	array
	 */
	var $Range;			
	/**
	 * RegExp for validate filed
	 * @param	string
	 */
	var $Reg;		
	/**
	 * name of callback function to validate field
	 * @param	string
	 */
	var $Callback;
	/**
	 * Value of the field
	 * @param	string
	 */
	var $Value;
	
	/**
	 * Constructor
	 * @param	string	name of field
	 * @param	string	value of field
	 * @param	string	label of field
	 * @param	array		attributes
	 * @access public
	 */
	function TextArea($name, $val='', $label='', $attr='')
	{
		parent::FormControl('textarea', $name, '', $label, $attr);
		$this->Value = $val;
	} // end func constructor

	/**
	 * Set field value
	 * @param	string field value
	 */
	function setValue($value) { $this->Value = $value; } // end func setValue
	
	/**
	 * Set min & max string lenth for field value
	 */
	function setRange($min=0, $max=0) 
	{
		if ($min) $this->Range['min'] = (int)$min;
		if ($max) $this->Range['max'] = (int)$max;
	} // end func setRange

	/**
	 * Set RegExp for validate field
	 * @param	string	regexp
	 * @access 	public
	 */
	function setReg($reg) { $this->Reg = $reg; } // end func setReg
	
	/**
	 * Set callback function for validate field
	 * @param	string	callback function name
	 * @access 	public
	 */
	function setCallback($callback) { $this->CallBack = $callback; } // end func setCallback

	/**
	 * Return field value
	 * @return array
	 */
	function getValue($struct=true) 
	{
		return $this->_getStruct($this->Value, $struct); 
	} // end func getValue
	
	/**
	 * Fetch value from _GET or _POST, passed by reference, if form was submitted.
	 * If element contains incorrect value, put into $err array pair 
	 * of element label and error message
	 * @param	array
	 * @param	array		array of error messages
	 * @access 	private
	 */
	function _complite(&$source, &$err) 
	{
		$this->Value = trim($this->_fetch($source));
		if (!$this->_valid())
			$err[($this->Label) ? $this->Label : $this->Attr['name']] = $this->ErrMsg;
	} // end func _complite

	/**
	 * Validate field value
	 * @return 	bool	coorect value or not
	 * @access 	private
	 */
	function _valid()
	{
		if ($this->Reg) {
			return preg_match($this->Reg, $this->Value);
		} elseif ($this->CallBack) {
			return $this->Callback($this->Value);
		} elseif ($this->Range) {
			if ($this->Range['min'] && $this->Value < $this->Range['min']) return false;
			if ($this->Range['max'] && $this->Value > $this->Range['max']) return false;
		}
		return true;
	} // end func _valid
	
	/**
	 * Build Html output
	 */
	function _createView()
	{
		$this->View = '<textarea'.$this->_attr2str().">\n";
		$this->View .= $this->Value . "</textarea>\n";
	} //end func _createView
} // end class TextArea


/*****************************************************************
 * produce hidden field
 *****************************************************************/
class Hidden extends FormControl
{
	/**
	 * Contructor
	 * @param	string	name  of the field
	 * @param	string 	value of the field
	 * @access	public
	 */
	function Hidden($name, $val='1')
	{
		parent::FormControl('input', $name, $val);
		$this->Attr['type'] = 'hidden';
	} // end func constructor

} // end class Hidden

/********************************************************************
 * produce password field
 ********************************************************************/
class Password extends FormControl
{
	/**
	 * RegExp for validate input
	 * @param string
	 */
	var $Reg = '/^[a-z0-9_\-\.]{6,12}$/i';
	/**
	 * Error message
	 * @param string
	 */
	var $ErrMsg = 'Incorrect chars';	

	/**
	 * Constructor
	 * @param	string	name of the field
	 * @param	string	value of the field
	 * @param	string	label of the field
	 * @param	array		attributes
	 * @access public
	 */
	function Password($name, $val='', $label='', $attr='')
	{	
		parent::FormControl('input', $name, '', $label, $attr);
		$this->Attr['type'] = 'password';
	} // end func constructor
	
	/**
	 * Set RegExp for validate field
	 * @param	string	regexp
	 * @access 	public
	 */
	function setReg($reg) { $this->Reg = $reg; } // end func setReg
	/**
	 * Fetch value from _GET or _POST, passed by reference, if form was submitted.
	 * If element contains incorrect value, put into $err array pair 
	 * of element label and error message
	 * @param	array
	 * @param	array		array of error messages
	 * @access 	private
	 */
	function _complite(&$source, &$err) 
	{	
		$this->Attr['value'] = trim($this->_fetch($source));
		
		if (!$this->_valid())
			$err[($this->Label) ? $this->Label : $this->Attr['name']] = $this->ErrMsg;
	} // end func _complite

	/**
	 * Validate field value
	 * @return 	bool	coorect value or not
	 * @access 	private
	 */
	function _valid()
	{
		if ($this->Reg) {
			return preg_match($this->Reg, $this->Attr['value']);
		} elseif ($this->CallBack) {
			return $this->Callback($this->Attr['value']);
		} 
		return true;
	} // end func _valid

} // end class Password

/***************************************************************
 * produce radio button
 ***************************************************************/
class Radio extends FormControl
{
	/**
	 * Constructor
	 * @param	string	name of the field
	 * @param	string	value of the field
	 * @param	string	label of the field
	 * @param	array		attributes
	 * @access public
	 */
	function Radio($name, $val, $label='', $attr='')
	{
		parent::FormControl('input', $name, $val, $label, $attr);
		$this->Attr['type'] = 'radio';
		if (!$label) $this->Label = $val;
	} // end func contructor

	/**
	 * Return value, if radio button checked
	 * If flag $struct is true, return whole structure, 
	 * according to the full element name (see _fetFullName()). 
	 * If - false, return name-value pair
	 * @param	boolean	flag
	 * @access public
	 * @return array
	 */
	function getValue($struct=true)
	{
		if (!$this->Attr['checked']) return false;
		return $this->_getStruct($this->Attr['value'], $struct);
	} // end func getValue
	
	/**
	 * Fetch field value from _GET or _POST, passed by reference.
	 * @param	array		_POST or _GET or part of it
	 * @param	array		array of error messages
	 * @access private
	 * @return array
	 */
	function _complite(&$source, &$err) 
	{ 
		$val = $this->_fetch($source);
	
		if (($this->Attr['name'] && $this->Attr['value'] == $val)
		|| (!$this->Attr['name'] && is_array($val) && in_array($this->Attr['value'], $val))) { 
			$this->Attr['checked'] = 'on';
		} else {
				unset($this->Attr['checked']);
		}
	} // end func _complite

	/**
	 * Build array for getValue method and put element value in it
	 *	@param	mix		element value
	 *	@param	boolean	build array accordind to "full" field name or not
	 * @access private
	 */
	function _getStruct($val, $struct)
	{
		if (!$this->Groups || !$struct)
			return array($this->Attr['name'] => $val);
		
		$res[$this->Groups[0]] = array();
		$data = &$res[$this->Groups[0]];
		for ($i=1; $i<sizeof($this->Groups); $i++) {
			$data[$this->Groups[$i]] = array();
			$data = &$data[$this->Groups[$i]];
		}
		if ($this->Attr['name'])			
			$data[$this->Attr['name']] = $val;
		else
			$data[] = $val;
		return $res;

	} // end func _getStruct

} // end class Radio

/******************************************************************
 * produce checkbox
 *****************************************************************/
class CheckBox extends Radio
{
	/**
	 * Constructor
	 * @param	string	name of the field
	 * @param	string	value of the field
	 * @param	string	label of the field
	 * @param	array		attributes
	 * @access public
	 */
	function CheckBox($name, $val='', $label='', $attr='')
	{
		parent::FormControl('input', $name, ($val)?$val:1, $label, $attr);
		$this->Attr['type'] = 'checkbox';
		if (!$label) $this->Label = ($name) ? $name :  $val ;
	} // end func contructor
	
	/**
	 * Fetch value from _GET or _POST, passed by reference, if form was submitted.
	 * If element contains incorrect value, put into $err array pair 
	 * of element label and error message
	 * @param	array
	 * @param	array		array of error messages
	 * @access 	private
	 */
	function _complite(&$source, &$err) 
	{ 
		unset($this->Attr['checked']);
		$val = $this->_fetch($source);
		
		if ($this->Attr['name']) { 
			
			if (($this->Attr['value'] && $this->Attr['value'] == $val))
		
				$this->Attr['checked'] = 'on';
			
		} elseif (!$this->Attr['name'] && $this->Attr['value']) {

			if (is_array($val) && in_array($this->Attr['value'], $val))
				$this->Attr['checked'] = 'on';
		}
	} // end func _complite
	
} // end class CheckBox

/*********************************************************************
 * produce tag "option". Not nessesery to use this class directly.
 * Use Select class.
 *********************************************************************/
class Option extends FormControl
{
	/**
	 * Constructor
	 * @param	string	value of the field
	 * @param	string	label of the field
	 * @param	array		attributes
	 * @access public
	 */
	function Option($val, $label='', $attr='')
	{
		parent::FormControl('option', '', $val, $label, $attr);
		if (!$this->Attr['value'] && $this->Label) $this->Attr['value'] = $this->Label;
		if ($this->Attr['value'] && !$this->Label) $this->Label = $this->Attr['value'];
	} // end func Option


	/**
	 * Return value, if option selected.
	 * @access public
	 * @return array
	 */
	function getValue()
	{
		if (!$this->Attr['selected']) return false;
		return $this->Attr['value'];
	} // end func getValue

	/**
	 * Fetch value from _GET or _POST, passed by reference, if form was submitted.
	 * @param	array
	 * @access 	private
	 */
	function _complite(&$source) 
	{
		unset($this->Attr['selected']);
		
		if (!is_array($source)) {
			if (isset($this->Attr['value']) &&  $this->Attr['value'] == $source)
				$this->Attr['selected'] = 'on';
		} elseif(is_array($source)) {
			if (isset($this->Attr['value']) &&  in_array($this->Attr['value'], $source))
				$this->Attr['selected'] = 'on';
		}
	} // end func _complite

	/**
	 * Build html output
	 * @access	private
	 * @return	void
	 */
	function _createView()
	{
		$this->View = '<option'.$this->_attr2str().'>';
		$this->View .= $this->Label . "</option>\n";
	} // end func _createView

} // end class Option

/************************************************************
 * produce select filed
 ***********************************************************/
class Select extends FormControl
{
	/**
	 * Array of childs objects (objects of the Option class)
	 * @param	array		childs objects
	 */
	var $Childs = array();
	
	/**
	 * Param for validate field. Min & max number of selected option
	 * @param array
	 */
	var $Range;
		
	/**
	 * Constructor
	 * @param	string	name of the field
	 * @param	string	value of the field
	 * @param	string	label of the field
	 * @param	array		attributes
	 * @access public
	 */
	function Select($name, $val='', $label='', $attr=null)
	{
		parent::FormControl('select', $name, '', $label, $attr);
		$this->Value = $val;
		if ($this->Attr['multiple'] ) { 
			$this->Groups[] = $this->Attr['name'];
			$this->Attr['name'] = '';
		}
	} // end func constructor
	
	/**
	 * Add new option object in $Childs array
	 * Return Id of added object on success or false
	 * @param	object	widget
	 * @access	public
	 * @return	int
	 */

	function add(&$Widget)
	{
		$this->Childs[] = &$Widget;
		if ($this->Value) {
			if ( isset($Widget->Attr['value']) && $this->Value == $Widget->Attr['value'] ) 
				$Widget->Attr['selected'] = 'on';
		}
		return $Widget->Id;
	} // end func add

	/**
	 * Wrapper for add method. 
	 * Create new option object(s) and add it to $Childs array
	 * If $value - string, only one option added
	 * If $value is array and $use_keys = true, array keys become options values. 
	 * If $use_keys = false, array values become options values
	 * @param	mix		option value or array of options values
	 * @param	string	option label
	 * @param	bool		use or not array keys as options values
	 * @access	public
	 * @return	mixed
	 */	
	function addOption($value, $label='', $use_keys=false)
	{
		if (!is_array($value)) {
			$id = $this->add(new Option($value, $label));
		} else {
			foreach ($value as $key=>$val) {
				$id[] = $this->add(new Option(($use_keys) ? $key : $val, $val));
			}
		}
		return $id;
	} // end func addOption
	
	function setValue($val) { $this->Value = $val; }
	/**
	 * Set min & max of selected options
	 * @param 	int	min value
	 * @param	int	max value
	 * @access 	public
	 */
	function setRange($min=0, $max=0) 
	{
		if ($min) $this->Range['min'] = ($this->Attr['multiple']) ? 1 : (int)$min;
		if ($max) $this->Range['max'] = ($this->Attr['multiple']) ? 1 : (int)$max;
	} // end func setRange

	/**
	 * Return value, selected option(s).
	 * If flag $struct is true, return whole structure, 
	 * according to the full element name (see _fetFullName()). 
	 * If - false, return name-value pair
	 * @param	boolean	flag
	 * @access public
	 * @return array
	 */
	function getValue($struct=true)
	{	

		foreach ($this->Childs as $i=>$Child) { 
			if (($data = $this->Childs[$i]->getValue()) !== false){
				if ($this->Attr['multiple']) 
					$res[] = $data;
				else 
					return $this->_getStruct($data, $struct);
			}
		}
		return  ($res) ? $this->_getStruct($res, $struct) : false;
	} // end func getValue

	/**
	 * Fetch value from _GET or _POST, passed by reference, if form was submitted.
	 * If element contains incorrect value, put into $err array pair 
	 * of element label and error message
	 * @param	array
	 * @param	array		array of error messages
	 * @access 	private
	 */
	function _complite(&$source, &$err) 
	{
		$s = $this->_fetch($source); 
		foreach ($this->Childs as $i=>$Child) {
			$this->Childs[$i]->_complite($s, $err);
			if ($this->Childs[$i]->Attr['selected'])
				$count++;
		}

		if ($this->Range) {
			if ($this->Range['min'] && $count <  $this->Range['min']) 
				$err[$this->Label] = $this->ErrMsg;
			if ($this->Range['max'] && $count > $this->Range['max'])
				$err[$this->Label] = $this->ErrMsg;
		}
	} // end func _complite

	/**
	 * Build array for getValue method and put element value in it
	 *	@param	mix	element value
	 *	@param	bool	build whole array?
	 * @access private
	 */
	function _getStruct($val, $struct)
	{
		if (!$this->Groups || !$struct)
			return array($this->Attr['name'] => $val);

		$res[$this->Groups[0]] = array();
		$data = &$res[$this->Groups[0]];
		for ($i=1; $i<sizeof($this->Groups); $i++) {
			$data[$this->Groups[$i]] = array();
			$data = &$data[$this->Groups[$i]];
		}
		if (!$this->Attr['name'])			
			$data = $val;
		else
			$data[$this->Attr['name']] = $val;
		return $res;

	} // end func _getStruct

	/**
	 * Build html output
	 * @access private
	 */
	function _createView()
	{
		$this->View = '<select' . $this->_attr2str() . ">\n";
		foreach ($this->Childs as $i=>$Child) {
			$this->View .= $this->Childs[$i]->getView();
		}
		$this->View .= "</select>\n";
	} // end func _createView
	
} // end class Select


/**********************************************************
 * Class to make submit button
 **********************************************************/
class Submit extends FormControl
{
	/**
	 * Flag indicate what button pressed
	 * @param bool
	 */
	var $_Submit = false;
	
	/**
	 * Constructor
	 * @param	string	button name
	 * @param	string	button value
	 * @param	array		attributes
	 * @access	public
	 */
	function Submit($name='', $val='Submit', $attr=null)
	{
		parent::FormControl('input', $name, $val, $label, $attr);
		$this->Attr['type'] = 'submit';

	} // end func constructor
	
	/**
	 * Return value only if button was pressed. So your can use 
	 * several buttons in one form. For example 'previous' - 'next', etc.
	 * If flag $struct is true, return whole structure, 
	 * according to the full element name (see _fetFullName()). 
	 * If - false, return name-value pair
	 * @param	bool	flag
	 * @access public
	 * @return array
	 */
	function getValue($struct=true)
	{
		if (!$this->_Submit) return false;
		return $this->_getStruct($this->Attr['value'], $struct);
	} // end func getValue

	/**
	 * Fetch value from _GET or _POST, passed by reference, if form was submitted.
	 * @param	array
	 * @param	array		array of error messages
	 * @access 	private
	 */
	function _complite(&$source, &$err)
	{
		if ($this->Attr['value'] == $this->_fetch($source))
			$this->_Submit = true;
	} // end func _complite

} // end class Submit


/***************************************************
 * Class to make reset button
 ***************************************************/
class Reset extends FormControl
{
	/**
	 * Constructor
	 * @param	string	button value
	 * @param	array		attributes
	 * @access	public
	 */
	function Reset($val='Submit', $attr=null)
	{
		parent::FormControl('input', '', $val, $label, $attr);
		$this->Attr['type'] = 'reset';

	} // end func constructor
	
	/**
	 * Overwrite parent method. Reset button returns no value
	 * @return 	boolean
	 */
	function getValue() { return false; } // end func getValue
} // end class Reset


/*******************************************************
 * produce form field for upload file
 *******************************************************/
class FileField extends FormControl
{
	/**
	 * Value of field.
	 * @param	array
	 */
	var $Value = array('name'=>'', 'type'=>'', 'tmp_name'=>'', 'size'=>0);
	
	/**
	 * Constructor. Has the same params as other FormControl childs classes contructors, 
	 * but $value param don't used.
	 * In difference from other form fields, 
	 * name of file field can be array element name, but no more then 2 dimentional array name
	 * @param	string	name of the field
	 * @param	string	value of the field
	 * @param	string	label of the field
	 * @param	array		attributes
	 * @access public
	 */
	function FileField($name, $value='', $label='', $attr='')
	{	
		parent::FormControl('input', $name, '', $label, $attr);
		$this->Attr['type'] = 'file';
	} // end func constructor
	
	/**
	 * Set min & max file size in bytes. 
	 * Min size means that file must be uploaded.
	 * @param	int		min size
	 * @param	int		max size
	 * @access	public
	 */
	function setRange($min=0, $max=0) 
	{
		if ($min) $this->Range['min'] = (int)$min;
		if ($max) $this->Range['max'] = (int)$max;
	} // end func setRange

	/**
	 * Fetch values from $_FILES array, if file was uploaded
	 * Has the same params as other fields, but do not use $source param
	 * @param	array
	 * @param	array		array of error message
	 */
	function _complite(&$source, &$err) 
	{
		if (!$this->Groups) {
			$this->Value = $_FILES[$this->Attr['name']];
		} else {
			$file = $_FILES[$this->Groups[0]];
			$this->Value['name'] = $file['name'][$this->Attr['name']];
			$this->Value['type'] = $file['type'][$this->Attr['name']];
			$this->Value['tmp_name'] = $file['tmp_name'][$this->Attr['name']];
			$this->Value['size'] = $file['size'][$this->Attr['name']];
		}
		//print_r($this->Value);
		if (!$this->_valid())
			$err[($this->Label) ? $this->Label : $this->Attr['name']] = $this->ErrMsg;
	} // end func _comlite
	
	/**
	 * Validate file size
	 *	@access	private
	 *	@return	bool
	 */
	function _valid()
	{
		if ($this->Range['max'] && $this->Value['size'] > $this->Range['max'])
			return false;
		return true;
	} // end func _valid
	
} // end class FileField

/******************************************************************
 * produce input tag with type=image
 *****************************************************************/
class ImageField extends FormControl
{
	var $Attr = array('border'=>1);
	/**
	 * Value of the field. Array of coords where image was clicked
	 * @param	array
	 */
	var $Value = array('x'=>0, 'y'=>0);
	/**
	 * Flag indicate that image was clicked
	 * @param	bool
	 */
	var $_Submit = false;
	
	/**
	 * Constructor
	 * @param	string	name of the field
	 * @param	string	value of the field
	 * @param	string	label of the field
	 * @param	array		attributes
	 * @access public
	 */
	function ImageField($name, $value='', $label='', $attr='')
	{	
		parent::FormControl('input', $name, '', $label, $attr);
		$this->Attr['type'] = 'image';
		$this->setAttr('src', $value);
	} // end func constructor
	
	/**
	 * Return value only when image was clicked. 
	 * If flag $struct is true, return whole structure, 
	 * according to the full element name (see _fetFullName()). 
	 * If - false, return name-value pair
	 * @param	bool	flag
	 * @access public
	 * @return array
	 */
	function getValue($struct=true)
	{
		if (!$this->_Submit) return false;
		return $this->_getStruct($this->Value, $struct);
	} // end func getValue

	/**
	 * Fetch value from _GET or _POST, passed by reference, if form was submitted.
	 * @param	array
	 * @param	array		array of error messages
	 * @access 	private
	 */
	function _complite(&$source, &$err)
	{	
		if ( (list($this->Value['x'], $this->Value['y']) = $this->_fetch($source)) != false) 
			$this->_Submit = true;
	} // end func _complite

	/**
	 * fetch click coord from GET or POST
	 * @param	array		_POST or _GET or part of it
	 * @access private
	 * @return array
	 */
	function &_fetch(&$source)
	{
		if ($this->Groups) {
			for ($i=0; $i<sizeof($this->Groups); $i++) {
				$source = &$source[$this->Groups[$i]];
			}
		} 
		
		if ($source[$this->Attr['name'].'_x'])
			return array($source[$this->Attr['name'].'_x'], $source[$this->Attr['name'].'_y']);
		return false;
	} // end func _fetch

} // end class ImageFiled

/******************************************************************
 * produce button tag, if need this exotic :))
 ******************************************************************/
class Button extends Submit
{
	var $Value;

	/**
	 * Constructor
	 * @param	string	name of the field
	 * @param	string	value of the field
	 * @param	string	label of the field
	 * @param	array		attributes
	 * @access public
	 */
	function Button($name, $val='', $label='', $attr='')
	{	
		parent::FormControl('button', $name, $val, $label, $attr);
		if ($label) $this->add(new CData($label));
	} // end func constructor

	/**
	 * Add new object to $Child array. 
	 * $Child can contain only text or image tag
	 * @param	object
	 * @access	public
	 * @return	int
	 */
	function add(&$Widget)
	{
		if ('cdata' != get_class($Widget) && 'img' != $Widget->Tag)
			return false;
		$this->Childs[] = &$Widget;
		return $Widget->Id;
	} // end func add

	/**
	 * Build html output
	 * @access	private
	 * @return	void
	 */
	function _createView()
	{
		$this->View = '<button' . $this->_attr2str().'>';
		foreach ($this->Childs as $i=>$Child)
			$this->View .= $this->Childs[$i]->getView();
		$this->View .= "</button>\n";
	} // end func _createView

} // end class Button

?>
Return current item: WebWidgets