Location: PHPKode > projects > OpenNitro > trunk/Nitro/Libraries/Form.inc.php
<?php
//
// +---------------------------------------------------------------------------+
// | Nitro :: Libraries :: Form                                                |
// +---------------------------------------------------------------------------+
// | Copyright (c) 2004-2007 June Systems BV                                   |
// +---------------------------------------------------------------------------+
// | This library is free software; you can redistribute it and/or modify it   |
// | under the terms of the GNU Lesser General Public License as published by  |
// | the Free Software Foundation; either version 2.1 of the License, or (at   |
// | your option) any later version.                                           |
// |                                                                           |
// | This library is distributed in the hope that it will be useful, but       |
// | WITHOUT ANY WARRANTY; without even the implied warranty of                |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser   |
// | General Public License for more details.                                  |
// |                                                                           |
// | You should have received a copy of the GNU Lesser General Public License  |
// | along with this library; if not, write to the Free Software Foundation,   |
// | Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA            |
// +---------------------------------------------------------------------------+
// | Authors: Siggi Oskarsson <hide@address.com>                          |
// | Authors: Jesper Avot <hide@address.com>                        |
// +---------------------------------------------------------------------------+
//
// $Id: Form.inc.php 230 2008-05-13 13:34:54Z june $
//

/**
 * This file contains all the Form classes in Nitro. These can be used
 * to create media independant forms which can be drawn for different
 * kinds of media, dependant on the template used.
 *
 * @package			Nitro
 * @subpackage	Libraries
 * @author 			Siggi Oskarsson
 * @author 			Jesper Avot
 * @version 		$Revision: 1.50 $
 * @copyright		2004-2007 June Systems BV
 */

/**
 * Defines need by the classes in this file
 */
define ('NITRO_DEFAULT_FORMTEMPLATE', 	"file:".NITRO_PATH."Defaults/Templates/Form.tpl");
define ('NITRO_DEFAULT_WIDGETTEMPLATE', "file:".NITRO_PATH."Defaults/Templates/Widget.tpl");

/**
 * Require the Nitro template engine
 */
require_once "Nitro/Template.inc.php";

/**
 * The Form Model class
 *
 * This is the base class for all the other Form classes.
 * This class contains the commonly used functions, so they
 * don't have to be rewritten in every class.
 * This is a private class and should only be used as a parent
 * for all Form classes.
 *
 * @package			Nitro
 * @subpackage	Libraries
 * @access			private
 */
class FormModel {
	/**
	 * Array with all the option objects.
	 *
	 * @var	array	$Options
	 */
	var $Options = array();

	/**
	 * Array with all the custom objects/values.
	 *
	 * @var array	$Custom
	 */
	var $Custom = array();

	/**
	 * FormModel class constructor
	 *
	 * Not used yet, but implemented for future use.
	 *
	 * @ignore
	 */
	function FormModel()
	{
	}

  /**
	 * FormModel factory
	 *
	 * Use this function to create a form instance i.o. the constructor.
	 *
	 * @param string $Subclass The subclass to instantiate
	 *        subclasses: Form, Group, Option, Tab
	 * @param array  $aParams  The input parameters for the subclass
	 *
	 * @todo  Split Form.inc.php in separate files for each subclass, build Lazy Load (require_once in switch stmnt)
	 *        Rename *this* file to FormModel.inc.php
	 */
	function &Factory($Subclass, $aParams)
	{
		DebugGroup(__CLASS__, __FUNCTION__, '', __FILE__, __LINE__, DEBUG_MOD_OK);

		if (!is_array($aParams)) {
		  Debug(__CLASS__, __FUNCTION__, 'Form: \'aParams\' is not an array', __FILE__, __LINE__, DEBUG_MOD_ERR);
		  $Subclass = '';
		  $instance = FALSE;
		}

		$classname = 'Form' . $Subclass;
    switch ($Subclass) {
      case 'Form':
	      //if (file_exists('Form.inc.php')) { }    For future use

	      if (class_exists('Form')) {
		      //ensure params are set
		      $aParams['name']        = isset($aParams['name'])
		                              ? $Name = $aParams['name'] : $Name = '';
		      $aParams['action']      = isset($aParams['action'])
		                              ? $Action = $aParams['action'] : $Action = FALSE;
		      $aParams['method']      = isset($aParams['method'])
		                              ? $Method = $aParams['method'] : $Method = 'POST';
          $aParams['encType']     = isset($aParams['encType'])
		                              ? $encType = $aParams['encType'] : $encType = 'multipart/form-data';
          $aParams['onsSubmit']   = isset($aParams['onsSubmit'])
		                              ? $onSubmit = $aParams['onsSubmit'] : $onSubmit = NULL;
          $aParams['splitValues'] = isset($aParams['splitValues'])
		                              ? $SplitValues = $aParams['splitValues'] : $SplitValues = FALSE;

          $instance = &new Form($Name, $Action , $Method , $encType, $onSubmit, $SplitValues);
				} else {
          $instance = FALSE;
				}
      break;

      case 'Group':
	      if (class_exists($classname)) {
         //ensure params are set
		      $aParams['name']        = isset($aParams['name'])
		                              ? $Name = $aParams['name'] : $Name = '';
		      $aParams['id']          = isset($aParams['id'])
		                              ? $ID = $aParams['id'] : $ID = NULL;
		      $aParams['lable']       = isset($aParams['lable'])
		                              ? $Lable = $aParams['lable'] : $Lable = NULL;
          $aParams['widgetType']  = isset($aParams['widgetType'])
		                              ? $WidgetType = $aParams['widgetType'] : $WidgetType = 'GROUP';
          $aParams['legend']      = isset($aParams['legend'])
		                              ? $Legend = $aParams['legend'] : $Legend = NULL;
          $aParams['display']     = isset($aParams['display'])
		                              ? $Display = $aParams['display'] : $Display = 'inline';

		    	$instance = &new $classname($Name, $ID, $Lable, $WidgetType, $Legend, $Display);
			  } else {
	        $instance = FALSE;
			  }
      break;

      case 'Option':
        if (class_exists($classname)) {
           //ensure params are set
		     	$aParams['name']   = isset($aParams['name'])
		                         ? $Name = $aParams['name'] : $Name = '';
		      $aParams['option'] = isset($aParams['option'])
		                         ? $Option = $aParams['option'] : $Option = NULL;

          $instance = &new $classname($Name, $Option);
				} else {
          $instance = FALSE;
				}
      break;

      case 'Tab':
        if (class_exists($classname)) {
          //ensure params are set
		     	$aParams['name']   = isset($aParams['name'])
		                         ? $Name = $aParams['name'] : $Name = '';
		      $aParams['id']     = isset($aParams['id'])
		                         ? $ID = $aParams['id'] : $ID = NULL;
		      $aParams['NewWay'] = isset($aParams['NewWay'])
		                         ? $NewWay = $aParams['NewWay'] : $NewWay = 'no';

          $instance = &new $classname($Name, $ID, $NewWay);
				} else {
          $instance = FALSE;
				}
      break;

      default:
        Debug(__CLASS__, __FUNCTION__, "Form: unknown subclass ".$Subclass, __FILE__, __LINE__, DEBUG_MOD_ERR);
        $instance = FALSE;
    }

		DebugCloseGroup(DEBUG_MOD_OK);

		return $instance;
	}

