Location: PHPKode > scripts > WebWidgets > webwidgets/Base.lib.php
<?php
/************************************************************
 *		WebWidgets
 * Library of classes to produce any HTML(XML) documents,
 * Also it can create, validate and return data from web-forms.
 * Any tag is an object. Your can build tags tree by inserting one tag 
 * into another and get its content as HTML.
 * Based upon "Composite" OOP patern.
 * Library is very flexible, so your may derive your own classes.
 * **********************************************************
 *	Version 0.8  09.10.02
 * **********************************************************
 * License: GPL - http://www.fsf.org/copyleft/gpl.txt
 * **********************************************************
 * Contain base classes:
 * 
 * WebWidget 	- abstract class
 * ETag 			- class for making any "empty" tags 
 * CData 		- class for making character data
 * Comments 	- guess :)
 * Bin 			- base class for making tags-containers
 * TableRow 	- for making tables row
 * Table 		- table creator
 * Form 			- for creating and manipulation with forms
 * TableForm 	- form in table
 * **********************************************************
 * Author: Dmitry Levashov (hide@address.com , hide@address.com)
 * *********************************************************/

/**
 * Abstract class. Parent for all widgets 
 * Declare common interface for widgets. 
 * Set default methods
 */
class WebWidget
{
	/**
	 * Unique ID
	 * @var		int
	 * @access	public
	 */
	var $Id;
	/**
	 * Tag name
	 * @var		string
	 * @access	public
	 */
	var $Tag;
	/**
	 * Array of tag's attributes
	 * @var		array
	 * @access	public
	 */
	var $Attr = array();
	/**
	 * Html output of tag
	 * @var 		string
	 * @access	public
	 */
	var $View;

	/**
	 * Constructor. Set Id, tag and attributes. 
	 * @param	string	tag name
	 * @param	array		attributes
	 */
	function WebWidget($tag, $attr='')
	{
		$this->Id = WebWidget::_makeId();
		$this->Tag = strtolower($tag);
		if ($attr) $this->setAttr($attr);
	} // end func constructor

	/**
	 * Set tag attribute(s) 
	 * @access 	public
	 * @returns	void
	 */
	function setAttr($attr, $val='')
	{	
		if (!$attr) return;
		if (!is_array($attr)) {
			$this->Attr[$attr] = $val;
		} else {
			foreach ($attr as $k=>$v) {
				$this->Attr[$k] = $v;
			}
		}
	} // end func setAttr

	/**
	 * Return attribute(s). If $attr param is not set, returns all attributes, 
	 * otherwise retun attrute with $attr name.
	 * @param	$attr	string
	 * @access	public
	 * @return	string(array)
	 */
	function getAttr($attr='')
	{
		if (!$attr) return $this->Attr;
		return $this->Attr[$attr] ? $this->Attr[$attr] : false;
	} // end func getAttr
	
	/**
	 * Insert object into object-container
	 * Virtual method
	 * Object-leaf do nothing
	 * Object-container add $Widget to his array of childs objects
	 * Return Id of added object on success or false
	 * @param	object	widget
	 * @access	public
	 * @return	int
	 */
	function add(&$Widget) { return false; } // end func add
	
	/**
	 * Search object with Id in his $Childs array and return it by reference if it exists. 
	 * if $rec set to true, search object in all childs
	 * @param	int	object Id
	 * @param	bool	recursive search?
	 * @access 	public
	 * @return	obj
	 */
	function &getChild($id, $rec=false) { return false; } // end func &getChild
	
	/**
	 * Return Html output
	 * @access	public
	 * @return	string
	 */
	function getView() 
	{ 
		if (!$this->View) $this->_createView(); 
		return $this->View;
	} // end func getView
	
	/**
	 *	show html output
	 *	@access	public
	 *	@retrun 	void
	 */
	function view() { echo $this->getView(); } // end func view
	
	/**
	 * Return value, which user input in form field. 
	 * Only form elements return his value. 
	 * Object-container call this method for all his childs
	 * Object-leaf do nothing and return false. 
	 * If name of field is set as name of array's element 
	 * return value as $array1[array2]...[element] = $value, 
	 * otherwise return value as array($element=>$value)
	 * @access	public
	 * @return	array
	 */
	function getValue($struct=true) { return false; } // end func getValue

		
	/**
	 * Return object attributes as string
	 * @access private
	 * @return string
	 */
	function _attr2str()
	{
		foreach ($this->Attr as $k=>$v) {
			$str .= ' ' . $k . '="' . htmlspecialchars($v) . '"';
		}
		return $str;
	}	// end func _attr2str
	