	/**
	 * AddOptionString
	 *
	 * Creates a new option on the form from the standard option string.
	 * This string is parsed and an object is created which is added to
	 * the form via the AddOption function.
	 *
	 * @see AddOption()
	 * @see FormOption::ParseOptionString()
	 * @param		string	$Name						Name of option to add. (default is FALSE)
	 * @param		string	$OptionString		String definition of option. (default is FALSE)
	 * @return	mixed										The output of the AddOption() function.
	 * @access	public
	 */
	function AddOptionString($Name = FALSE, $OptionString = FALSE)
	{
		$Option = FALSE;

		if ($Name !== FALSE && $OptionString !== FALSE) $Option = new FormOption($Name, $OptionString);

		return $this->AddOption($Option);
	}

	/**
	 * AddOptionsFromArray
	 *
	 * Loops through the given array and adds all the options.
	 *
	 * @see AddOptionString()
	 * @param		array		$Options	Array with the Options to add. (default is FALSE)
	 * @return	mixed							The output of the AddOptionString() function.
	 * @access	public
	 */
	function AddOptionsFromArray($Options = FALSE)
	{
		$RV = FALSE;

		if ($Options !== FALSE && is_array($Options)) {
			foreach ($Options AS $Name => $OptionString) {
				$this->AddOptionString($Name, $OptionString);
				$RV = TRUE;
			}
		}

		return $RV;
	}

	/**
	 * AddOption
	 *
	 * Adds an new Form option to the Options array.
	 *
	 * @param		object	$Option		The new Form option object. (default is FALSE)
	 * @return	bool		$RV				TRUE or FALSE
	 * @access	public
	 */
	function AddOption($Option = FALSE)
	{
		$RV = FALSE;

		if ($Option !== FALSE && is_object($Option)) {
			$this->Options[] = $Option;
			$RV = TRUE;
		}

		return $RV;
	}

	/**
	 * AddTab
	 *
	 * Alias for AddOption()
	 *
	 * @see AddOption()
	 * @param		object	$Option		The new Form option object. (default is FALSE)
	 * @return	mixed							The output of the AddOption() function.
	 * @access	public
	 */
	function AddTab($Option = FALSE)
	{
		return $this->AddOption($Option);
	}

	/**
	 * AddCustom
	 *
	 * Adds an new Custom object/value to the Custom array.
	 * The custom object/value can be called within the template
	 * by {$Custom.xxx}.
	 *
	 * @param		string	$Variable		The variable-name of the new Custom object/value.
	 * @param 	mixed		$Value			The value of the new variable.
	 * @return	bool		$RV					TRUE or FALSE.
	 * @access	public
	 */
	function AddCustom($Variable = FALSE, $Value = FALSE)
	{
		$RV = FALSE;

		if ($Variable !== FALSE && $Value !== FALSE) {
			$this->Custom[$Variable] = $Value;
			$RV = TRUE;
		}

		return $RV;
	}


	/**
	 * Draw
	 *
	 * This function is just a placeholder, it should be overwritten by the children.
	 */
	function Draw()
	{
	}

	/**
	 * DrawXML
	 *
	 * This function is just a placeholder, it should be overwritten by the children.
	 */
	function DrawXML()
	{
	}

	/**
	* function array_join
	* merges 2 arrays preserving the keys,
	* even if they are numeric (unlike array_merge)
	* if 2 keys are identical, the last one overwites
	* the existing one, just like array_merge
	* merges up to 10 arrays, minimum 2.
	*
	* Author: hide@address.com
	* Source: http://nl3.php.net/manual/en/function.array-merge.php#69991
	*/
	function array_join($a1, $a2, $a3=null, $a4=null, $a5=null, $a6=null, $a7=null, $a8=null, $a9=null, $a10=null)
	{
		$a = array();
		foreach ($a1 AS $key => $value) $a[$key]=$value;
		foreach ($a2 AS $key => $value) $a[$key]=$value;
		if (is_array($a3)) $a = array_join($a,$a3,$a4,$a5,$a6,$a7,$a8,$a9,$a10);

		return $a;
	}
}

/**
 * The Form class
 *
 * This class contains the form definition. All controls will
 * be added to the main form class to be drawn.
 *
 * <CODE>
 * $myForm = new Form("FormName", "FormAction", "FormMethod: POST or GET", "FormEncType", "FormOnSubmitHandler", "SplitValues: TRUE/FALSE");
 *
 * $myForm->AddButton('Method[SAVE]', array('Type' => 'SUBMIT', 'ID' => '', 'Value' => Language('Save')));
 * $myForm->AddButton('Method[APPLY]', array('Type' => 'SUBMIT', 'ID' => '', 'Value' => Language('Apply')));
 * $myForm->AddButton('Method[CANCEL]', array('Type' => 'SUBMIT', 'ID' => '', 'Value' => Language('Cancel')));
 *
 * $myForm->AddOptionString("ID", "HIDDEN/VALUE=".$ID);
 * $myForm->AddOptionString("Name", "TEXT/VALUE=Name/MAXLENGTH=50/LABLE=Name/STYLE=width: 250");
 * $myForm->AddOptionString("Username", "TEXT/VALUE=$Username/LABLE=Username/MAXLENGTH=16");
 * $myForm->AddOptionString("Password", "PASSWORD/LABLE=Password/MAXLENGTH=16");
 * $myForm->AddOptionString("PasswordRepeat", "PASSWORD/LABLE=Repeat Password");
 * $myForm->AddOptionString("Active", "CHECKBOX/SELECTED=1/VALUES=1: /LABLE=Active");
 * $Query = "SELECT TemplateID AS ID, Name FROM Template ORDER BY Name";
 * $myForm->AddOptionString("TemplateID", "SELECT/SELECTED=14/VALUES=: -- Select a Template -- /STYLE=width: 250/QUERY=NitroBO:$Query/LABLE=Template");
 * $Query = "SELECT UserID AS ID, UserName AS Name FROM User";
 * $myForm->AddOptionString("Selectbox[]", "SELECTMULTIPLE/SELECTED=1,2,3/STYLE=width: 250/QUERY=NitroBO:$Query/LABLE=Security/ROWS=10");
 *
 * $tab = new FormTab("UserTabs");
 * $tab->AddTab("Adress", "Adress");
 * $tab->AddOptionString("Address", "TEXT/VALUE=$Adress/LABLE=Address");
 * $tab->AddOptionString("Zipcode", "TEXT/VALUE=$Zipcode/LABLE=Zipcode/MAXLENGTH=8");
 * $tab->AddOptionString("City", "TEXT/VALUE=$Adress/LABLE=City");
 * $tab->AddOptionString("Country", "TEXT/VALUE=$Adress/LABLE=Country");
 * $tab->AddOptionString("Directions", "TEXTAREA/VALUE=$Directions/LABLE=Country/ROWS=5/COLS=10");
 * $tab->AddTab("Bio", "Bio");
 * $tab->AddOptionString("Bio", "HTML/LABLE=&nbsp;/VALUE=".urlencode($Bio));
 * $tab->AddTab("Photo", "Photo");
 * $tab->AddOptionString("Photo", "FILE/TYPE=IMAGE");
 * $tab->AddOptionString("Preview", "PREVIEW/TYPE=IMAGE/VALUE=$PhotoPath");
 * $myForm->AddOption($tab);
 *
 * echo $myForm->Draw();
 *</CODE>
 *
 * @see					FormModel class
 * @package			Nitro
 * @subpackage	Libraries
 * @access			public
 */
class Form extends FormModel {
	var $Name;
	var $Action;
	var $Method;
	var $Buttons;
	var $HideButtons;
	var $FormTemplateID = NULL;
	var $WidgetTemplateID = NULL;
	var $SplitValues = FALSE;

	/**
	 * Form class constructor
	 *
	 * @param		string	$Name					Name of the form
	 * @param		string	$Action				Action of form when submitted (default FALSE, <empty>)
	 * @param		string	$Method				Method by which to submit form (default POST)
	 * @param		string	$encType			Encoding to use in the form
	 * @param		string	$onSubmit			onSubmit javascript action
	 * @param		bool		$SplitValues	Boolean telling the Form-class if it should split the values (if TRUE, values will be drawn after the form elements have been drawn).
	 * @access	public
	 */
	function Form ($Name, $Action = FALSE, $Method = "POST", $encType = "multipart/form-data", $onSubmit = NULL, $SplitValues = FALSE)
	{
		$this->Name							= $Name;
		$this->ID								= $Name;
		$this->Action						= $Action;
		$this->Method						= $Method;
		$this->encType					= $encType;
		$this->onSubmit					= $onSubmit;
		$this->FormTemplateID		= FALSE;
		$this->WidgetTemplateID	= FALSE;
		$this->SplitValues			= $SplitValues;

		parent::FormModel();
	}

	/**
	 * Set the Action to do when the form is submitted
	 *
	 * @param		string	$Action		Action of form
	 * @access	public
	 */
	function SetAction($Action)
	{
		$this->Action = $Action;
	}

	/**
	 * Set the Method to use when form is submitted
	 *
	 * @param		string	$Method		Method of form
	 * @access	public
	 */
	function SetMethod($Method)
	{
		$this->Method = $Method;
	}

	/**
	 * Set the templates to use to draw the form
	 *
	 * This functions sets the templates to use to draw the form and
	 * the controls contained on the form. If none are set, the class
	 * will use the Nitro default templates.
	 */
	function SetTemplateIDs($FormTemplateID = FALSE, $WidgetTemplateID = FALSE)
	{
		if ($FormTemplateID) $this->FormTemplateID = $FormTemplateID;
		if ($WidgetTemplateID) $this->WidgetTemplateID = $WidgetTemplateID;
	}

	/**
	 * Hide all form Buttons
	 *
	 * This function tells the form class to hide the default buttons, aswell
	 * as the buttons set on the form!
	 *
	 * @param	boolean	$Hide	Hide or show buttons
	 * @access	public
	 */
	function HideButtons($Hide = TRUE)
	{
		$this->HideButtons = $Hide;
	}

	/**
	 * Add Button to form
	 *
	 * This function adds a button definition to the form. If no buttons are
	 * added to the form, the default buttons (Reset, Submit, Cancel) will be
	 * shown.
	 *
	 * @param	string	$Name	Name of button
	 * @param	array	$Parameters	Button parameters used to draw the button in the template
	 * @access	public
	 */
	function AddButton($Name, $Parameters)
	{
		$this->Buttons[$Name] = $Parameters;

		if(!(array_key_exists('Value', $Parameters) && $Parameters["Value"])) $this->Buttons[$Name]["Value"] = $Name;
	}

	/**
	 * Draw the form
	 *
	 * This function draws the form and all options contained on the form. First the
	 * options are drawn via their own draw function, using the Widget template, and
	 * then the form itself is drawn using the form template.
	 *
	 * @access	public
	 */
	function Draw()
	{
		$Template = new NitroTemplate($this->FormTemplateID);
		$Widget 	= new NitroTemplate($this->WidgetTemplateID);
		$ParsedOptions = array();

		if (is_array($this->Options)) {
			foreach ($this->Options AS $Option) {
				$Widget->ClearAll();

				if (count($this->Custom)) {
					// Add custom values from Form to widgets
					foreach ($this->Custom AS $id => $custom) {
						if (!isset($Option->Custom[$id])) $Option->AddCustom($id, $custom);
					}
				}

				$ParsedOptions[] = $Option->Draw($Widget, $this->SplitValues);
			}
		}

		$Template->Assign("Options", $ParsedOptions);
		$RV = FALSE;

		// Assign Form variables
		if ($this->Name || $this->Action) {
			$Template->Assign("FormType", 		"OpenForm");
			$Template->Assign("Name", 				$this->Name);
			$Template->Assign("Id", 					$this->ID);
			$Template->Assign("Method", 			$this->Method);
			$Template->Assign("Action", 			$this->Action);
			$Template->Assign("encType", 			$this->encType);
			$Template->Assign("onSubmit", 		$this->onSubmit);
			$Template->Assign("SplitValues", 	$this->SplitValues);

			if (count($this->Custom)) $Template->Assign("Custom", $this->Custom);
		}

		if ($this->Name || $this->Action) {
			$Buttons = array();
			if (!$this->HideButtons && $this->Buttons) {
				$Buttons = $this->Buttons;
			} elseif (!$this->HideButtons) {
				//Do nothing seems better than always drawing buttons
				//Don't agree => Always have defaults ready!!!
				$Buttons["Submit"]["Type"] 		= "SUBMIT";
				$Buttons["Submit"]["Value"] 	= "Submit";
				$Buttons["Reset"]["Type"] 		= "RESET";
				$Buttons["Reset"]["Value"] 		= "Reset";
				$Buttons["Cancel"]["Type"] 		= "BUTTON";
				$Buttons["Cancel"]["Value"] 	= "Cancel";
				$Buttons["Cancel"]["onClick"] = "document.location.href='$this->Action'";
			}

			$Template->Assign("Buttons", $Buttons);
			$RV = $Template->Fetch(NITRO_DEFAULT_FORMTEMPLATE);
		}

		return $RV;
	}