	/**
	 * Produce unique Id, small int. Static method
	 * @access 	privare
	 * @access	static
	 * @return	int
	 */
	function _makeId() 
	{
		static $id = 0;
		return ++$id;
	} // end func _makeId
	
	/**
	 * Build Html output
	 * @access private
	 * @return void
	 */
	function _createView() {} // end func _createView

	/**
	 * Used by form elements. 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		_GET or _POST by reference 
	 * @param	array		array of error messages	
	 * @access	private
	 * @return void
	 **/

	function _complite(&$source, &$err) {} // end func _complite
	
} // end class WebWidget


/**********************************************************
 * Class to build any empty tags
 **********************************************************/
class ETag extends WebWidget
{
	/**
	 * Build html output
	 */
	function _createView()
	{
		$this->View = '<' . $this->Tag . $this->_attr2str() . "/>\n";
	} // end func _createView
	
} // end class ETag

/*********************************************************
 * Class to create any character data
 *********************************************************/
class CData extends WebWidget
{
	/**
	 * Constructor
	 * @param	string	character data
	 */
	function CData($str) 
	{
		$this->Id = WebWidget::_makeId();
		$this->View = $str; 
	} // end func constructor

	/**
	 * Add text to his content. 
	 * If $pos = 0 new text replace old content, 
	 * if $pos > 0 text adeed after old content, 
	 * if < 0 - before
	 * @param	string	new text
	 * @param	int		position where text will added
	 * @return void
	 */
	function add($str, $pos=1)
	{
		if ($pos == 0) $this->View = $str;
		$this->View = $pos>0 ? $this->View . $str : $str . $this->View;
	} // end func add

} // end class CData

/********************************************************
 * Simply html comments 
 *******************************************************/
class Comments extends WebWidget
{
	/**
	 * @param string	comments content
	 */
	function Comments($str) 
	{ 
		$this->Id = WebWidget::_makeId();
		$this->View .= '<!-- ' . $str . " -->\n"; 
	} // end func constructor
} // end class Comments


/*******************************************************
 * Base class for tags - containers
 *******************************************************/
class Bin extends WebWidget
{
	/**
	 * @param	array Array of childs objects
	 */
	var $Childs = array();
		
	/**
	 * Add object to $Childs array
	 * @param	object	object to add in container
	 * @access	public
	 * @return	int
	 */
	function add(&$Widget)
	{
		if (!is_subclass_of($Widget, 'webwidget'))
			return false;

		$this->Childs[] = &$Widget;
		return $Widget->Id;
	} // end func add

	/**
	 * Search object with Id in his $Childs array and return it by reference if it exists. 
	 * if $rec set to true, search object in all childs
	 * @param	int	object Id
	 * @param	bool	recursive search?
	 * @access 	public
	 * @return	object
	 */
	function &getChild($id, $rec=false)
	{
		foreach ($this->Childs as $i=>$Child)
		{
			if ($id == $Child->Id)
				return $this->Childs[$i];
			if ($rec && ($Child = &$this->Childs[$i]->getChild($id)) != false)
				return $Child;
		}
		return false;
	} // end func &getChild

	/**
	 * Collect values from all childs and return its. 
	 * @param	array
	 * @access	public
	 * @return array
	 */
	function getValue($struct=true)
	{
		$data = array();
		foreach ($this->Childs as $i=>$Child) {
			if ( ($child_data = $this->Childs[$i]->getValue($struct)) !== false )
				$data = array_merge_recursive($data, $child_data);
		}
		return $data;
	} // end func getValue


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

	/**
	 * Call _complite method for all childs
	 * @param	array		_GET or _POST by reference 
	 * @param	array		array of error messages	
	 * @access	private
	 */
	function _complite(&$source, &$err) 
	{
	//	echo "Im ".$this->Tag.'<br>';
		
		foreach ($this->Childs as $i=>$Child) { //echo get_class($Child).'<br>';
			$this->Childs[$i]->_complite($source, $err);
		}
	} // end func _complite
	
} // end class Bin


/******************************************************
 * produce row of table
 ******************************************************/
class TableRow extends Bin
{
	var $Tag = 'tr';
	/**
	 * Row size. Number of cells in row, unlimited if 0
	 * @param	int
	 */
	var $Size = 0;