	/**
	 * DrawXML
	 *
	 * Draws the ValuesXML for the current Form when this->SplitValues is TRUE.
	 *
	 * @return	string	The FormXML of all values. (default is an empty array)
	 */
	function DrawXML()
	{
		$ResponseXML = array();

		if ($this->SplitValues === TRUE) {
			if (is_array($this->Options)) {
				foreach ($this->Options AS $Option) {
					if (count($this->Custom)) {
						// Add custom values from Form to widgets
						foreach ($this->Custom AS $id => $custom) {
							if (!isset($Option->Custom[$id])) $Option->AddCustom($id, $custom);
						}
					}

					$Option->DrawXML($ResponseXML);
				}
			}
		}

		return $ResponseXML;
	}
}

/**
 * Form option class
 *
 * This class holds the definitions of the form options themselves.
 *
 * @see					FormModel class
 * @package			Nitro
 * @subpackage	Libraries
 * @access			public
 */
class FormOption extends FormModel {
	var $Name;
	var $Option;
	var $OptionParsed;
	var $Type;
	var $Values;
	var $Style;
	var $Lable;
	var $AutoSubmit;
	var $Script;
	var $OnChange;
	var $SelectedValues = array();
	var $TypesToDrawWithSplitValues = array(
		'CHECKBOX', 'CHECKBOXV', 'RADIO', 'RADIOV', 'LABLE'
	);
	
	/**
	 * Form option class constructor
	 *
	 * This functions new FormOption();initializes the form option object.
	 *
	 * @param		string	$Name		Option name
	 * @param		string	$Option	Option string definition
	 * @access	public
	 */
	function FormOption($Name, $Option = NULL)
	{
		$this->Name 	= $Name;
		$this->Option = $Option;

		parent::FormModel();

		if ($Option) {
			$this->OptionParsed = $this->ParseOptionString($Option);
			$this->SetOption($this->OptionParsed);
		}
	}

	/**
	 * Set option properties from parsed option string
	 *
	 * This function sets the object properties from a parsed option string
	 * definition. This string definition can be parsed by ParseOptionString.
	 *
	 * @see ParseOptionString()
	 * @param		array		$ParsedOption		Parsed option string definition
	 * @access	public
	 */
	function SetOption($ParsedOption)
	{
		$this->Type 			= (isset($ParsedOption["Type"]) ? $ParsedOption["Type"] : '');
		$this->ID 				= (isset($ParsedOption["ID"]) ? $ParsedOption["ID"] : '');
		$this->Disabled 	= (isset($ParsedOption["Disabled"]) ? TRUE : FALSE);
		$this->Values 		= (isset($ParsedOption["Values"]) ? $ParsedOption["Values"] : '');
		$this->Style 			= (isset($ParsedOption["Style"]) ? $ParsedOption["Style"] : '');
		$this->Custom 		= (isset($ParsedOption["Custom"]) ? $ParsedOption["Custom"] : array());
		$this->Lable 			= (isset($ParsedOption["Lable"]) ? $ParsedOption["Lable"] : $this->Name);
		$this->Help				= (isset($ParsedOption["Help"]) ? $ParsedOption["Help"] : '');
		$this->AutoSubmit	= (isset($ParsedOption["AutoSubmit"]) ? $ParsedOption["AutoSubmit"] : '');
		$this->Script			= (isset($ParsedOption["Script"]) ? $ParsedOption["Script"] : '');
		$this->OnChange 	= (isset($ParsedOption["OnChange"]) ? $ParsedOption["OnChange"] : '');

		if (isset($ParsedOption["SelectedValues"]) && is_array($ParsedOption["SelectedValues"]) && count($ParsedOption["SelectedValues"])) {
			$this->SelectedValues = array_merge($this->SelectedValues, $ParsedOption["SelectedValues"]);
		} elseif (isset($ParsedOption["Default"]) && is_array($ParsedOption["Default"]) && count($ParsedOption["Default"])) {
			$this->SelectedValues = array_merge($this->SelectedValues, $ParsedOption["Default"]);
		}
	}

	/**
	 * Add selected values for option
	 *
	 * This function adds values that are supposed to be selected in the
	 * option. It can take either a single value or an array of values as
	 * its parameter.
	 *
	 * @param	mixed	$Value	Selected value(s)
	 */
	function AddSelected($Value)
	{
		if (is_array($Value)) {
			foreach($Value AS $val) {
				if (strlen($val)) $this->SelectedValues[] = $val;
			}
		} else {
			if (strlen($Value)) $this->SelectedValues[] = $Value;
		}
	}

	/**
	 * Draw the option
	 *
	 * This function draws the option according to the widget template passed
	 * to it.
	 * <CODE>
	 * The variables that er passed to the template are:
	 * - WidgetType       = Type of widget
	 * - Disabled         = TRUE or $Value if given
	 * - Name             = Name of widget
	 * - Lable            = Widget lable
	 * - Values           = Selected values
	 * - Style            = Style to set inline
	 * - Custom           = Array of custom elements not recognized by parseOptionString()
	 * - WidgetAutoSubmit = TRUE or FALSE, auto submit widget on change
	 * - Script           = SCRIPT to add inline to widget
	 * - Selected         = TRUE|FALSE
	 * - Nitro_Editor     = Editor to use for HTML forms
	 * - SplitValues			= TRUE|FALSE
	 * </CODE>
	 *
	 * @param		object	$Template			Widget template object.
	 * @param		bool		$SplitValues	TRUE or FALSE.
	 * @return	array
	 * @access	public
	 */
	function Draw(&$Template, $SplitValues = FALSE)
	{
		$Template->Assign("WidgetType", 			$this->Type);
		$Template->Assign("Disabled", 				$this->Disabled);
		$Template->Assign("Name", 						$this->Name);
		$Template->Assign("Id", 							$this->ID);
		$Template->Assign("Lable", 						$this->Lable);
		$Template->Assign("Help", 						$this->Help);
		$Template->Assign("Style", 						$this->Style);
		$Template->Assign("Custom", 					$this->Custom);
		$Template->Assign("WidgetAutoSubmit", $this->AutoSubmit);
		$Template->Assign("Script", 					$this->Script);
		$Template->Assign("OnChange", 				$this->OnChange);
		$Template->Assign("Nitro_Editor", 		"1"); //Jesper: Why is this always 1?!?!?!
		$Template->Assign("SplitValues", 			$SplitValues);

		// Assign values if the current WidetType is in the TypesToDrawWithSplitValues array or SplitValues is FALSE.
		if (in_array($this->Type, $this->TypesToDrawWithSplitValues) || $SplitValues === FALSE) {
			$Template->Assign("Values", $this->Values);
		} else {
			$Template->Assign("Values", array());
		}

		if ($SplitValues === FALSE) {
			$Template->Assign("Selected", $this->SelectedValues);
		} else {
			$Template->Assign("Selected", array());
		}

		return array(
			"WidgetType"	=> $this->Type,
			"Lable"				=> $this->Lable,
			"Help"				=> $this->Help,
			"Name"				=> $this->Name,
			"Id"					=> $this->ID,
			"Custom"			=> $this->Custom,
			"Controls"		=> $Template->fetch(NITRO_DEFAULT_WIDGETTEMPLATE)
		);
	}

	/**
	 * DrawXML
	 *
	 * Draws the values in XML.
	 *
	 * @param		array	$ResponseXML		The ResponseXML array.
	 * @access	public
	 */
	function DrawXML(&$ResponseXML)
	{
		if (is_array($ResponseXML)) {
			$ResponseXML[$this->Name] = array(
				'WidgetType' 	=> $this->Type,
				'Values' 			=> array()
			);

			if (count($this->Values) > 0) {
				foreach ($this->Values AS $K => $V) {
					$ResponseXML[$this->Name]['Values'][rawurlencode($K)] = array(
						'Selected' 	=> (in_array($K, $this->SelectedValues) ? TRUE : FALSE),
						'Value' 		=> rawurlencode($V)
					);
				}
			}
		}
	}

	/**
	 * Parse option string and load into object
	 *
	 * This function parses an option string and returns an array of all the
	 * properties found. This array can be used to set the values in the object.
	 *
   * <CODE>
   * Option Types:
   * - SELECT         = Select box
   * - SELECTMULTIPLE = Select box with multiple selection possible
   * - TEXT           = Text input
   * - TEXTAREA       = Text area
   * - TEXTHTML       = HTML area
   * - PASSWORD       = Password input
   * - HIDDEN         = Hidden input
   * - RADIO          = Radio select group
   * - CHECKBOX       = Checkbox
   * - READONLY       = Read only element, text
   * - BUTTON         = Button element
   * - TAB            = Tab group, uses all other elements
   * - GROUP          = Group, uses all other elements
   * - DATE           = Date element, Y-M-D
   * - FILE           = File input
   *
   * Option actions:
   * - LOOKUP      = DB lookup, one answer <- NOT IMPLEMENTED YET
   * - VALUE       = Single value, may be associative
   *      e.g. /VALUE=Key:Value/
   *      e.g. /VALUE=Username/ <- in TEXT, HTML and TEXTAREA
   * - VALUES      = Range with values (comma seperated)
   *      e.g. /VALUES=Key1:Value1,Key2:Value2/
   * - NUMLIST     = Numeric range (id and value identical)
   *      e.g. /NUMLIST=1:10/ <- List from 1 to 10 with key and value
   * - DB          = DB lookup, multiple, sets VALUES
   *      e.g. /DB={[DBAlias]:[Table]:[IDColumn]:[NameColumn]}/
   * - QUERY       = DB lookup from query, sets VALUES
   *      e.g. /QUERY=[DBAlias]:$Query/
   * - STYLE       = Literal string for STYLE of option element
   *      e.g. /STYLE=color: black; background-color: white/
   * - LITERAL     = Literal string for options
   *      e.g. /LITERAL=This is a text that will be literally shown/
   * - LABLE       = Lable of form element, default is name
   *      e.g. /LABLE=This is the lable of the element/
   * - LABEL       = Alias for LABLE
   * - ID          = ID of element
   *      e.g. /ID=Element_ID/
   * - SELECTED    = Value of selected element in RADIO, CHECKBOX, SELECT
   *      e.g. /SELECTED=1/
   *      e.g. /SELECTED=1,2,3/
   *      e.g. /SELECTED=User1,User2/
   * - DEFAULT     = Default selected element if SELECTED is empty
   *      e.g. /DEFAULT=User1/
   * - DEFAULTS    = Alias for DEFAULT
   * - AUTO        = Auto submit form on element change
   *      e.g. /AUTO/
   * - SCRIPT      = Javascript to add inline to element
   *      e.g. /SCRIPT=onClick:onClickFunction()/
   * - DISABLED    = Element disabled if true
   *      e.g. /DISABLED/
   * </CODE>
   *
	 * @see GetDBValues()
	 * @see GetDBValuesFromQuery()
	 * @param		string	$Option		Option string definition
	 * @access	public
	 * @return	array		Parsed option string
	 */
	function ParseOptionString($Option = FALSE)
	{
		$ParsedOption = array();

		if ($Option !== FALSE) {
			$Option = explode('/', $Option);
			$OptionType = array_shift($Option);

			$ParsedOption["Type"] = $OptionType;
			$ParsedOption["Values"] = array();

			if (is_array($Option)) {
				foreach ($Option AS $OptionType) {
					$OptionData = explode('=', $OptionType, 2);

					if (isset($OptionData[0])) {
						$OptionString = $OptionData[1];

						switch (strtoupper($OptionData[0])) {
							case "VALUE":
								$ParsedOption["Values"] = $this->array_join($ParsedOption["Values"], $this->Option_Value($OptionString));
								break;
							case "VALUES":
								$ParsedOption["Values"] = $this->array_join($ParsedOption["Values"], $this->Option_Value($OptionString, 2));
								break;
							case "NUMLIST":
								$ParsedOption["Values"] = $this->array_join($ParsedOption["Values"], $this->Option_NumList($OptionString));
								break;
							case "DB":
								$ParsedOption["Values"] = $this->array_join($ParsedOption["Values"], $this->Option_DataBase($OptionString));
								break;
							case "QUERY":
								$ParsedOption["Values"] = $this->array_join($ParsedOption["Values"], $this->Option_DataBase($OptionString, 2));
								break;
							case "STYLE":
								$ParsedOption["Style"] = $OptionString;
								break;
							case "LITERAL":
								$ParsedOption["Literal"] = $OptionString;
								break;
							case "LABEL":
							case "LABLE":
								$ParsedOption["Lable"] = urldecode($OptionString);
								break;
							case "HELP":
								$ParsedOption["Help"] = urldecode($OptionString);
								break;
							case "ID":
								$ParsedOption["ID"] = $OptionString;
								break;
							case "SELECTED":
								$ParsedOption["SelectedValues"] = $this->Option_Selected($OptionString);
								break;
							case "DEFAULT":
							case "DEFAULTS":
								$ParsedOption["Default"] = $this->Option_Default($OptionString);
								break;
							case "AUTO":
								$ParsedOption["AutoSubmit"] = $OptionString;
								break;
							case "SCRIPT":
								$ParsedOption["Script"][] = $this->Option_Script($OptionString);
								break;
							case "ONCHANGE":
								$ParsedOption["OnChange"] = urldecode($OptionString);
								break;
							case "DISABLED":
								$ParsedOption["Disabled"] = (isset($OptionString) ? $OptionString : TRUE);
								break;
							default:
								$ParsedOption["Custom"][$OptionData[0]][] = urldecode($OptionString);
								break;
						}
					}
				}
			}
		}

		return $ParsedOption;
	}

	function Option_Value($OptionString = '', $Type = 1)
	{
		$RV = array();

		if (eregi(',', $OptionString)) {
			$Options = explode(',', $OptionString);

			foreach ($Options AS $Option) {
				$RV = $this->array_join($RV, $this->Option_Value($Option, $Type));
			}
		} else {
			if (eregi(':', $OptionString)) {
				$Option = explode(':', $OptionString);

				if (isset($Option[1])) {
					$RV[urldecode($Option[0])] = urldecode($Option[1]);
				} else {
					$RV[] = urldecode($Option[0]);
				}
			} else {
				if ($Type === 2) {
					$RV[urldecode($OptionString)] = urldecode($OptionString);
				} else {
					$RV[] = urldecode($OptionString);
				}
			}
		}

		return $RV;
	}