	/**
	 * Empty cells attrubutes
	 * @param	array
	 */
	var $CellAttr = array();

	/**
	 * Position of next free cell
	 * @param	int
	 */
	var $_next = 0;
		
	/**
	 * Constructor
	 * @param	int	number of cells in row
	 * @param	array	attrubutes
	 */
	function TableRow($w=0, $attr = null)
	{
		$this->Id = WebWidget::_makeId();
		$this->setAttr($attr);
		if ($w > 0) $this->Size = (int)$w;
	} // end func constructor 

	/**
	 * Set attrubutes for empty cells
	 * @param	mixed		attribute name or array of attributes
	 * @param	string	attrubute value
	 */
	function setEmptyCellAttr($attr, $value='') 
	{
		if (!is_array($attr))
			$this->CellAttr[$attr] = $value;
		else
			$this->CellAttr = $attr;
	} // end func setEmptyCellAttr
	
	/**
	 * Add cell to row.
	 * If $x is set, add cell in position number $x,
	 * if no - add to next free position
	 * @param	object 	cell object
	 * @param	int		position number
	 * @return	int		cell Id
	 */
	function add(&$Cell, $x=null)
	{
		$w = ($Cell->Attr['colspan']>1) ? $Cell->Attr['colspan'] : 1;
	
		if (($x = $this->_checkPosition($x, $w-1, is_int($x)?false:true)) === false)
			return false;

		$this->Childs[$x] = &$Cell;
		if ($this->_next <= $x) 
			$this->_next = $x + $w;
		if ($w > 1) 
			$this->_markSpanned($x+1, $x+$w);
		
		return $Cell->Id;
	} // end func add

	/**
	 *	Mark spanned positions.
	 *	@param	int	first spanned position
	 *	@param	int	last spanned position
	 *	@access private
	 */
	function _markSpanned($begin, $end) 
	{	
		while ($begin < $end) { $this->Childs[$begin++] = new CData(''); }
	} // end func _markSpanned

	/**
	 * Check is it free position $x, if $x is set, or
	 * search next free position
	 * @param	int	position number
	 * @param	int	number of neede free positions after $x
	 * @param	int	do we search free position?
	 *
	 */
	function _checkPosition($x='', $w=0, $search=true)
	{	
		if (!is_int($x)) $x = $this->_next;
		if ($this->Size > 0 && $x+$w >= $this->Size)
			return false;
		
		$pos = array_keys($this->Childs);
		sort($pos);
		$test = array_intersect($pos, range($x, $x+$w));	
	
		if (sizeof($test)) {
			
			if (!$search) { 
				return false;
			}
			return $this->_checkPosition(end($test)+1, $w, 1);
		}
		return $x;
	} // end func _checkPosition
	
	/**
	 * build html output
	 * @access private
	 */
	function _createView()
	{	
		ksort($this->Childs);
		$prev = -1;
		$this->View = '<' . $this->Tag . $this->_attr2str() . ">\n";

		foreach ($this->Childs as $i=>$Childs) {
			if ($i - $prev > 1) {
				$this->View .= $this->_emptyCell($i-$prev-1);
			}
			$this->View .= $this->Childs[$i]->getView();
			$prev = $i;
		}
		
		if ($this->Size && $i < $this->Size+1) {
			$this->View .= $this->_emptyCell($this->Size - $i -1	);
		}				

		$this->View .= '</' . $this->Tag . ">\n";
	
	} // end func _createView

	/**
	 * Return html string with $num empty cells.
	 *	@param	int	number of neede empty cells
	 */
	function _emptyCell($num) {

		if ($this->CellAttr) {
			foreach ($this->CellAttr as $k=>$v) {
				$attr .= ' '. $k . '="'.htmlspecialchars($v).'"';
			}
		}
		while($i++ < $num)
			$str .= '<td'.$attr.">&nbsp;</td>\n";
		return $str;
	} // end func _emptyCell

} // end class TableRow


/**************************************************************
 * produce table
 * There are two ways to add cells in table:
 * one by one - to next free place,
 * to set coordinates (column number, row number).
 * Your can combine its.
 *************************************************************/
class Table extends Bin
{
	var $Tag = 'table';
	/**
	 * Table height.
	 * @param	int	Number of rows in table
	 */
	var $Height;

	/**
	 * Table width.
	 * @param	int	Number of cells in row
	 */
	var $Width;
	
	/**
	 * Default cell attrubutes
	 * @param	array
	 */
	var $CellAttr = array();

	/**
	 * Position of next free row
	 * @param	integer
	 */
	var $_next = 0;
	
	/**
	 * Constructor. To create 'unlimited' table set $w and $h to 0.
	 * @param	int	number of cells in row
	 * @param	int	number or rows in table
	 * @param	array	attrubutes
	 */
	function Table($w=0, $h=0, $attr = null)
	{
		$this->Id = WebWidget::_makeId();
		$this->setAttr($attr);
		$this->Height = (int)$h;
		$this->Width = (int)$w;
	} // end func constructor
	
	/**
	 * Set default table cells attrubutes
	 * @param	mixed		attribute name or array of attributes
	 * @param	string	attrubute value
	 */
	function setCellAttr($attr, $value='')
	{
		if (!is_array($attr)) {
			$this->CellAttr[$attr] = $value;
		} else {
			$this->CellAttr = $attr;
		}
	} // end func setCellAttr

	/**
	 * (Create and) add cell to table.
	 * If Widget is table cell (Bin object with Tag=td or th) - add it.
	 * If no - create new cell, put Widget to this new cell and add cell to table.
	 * (see _makeCell() method)
	 * @param	object	cell object or cell content object
	 * @param	int		cell number
	 * @param	int		row number
	 * @array	array		attribute for new cell
	 * @param	string	type of creating cell (td || th)
	 * @access	public
	 * @return	int
	 */
	function add(&$Widget, $x=null, $y=null, $attr=null, $type='td')
	{	
		if ('td' == $Widget->Tag || 'th' == $Widget->Tag) {
			return $this->_addCell($Widget, $x, $y);
		} else {
			return $this->_makeCell($Widget, $x, $y, $attr, strtolower($type));
		}
	} // add func add
	

	/**
	 * Add cell to table. This method calls by add() and _makeCell() methods.
	 * @param	object	cell object
	 * @param	int		cell number
	 * @param	int		row number
	 * @access	private
	 * @retur	int
	 */
	function _addCell(&$Cell, $x, $y) 
	{
		$w = ($Cell->Attr['colspan']>1) ? $Cell->Attr['colspan'] : 1;
		$h = ($Cell->Attr['rowspan']>1) ? $Cell->Attr['rowspan'] : 1;
		
		if ($this->Width && $x + $w - 1 >= $this->Width) return false;

		if (is_int($y)) {
			if (($id = $this->_getRowId($y)) === false) return false;
			if (!$this->Childs[$y]->add($Cell, $x)) return false;
		} else {
			$y = $this->_next;
			while ($this->_getRowId($y) && ($id = $this->Childs[$y]->add($Cell, $x))===false) {
				$y++;
			}
			if (!$id) return false;
		}
		
		if ($y >= $this->_next) $this->_next = $y;
		if ($h > 1)	$this->_markSpanned($y+1, $y+$h, (int)$x, $x+$w);
		
		return $Cell->Id;
	} // end func _addCell
	
	
	/**
	 * Create new cell object and passed it to _addCell method.
	 * @param	object	content for new cell
	 * @param	int		cell number
	 * @param	int		row number
	 * @param	array		cell attrubutes
	 * @param	string	type of creating cell (td || th)
	 * @access	private
	 * @return	int
	 */
	function _makeCell(&$Widget, $x,$y, $attr, $type)
	{
		if (!$attr) $attr = $this->CellAttr;

		$Cell = new Bin($type == 'th' ? $type : 'td', $attr);
		$Cell->add($Widget);
		return $this->_addCell($Cell,$x,$y);
	} // end func _createCell
	
	/**
	 * Mark spanned cells in row objects.
	 * @param	int	first row number
	 * @param	int	last row number
	 * @param	int	first cell number
	 * @param	int	last cell number
	 */
	function _markSpanned($y1, $y2, $x1, $x2) 
	{ 
		while ($y1 < $y2) {
			if (!$this->_getRowId($y1))
				return false;
			$this->Childs[$y1]->_markSpanned($x1,$x2);
			$y1++;
		}
	} // end func _markSpanned
	