	function Option_NumList($OptionString = '')
	{
		$RV = array();

		if (eregi(':', $OptionString)) {
			$Option = explode(':', $OptionString);

			if (count($Option) == 2) {
				if ($Option[0] > $Option[1]) {
					for ($i = $Option[0]; $i >= $Option[1]; $i--) {
						$RV[$i] = $i;
					}
				} else {
					for ($i = $Option[0]; $i <= $Option[1]; $i++) {
						$RV[$i] = $i;
					}
				}
			}
		}

		return $RV;
	}

	function Option_DataBase($OptionString = '', $Type = 1)
	{

		$RV = array();
		$DBValues = ($Type === 2 ? $this->GetDBValuesFromQuery($OptionString) : $this->GetDBValues($OptionString));

		foreach ($DBValues AS $Key => $Value) {
			$RV[$Key] = $Value;
		}

		return $RV;
	}

	function Option_Selected($OptionString = '')
	{
		return $this->Option_Default($OptionString);
	}

	function Option_Default($OptionString = '')
	{
		$RV = array();

		if (eregi(',', $OptionString)) {
			$Option = explode(',', $OptionString);

			foreach($Option AS $Default) {
				if (strlen($Default)) $RV[] = $Default;
			}
		} else {
			if (strlen($OptionString)) $RV[] = $OptionString;
		}

		return $RV;
	}

	function Option_Script($OptionString = '')
	{
		$RV = '';

		if (eregi(':', $OptionString)) {
			$Option = explode(':', $OptionString);

			if (count($Option) == 2) $RV = $Option[0].'=\''.urldecode($Option[1]).'\'';
		}

		return $RV;
	}

	/**
	 * Get values from db by query
	 *
	 * This function executes the query and fetches the values from the result.
	 * The default DB array of objects $DB is globalized and used for the query.
	 *
	 * <CODE>
	 * $Query = "SELECT UserID AS ID, UserName AS Name FROM User";
	 * e.g. string => "[DBAlias]:$Query"
	 * </CODE>
	 *
	 * @param		string		$String		DB query string
	 * @access 	private
	 * @TODO		Catch DB Errors!
	 */
	function GetDBValuesFromQuery($String)
	{
		global $DB;

		$OriginalString = $String;
		$String					= ereg_replace("^{", "", $String);

		if ($OriginalString != $String) $String = ereg_replace("}$", "", $String);

		$tmp			= explode(":", $String);
		$DBAlias	= array_shift($tmp);
		$Query		= array_shift($tmp);

		if (DB::isDBCon($DB[$DBAlias])) {
			$Result = $DB[$DBAlias]->query($Query);
			$Values = array();

			while($Row = $Result->FetchArray()) {
				$Values[$Row["ID"]] = $Row["Name"];

				if ($Row["SELECTED"]) $this->SelectedValues[] = $Row["ID"];
			}

			$Result->free();

			return $Values;
		} else {
			return FALSE;
		}
	}

	/**
	 * Get values from db by string
	 *
	 * This function parses a DB query string, creates the query and fetches
	 * the result. It uses GetDBValuesFromQuery to perform the actual query.
	 * The default DB array of objects $DB is globalized and used for the Lookup.
	 *
	 * <CODE>
	 * Format:
	 * [DBAlias]:[Table]:[IDColumn]:[NameCol]:[[WHERE CLAUSE]]
	 * - DBAlias      = DB object in $DB array
	 * - Table        = Table in database to use
	 * - IDColumn     = Name of ID column in table to use
	 * - NameCol      = Name of column to use for the name, comma seperated list will be concated
	 * - WHERE CLAUSE = Optional, extra where clause to use in query after WHERE
	 *
	 * e.g. Nitro:Menu:MenuID:Name
	 * e.g. Nitro:Menu:MenuID:Name:TemplateID=1
	 * e.g. Nitro:User:UserID:FirstName, ,LastName
	 * </CODE>
	 *
   * @see GetDBValuesFromQuery()
	 * @param		string		$String		DB query string
	 * @access 	private
	 * @TODO		Catch DB Errors!
	 */
	function GetDBValues($String)
	{
		global $DB;

		$OriginalString = $String;
		$String					= ereg_replace("^{", "", $String);

		if ($OriginalString != $String) $String = ereg_replace("}$", "", $String);

		$tmp			= explode(":", $String);
		$DBAlias	= array_shift($tmp);
		$Table		= array_shift($tmp);
		$IDCol		= array_shift($tmp);
		$NameCol	= explode(",", array_shift($tmp));
		$Where		= explode(",", implode(":", $tmp));
		$Query = "
			SELECT
				".$IDCol." AS ID,
				".(count($NameCol) > 1 ? "
					CONCAT(".urldecode(implode(",", $NameCol)).")
				" :
					urldecode($NameCol[0])
				)." AS Name
			FROM ".$Table."
		";

		if (count($Where) && $Where[0] != "") {
			foreach ($Where AS $WhereStatement) {
				if (ereg("\{LOOKUP\:", $WhereStatement)) {
					$tmp 						= explode("=", $WhereStatement, 2);
					$Column 				= $tmp[0];
					$Lookup 				= $tmp[1];
					$OriginalLookup = $Lookup;
					$Lookup 				= ereg_replace("^{", "", $Lookup);

					if ($OriginalLookup != $Lookup) $Lookup = ereg_replace("}$", "", $Lookup);

					$tmp					= explode(":", $Lookup);
					$null					= array_shift($tmp);
					$LookupTable	= array_shift($tmp);
					$LookupValue	= array_shift($tmp);
					$LookupWhere	= array_shift($tmp);
					$LookupQuery 	= "
						SELECT ".$LookupValue."
						FROM ".$LookupTable."
						WHERE ".$LookupWhere."
					";
					$LookupResult	= $DB[$DBAlias]->getOne($LookupQuery);
					$Query.= "
						WHERE ".$Column." = ".($LookupResult ? NitroPrepareDB($LookupResult) : "''")."
					";
				} else {
					$Query.= "
						WHERE ".$WhereStatement."
					";
				}
			}
		}

		$Query.= "
			ORDER BY Name
		";

		return $this->GetDBValuesFromQuery($DBAlias.":".$Query);
	}
}

/**
 * Form group class
 *
 * With this class multiple options on a form can be grouped together
 * into a group of options (Fieldset).
 *
 * @see					FormModel class
 * @package			Nitro
 * @subpackage	Libraries
 * @access			public
 */
class FormGroup extends FormModel {
	var $Name;
	var $ID;
	var $Lable;
	var $Legend;
	var $WidgetType = 'GROUP';