	/**
	 * Check, is it free position with coord $x $y (if $x & $y is set), 
	 * or search next free position.
	 * @param	int	cell number
	 * @param	int	row number
	 * @param	int	cell width
	 * @param	int	cell height
	 * @access	private
	 * @return	bool
	 */
	function _getFree($x,$y,$w,$h)
	{
		if (is_int($y)) {
			
			if ($y + $w -1 >= $this->Size) return false;
			
			$id = $this->_getRowId($y);
			
			if (($x = $this->Childs[$id]->_getFree($x, $w)) !== false)
				return array($id, $x, $y);
							
		} else {

			while ($this->_next + $h - 1 < $this->Size) {
				
				$id = $this->_getRowId($this->_next);
				if ( ($x = $this->Childs[$id]->_getFree($x, $w)) !== false )
					return array($id, $x, $y);
				$this->_next++;
			}
			
		}
		return false;
	} // end func _getFree
	
	/**
	 * Return Id of row in position $pos.
	 * If row does not exist - create it.
	 *	@param	int	row position
	 *	@access	private
	 *	@retrun	int
	 */
	function _getRowId($pos)
	{
		if ($this->Childs[$pos])
			return $this->Childs[$pos]->Id;
		if ($this->Height > 0 && $pos >= $this->Height)
			return false;
		
		$Row = new TableRow($this->Width);
		if ($this->CellAttr)
			$Row->setEmptyCellAttr($this->CellAttr);
		$this->Childs[$pos] = $Row;
		return $Row->Id;
		
	} // end func _getRowId
	
} // end class Table



/********************************************************************
 * produce and manipulate form
 * 
 * Synopsis:
 *
 * $MyForm = new Form('my_form.php', 'POST', array('enctype'=>'multipart/form-data'));
 * $MyForm->add(new CData('Your name: '));
 * $MyForm->add(new TextField('user_name', '', 'Name'));
 * $MyForm->add(new CData('Your email: '));
 * $Email = new TextField('email', 'hide@address.com', 'Email');
 * $Email->setReg('/\w{2,20}@\w{2,20}\.([a-z]){2,4}/i');
 * $MyForm->add($Email);
 * $MyForm->add(new Submit());
 *
 * if (!$MyForm->isSubmit()) {
 *		$MyForm->view();
 * } else {
 *		if (!$MyForm->valid()) {
 *			echo $MyForm->getErrMsg();
 *			$MyForm->view();
 *		} else {
 *			$data = $MyForm->getValue();
 *			echo "Your name is: " . $data['user_name'] . "<br>";
 *			echo "Your email is: " . $data['email'] . "<br>";
 *		}
 * }
 *********************************************************************/

class Form extends Bin
{
	var $Tag = 'form';
	/**
	 * Flag indicate that form was sumitted
	 * @param	bool
	 */
	var $Submit = false;
	/**
	 * Array of error messages. Keys are labels of filelds with incorrect input data, 
	 * values are - error messages
	 * @param	array
	 */
	var $Err = array();
	
	/**
	 * Constructor
	 * @param	string	"action" attribute of form, url
	 * @param	string	"method" attribute
	 *	@param	array		attributes
	 */
	function Form($action, $method='POST', $attr='')
	{
		$this->Id = WebWidget::_makeId();
		if ($attr) $this->setAttr($attr);
		$this->Attr['action'] = $action;
		$this->Attr['method'] = strtoupper($method);
		$this->add(new Hidden('_form_'));
	} // end func constructor

	/**
	 * Check, is form submit or not.
	 * If form submit, call _complite method to all childs
	 *	@access	public
	 *	@return	bool
	 */
	function isSubmit()
	{
		if ($this->Submit) return true;
		if ('POST' == $this->Attr['method'] && isset($_POST['_form_'])) {
			$this->_complite($_POST, $this->Err);
			return $this->Submit = true;
		}
		if ('GET' == $this->Attr['method'] && isset($_GET['_form_'])) {
			$this->_complite($_GET, $this->Err);
			return $this->Submit = true;
		}
		return false;
	} // end func isSubmit

	/**
	 * Validate form fields
	 * @access	public
	 * @return	bool
	 */
	function valid()
	{
		return (sizeof($this->Err)) ? false : true;
	} // end func valid
	

	function getValue()
	{
		$value = parent::getValue();
		unset($value['_form_']);
		return $value;
	}
	/**
	 * return error messages as string
	 * @access	public
	 * @return	string
	 */
	function getErrMsg()
	{
		foreach ($this->Err as $k=>$v) {
			$str .= $k . ': ' . $v . '<br>';
		}
		return $str;
	} // end func getErrMsg
	
} // end class Form