	/**
	 * Form group class constructor
	 *
	 * This is the class constructor of the form group.
	 *
	 * @param		string 	$Name		Name of the form group
	 * @param		string	$ID			ID of the form group (default is Name if ID is empty)
	 * @param		string	$Lable	Lable of form group
	 * @access	public
	 */
	function FormGroup($Name, $ID = NULL, $Lable = NULL, $WidgetType = 'GROUP', $Legend = NULL, $Display = 'inline')
	{
		$this->Name 			= $Name;
		$this->ID 				= ($ID ? $ID : $Name);
		$this->Lable 			= $Lable;
		$this->WidgetType = $WidgetType;
		$this->Legend 		= ($Legend ? $Legend : $Lable);
		$this->Display 		= $Display;

		parent::FormModel();
	}

	/**
	 * Set the lable of the group
	 *
	 * @param	string	$Lable	Lable of the group
	 * @access	public
	 */
	function SetLable($Lable)
	{
		$this->Lable = $Lable;
	}

	/**
	 * Draw the option group
	 *
	 * This function draws all options in the group and then the group itself
	 * using the widget template.
	 *
	 * @param		object	$TemplateHandler	Widget template object.
	 * @param		bool		$SplitValues			TRUE or FALSE.
	 * @access	public
	 */
	function Draw(&$TemplateHandler, $SplitValues = FALSE)
	{
		$GroupOptions = array();

		if (is_array($this->Options)) {
			foreach ($this->Options AS $Option) {
				if (count($this->Custom)) {
					// Add custom values from Form to widgets
					foreach ($this->Custom AS $id => $custom) {
						if (!isset($Option->Custom[$id])) $Option->AddCustom($id, $custom);
					}
				}

				$GroupOptions[] = $Option->Draw($TemplateHandler, $SplitValues);
			}
		}

		$TemplateHandler->ClearAll();
		$TemplateHandler->assign("WidgetType", 	$this->WidgetType);
		$TemplateHandler->assign("Display", 		$this->Display);
		$TemplateHandler->assign("Name", 				$this->Name);
		$TemplateHandler->assign("ID", 					$this->ID);
		$TemplateHandler->assign("Lable", 			$this->Lable);
		$TemplateHandler->assign("Legend",	 		$this->Legend);
		$TemplateHandler->assign("Help", 				$this->Help);
		$TemplateHandler->assign("Controls", 		$GroupOptions);

		if (count($this->Custom)) $TemplateHandler->Assign("Custom", $this->Custom);

		return Array(
			"WidgetType"	=> $this->WidgetType,
			"Lable" 			=> $this->Lable,
			"Name"				=> $this->Name,
			"ID"					=> $this->ID,
			"Controls"		=> $TemplateHandler->fetch(NITRO_DEFAULT_WIDGETTEMPLATE)
		);
	}

	/**
	 * DrawXML
	 *
	 * Draws the values in XML.
	 *
	 * @param		array	$ResponseXML		The ResponseXML array.
	 * @access	public
	 */
	function DrawXML(&$ResponseXML)
	{
		if (is_array($ResponseXML)) {
			if (is_array($this->Options)) {
				foreach ($this->Options AS $Option) {
					if (count($this->Custom)) {
						// Add custom values from Form to widgets
						foreach ($this->Custom AS $id => $custom) {
							if (!isset($Option->Custom[$id])) $Option->AddCustom($id, $custom);
						}
					}

					$Option->DrawXML($ResponseXML);
				}
			}
		}
	}
}

/**
 * Form Tab control
 *
 * This is the tab control that can be used in a form.
 *
 * Usage example:
 * <CODE>
 * $Version = Array(1 => "Version 1", 2 => "Version 2");
 * $form = new form("TemplateForm");
 * $tab = new FormTab("MainTab", "MainTabID");
 * foreach($Version AS $V => $Val) {
 *   $tab->AddTab($V);
 *   $tab->AddOptionString("Title", "TEXT/VALUES=$Val");
 *   $tab2 = new FormTab("SubTab", "SubTabID");
 *   $tab2->AddTab($V."_sub1");
 *   $tab2->AddOptionString("1", "TEXT");
 *   $tab2->AddTab($V."_sub2");
 *   $tab2->AddOptionString("2", "TEXT");
 *   $tab2->AddTab($V."_sub3");
 *   $tab2->AddOptionString("3", "TEXT");
 *   $tab->AddOption($tab2);
 * }
 * $form->AddOption($tab);
 * $form->Draw()
 * </CODE>
 *
 * @package	Nitro
 * @subpackage	Libraries
 * @access	public
 */
class FormTab extends FormModel {
	var $Name;
	var $NewWay;
	var $Lable = NULL;
	var $Tabs = array();
	var $SelectedTab;
	var $Actions = array();
	var $TabActions = array();
	var $TabStyles = array();
	var $TabOnClick = array();
	var $CurrentTab;

	/**
	 * Form tab constructor
	 *
	 * This function initialized the form tab control.
	 *
	 * @param	string	$Name	Name of the tab control
	 * @param	string	$ID	ID of the tab control (default is Name)
	 */
	function FormTab($Name, $ID = NULL, $NewWay = "no")
	{
		$this->Name 	= $Name;
		$this->ID 		= ($ID ? $ID : $Name);
		$this->NewWay = $NewWay;

		parent::FormModel();
	}

	/**
	 * Add tab to tab control
	 *
	 * This function adds a new tab to the tab control.
	 *
	 * @param	string	$Name	Name of the tab
	 * @param	string	$ID	ID of the tab (default is Name)
	 * @param	string	$Lable Lable of the tab
	 */
	function AddTab($TabName, $ID = NULL, $Lable = NULL, $Style = NULL, $OnClick = NULL)
	{
		if (!$ID) $ID = $TabName;

		$this->Tabs[$ID] = $TabName;
		$this->Lable = $Lable;
		$this->TabStyles[$ID] = $Style;
		$this->TabOnClick[$ID] = $OnClick;
		$this->CurrentTab = $ID;
		$RV = TRUE;

		return $RV;
	}

	/**
	 * Add action to tab control
	 *
	 * This function adds an action to the tab control. This action can be used to
	 * for instance create a new tab of options.
	 *
	 * @param	string	$Name	Name of the action
	 * @param	string	$URL	URL of the tab action
	 * @param	string	$Image	Image to show as the action button
	 */
	function AddAction($Name, $URL, $Image = NULL, $onClick = NULL)
	{
		$this->Actions[] = array("Name" => $Name, "URL" => $URL, "Image" => $Image, "onClick" => $onClick);
	}

	/**
	 * Add action to tab
	 *
	 * This function adds an action to the tab itself. This action can be used to
	 * for instance delete a tab. This action should only apply to the tab.
	 *
	 * @param	string	$Name	Name of the action
	 * @param	string	$URL	URL of the tab action
	 * @param	string	$Image	Image to show as the action button
	 * @param	string	$TabID	ID of the tab to add an action to (Default is current (last added) tab)
	 */
	function AddTabAction($Name, $URL, $Image = NULL, $TabID = NULL)
	{
		if (!$TabID) $TabID = $this->CurrentTab;

		$this->TabActions[$TabID][] = array("Name" => $Name, "URL" => $URL, "Image" => $Image);
	}