/***************************************************************************
 * Produce form in table
 * 
 * Synopsys:
 * 
 * $Form = new TableForm($PHP_SELF);
 * $Form->setTableAttr(array('border'=>1, 'cellpadding'=>4, 'cellspacing'=>0));
 *	$Form->setTableSize(2);
 * $Form->add(new CData('For header'), '', '', 2,'', array('align'=>'center'));
 * $Field = new TextField('field_name', 'Default value', 'Field label');
 * $Form->addFieldWithLabel($Field);
 * $Form->add(new Submit(), '','',2,'',array('align'=>'center'));
 * 
 * if (!$Form->isSubmit()) {
 *		$Form->view();
 * } else {
 *		if (!$Form->valid()) {
 *			echo $Form->getErrMsg();
 *			$Form->view();
 *		} else {
 *			$data = $Form->getValue();
 *		}
 * }
 *******************************************************************************/
class TableForm extends Form
{
	/**
	 * Table, where placed input fields
	 * @param	object
	 */
	var $Table;

	/**
	 * Default cell attrubutes
	 * @param	array
	 */
	var $CellAttr = array();
	
	/**
	 * Constructor
	 * @param	string	"action" attribute of form, url
	 * @param	string	"method" attribute
	 *	@param	array		attributes
	 */
	function TableForm($action, $method='POST', $attr='')
	{
		parent::Form($action, $method, $attr);
		$this->Table = new Table(2);
		$this->Childs[] =&$this->Table;
	} // end func constructor

	/**
	 * Set Table width and height
	 * @param	int	table width
	 * @param	int	table height
	 */
	function setTableSize($w=0, $h=0)
	{
		$this->Table->Width = (int)$w;
		$this->Table->Height = (int)$h;
	} // end func setTableSize
	
	/**
	 * Set Table attributes
	 * @param	mixed		attribute name or array of attributes
	 * @param	string	attribute value
	 */
	function setTableAttr($attr, $value='')
	{
		$this->Table->setAttr($attr, $value);
	} // end func setTableAttr

	/**
	 * Set default table cells attrubutes
	 * @param	mixed		attribute name or array of attributes
	 * @param	string	attrubute value
	 */
	function setCellAttr($attr, $value='')
	{
		if (!is_array($attr)) {
			$this->CellAttr[$attr] = $value;
		} else {
			foreach ($attr as $k=>$v)
				$this->CellAttr[$k] = $v;
		}
	} // end func setCellAttr

	/**
	 * Add Widget th $Childs array. 
	 * @param	object	widget
	 * @param	int		cell number
	 * @param	int		row number
	 * @param	int		cell colspan attribute
	 * @param	int		cell rowspan attribute
	 * @param	array		cell attrutes
	 *	@return	int		widget id
	 */
	function add(&$Widget, $x='', $y='', $colspan='', $rowspan='', $attr='')
	{	
		if (!is_subclass_of($Widget, 'webwidget'))
			return false;

		if ('hidden' == get_class($Widget)) {
			$this->Childs[] = &$Widget;
		} else {
			if (!$attr) 
				$attr = $this->CellAttr;
			if ($colspan > 1)
				$attr['colspan'] = (int)$colspan;
			if ($rowspan > 1)
				$attr['rowspan'] = (int)$rowspan;
			
			$this->Table->add($Widget, $x, $y, $attr);
		}	 
		return $Widget->Id;
		
	} // end func add

	/**
	 * Add 2 cells to table.
	 * First contain Widget->Label, second - Widget
	 * @param	object	widget
	 * @param	int		label cell number
	 * @param	int		row number
	 * @param	int		label's cell colspan attribute
	 * @param	int		label's cell rowspan attribute
	 * @param	array		label's cell attrutes
	 * @param	int		widget's cell colspan attribute
	 * @param	int		widget's cell rowspan attribute
	 * @param	array		widget's cell attrutes
	 * @return	int		widget id
	 */
	function addFieldWithLabel(&$Widget, $x='', $y='', $l_cspan='', $l_rspan='', $l_attr='', 
			$f_cspan='', $f_rspan='', $f_attr='') 
	{
	
		$this->add(new CData($Widget->Label), $x, $y, $l_cspan, $l_rspan, $l_attr);
		$this->add($Widget,'','', $f_cspan, $f_rspan, $f_attr);
		return $Widget->Id;
	} // end func addFieldWithLabel
	
} // end class TableForm


?>
Return current item: WebWidgets