	/**
	 * Set lable of tab control
	 *
	 * This function sets the lable of the tab control to show in the form. The form
	 * template whill show the lable as the label of an option.
	 *
	 * @param	string	$Lable	Lable of tab control
	 */
	function SetLable($Lable)
	{
		$this->Lable = $Lable;
	}

	function SetSelectedTab($TabID)
	{
		$this->SelectedTab = $TabID;
	}

	/**
	 * Add option to tab via string
	 *
	 * This function creates a new option on the tab from the standard option
	 * string. This string is parsed and an object is created which is added to
	 * the form via the AddOption function.
	 *
	 * @see AddOption()
	 * @param	string	$Name	Name of option to add
	 * @param	string	$OptionString	String definition of option
	 * @param	string	$TabID	ID of the tab to add the option to (Default is current (last added) tab)
	 * @access	public
	 */
	function AddOptionString($Name, $OptionString, $TabID = NULL)
	{
		if (!$TabID) $TabID = $this->CurrentTab;

		$Option = new FormOption($Name, $OptionString);

		return $this->AddOption($Option, $TabID);
	}

	/**
	 * Add multiple options via array of strings
	 *
	 * This function accepts an array of options in string format and adds
	 * them to the tab. The name of the option to add is taken from the key
	 * of the array. This function uses the AddOption function
	 * to add the options to the form.
	 *
	 * @see AddOption()
	 * @param	array	$Options	Array of option strings
	 * @param	string	$TabID	ID of the tab to add the option to (Default is current (last added) tab)
	 * @access	public
	 */
	function AddOptionsFromArray($Options, $TabID = NULL)
	{
		if (!$TabID) $TabID = $this->CurrentTab;

		if (is_array($Options)) {
			foreach($Options AS $ID => $Option) {
				$Option = new FormOption($ID, $Option);
				$this->AddOption($Option, $TabID);
			}
		}
	}

	/**
	 * Add option to tab
	 *
	 * This functions adds the option (object) to the list of controls in
	 * the tab.
	 *
	 * @param	object	$Option	Option object
	 * @param	string	$TabID	ID of the tab to add the option to (Default is current (last added) tab)
	 * @access	public
	 */
	function AddOption($Option, $TabID = NULL)
	{
		if (!$TabID) $TabID = $this->CurrentTab;

		if (is_object($Option)) {
			$this->Options[$TabID][] = $Option;
			$RV = TRUE;
		} else {
			$RV = FALSE;
		}

		return $RV;
	}

	/**
	 * Draw the tab control
	 *
	 * This function draws all options on the tab and then the tab itself
	 * using the widget template.
	 *
	 * @param		object	$TemplateHandler	Widget template object.
	 * @param		bool		$SplitValues			TRUE or FALSE.
	 * @access	public
	 */
	function Draw(&$TemplateHandler, $SplitValues = FALSE)
	{
		$TabOptions = array();

		foreach ($this->Tabs AS $ID => $TabName) {
			// draw controls on tab template
			if ($this->Options[$ID]) {
				foreach($this->Options[$ID] AS $Option) {
					$Option->Name = $Option->Name;
					if (count($this->Custom)) {
						// Add custom values from Form to widgets
						foreach($this->Custom AS $id => $custom) {
							if (!isset($Option->Custom[$id])) $Option->AddCustom($id, $custom);
						}
					}
					$TabOptions[$ID][] = $Option->Draw($TemplateHandler, $SplitValues);
				}
			}
		}

		$TemplateHandler->ClearAll();
		$TemplateHandler->assign("WidgetType", 	"TAB");
		$TemplateHandler->assign("Name", 				$this->Name);
		$TemplateHandler->assign("Id", 					$this->ID);
		$TemplateHandler->assign("NewWay", 			$this->NewWay);
		$TemplateHandler->assign("Tabs", 				$this->Tabs);

		reset($this->Tabs);

		if (!isset($this->SelectedTab) || !strlen($this->SelectedTab)) $this->SelectedTab = key($this->Tabs);

		$TemplateHandler->assign("TabStyles", 	$this->TabStyles);
		$TemplateHandler->assign("TabOnClick", 	$this->TabOnClick);
		$TemplateHandler->assign("SelectedTab", $this->SelectedTab);
		$TemplateHandler->assign("Actions", 		$this->Actions);
		$TemplateHandler->assign("TabActions", 	$this->TabActions);
		$TemplateHandler->assign("Controls",	 	$TabOptions);

		if (count($this->Custom)) $TemplateHandler->Assign("Custom", $this->Custom);

		return array(
			"WidgetType" 	=> "TAB",
			"Lable" 			=> $this->Lable,
			"Name" 				=> $this->Name,
			"Id"			 		=> $this->ID,
			"Controls" 		=> $TemplateHandler->fetch(NITRO_DEFAULT_WIDGETTEMPLATE)
		);
	}

	/**
	 * DrawXML
	 *
	 * Draws the values in XML.
	 *
	 * @param		array	$ResponseXML		The ResponseXML array.
	 * @access	public
	 */
	function DrawXML(&$ResponseXML)
	{
		if (is_array($ResponseXML)) {
			if (is_array($this->Tabs)) {
				foreach ($this->Tabs AS $ID => $TabName) {
					if ($this->Options[$ID]) {
						foreach($this->Options[$ID] AS $Option) {
							$Option->Name = $Option->Name;

							if (count($this->Custom)) {
								// Add custom values from Form to widgets
								foreach($this->Custom AS $id => $custom) {
									if (!isset($Option->Custom[$id])) $Option->AddCustom($id, $custom);
								}
							}

							$Option->DrawXML($ResponseXML);
						}
					}
				}
			}
		}
	}
}

function Nitro_Editor($Name, $Rows = 8, $Cols = 40, $Content = '', $WidgetAutoSubmit = FALSE)
{
	global $__NitroConf;

	$Return = "";
	$Height = (((int)$Rows>0) ? ((int)$Rows)*16 : '384');
	$Width = (((int)$Cols>0) ? ((int)$Cols)*16 : '800');

	if ($__NitroConf->CONF['Settings']['HTMLEditor'] != "") {
		if ($__NitroConf->CONF['Settings']['HTMLEditorInclude'] != "") {
			include_once $__NitroConf->CONF['Settings']['HTMLEditorInclude'];
		}
		if ($__NitroConf->CONF['Settings']['HTMLEditorInit'] != "") {
			eval('$Return.= '.$__NitroConf->CONF['Settings']['HTMLEditorInit'].';');
		}
	} else {
		$Return = "<TEXTAREA NAME=\"$Name\" ID=\"$Name\" ROWS=\"".($Rows ? $Rows : 10)."\" COLS=\"".($Cols ? $Cols : 50)."\"".(($WidgetAutoSubmit) ? 'onChange="this.form.submit();"' : '').">$Content</TEXTAREA>";
	}

	return $Return;
}
?>
Return current item: OpenNitro