diff options
| -rw-r--r-- | framework/Web/Javascripts/packages.php | 47 | ||||
| -rw-r--r-- | framework/Web/UI/ActiveControls/TActiveControlAdapter.php | 2 | ||||
| -rwxr-xr-x | framework/Web/UI/ActiveControls/TActiveFileUpload.php | 2 | ||||
| -rwxr-xr-x | framework/Web/UI/ActiveControls/TDraggable.php | 10 | ||||
| -rwxr-xr-x | framework/Web/UI/ActiveControls/TDropContainer.php | 2 | ||||
| -rw-r--r-- | framework/Web/UI/TClientScriptManager.php | 102 | ||||
| -rw-r--r-- | framework/Web/UI/WebControls/TAccordion.php | 7 | ||||
| -rw-r--r-- | framework/Web/UI/WebControls/TBaseValidator.php | 1503 | ||||
| -rw-r--r-- | framework/Web/UI/WebControls/TClientScript.php | 288 | ||||
| -rw-r--r-- | framework/Web/UI/WebControls/THtmlArea.php | 1081 | ||||
| -rw-r--r-- | framework/Web/UI/WebControls/TTabPanel.php | 1459 | ||||
| -rw-r--r-- | framework/Web/UI/WebControls/TTextHighlighter.php | 419 | 
12 files changed, 2478 insertions, 2444 deletions
| diff --git a/framework/Web/Javascripts/packages.php b/framework/Web/Javascripts/packages.php index a32c54b5..316716d6 100644 --- a/framework/Web/Javascripts/packages.php +++ b/framework/Web/Javascripts/packages.php @@ -8,13 +8,15 @@ if (!defined('SCRIPTACULOUS_DIR')) define ('SCRIPTACULOUS_DIR', 'scriptaculous-1  //package names and its contents (files relative to the current directory)
  $packages = array(
 -	'prado' => array(
 +	'prototype' => array(
  		PROTOTYPE_DIR.'/prototype.js',
  		SCRIPTACULOUS_DIR.'/builder.js',
 -		SCRIPTACULOUS_DIR.'/effects.js',
 +	),
 +	'prado' => array(
  		'prado/prado.js',
  		'prado/scriptaculous-adapter.js',
 -		'prado/controls/controls.js'
 +		'prado/controls/controls.js',
 +		SCRIPTACULOUS_DIR.'/effects.js'
  	),
  	'effects' => array(
 @@ -41,7 +43,7 @@ $packages = array(  		SCRIPTACULOUS_DIR.'/controls.js',
  		'prado/activecontrols/json2.js',
  		'prado/activecontrols/ajax3.js',
 -		'prado/activecontrols/activecontrols3.js'
 +		'prado/activecontrols/activecontrols3.js',
  	),
  	'dragdrop'=>array(
 @@ -94,24 +96,25 @@ $packages = array(  //package names and their dependencies
  $dependencies = array(
 -		'prado'				=> array('prado'),
 -		'effects'			=> array('prado', 'effects'),
 -		'validator'			=> array('prado', 'validator'),
 -		'logger'			=> array('prado', 'logger'),
 -		'datepicker'		=> array('prado', 'datepicker'),
 -		'colorpicker'		=> array('prado', 'colorpicker'),
 -		'ajax'				=> array('prado', 'effects', 'ajax'),
 -		'dragdrop'			=> array('prado', 'effects', 'ajax', 'dragdrop'),
 -		'slider'			=> array('prado', 'slider'),
 -		'keyboard'			=> array('prado', 'keyboard'),
 -		'tabpanel'			=> array('prado', 'tabpanel'),
 -		'activedatepicker'	=> array('prado', 'datepicker', 'ajax', 'activedatepicker'),
 -		'activefileupload'	=> array('prado', 'effects', 'ajax', 'activefileupload'),
 -		'dragdropextra'		=> array('prado', 'effects', 'ajax', 'dragdrop','dragdropextra'),
 -		'accordion'			=> array('prado', 'effects', 'accordion'),
 -		'htmlarea'			=> array('prado', 'htmlarea'),
 -		'ratings'			=> array('prado', 'effects', 'ajax', 'ratings'),
 -		'inlineeditor'		=> array('prado', 'effects', 'ajax', 'inlineeditor'),
 +		'prototype'			=> array('prototype'),
 +		'prado'				=> array('prototype', 'prado'),
 +		'effects'			=> array('prototype', 'prado', 'effects'),
 +		'validator'			=> array('prototype', 'prado', 'validator'),
 +		'logger'			=> array('prototype', 'prado', 'logger'),
 +		'datepicker'		=> array('prototype', 'prado', 'datepicker'),
 +		'colorpicker'		=> array('prototype', 'prado', 'colorpicker'),
 +		'ajax'				=> array('prototype', 'prado', 'effects', 'ajax'),
 +		'dragdrop'			=> array('prototype', 'prado', 'effects', 'ajax', 'dragdrop'),
 +		'slider'			=> array('prototype', 'prado', 'slider'),
 +		'keyboard'			=> array('prototype', 'prado', 'keyboard'),
 +		'tabpanel'			=> array('prototype', 'prado', 'tabpanel'),
 +		'activedatepicker'	=> array('prototype', 'prado', 'datepicker', 'ajax', 'activedatepicker'),
 +		'activefileupload'	=> array('prototype', 'prado', 'effects', 'ajax', 'activefileupload'),
 +		'dragdropextra'		=> array('prototype', 'prado', 'effects', 'ajax', 'dragdrop','dragdropextra'),
 +		'accordion'			=> array('prototype', 'prado', 'effects', 'accordion'),
 +		'htmlarea'			=> array('prototype', 'prado', 'htmlarea'),
 +		'ratings'			=> array('prototype', 'prado', 'effects', 'ajax', 'ratings'),
 +		'inlineeditor'		=> array('prototype', 'prado', 'effects', 'ajax', 'inlineeditor'),
  );
  return array($packages, $dependencies);
 diff --git a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php index 3e6747b3..a2e5d0ce 100644 --- a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php +++ b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php @@ -81,7 +81,6 @@ class TActiveControlAdapter extends TControlAdapter  	public function onPreRender($param)
  	{
  		parent::onPreRender($param);
 -		$this->getPage()->getClientScript()->registerPradoScript('ajax');
  	}
  	/**
 @@ -89,6 +88,7 @@ class TActiveControlAdapter extends TControlAdapter  	 */
  	public function render($writer)
  	{
 +		$this->getPage()->getClientScript()->registerPradoScript('ajax');
  		$this->renderCallbackClientScripts();
  		if($this->_control->getVisible(false))
  		{
 diff --git a/framework/Web/UI/ActiveControls/TActiveFileUpload.php b/framework/Web/UI/ActiveControls/TActiveFileUpload.php index b4557cd8..ca924026 100755 --- a/framework/Web/UI/ActiveControls/TActiveFileUpload.php +++ b/framework/Web/UI/ActiveControls/TActiveFileUpload.php @@ -270,7 +270,6 @@ EOS;  	public function onPreRender($param)  	{  		parent::onPreRender($param); -		$this->getPage()->getClientScript()->registerPradoScript('activefileupload');  		if(!$this->getPage()->getIsPostBack() && isset($_GET['TActiveFileUpload_InputId']) && isset($_GET['TActiveFileUpload_TargetId']) && $_GET['TActiveFileUpload_InputId'] == $this->getClientID())  		{ @@ -369,6 +368,7 @@ EOS;  		parent::addAttributesToRender($writer);  		$writer->addAttribute('id',$this->getClientID()); +		$this->getPage()->getClientScript()->registerPradoScript('activefileupload');  		$this->getActiveControl()->registerCallbackClientScript($this->getClientClassName(),$this->getClientOptions());  	} diff --git a/framework/Web/UI/ActiveControls/TDraggable.php b/framework/Web/UI/ActiveControls/TDraggable.php index 10ecf5a5..fccc9328 100755 --- a/framework/Web/UI/ActiveControls/TDraggable.php +++ b/framework/Web/UI/ActiveControls/TDraggable.php @@ -145,11 +145,6 @@ class TDraggable extends TPanel  	public function onPreRender($param)  	{  		parent::onPreRender($param); -		$cs=$this->getPage()->getClientScript(); -		if ($this->getGhosting()==TDraggableGhostingOptions::SuperGhosting) -			$cs->registerPradoScript('dragdropextra'); -		else -			$cs->registerPradoScript('dragdrop');  	}  	/** @@ -159,7 +154,12 @@ class TDraggable extends TPanel  	protected function addAttributesToRender($writer)  	{  		parent::addAttributesToRender($writer); +  		$cs=$this->getPage()->getClientScript(); +		if ($this->getGhosting()==TDraggableGhostingOptions::SuperGhosting) +			$cs->registerPradoScript('dragdropextra'); +		else +			$cs->registerPradoScript('dragdrop');  		$writer->addAttribute('id',$this->getClientID());  		$options=TJavascript::encode($this->getPostBackOptions());  		$class=$this->getClientClassName(); diff --git a/framework/Web/UI/ActiveControls/TDropContainer.php b/framework/Web/UI/ActiveControls/TDropContainer.php index daa8469b..072762df 100755 --- a/framework/Web/UI/ActiveControls/TDropContainer.php +++ b/framework/Web/UI/ActiveControls/TDropContainer.php @@ -181,7 +181,6 @@ class TDropContainer extends TPanel implements IActiveControl, ICallbackEventHan  	public function onPreRender($param)  	{  		parent::onPreRender($param); -		$this->getPage()->getClientScript()->registerPradoScript('dragdrop');  	}  	/** @@ -193,6 +192,7 @@ class TDropContainer extends TPanel implements IActiveControl, ICallbackEventHan  		parent::addAttributesToRender($writer);  		$writer->addAttribute('id',$this->getClientID()); +		$this->getPage()->getClientScript()->registerPradoScript('dragdrop');  		$this->getActiveControl()->registerCallbackClientScript(  			$this->getClientClassName(), $this->getPostBackOptions());  	} diff --git a/framework/Web/UI/TClientScriptManager.php b/framework/Web/UI/TClientScriptManager.php index 3f1664ac..08b528b1 100644 --- a/framework/Web/UI/TClientScriptManager.php +++ b/framework/Web/UI/TClientScriptManager.php @@ -87,7 +87,7 @@ class TClientScriptManager extends TApplicationComponent  	private $_renderedScriptFiles; -	private $_renderedPradoScripts; +	private $_expandedPradoScripts;  	/**  	 * Constructor. @@ -133,7 +133,7 @@ class TClientScriptManager extends TApplicationComponent  	/**  	 * Registers a Prado javascript library to be loaded.  	 */ -	private function registerPradoScriptInternal($name) +	protected function registerPradoScriptInternal($name)  	{  		// $this->checkIfNotInRender();  		if(!isset($this->_registeredPradoScripts[$name])) @@ -146,70 +146,63 @@ class TClientScriptManager extends TApplicationComponent  				self::$_pradoPackages = $packages;  			} -			if(isset(self::$_pradoScripts[$name])) +			if (isset(self::$_pradoScripts[$name]))  				$this->_registeredPradoScripts[$name]=true;  			else  				throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name); -		} -	} - -	/** -	 * @return string Prado javascript library base asset url. -	 */ -	public function getPradoScriptAssetUrl() -	{ -		$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; -		$assets = Prado::getApplication()->getAssetManager(); -		return $assets->getPublishedUrl($base); -	} - -	/** -	 * Renders the HTML tags for PRADO js files -	 * @param THtmlWriter writer -	 */ -	protected function renderPradoScriptsInt($writer, $initial) -	{ -		if($initial) $this->_renderedPradoScripts = array(); -		$addedScripts = array_diff($this->_registeredPradoScripts,$this->_renderedPradoScripts); -		if(($packages=array_keys($addedScripts))!==array()) -		{ -			$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; -			list($path,$baseUrl)=$this->getPackagePathUrl($base); -			$packagesUrl=array(); -			$isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug; -			foreach ($packages as $p) +				 +			if(($packages=array_keys($this->_registeredPradoScripts))!==array())  			{ -				foreach (self::$_pradoScripts[$p] as $dep) +				$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; +				list($path,$baseUrl)=$this->getPackagePathUrl($base); +				$packagesUrl=array(); +				$isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug; +				foreach ($packages as $p)  				{ -					foreach (self::$_pradoPackages[$dep] as $script) +					foreach (self::$_pradoScripts[$p] as $dep)  					{ -						if($isDebug) +						foreach (self::$_pradoPackages[$dep] as $script) +						if (!isset($this->_expandedPradoScripts[$script]))  						{ -							if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl)) -								$packagesUrl[]=$url; -						} else { -							if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl)) +							$this->_expandedPradoScripts[$script] = true; +							if($isDebug)  							{ -								if(!is_file($filePath=$path.'/min/'.$script)) +								if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl)) +									$packagesUrl[]=$url; +							} else { +								if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl))  								{ -									$dirPath=dirname($filePath); -									if(!is_dir($dirPath)) -										mkdir($dirPath, PRADO_CHMOD, true); -									file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script))); -									chmod($filePath, PRADO_CHMOD); +									if(!is_file($filePath=$path.'/min/'.$script)) +									{ +										$dirPath=dirname($filePath); +										if(!is_dir($dirPath)) +											mkdir($dirPath, PRADO_CHMOD, true); +										file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script))); +										chmod($filePath, PRADO_CHMOD); +									} +									$packagesUrl[]=$url;  								} -								$packagesUrl[]=$url;  							}  						}  					}  				} +				foreach($packagesUrl as $url) +					$this->registerScriptFile($url,$url);  			} -			$writer->write(TJavaScript::renderScriptFiles($packagesUrl)); -			$this->_renderedPradoScripts = $this->_registeredPradoScripts;  		}  	}  	/** +	 * @return string Prado javascript library base asset url. +	 */ +	public function getPradoScriptAssetUrl() +	{ +		$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; +		$assets = Prado::getApplication()->getAssetManager(); +		return $assets->getPublishedUrl($base); +	} + +	/**  	 * Returns the URLs of all script files referenced on the page  	 * @return array Combined list of all script urls used in the page  	 */ @@ -492,10 +485,10 @@ class TClientScriptManager extends TApplicationComponent  	 * @param string a unique key identifying the file  	 * @param string URL to the javascript file to be rendered  	 */ -	public function registerScriptFile($key,$url) +	public function registerScriptFile($key, $url)  	{  		$this->_scriptFiles[$key]=$url; - +		  		$params=func_get_args();  		$this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);  	} @@ -686,7 +679,6 @@ class TClientScriptManager extends TApplicationComponent  	public function renderScriptFilesInt($writer, $initial)  	{  		if ($initial) $this->_renderedScriptFiles = array(); -		$this->renderPradoScriptsInt($writer, $initial);  		if(!empty($this->_scriptFiles))  		{  			$addedScripts = array_diff($this->_scriptFiles,$this->_renderedScriptFiles); @@ -723,6 +715,16 @@ class TClientScriptManager extends TApplicationComponent  	}  	/** +	 * Flushes all pending script registrations +	 * @param THtmlWriter writer for the rendering purpose +	 */ +	public function flushScriptFiles($writer) +	{ +		assert($this->_page->InFormRender); +		$this->renderScriptFilesInt($writer,false); +	} + +	/**  	 * @param THtmlWriter writer for the rendering purpose  	 */  	protected function renderHiddenFieldsInt($writer, $initial) diff --git a/framework/Web/UI/WebControls/TAccordion.php b/framework/Web/UI/WebControls/TAccordion.php index 8fd53e29..ba38d14d 100644 --- a/framework/Web/UI/WebControls/TAccordion.php +++ b/framework/Web/UI/WebControls/TAccordion.php @@ -415,7 +415,6 @@ class TAccordion extends TWebControl implements IPostBackDataHandler  		parent::onPreRender($param);
  		$this->getActiveView();  // determine the active view
  		$this->registerStyleSheet();
 -		$this->registerClientScript();
  	}
  	/**
 @@ -509,6 +508,12 @@ class TAccordion extends TWebControl implements IPostBackDataHandler  		return $this->getControls();
  	}
 +	public function render($writer)
 +	{
 +		$this->registerClientScript();
 +		parent::render($writer);
 +	}
 +
  	/**
  	 * Renders body contents of the accordion control.
  	 * @param THtmlWriter the writer used for the rendering purpose.
 diff --git a/framework/Web/UI/WebControls/TBaseValidator.php b/framework/Web/UI/WebControls/TBaseValidator.php index abf959cd..a4307f70 100644 --- a/framework/Web/UI/WebControls/TBaseValidator.php +++ b/framework/Web/UI/WebControls/TBaseValidator.php @@ -1,752 +1,751 @@ -<?php
 -/**
 - * TBaseValidator class file
 - *
 - * @author Qiang Xue <qiang.xue@gmail.com>
 - * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2011 PradoSoft
 - * @license http://www.pradosoft.com/license/
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - */
 -
 -/**
 - * Using TLabel class
 - */
 -Prado::using('System.Web.UI.WebControls.TLabel');
 -
 -/**
 - * TBaseValidator class
 - *
 - * TBaseValidator serves as the base class for validator controls.
 - *
 - * Validation is performed when a postback control, such as a TButton, a TLinkButton
 - * or a TTextBox (under AutoPostBack mode) is submitting the page and
 - * its <b>CausesValidation</b> property is true.
 - * You can also manually perform validation by calling {@link TPage::validate()}.
 - * The input control to be validated is specified by {@link setControlToValidate ControlToValidate}.
 - *
 - * Validator controls always validate the associated input control on the serve side.
 - * In addition, if {@link getEnableClientScript EnableClientScript} is true,
 - * validation will also be performed on the client-side using javascript.
 - * Client-side validation will validate user input before it is sent to the server.
 - * The form data will not be submitted if any error is detected. This avoids
 - * the round-trip of information necessary for server-side validation.
 - *
 - * You can use multiple validator controls to validate a single input control,
 - * each responsible for validating against a different criteria.
 - * For example, on a user registration form, you may want to make sure the user
 - * enters a value in the username text box, and the input must consist of only word
 - * characters. You can use a {@link TRequiredFieldValidator} to ensure the input
 - * of username and a {@link TRegularExpressionValidator} to ensure the proper input.
 - *
 - * If an input control fails validation, the text specified by the {@link setErrorMessage ErrorMessage}
 - * property is displayed in the validation control. However, if the {@link setText Text}
 - * property is set, it will be displayed instead. If both {@link setErrorMessage ErrorMessage}
 - * and {@link setText Text} are empty, the body content of the validator will
 - * be displayed. Error display is controlled by {@link setDisplay Display} property.
 - *
 - * You can also customized the client-side behaviour by adding javascript
 - * code to the subproperties of the {@link getClientSide ClientSide}
 - * property. See quickstart documentation for further details.
 - *
 - * You can also place a {@link TValidationSummary} control on a page to display error messages
 - * from the validators together. In this case, only the {@link setErrorMessage ErrorMessage}
 - * property of the validators will be displayed in the {@link TValidationSummary} control.
 - *
 - * Validators can be partitioned into validation groups by setting their
 - * {@link setValidationGroup ValidationGroup} property. If the control causing the
 - * validation also sets its ValidationGroup property, only those validators having
 - * the same ValidationGroup value will do input validation.
 - *
 - * Note, the {@link TPage::getIsValid IsValid} property of the current {@link TPage}
 - * instance will be automatically updated by the validation process which occurs
 - * after {@link TPage::onLoad onLoad} of {@link TPage} and before the postback events.
 - * Therefore, if you use the {@link TPage::getIsValid()} property in
 - * the {@link TPage::onLoad()} method, you must first explicitly call
 - * the {@link TPage::validate()} method.
 - *
 - * <b>Notes to Inheritors</b>  When you inherit from TBaseValidator, you must
 - * override the method {@link evaluateIsValid}.
 - *
 - * @author Qiang Xue <qiang.xue@gmail.com>
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.0
 - */
 -abstract class TBaseValidator extends TLabel implements IValidator
 -{
 -	/**
 -	 * @var boolean whether the validation succeeds
 -	 */
 -	private $_isValid=true;
 -	/**
 -	 * @var boolean whether the validator has been registered with the page
 -	 */
 -	private $_registered=false;
 -	/**
 -	 * @var TValidatorClientSide validator client-script options.
 -	 */
 -	private $_clientSide;
 -	/**
 -	 * Controls for which the client-side validation3.js file needs to handle
 -	 * them specially.
 -	 * @var array list of control class names
 -	 */
 -	private static $_clientClass = array('THtmlArea', 'TDatePicker', 'TListBox', 'TCheckBoxList');
 -
 -	/**
 -	 * Constructor.
 -	 * This method sets the foreground color to red.
 -	 */
 -	public function __construct()
 -	{
 -		parent::__construct();
 -		$this->setForeColor('red');
 -	}
 -
 -	/**
 -	 * Registers the validator with page.
 -	 * @param mixed event parameter
 -	 */
 -	public function onInit($param)
 -	{
 -		parent::onInit($param);
 -		$this->getPage()->getValidators()->add($this);
 -		$this->_registered=true;
 -	}
 -
 -	/**
 -	 * Unregisters the validator from page.
 -	 * @param mixed event parameter
 -	 */
 -	public function onUnload($param)
 -	{
 -		if($this->_registered && ($page=$this->getPage())!==null)
 -			$page->getValidators()->remove($this);
 -		$this->_registered=false;
 -		parent::onUnload($param);
 -	}
 -
 -	/**
 -	 * Adds attributes to renderer. Calls parent implementation and renders the
 -	 * client control scripts.
 -	 * @param THtmlWriter the renderer
 -	 */
 -	protected function addAttributesToRender($writer)
 -	{
 -		$display=$this->getDisplay();
 -		$visible=$this->getEnabled(true) && !$this->getIsValid();
 -		if($display===TValidatorDisplayStyle::None || (!$visible && $display===TValidatorDisplayStyle::Dynamic))
 -			$writer->addStyleAttribute('display','none');
 -		else if(!$visible)
 -			$writer->addStyleAttribute('visibility','hidden');
 -		$writer->addAttribute('id',$this->getClientID());
 -		parent::addAttributesToRender($writer);
 -		$this->renderClientControlScript($writer);
 -	}
 -
 -	/**
 -	 * Returns an array of javascript validator options.
 -	 * @return array javascript validator options.
 -	 */
 -	protected function getClientScriptOptions()
 -	{
 -		$control = $this->getValidationTarget();
 -		$options['ID'] = $this->getClientID();
 -		$options['FormID'] = $this->getPage()->getForm()->getClientID();
 -		$options['Display'] = $this->getDisplay();
 -		$options['ErrorMessage'] = $this->getErrorMessage();
 -		if($this->getFocusOnError())
 -		{
 -			$options['FocusOnError'] = $this->getFocusOnError();
 -			$options['FocusElementID'] = $this->getFocusElementID();
 -		}
 -		$options['ValidationGroup'] = $this->getValidationGroup();
 -		if($control)
 -			$options['ControlToValidate'] = $control->getClientID();
 -		$options['ControlCssClass'] = $this->getControlCssClass();
 -
 -		$options['ControlType'] = $this->getClientControlClass($control);
 -		$options['Enabled'] = $this->getEnabled(true);
 -
 -		//get date format from date picker target control
 -		if($control instanceof TDatePicker)
 -			$options['DateFormat'] = $control->getDateFormat();
 -
 -		$options = array_merge($options,$this->getClientSide()->getOptions()->toArray());
 -
 -		return $options;
 -	}
 -
 -	/**
 -	 * Gets the Control type for client-side validation. If new cases exists in
 -	 * TBaseValidator::$_clientClass, be sure to update the corresponding
 -	 * "Javascript/validation3.js" file as well.
 -	 * @param TControl control to validate.
 -	 * @return string control type for client-side validation.
 -	 */
 -	private function getClientControlClass($control)
 -	{
 -		foreach(self::$_clientClass as $type)
 -			if($control instanceof $type)
 -				return $type;
 -		return get_class($control);
 -	}
 -
 -	/**
 -	 * Gets the TValidatorClientSide that allows modification of the client-
 -	 * side validator events.
 -	 *
 -	 * The client-side validator supports the following events.
 -	 * # <tt>OnValidate</tt> -- raised before client-side validation is
 -	 * executed.
 -	 * # <tt>OnValidationSuccess</tt> -- raised after client-side validation is completed
 -	 * and is successfull, overrides default validator error messages updates.
 -	 * # <tt>OnValidationError</tt> -- raised after client-side validation is completed
 -	 * and failed, overrides default validator error message updates.
 -	 *
 -	 * You can attach custom javascript code to each of these events
 -	 *
 -	 * @return TValidatorClientSide javascript validator event options.
 -	 */
 -	public function getClientSide()
 -	{
 -		if($this->_clientSide===null)
 -			$this->_clientSide = $this->createClientSide();
 -		return $this->_clientSide;
 -	}
 -
 -	/**
 -	 * @return TValidatorClientSide javascript validator event options.
 -	 */
 -	protected function createClientSide()
 -	{
 -		return new TValidatorClientSide;
 -	}
 -
 -	/**
 -	 * Renders the javascript code to the end script.
 -	 * If you override this method, be sure to call the parent implementation
 -	 * so that the event handlers can be invoked.
 -	 * @param THtmlWriter the renderer
 -	 */
 -	public function renderClientControlScript($writer)
 -	{
 -		$scripts = $this->getPage()->getClientScript();
 -		$formID=$this->getPage()->getForm()->getClientID();
 -		$scriptKey = "TBaseValidator:$formID";
 -		if($this->getEnableClientScript() && !$scripts->isEndScriptRegistered($scriptKey))
 -		{
 -			$manager['FormID'] = $formID;
 -			$options = TJavaScript::encode($manager);
 -			$scripts->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});");
 -		}
 -		if($this->getEnableClientScript())
 -			$this->registerClientScriptValidator();
 -	}
 -
 -	/**
 -	 * Override parent implementation to update the control CSS Class before
 -	 * the validated control is rendered
 -	 */
 -	public function onPreRender ($param)
 -	{
 -		parent::onPreRender($param);
 -		$this->updateControlCssClass();
 -		if ($this->getEnableClientScript())
 -			$this->getPage()->getClientScript()->registerPradoScript('validator');
 -	}
 -
 -	/**
 -	 * Update the ControlToValidate component's css class depending
 -	 * if the ControlCssClass property is set, and whether this is valid.
 -	 * @return boolean true if change, false otherwise.
 -	 */
 -	protected function updateControlCssClass()
 -	{
 -		if(($cssClass=$this->getControlCssClass())!=='')
 -		{
 -			$control=$this->getValidationTarget();
 -			if($control instanceof TWebControl)
 -			{
 -				$class = preg_replace ('/ '.preg_quote($cssClass).'/', '',$control->getCssClass());
 -				if(!$this->getIsValid())
 -				{
 -					$class .= ' '.$cssClass;
 -					$control->setCssClass($class);
 -				} elseif ($control->getIsValid())
 -					$control->setCssClass($class);
 -			}
 -		}
 -	}
 -
 -	/**
 -	 * Registers the individual validator client-side javascript code.
 -	 */
 -	protected function registerClientScriptValidator()
 -	{
 -		$key = 'prado:'.$this->getClientID();
 -		if(!$this->getPage()->getClientScript()->isEndScriptRegistered($key))
 -		{
 -			$options = TJavaScript::encode($this->getClientScriptOptions());
 -			$script = 'new '.$this->getClientClassName().'('.$options.');';
 -			$this->getPage()->getClientScript()->registerEndScript($key, $script);
 -		}
 -	}
 -
 -	/**
 -	 * Gets the name of the javascript class responsible for performing validation for this control.
 -	 * This method overrides the parent implementation.
 -	 * @return string the javascript class name
 -	 */
 -	abstract protected function getClientClassName();
 -
 -	/**
 -	 * This method overrides the parent implementation to forbid setting ForControl.
 -	 * @param string the associated control ID
 -	 * @throws TNotSupportedException whenever this method is called
 -	 */
 -	public function setForControl($value)
 -	{
 -		throw new TNotSupportedException('basevalidator_forcontrol_unsupported',get_class($this));
 -	}
 -
 -	/**
 -	 * This method overrides parent's implementation by setting {@link setIsValid IsValid} to true if disabled.
 -	 * @param boolean whether the validator is enabled.
 -	 */
 -	public function setEnabled($value)
 -	{
 -		$value=TPropertyValue::ensureBoolean($value);
 -		parent::setEnabled($value);
 -		if(!$value)
 -			$this->_isValid=true;
 -	}
 -
 -	/**
 -	 * @return TValidatorDisplayStyle the style of displaying the error message. Defaults to TValidatorDisplayStyle::Fixed.
 -	 */
 -	public function getDisplay()
 -	{
 -		return $this->getViewState('Display',TValidatorDisplayStyle::Fixed);
 -	}
 -
 -	/**
 -	 * @param TValidatorDisplayStyle the style of displaying the error message
 -	 */
 -	public function setDisplay($value)
 -	{
 -		$this->setViewState('Display',TPropertyValue::ensureEnum($value,'TValidatorDisplayStyle'),TValidatorDisplayStyle::Fixed);
 -	}
 -
 -	/**
 -	 * @return boolean whether client-side validation is enabled.
 -	 */
 -	public function getEnableClientScript()
 -	{
 -		return $this->getViewState('EnableClientScript',true);
 -	}
 -
 -	/**
 -	 * @param boolean whether client-side validation is enabled.
 -	 */
 -	public function setEnableClientScript($value)
 -	{
 -		$this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
 -	}
 -
 -	/**
 -	 * @return string the text for the error message.
 -	 */
 -	public function getErrorMessage()
 -	{
 -		return $this->getViewState('ErrorMessage','');
 -	}
 -
 -	/**
 -	 * Sets the text for the error message.
 -	 * @param string the error message
 -	 */
 -	public function setErrorMessage($value)
 -	{
 -		$this->setViewState('ErrorMessage',$value,'');
 -	}
 -
 -	/**
 -	 * @return string the ID path of the input control to validate
 -	 */
 -	public function getControlToValidate()
 -	{
 -		return $this->getViewState('ControlToValidate','');
 -	}
 -
 -	/**
 -	 * Sets the ID path of the input control to validate.
 -	 * The ID path is the dot-connected IDs of the controls reaching from
 -	 * the validator's naming container to the target control.
 -	 * @param string the ID path
 -	 */
 -	public function setControlToValidate($value)
 -	{
 -		$this->setViewState('ControlToValidate',$value,'');
 -	}
 -
 -	/**
 -	 * @return boolean whether to set focus at the validating place if the validation fails. Defaults to false.
 -	 */
 -	public function getFocusOnError()
 -	{
 -		return $this->getViewState('FocusOnError',false);
 -	}
 -
 -	/**
 -	 * @param boolean whether to set focus at the validating place if the validation fails
 -	 */
 -	public function setFocusOnError($value)
 -	{
 -		$this->setViewState('FocusOnError',TPropertyValue::ensureBoolean($value),false);
 -	}
 -
 -	/**
 -	 * Gets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true.
 -	 * Defaults to the client ID of the {@link getControlToValidate ControlToValidate}.
 -	 * @return string the ID of the HTML element to receive focus
 -	 */
 -	public function getFocusElementID()
 -	{
 -		if(($id=$this->getViewState('FocusElementID',''))==='')
 -		{
 -			$target=$this->getValidationTarget();
 -			/* Workaround: TCheckBoxList and TRadioButtonList nests the actual
 -			 * inputs inside a table; we ensure the first input gets focused
 -			 */
 -			if($target instanceof TCheckBoxList && $target->getItemCount()>0)
 -			{
 -				$id=$target->getClientID().'_c0';
 -			} else {
 -				$id=$target->getClientID();
 -			}
 -		}
 -		return $id;
 -	}
 -
 -	/**
 -	 * Sets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true.
 -	 * @param string the ID of the HTML element to receive focus
 -	 */
 -	public function setFocusElementID($value)
 -	{
 -		$this->setViewState('FocusElementID', $value, '');
 -	}
 -
 -	/**
 -	 * @return string the group which this validator belongs to
 -	 */
 -	public function getValidationGroup()
 -	{
 -		return $this->getViewState('ValidationGroup','');
 -	}
 -
 -	/**
 -	 * @param string the group which this validator belongs to
 -	 */
 -	public function setValidationGroup($value)
 -	{
 -		$this->setViewState('ValidationGroup',$value,'');
 -	}
 -
 -	/**
 -	 * @return boolean whether the validation succeeds
 -	 */
 -	public function getIsValid()
 -	{
 -		return $this->_isValid;
 -	}
 -
 -	/**
 -	 * Sets the value indicating whether the validation succeeds
 -	 * @param boolean whether the validation succeeds
 -	 */
 -	public function setIsValid($value)
 -	{
 -		$this->_isValid=TPropertyValue::ensureBoolean($value);
 -	}
 -
 -	/**
 -	 * @return TControl control to be validated. Null if no control is found.
 -	 * @throws TConfigurationException if {@link getControlToValidate
 -	 * ControlToValidate} is empty or does not point to a valid control
 -	 */
 -	public function getValidationTarget()
 -	{
 -		if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null)
 -			return $control;
 -		else
 -			throw new TConfigurationException('basevalidator_controltovalidate_invalid',get_class($this));
 -	}
 -
 -	/**
 -	 * Retrieves the property value of the control being validated.
 -	 * @param TControl control being validated
 -	 * @return string property value to be validated
 -	 * @throws TInvalidDataTypeException if the control to be validated does not implement {@link IValidatable}.
 -	 */
 -	protected function getValidationValue($control)
 -	{
 -		if($control instanceof IValidatable)
 -			return $control->getValidationPropertyValue();
 -		else
 -			throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this));
 -	}
 -
 -	/**
 -	 * Validates the specified control.
 -	 * Do not override this method. Override {@link evaluateIsValid} instead.
 -	 * @return boolean whether the validation succeeds
 -	 */
 -	public function validate()
 -	{
 -		$this->onValidate();
 -		if($this->getVisible(true) && $this->getEnabled(true))
 -		{
 -			$target=$this->getValidationTarget();
 -			// if the target is not a disabled web control
 -			if($target===null ||
 -				($target!==null && 
 -				!($target instanceof TWebControl && !$target->getEnabled(true))))
 -			{
 -				if($this->evaluateIsValid())
 -				{
 -					$this->setIsValid(true);
 -					$this->onValidationSuccess();
 -				}
 -				else
 -				{
 -					if($target)
 -						$target->setIsValid(false);
 -					$this->setIsValid(false);
 -					$this->onValidationError();
 -				}
 -			}
 -			else
 -			{
 -				$this->evaluateIsValid();
 -				$this->setIsValid(true);
 -				$this->onValidationSuccess();
 -			}
 -		} else {
 -			$this->setIsValid(true);
 -		}
 -		return $this->getIsValid();
 -	}
 -
 -	/**
 -	 * @return string the css class that is applied to the control being validated in case the validation fails
 -	 */
 -	public function getControlCssClass()
 -	{
 -		return $this->getViewState('ControlCssClass','');
 -	}
 -
 -	/**
 -	 * @param string the css class that is applied to the control being validated in case the validation fails
 -	 */
 -	public function setControlCssClass($value)
 -	{
 -		$this->setViewState('ControlCssClass',$value,'');
 -	}
 -
 -	/**
 -	 * This is the major method for validation.
 -	 * Derived classes should implement this method to provide customized validation.
 -	 * @return boolean whether the validation succeeds
 -	 */
 -	abstract protected function evaluateIsValid();
 -
 -	/**
 -	 * This event is raised when the validator succeeds in validation.
 -	 */
 -	public function onValidationSuccess()
 -	{
 -		$this->raiseEvent('OnValidationSuccess',$this,null);
 -	}
 -
 -	/**
 -	 * This event is raised when the validator fails in validation.
 -	 */
 -	public function onValidationError()
 -	{
 -		$this->raiseEvent('OnValidationError',$this,null);
 -	}
 -
 -	/**
 -	 * This event is raised right before the validator starts to perform validation.
 -	 * You may use this event to change the behavior of validation.
 -	 * For example, you may disable the validator if certain condition is satisfied.
 -	 * Note, the event will NOT be raised if the validator is invisible.
 -	 */
 -	public function onValidate()
 -	{
 -		$this->raiseEvent('OnValidate',$this,null);
 -	}
 -
 -	/**
 -	 * Renders the validator control.
 -	 * @param THtmlWriter writer for the rendering purpose
 -	 */
 -	public function renderContents($writer)
 -	{
 -		if(($text=$this->getText())!=='')
 -			$writer->write($text);
 -		else if(($text=$this->getErrorMessage())!=='')
 -			$writer->write($text);
 -		else
 -			parent::renderContents($writer);
 -	}
 -}
 -
 -/**
 - * TValidatorClientSide class.
 - *
 - * Client-side validator events can be modified through the {@link
 - * TBaseValidator::getClientSide ClientSide} property of a validator. The
 - * subproperties of ClientSide are those of the TValidatorClientSide
 - * properties. The client-side validator supports the following events.
 - *
 - * The <tt>OnValidate</tt> event is raise before the validator validation
 - * functions are called.
 - *
 - * The <tt>OnValidationSuccess</tt> event is raised after the validator has successfully
 - * validate the control.
 - *
 - * The <tt>OnValidationError</tt> event is raised after the validator fails validation.
 - *
 - * See the quickstart documentation for further details.
 - *
 - * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.0
 - */
 -class TValidatorClientSide extends TClientSideOptions
 -{
 -	/**
 -	 * @return string javascript code for client-side OnValidate event.
 -	 */
 -	public function getOnValidate()
 -	{
 -		return $this->getOption('OnValidate');
 -	}
 -
 -	/**
 -	 * Client-side OnValidate validator event is raise before the validators
 -	 * validation functions are called.
 -	 * @param string javascript code for client-side OnValidate event.
 -	 */
 -	public function setOnValidate($javascript)
 -	{
 -		$this->setFunction('OnValidate', $javascript);
 -	}
 -
 -	/**
 -	 * Client-side OnSuccess event is raise after validation is successfull.
 -	 * This will override the default client-side validator behaviour.
 -	 * @param string javascript code for client-side OnSuccess event.
 -	 */
 -	public function setOnValidationSuccess($javascript)
 -	{
 -		$this->setFunction('OnValidationSuccess', $javascript);
 -	}
 -
 -	/**
 -	 * @return string javascript code for client-side OnSuccess event.
 -	 */
 -	public function getOnValidationSuccess()
 -	{
 -		return $this->getOption('OnValidationSuccess');
 -	}
 -
 -	/**
 -	 * Client-side OnError event is raised after validation failure.
 -	 * This will override the default client-side validator behaviour.
 -	 * @param string javascript code for client-side OnError event.
 -	 */
 -	public function setOnValidationError($javascript)
 -	{
 -		$this->setFunction('OnValidationError', $javascript);
 -	}
 -
 -	/**
 -	 * @return string javascript code for client-side OnError event.
 -	 */
 -	public function getOnValidationError()
 -	{
 -		return $this->getOption('OnValidationError');
 -	}
 -
 -	/**
 -	 * @param boolean true to revalidate when the control to validate changes value.
 -	 */
 -	public function setObserveChanges($value)
 -	{
 -		$this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value));
 -	}
 -
 -	/**
 -	 * @return boolean true to observe changes.
 -	 */
 -	public function getObserveChanges()
 -	{
 -		$changes = $this->getOption('ObserveChanges');
 -		return ($changes===null) ? true : $changes;
 -	}
 -}
 -
 -
 -/**
 - * TValidatorDisplayStyle class.
 - * TValidatorDisplayStyle defines the enumerable type for the possible styles
 - * that a validator control can display the error message.
 - *
 - * The following enumerable values are defined:
 - * - None: the error message is not displayed
 - * - Dynamic: the error message dynamically appears when the validator fails validation
 - * - Fixed: Similar to Dynamic except that the error message physically occupies the page layout (even though it may not be visible)
 - *
 - * @author Qiang Xue <qiang.xue@gmail.com>
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.0.4
 - */
 -class TValidatorDisplayStyle extends TEnumerable
 -{
 -	const None='None';
 -	const Dynamic='Dynamic';
 -	const Fixed='Fixed';
 -}
 -
 -/**
 - * TValidationDataType class.
 - * TValidationDataType defines the enumerable type for the possible data types that
 - * a comparison validator can validate upon.
 - *
 - * The following enumerable values are defined:
 - * - Integer
 - * - Float
 - * - Date
 - * - String
 - *
 - * @author Qiang Xue <qiang.xue@gmail.com>
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.0.4
 - */
 -class TValidationDataType extends TEnumerable
 -{
 -	const Integer='Integer';
 -	const Float='Float';
 -	const Date='Date';
 -	const String='String';
 -}
 -
 +<?php +/** + * TBaseValidator class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2011 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TLabel class + */ +Prado::using('System.Web.UI.WebControls.TLabel'); + +/** + * TBaseValidator class + * + * TBaseValidator serves as the base class for validator controls. + * + * Validation is performed when a postback control, such as a TButton, a TLinkButton + * or a TTextBox (under AutoPostBack mode) is submitting the page and + * its <b>CausesValidation</b> property is true. + * You can also manually perform validation by calling {@link TPage::validate()}. + * The input control to be validated is specified by {@link setControlToValidate ControlToValidate}. + * + * Validator controls always validate the associated input control on the serve side. + * In addition, if {@link getEnableClientScript EnableClientScript} is true, + * validation will also be performed on the client-side using javascript. + * Client-side validation will validate user input before it is sent to the server. + * The form data will not be submitted if any error is detected. This avoids + * the round-trip of information necessary for server-side validation. + * + * You can use multiple validator controls to validate a single input control, + * each responsible for validating against a different criteria. + * For example, on a user registration form, you may want to make sure the user + * enters a value in the username text box, and the input must consist of only word + * characters. You can use a {@link TRequiredFieldValidator} to ensure the input + * of username and a {@link TRegularExpressionValidator} to ensure the proper input. + * + * If an input control fails validation, the text specified by the {@link setErrorMessage ErrorMessage} + * property is displayed in the validation control. However, if the {@link setText Text} + * property is set, it will be displayed instead. If both {@link setErrorMessage ErrorMessage} + * and {@link setText Text} are empty, the body content of the validator will + * be displayed. Error display is controlled by {@link setDisplay Display} property. + * + * You can also customized the client-side behaviour by adding javascript + * code to the subproperties of the {@link getClientSide ClientSide} + * property. See quickstart documentation for further details. + * + * You can also place a {@link TValidationSummary} control on a page to display error messages + * from the validators together. In this case, only the {@link setErrorMessage ErrorMessage} + * property of the validators will be displayed in the {@link TValidationSummary} control. + * + * Validators can be partitioned into validation groups by setting their + * {@link setValidationGroup ValidationGroup} property. If the control causing the + * validation also sets its ValidationGroup property, only those validators having + * the same ValidationGroup value will do input validation. + * + * Note, the {@link TPage::getIsValid IsValid} property of the current {@link TPage} + * instance will be automatically updated by the validation process which occurs + * after {@link TPage::onLoad onLoad} of {@link TPage} and before the postback events. + * Therefore, if you use the {@link TPage::getIsValid()} property in + * the {@link TPage::onLoad()} method, you must first explicitly call + * the {@link TPage::validate()} method. + * + * <b>Notes to Inheritors</b>  When you inherit from TBaseValidator, you must + * override the method {@link evaluateIsValid}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TBaseValidator extends TLabel implements IValidator +{ +	/** +	 * @var boolean whether the validation succeeds +	 */ +	private $_isValid=true; +	/** +	 * @var boolean whether the validator has been registered with the page +	 */ +	private $_registered=false; +	/** +	 * @var TValidatorClientSide validator client-script options. +	 */ +	private $_clientSide; +	/** +	 * Controls for which the client-side validation3.js file needs to handle +	 * them specially. +	 * @var array list of control class names +	 */ +	private static $_clientClass = array('THtmlArea', 'TDatePicker', 'TListBox', 'TCheckBoxList'); + +	/** +	 * Constructor. +	 * This method sets the foreground color to red. +	 */ +	public function __construct() +	{ +		parent::__construct(); +		$this->setForeColor('red'); +	} + +	/** +	 * Registers the validator with page. +	 * @param mixed event parameter +	 */ +	public function onInit($param) +	{ +		parent::onInit($param); +		$this->getPage()->getValidators()->add($this); +		$this->_registered=true; +	} + +	/** +	 * Unregisters the validator from page. +	 * @param mixed event parameter +	 */ +	public function onUnload($param) +	{ +		if($this->_registered && ($page=$this->getPage())!==null) +			$page->getValidators()->remove($this); +		$this->_registered=false; +		parent::onUnload($param); +	} + +	/** +	 * Adds attributes to renderer. Calls parent implementation and renders the +	 * client control scripts. +	 * @param THtmlWriter the renderer +	 */ +	protected function addAttributesToRender($writer) +	{ +		$display=$this->getDisplay(); +		$visible=$this->getEnabled(true) && !$this->getIsValid(); +		if($display===TValidatorDisplayStyle::None || (!$visible && $display===TValidatorDisplayStyle::Dynamic)) +			$writer->addStyleAttribute('display','none'); +		else if(!$visible) +			$writer->addStyleAttribute('visibility','hidden'); +		$writer->addAttribute('id',$this->getClientID()); +		parent::addAttributesToRender($writer); +		$this->renderClientControlScript($writer); +	} + +	/** +	 * Returns an array of javascript validator options. +	 * @return array javascript validator options. +	 */ +	protected function getClientScriptOptions() +	{ +		$control = $this->getValidationTarget(); +		$options['ID'] = $this->getClientID(); +		$options['FormID'] = $this->getPage()->getForm()->getClientID(); +		$options['Display'] = $this->getDisplay(); +		$options['ErrorMessage'] = $this->getErrorMessage(); +		if($this->getFocusOnError()) +		{ +			$options['FocusOnError'] = $this->getFocusOnError(); +			$options['FocusElementID'] = $this->getFocusElementID(); +		} +		$options['ValidationGroup'] = $this->getValidationGroup(); +		if($control) +			$options['ControlToValidate'] = $control->getClientID(); +		$options['ControlCssClass'] = $this->getControlCssClass(); + +		$options['ControlType'] = $this->getClientControlClass($control); +		$options['Enabled'] = $this->getEnabled(true); + +		//get date format from date picker target control +		if($control instanceof TDatePicker) +			$options['DateFormat'] = $control->getDateFormat(); + +		$options = array_merge($options,$this->getClientSide()->getOptions()->toArray()); + +		return $options; +	} + +	/** +	 * Gets the Control type for client-side validation. If new cases exists in +	 * TBaseValidator::$_clientClass, be sure to update the corresponding +	 * "Javascript/validation3.js" file as well. +	 * @param TControl control to validate. +	 * @return string control type for client-side validation. +	 */ +	private function getClientControlClass($control) +	{ +		foreach(self::$_clientClass as $type) +			if($control instanceof $type) +				return $type; +		return get_class($control); +	} + +	/** +	 * Gets the TValidatorClientSide that allows modification of the client- +	 * side validator events. +	 * +	 * The client-side validator supports the following events. +	 * # <tt>OnValidate</tt> -- raised before client-side validation is +	 * executed. +	 * # <tt>OnValidationSuccess</tt> -- raised after client-side validation is completed +	 * and is successfull, overrides default validator error messages updates. +	 * # <tt>OnValidationError</tt> -- raised after client-side validation is completed +	 * and failed, overrides default validator error message updates. +	 * +	 * You can attach custom javascript code to each of these events +	 * +	 * @return TValidatorClientSide javascript validator event options. +	 */ +	public function getClientSide() +	{ +		if($this->_clientSide===null) +			$this->_clientSide = $this->createClientSide(); +		return $this->_clientSide; +	} + +	/** +	 * @return TValidatorClientSide javascript validator event options. +	 */ +	protected function createClientSide() +	{ +		return new TValidatorClientSide; +	} + +	/** +	 * Renders the javascript code to the end script. +	 * If you override this method, be sure to call the parent implementation +	 * so that the event handlers can be invoked. +	 * @param THtmlWriter the renderer +	 */ +	public function renderClientControlScript($writer) +	{ +		$scripts = $this->getPage()->getClientScript(); +		if ($this->getEnableClientScript()) +			$scripts->registerPradoScript('validator'); +		$formID=$this->getPage()->getForm()->getClientID(); +		$scriptKey = "TBaseValidator:$formID"; +		if($this->getEnableClientScript() && !$scripts->isEndScriptRegistered($scriptKey)) +		{ +			$manager['FormID'] = $formID; +			$options = TJavaScript::encode($manager); +			$scripts->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});"); +		} +		if($this->getEnableClientScript()) +			$this->registerClientScriptValidator(); +	} + +	/** +	 * Override parent implementation to update the control CSS Class before +	 * the validated control is rendered +	 */ +	public function onPreRender ($param) +	{ +		parent::onPreRender($param); +		$this->updateControlCssClass(); +	} + +	/** +	 * Update the ControlToValidate component's css class depending +	 * if the ControlCssClass property is set, and whether this is valid. +	 * @return boolean true if change, false otherwise. +	 */ +	protected function updateControlCssClass() +	{ +		if(($cssClass=$this->getControlCssClass())!=='') +		{ +			$control=$this->getValidationTarget(); +			if($control instanceof TWebControl) +			{ +				$class = preg_replace ('/ '.preg_quote($cssClass).'/', '',$control->getCssClass()); +				if(!$this->getIsValid()) +				{ +					$class .= ' '.$cssClass; +					$control->setCssClass($class); +				} elseif ($control->getIsValid()) +					$control->setCssClass($class); +			} +		} +	} + +	/** +	 * Registers the individual validator client-side javascript code. +	 */ +	protected function registerClientScriptValidator() +	{ +		$key = 'prado:'.$this->getClientID(); +		if(!$this->getPage()->getClientScript()->isEndScriptRegistered($key)) +		{ +			$options = TJavaScript::encode($this->getClientScriptOptions()); +			$script = 'new '.$this->getClientClassName().'('.$options.');'; +			$this->getPage()->getClientScript()->registerEndScript($key, $script); +		} +	} + +	/** +	 * Gets the name of the javascript class responsible for performing validation for this control. +	 * This method overrides the parent implementation. +	 * @return string the javascript class name +	 */ +	abstract protected function getClientClassName(); + +	/** +	 * This method overrides the parent implementation to forbid setting ForControl. +	 * @param string the associated control ID +	 * @throws TNotSupportedException whenever this method is called +	 */ +	public function setForControl($value) +	{ +		throw new TNotSupportedException('basevalidator_forcontrol_unsupported',get_class($this)); +	} + +	/** +	 * This method overrides parent's implementation by setting {@link setIsValid IsValid} to true if disabled. +	 * @param boolean whether the validator is enabled. +	 */ +	public function setEnabled($value) +	{ +		$value=TPropertyValue::ensureBoolean($value); +		parent::setEnabled($value); +		if(!$value) +			$this->_isValid=true; +	} + +	/** +	 * @return TValidatorDisplayStyle the style of displaying the error message. Defaults to TValidatorDisplayStyle::Fixed. +	 */ +	public function getDisplay() +	{ +		return $this->getViewState('Display',TValidatorDisplayStyle::Fixed); +	} + +	/** +	 * @param TValidatorDisplayStyle the style of displaying the error message +	 */ +	public function setDisplay($value) +	{ +		$this->setViewState('Display',TPropertyValue::ensureEnum($value,'TValidatorDisplayStyle'),TValidatorDisplayStyle::Fixed); +	} + +	/** +	 * @return boolean whether client-side validation is enabled. +	 */ +	public function getEnableClientScript() +	{ +		return $this->getViewState('EnableClientScript',true); +	} + +	/** +	 * @param boolean whether client-side validation is enabled. +	 */ +	public function setEnableClientScript($value) +	{ +		$this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true); +	} + +	/** +	 * @return string the text for the error message. +	 */ +	public function getErrorMessage() +	{ +		return $this->getViewState('ErrorMessage',''); +	} + +	/** +	 * Sets the text for the error message. +	 * @param string the error message +	 */ +	public function setErrorMessage($value) +	{ +		$this->setViewState('ErrorMessage',$value,''); +	} + +	/** +	 * @return string the ID path of the input control to validate +	 */ +	public function getControlToValidate() +	{ +		return $this->getViewState('ControlToValidate',''); +	} + +	/** +	 * Sets the ID path of the input control to validate. +	 * The ID path is the dot-connected IDs of the controls reaching from +	 * the validator's naming container to the target control. +	 * @param string the ID path +	 */ +	public function setControlToValidate($value) +	{ +		$this->setViewState('ControlToValidate',$value,''); +	} + +	/** +	 * @return boolean whether to set focus at the validating place if the validation fails. Defaults to false. +	 */ +	public function getFocusOnError() +	{ +		return $this->getViewState('FocusOnError',false); +	} + +	/** +	 * @param boolean whether to set focus at the validating place if the validation fails +	 */ +	public function setFocusOnError($value) +	{ +		$this->setViewState('FocusOnError',TPropertyValue::ensureBoolean($value),false); +	} + +	/** +	 * Gets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true. +	 * Defaults to the client ID of the {@link getControlToValidate ControlToValidate}. +	 * @return string the ID of the HTML element to receive focus +	 */ +	public function getFocusElementID() +	{ +		if(($id=$this->getViewState('FocusElementID',''))==='') +		{ +			$target=$this->getValidationTarget(); +			/* Workaround: TCheckBoxList and TRadioButtonList nests the actual +			 * inputs inside a table; we ensure the first input gets focused +			 */ +			if($target instanceof TCheckBoxList && $target->getItemCount()>0) +			{ +				$id=$target->getClientID().'_c0'; +			} else { +				$id=$target->getClientID(); +			} +		} +		return $id; +	} + +	/** +	 * Sets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true. +	 * @param string the ID of the HTML element to receive focus +	 */ +	public function setFocusElementID($value) +	{ +		$this->setViewState('FocusElementID', $value, ''); +	} + +	/** +	 * @return string the group which this validator belongs to +	 */ +	public function getValidationGroup() +	{ +		return $this->getViewState('ValidationGroup',''); +	} + +	/** +	 * @param string the group which this validator belongs to +	 */ +	public function setValidationGroup($value) +	{ +		$this->setViewState('ValidationGroup',$value,''); +	} + +	/** +	 * @return boolean whether the validation succeeds +	 */ +	public function getIsValid() +	{ +		return $this->_isValid; +	} + +	/** +	 * Sets the value indicating whether the validation succeeds +	 * @param boolean whether the validation succeeds +	 */ +	public function setIsValid($value) +	{ +		$this->_isValid=TPropertyValue::ensureBoolean($value); +	} + +	/** +	 * @return TControl control to be validated. Null if no control is found. +	 * @throws TConfigurationException if {@link getControlToValidate +	 * ControlToValidate} is empty or does not point to a valid control +	 */ +	public function getValidationTarget() +	{ +		if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null) +			return $control; +		else +			throw new TConfigurationException('basevalidator_controltovalidate_invalid',get_class($this)); +	} + +	/** +	 * Retrieves the property value of the control being validated. +	 * @param TControl control being validated +	 * @return string property value to be validated +	 * @throws TInvalidDataTypeException if the control to be validated does not implement {@link IValidatable}. +	 */ +	protected function getValidationValue($control) +	{ +		if($control instanceof IValidatable) +			return $control->getValidationPropertyValue(); +		else +			throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this)); +	} + +	/** +	 * Validates the specified control. +	 * Do not override this method. Override {@link evaluateIsValid} instead. +	 * @return boolean whether the validation succeeds +	 */ +	public function validate() +	{ +		$this->setIsValid(true); +		$this->onValidate(); +		if($this->getVisible(true) && $this->getEnabled(true)) +		{ +			$target=$this->getValidationTarget(); +			// if the target is not a disabled web control +			if($target===null || +				($target!==null &&  +				!($target instanceof TWebControl && !$target->getEnabled(true)))) +			{ +				if($this->evaluateIsValid()) +				{ +					$this->setIsValid(true); +					$this->onValidationSuccess(); +				} +				else +				{ +					if($target) +						$target->setIsValid(false); +					$this->setIsValid(false); +					$this->onValidationError(); +				} +			} +			else +			{ +				$this->evaluateIsValid(); +				$this->setIsValid(true); +				$this->onValidationSuccess(); +			} +		} +		return $this->getIsValid(); +	} + +	/** +	 * @return string the css class that is applied to the control being validated in case the validation fails +	 */ +	public function getControlCssClass() +	{ +		return $this->getViewState('ControlCssClass',''); +	} + +	/** +	 * @param string the css class that is applied to the control being validated in case the validation fails +	 */ +	public function setControlCssClass($value) +	{ +		$this->setViewState('ControlCssClass',$value,''); +	} + +	/** +	 * This is the major method for validation. +	 * Derived classes should implement this method to provide customized validation. +	 * @return boolean whether the validation succeeds +	 */ +	abstract protected function evaluateIsValid(); + +	/** +	 * This event is raised when the validator succeeds in validation. +	 */ +	public function onValidationSuccess() +	{ +		$this->raiseEvent('OnValidationSuccess',$this,null); +	} + +	/** +	 * This event is raised when the validator fails in validation. +	 */ +	public function onValidationError() +	{ +		$this->raiseEvent('OnValidationError',$this,null); +	} + +	/** +	 * This event is raised right before the validator starts to perform validation. +	 * You may use this event to change the behavior of validation. +	 * For example, you may disable the validator if certain condition is satisfied. +	 * Note, the event will NOT be raised if the validator is invisible. +	 */ +	public function onValidate() +	{ +		$this->raiseEvent('OnValidate',$this,null); +	} + +	/** +	 * Renders the validator control. +	 * @param THtmlWriter writer for the rendering purpose +	 */ +	public function renderContents($writer) +	{ +		if(($text=$this->getText())!=='') +			$writer->write($text); +		else if(($text=$this->getErrorMessage())!=='') +			$writer->write($text); +		else +			parent::renderContents($writer); +	} +} + +/** + * TValidatorClientSide class. + * + * Client-side validator events can be modified through the {@link + * TBaseValidator::getClientSide ClientSide} property of a validator. The + * subproperties of ClientSide are those of the TValidatorClientSide + * properties. The client-side validator supports the following events. + * + * The <tt>OnValidate</tt> event is raise before the validator validation + * functions are called. + * + * The <tt>OnValidationSuccess</tt> event is raised after the validator has successfully + * validate the control. + * + * The <tt>OnValidationError</tt> event is raised after the validator fails validation. + * + * See the quickstart documentation for further details. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TValidatorClientSide extends TClientSideOptions +{ +	/** +	 * @return string javascript code for client-side OnValidate event. +	 */ +	public function getOnValidate() +	{ +		return $this->getOption('OnValidate'); +	} + +	/** +	 * Client-side OnValidate validator event is raise before the validators +	 * validation functions are called. +	 * @param string javascript code for client-side OnValidate event. +	 */ +	public function setOnValidate($javascript) +	{ +		$this->setFunction('OnValidate', $javascript); +	} + +	/** +	 * Client-side OnSuccess event is raise after validation is successfull. +	 * This will override the default client-side validator behaviour. +	 * @param string javascript code for client-side OnSuccess event. +	 */ +	public function setOnValidationSuccess($javascript) +	{ +		$this->setFunction('OnValidationSuccess', $javascript); +	} + +	/** +	 * @return string javascript code for client-side OnSuccess event. +	 */ +	public function getOnValidationSuccess() +	{ +		return $this->getOption('OnValidationSuccess'); +	} + +	/** +	 * Client-side OnError event is raised after validation failure. +	 * This will override the default client-side validator behaviour. +	 * @param string javascript code for client-side OnError event. +	 */ +	public function setOnValidationError($javascript) +	{ +		$this->setFunction('OnValidationError', $javascript); +	} + +	/** +	 * @return string javascript code for client-side OnError event. +	 */ +	public function getOnValidationError() +	{ +		return $this->getOption('OnValidationError'); +	} + +	/** +	 * @param boolean true to revalidate when the control to validate changes value. +	 */ +	public function setObserveChanges($value) +	{ +		$this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value)); +	} + +	/** +	 * @return boolean true to observe changes. +	 */ +	public function getObserveChanges() +	{ +		$changes = $this->getOption('ObserveChanges'); +		return ($changes===null) ? true : $changes; +	} +} + + +/** + * TValidatorDisplayStyle class. + * TValidatorDisplayStyle defines the enumerable type for the possible styles + * that a validator control can display the error message. + * + * The following enumerable values are defined: + * - None: the error message is not displayed + * - Dynamic: the error message dynamically appears when the validator fails validation + * - Fixed: Similar to Dynamic except that the error message physically occupies the page layout (even though it may not be visible) + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TValidatorDisplayStyle extends TEnumerable +{ +	const None='None'; +	const Dynamic='Dynamic'; +	const Fixed='Fixed'; +} + +/** + * TValidationDataType class. + * TValidationDataType defines the enumerable type for the possible data types that + * a comparison validator can validate upon. + * + * The following enumerable values are defined: + * - Integer + * - Float + * - Date + * - String + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TValidationDataType extends TEnumerable +{ +	const Integer='Integer'; +	const Float='Float'; +	const Date='Date'; +	const String='String'; +} + diff --git a/framework/Web/UI/WebControls/TClientScript.php b/framework/Web/UI/WebControls/TClientScript.php index 9e2f247d..6eba3d57 100644 --- a/framework/Web/UI/WebControls/TClientScript.php +++ b/framework/Web/UI/WebControls/TClientScript.php @@ -1,131 +1,157 @@ -<?php
 -/**
 - * TClientScript class file
 - *
 - * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 - * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2011 PradoSoft
 - * @license http://www.pradosoft.com/license/
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - */
 -
 -/**
 - * TClientScript class
 - *
 - * Allows importing of Prado Client Scripts from template via the
 - * {@link setPradoScripts PradoScripts} property. Multiple Prado
 - * client-scripts can be specified using comma delimited string of the
 - * javascript library to include on the page. For example,
 - *
 - * <code>
 - * <com:TClientScript PradoScripts="effects, rico" />
 - * </code>
 - *
 - * Custom javascript files can be register using the {@link setScriptUrl ScriptUrl}
 - * property.
 - * <code>
 - * <com:TClientScript ScriptUrl=<%~ test.js %> />
 - * </code>
 - *
 - * Contents within TClientScript will be treated as javascript code and will be
 - * rendered in place.
 - *
 - * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.0
 - */
 -class TClientScript extends TControl
 -{
 -	/**
 -	 * @return string comma delimited list of javascript libraries to included
 -	 * on the page.
 -	 */
 -	public function getPradoScripts()
 -	{
 -		return $this->getViewState('PradoScripts', '');
 -	}
 -
 -	/**
 -	 * Include javascript library to the current page. The current supported
 -	 * libraries are: "prado", "effects", "ajax", "validator", "logger",
 -	 * "datepicker", "colorpicker". Library dependencies are automatically resolved.
 -	 *
 -	 * @param string comma delimited list of javascript libraries to include.
 -	 */
 -	public function setPradoScripts($value)
 -	{
 -		$this->setViewState('PradoScripts', $value, '');
 -	}
 -
 -	/**
 -	 * @return string custom javascript file url.
 -	 */
 -	public function getScriptUrl()
 -	{
 -		return $this->getViewState('ScriptUrl', '');
 -	}
 -
 -	/**
 -	 * @param string custom javascript file url.
 -	 */
 -	public function setScriptUrl($value)
 -	{
 -		$this->setViewState('ScriptUrl', $value, '');
 -	}
 -
 -	/**
 -	 * Calls the client script manager to add each of the requested client
 -	 * script libraries.
 -	 * @param mixed event parameter
 -	 */
 -	public function onPreRender($param)
 -	{
 -		parent::onPreRender($param);
 -		$scripts = preg_split('/,|\s+/', $this->getPradoScripts());
 -		$cs = $this->getPage()->getClientScript();
 -		foreach($scripts as $script)
 -		{
 -			if(($script = trim($script))!=='')
 -				$cs->registerPradoScript($script);
 -		}
 -	}
 -
 -	/**
 -	 * Renders the body content as javascript block.
 -	 * Overrides parent implementation, parent renderChildren method is called during
 -	 * {@link registerCustomScript}.
 -	 * @param THtmlWriter the renderer
 -	 */
 -	public function render($writer)
 -	{
 -		$this->renderCustomScriptFile($writer);
 -		$this->renderCustomScript($writer);
 -	}
 -
 -	/**
 -	 * Renders the custom script file.
 -	 * @param THtmLWriter the renderer
 -	 */
 -	protected function renderCustomScriptFile($writer)
 -	{
 -		if(($scriptUrl = $this->getScriptUrl())!=='')
 -			$writer->write("<script type=\"text/javascript\" src=\"$scriptUrl\"></script>\n");
 -	}
 -
 -	/**
 -	 * Registers the body content as javascript.
 -	 * @param THtmlWriter the renderer
 -	 */
 -	protected function renderCustomScript($writer)
 -	{
 -		if($this->getHasControls())
 -		{
 -			$writer->write("<script type=\"text/javascript\">\n/*<![CDATA[*/\n");
 -			$this->renderChildren($writer);
 -			$writer->write("\n/*]]>*/\n</script>\n");
 -		}
 -	}
 -}
 -
 +<?php +/** + * TClientScript class file + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2011 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TClientScript class + * + * Allows importing of Prado Client Scripts from template via the + * {@link setPradoScripts PradoScripts} property. Multiple Prado + * client-scripts can be specified using comma delimited string of the + * javascript library to include on the page. For example, + * + * <code> + * <com:TClientScript PradoScripts="effects, rico" /> + * </code> + * + * Custom javascript files can be register using the {@link setScriptUrl ScriptUrl} + * property. + * <code> + * <com:TClientScript ScriptUrl=<%~ test.js %> /> + * </code> + * + * Contents within TClientScript will be treated as javascript code and will be + * rendered in place. + * + * Since Prado 3.2 the property {@link setFlushScriptFiles FlushScriptFiles} controls + * whether Prado will flush the script files defined in the page before rendering the + * TClientScript contents. + * If you're not using any external functions in your TClientScript block, you should + * set the {@link setFlushScriptFiles FlushScriptFiles} property to false, so Prado + * can postpone the loading of all the referenced script files further down the page + * generation cycle. + *  + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TClientScript extends TControl +{ +	/** +	 * @return string comma delimited list of javascript libraries to included +	 * on the page. +	 */ +	public function getPradoScripts() +	{ +		return $this->getViewState('PradoScripts', ''); +	} + +	/** +	 * Include javascript library to the current page. The current supported +	 * libraries are: "prado", "effects", "ajax", "validator", "logger", +	 * "datepicker", "colorpicker". Library dependencies are automatically resolved. +	 * +	 * @param string comma delimited list of javascript libraries to include. +	 */ +	public function setPradoScripts($value) +	{ +		$this->setViewState('PradoScripts', $value, ''); +	} + +	/** +	 * @return string custom javascript file url. +	 */ +	public function getScriptUrl() +	{ +		return $this->getViewState('ScriptUrl', ''); +	} + +	/** +	 * @param string custom javascript file url. +	 */ +	public function setScriptUrl($value) +	{ +		$this->setViewState('ScriptUrl', $value, ''); +	} + +	/** +	 * @return bool whether to flush script files using TClientScriptManager::flushScriptFiles() before rendering the script block +	 */ +	public function getFlushScriptFiles() +	{ +		return TPropertyValue::ensureBoolean($this->getViewState('FlushScriptFiles', true)); +	} + +	/** +	 * @param bool whether to flush script files using TClientScriptManager::flushScriptFiles() before rendering the script block +	 */ +	public function setFlushScriptFiles($value) +	{ +		$this->setViewState('FlushScriptFiles', TPropertyValue::ensureBoolean($value)); +	} + +	/** +	 * Calls the client script manager to add each of the requested client +	 * script libraries. +	 * @param mixed event parameter +	 */ +	public function onPreRender($param) +	{ +		parent::onPreRender($param); +		$scripts = preg_split('/,|\s+/', $this->getPradoScripts()); +		$cs = $this->getPage()->getClientScript(); +		foreach($scripts as $script) +		{ +			if(($script = trim($script))!=='') +				$cs->registerPradoScript($script); +		} +	} + +	/** +	 * Renders the body content as javascript block. +	 * Overrides parent implementation, parent renderChildren method is called during +	 * {@link registerCustomScript}. +	 * @param THtmlWriter the renderer +	 */ +	public function render($writer) +	{ +		if ($this->getFlushScriptFiles()) +			$this->getPage()->getClientScript()->flushScriptFiles($writer); +		$this->renderCustomScriptFile($writer); +		$this->renderCustomScript($writer); +	} + +	/** +	 * Renders the custom script file. +	 * @param THtmLWriter the renderer +	 */ +	protected function renderCustomScriptFile($writer) +	{ +		if(($scriptUrl = $this->getScriptUrl())!=='') +			$writer->write("<script type=\"text/javascript\" src=\"$scriptUrl\"></script>\n"); +	} + +	/** +	 * Registers the body content as javascript. +	 * @param THtmlWriter the renderer +	 */ +	protected function renderCustomScript($writer) +	{ +		if($this->getHasControls()) +		{ +			$writer->write("<script type=\"text/javascript\">\n/*<![CDATA[*/\n"); +			$this->renderChildren($writer); +			$writer->write("\n/*]]>*/\n</script>\n"); +		} +	} +} + diff --git a/framework/Web/UI/WebControls/THtmlArea.php b/framework/Web/UI/WebControls/THtmlArea.php index f2caa303..7844a131 100644 --- a/framework/Web/UI/WebControls/THtmlArea.php +++ b/framework/Web/UI/WebControls/THtmlArea.php @@ -1,546 +1,535 @@ -<?php
 -/**
 - * THtmlArea class file.
 - *
 - * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 - * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2011 PradoSoft
 - * @license http://www.pradosoft.com/license/
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - */
 -
 -/**
 - * Includes TTextBox class
 - */
 -Prado::using('System.Web.UI.WebControls.TTextBox');
 -
 -/**
 - * THtmlArea class
 - *
 - * THtmlArea wraps the visual editting functionalities provided by the
 - * TinyMCE project {@link http://tinymce.moxiecode.com/}.
 - *
 - * THtmlArea displays a WYSIWYG text area on the Web page for user input
 - * in the HTML format. The text displayed in the THtmlArea component is
 - * specified or determined by using the <b>Text</b> property.
 - *
 - * To enable the visual editting on the client side, set the property
 - * <b>EnableVisualEdit</b> to true (which is default value).
 - * To set the size of the editor when the visual editting is enabled,
 - * set the <b>Width</b> and <b>Height</b> properties instead of
 - * <b>Columns</b> and <b>Rows</b> because the latter has no meaning
 - * under the situation.
 - *
 - * The default editor gives only the basic tool bar. To change or add
 - * additional tool bars, use the {@link setOptions Options} property to add additional
 - * editor options with each options on a new line.
 - * See http://tinymce.moxiecode.com/tinymce/docs/index.html
 - * for a list of options. The options can be change/added as shown in the
 - * following example.
 - * <code>
 - * <com:THtmlArea>
 - *      <prop:Options>
 - *           plugins : "contextmenu,paste"
 - *           language : "zh_cn"
 - *      </prop:Options>
 - * </com:THtmlArea>
 - * </code>
 - *
 - * Compatibility
 - * The client-side visual editting capability is supported by
 - * Internet Explorer 5.0+ for Windows and Gecko-based browser.
 - * If the browser does not support the visual editting,
 - * a traditional textarea will be displayed.
 - *
 - * Browser support
 - *
 - * <code>
 - *                    Windows XP        MacOS X 10.4
 - * ----------------------------------------------------
 - * MSIE 6                  OK
 - * MSIE 5.5 SP2            OK
 - * MSIE 5.0                OK
 - * Mozilla 1.7.x           OK              OK
 - * Firefox 1.0.x           OK              OK
 - * Firefox 1.5b2           OK              OK
 - * Safari 2.0 (412)                        OK(1)
 - * Opera 9 Preview 1       OK(1)           OK(1)
 - * ----------------------------------------------------
 - *    * (1) - Partialy working
 - * ----------------------------------------------------
 - * </code>
 - *
 - * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.0
 - */
 -class THtmlArea extends TTextBox
 -{
 -	/**
 -	 * @var array list of locale => language file pairs.
 -	 */
 -	private static $_langs = array(
 -			'ar' => 'ar',
 -			'az' => 'az',
 -			'be' => 'be',
 -			'bg' => 'bg',
 -			'bn' => 'bn',
 -			'br' => 'br',
 -			'bs' => 'bs',
 -			'ca' => 'ca',
 -			'ch' => 'ch',
 -			'cn' => 'cn',
 -			'cs' => 'cs',
 -			'cy' => 'cy',
 -			'da' => 'da',
 -			'de' => 'de',
 -			'dv' => 'dv',
 -			'el' => 'el',
 -			'en' => 'en',
 -			'eo' => 'eo',
 -			'es' => 'es',
 -			'et' => 'et',
 -			'eu' => 'eu',
 -			'fa' => 'fa',
 -			'fi' => 'fi',
 -			'fr' => 'fr',
 -			'gl' => 'gl',
 -			'gu' => 'gu',
 -			'he' => 'he',
 -			'hi' => 'hi',
 -			'hr' => 'hr',
 -			'hu' => 'hu',
 -			'hy' => 'hy',
 -			'ia' => 'ia',
 -			'id' => 'id',
 -			'is' => 'is',
 -			'it' => 'it',
 -			'ja' => 'ja',
 -			'ka' => 'ka',
 -			'kl' => 'kl',
 -			'km' => 'km',
 -			'ko' => 'ko',
 -			'lb' => 'lb',
 -			'lt' => 'lt',
 -			'lv' => 'lv',
 -			'mk' => 'mk',
 -			'ml' => 'ml',
 -			'mn' => 'mn',
 -			'ms' => 'ms',
 -			'my' => 'my',
 -			'nb' => 'nb',
 -			'nl' => 'nl',
 -			'nn' => 'nn',
 -			'no' => 'no',
 -			'pl' => 'pl',
 -			'ps' => 'ps',
 -			'pt' => 'pt',
 -			'ro' => 'ro',
 -			'ru' => 'ru',
 -			'sc' => 'sc',
 -			'se' => 'se',
 -			'si' => 'si',
 -			'sk' => 'sk',
 -			'sl' => 'sl',
 -			'sq' => 'sq',
 -			'sr' => 'sr',
 -			'sv' => 'sv',
 -			'ta' => 'ta',
 -			'te' => 'te',
 -			'th' => 'th',
 -			'tn' => 'tn',
 -			'tr' => 'tr',
 -			'tt' => 'tt',
 -			'tw' => 'tw',
 -			'uk' => 'vi',
 -			'ur' => 'vi',
 -			'vi' => 'vi',
 -			'zh_CN' => 'zh-cn',
 -			'zh_TW' => 'zh-tw',
 -			'zh' => 'zh',
 -			'zu' => 'zu',
 -		);
 -
 -	/**
 -	 * @var array list of default plugins to load, override using getAvailablePlugins();
 -	 */
 -	private static $_plugins = array(
 -		'advhr',
 -		'advimage',
 -		'advlink',
 -		'advlist',
 -		'autolink',
 -		'autoresize',
 -		'autosave',
 -		'bbcode',
 -		'contextmenu',
 -		'directionality',
 -		'emotions',
 -		'example',
 -		'fullpage',
 -		'fullscreen',
 -		'iespell',
 -		'inlinepopups',
 -		'insertdatetime',
 -		'layer',
 -		'legacyoutput',
 -		'lists',
 -		'media',
 -		'nonbreaking',
 -		'noneditable',
 -		'pagebreak',
 -		'paste',
 -		'preview',
 -		'print',
 -		'save',
 -		'searchreplace',
 -		'spellchecker',
 -		'style',
 -		'tabfocus',
 -		'table',
 -		'template',
 -		'visualchars',
 -		'wordc',
 -		'wordcount',
 -		'xhtmlxtras'
 -	);
 -
 -	/**
 -	 * @var array default themes to load
 -	 */
 -	private static $_themes = array(
 -		'simple',
 -		'advanced'
 -	);
 -
 -	/**
 -	 * Constructor.
 -	 * Sets default width and height.
 -	 */
 -	public function __construct()
 -	{
 -		$this->setWidth('470px');
 -		$this->setHeight('250px');
 -	}
 -
 -	/**
 -	 * Overrides the parent implementation.
 -	 * TextMode for THtmlArea control is always 'MultiLine'
 -	 * @return string the behavior mode of the THtmlArea component.
 -	 */
 -	public function getTextMode()
 -	{
 -		return 'MultiLine';
 -	}
 -
 -	/**
 -	 * Overrides the parent implementation.
 -	 * TextMode for THtmlArea is always 'MultiLine' and cannot be changed to others.
 -	 * @param string the text mode
 -	 */
 -	public function setTextMode($value)
 -	{
 -		throw new TInvalidOperationException("htmlarea_textmode_readonly");
 -	}
 -
 -	/**
 -	 * @return boolean whether change of the content should cause postback. Return false if EnableVisualEdit is true.
 -	 */
 -	public function getAutoPostBack()
 -	{
 -		return $this->getEnableVisualEdit() ? false : parent::getAutoPostBack();
 -	}
 -
 -	/**
 -	 * @return boolean whether to show WYSIWYG text editor. Defaults to true.
 -	 */
 -	public function getEnableVisualEdit()
 -	{
 -		return $this->getViewState('EnableVisualEdit',true);
 -	}
 -
 -	/**
 -	 * Sets whether to show WYSIWYG text editor.
 -	 * @param boolean whether to show WYSIWYG text editor
 -	 */
 -	public function setEnableVisualEdit($value)
 -	{
 -		$this->setViewState('EnableVisualEdit',TPropertyValue::ensureBoolean($value),true);
 -	}
 -
 -	/**
 -	 * Gets the current culture.
 -	 * @return string current culture, e.g. en_AU.
 -	 */
 -	public function getCulture()
 -	{
 -		return $this->getViewState('Culture', '');
 -	}
 -
 -	/**
 -	 * Sets the culture/language for the html area
 -	 * @param string a culture string, e.g. en_AU.
 -	 */
 -	public function setCulture($value)
 -	{
 -		$this->setViewState('Culture', $value, '');
 -	}
 -
 -	/**
 -	 * Gets the list of options for the WYSIWYG (TinyMCE) editor
 -	 * @see http://tinymce.moxiecode.com/tinymce/docs/index.html
 -	 * @return string options
 -	 */
 -	public function getOptions()
 -	{
 -		return $this->getViewState('Options', '');
 -	}
 -
 -	/**
 -	 * Sets the list of options for the WYSIWYG (TinyMCE) editor
 -	 * @see http://tinymce.moxiecode.com/tinymce/docs/index.html
 -	 * @param string options
 -	 */
 -	public function setOptions($value)
 -	{
 -		$this->setViewState('Options', $value, '');
 -	}
 -
 -	/**
 -	 * @param string path to custom plugins to be copied.
 -	 */
 -	public function setCustomPluginPath($value)
 -	{
 -		$this->setViewState('CustomPluginPath', $value);
 -	}
 -
 -	/**
 -	 * @return string path to custom plugins to be copied.
 -	 */
 -	public function getCustomPluginPath()
 -	{
 -		return $this->getViewState('CustomPluginPath');
 -	}
 -
 -	/**
 -	 * @return boolean enable compression of the javascript files, default is true.
 -	 */
 -	public function getEnableCompression()
 -	{
 -		return $this->getViewState('EnableCompression', true);
 -	}
 -
 -	/**
 -	 * @param boolean enable compression of the javascript files, default is true.
 -	 */
 -	public function setEnableCompression($value)
 -	{
 -		$this->setViewState('EnableCompression', TPropertyValue::ensureBoolean($value));
 -	}
 -
 -	/**
 -	 * Registers clientscripts
 -	 *
 -	 * This method overrides the parent implementation and is invoked before render.
 -	 * @param mixed event parameter
 -	 */
 -	public function onPreRender($param)
 -	{
 -		parent::onPreRender($param);
 -		$this->loadJavascriptLibrary();
 -	}
 -
 -	/**
 -	 * Adds attribute name-value pairs to renderer.
 -	 * This method overrides the parent implementation by registering
 -	 * additional javacript code.
 -	 * @param THtmlWriter the writer used for the rendering purpose
 -	 */
 -	protected function addAttributesToRender($writer)
 -	{
 -		if($this->getEnableVisualEdit() && $this->getEnabled(true))
 -		{
 -			$writer->addAttribute('id',$this->getClientID());
 -			$this->registerEditorClientScript($writer);
 -		}
 -
 -		parent::addAttributesToRender($writer);
 -	}
 -
 -	/**
 -	 * Returns a list of plugins to be loaded.
 -	 * Override this method to customize.
 -	 * @return array list of plugins to be loaded
 -	 */
 -	public function getAvailablePlugins()
 -	{
 -		return self::$_plugins;
 -	}
 -
 -	/**
 -	 * @return array list of available themese
 -	 */
 -	public function getAvailableThemes()
 -	{
 -		return self::$_themes;
 -	}
 -
 -	protected function getCompressionOptions()
 -	{
 -		return array(
 -			'plugins' => implode(',', $this->getAvailablePlugins()),
 -			'themes' => implode(',', $this->getAvailableThemes()),
 -			'languages' => $this->getLanguageSuffix($this->getCulture()),
 -			'disk_cache' => true,
 -			'debug' => false
 -		);
 -	}
 -
 -	protected function loadJavascriptLibrary()
 -	{
 -		$scripts = $this->getPage()->getClientScript();
 -		$scripts->registerPradoScript('htmlarea');
 -		$scripts->registerScriptFile('prado:THtmlArea', $this->getScriptUrl());
 -	}
 -
 -	/**
 -	 * Registers the editor javascript file and code to initialize the editor.
 -	 */
 -	protected function registerEditorClientScript($writer)
 -	{
 -		$scripts = $this->getPage()->getClientScript();
 -		$options = array(
 -			'EditorOptions' => $this->getEditorOptions()
 -		);
 -		if($this->getEnableCompression())
 -			$options['CompressionOptions'] = $this->getCompressionOptions();
 -
 -		$options = TJavaScript::encode($options,true,true);
 -		$script = "new Prado.WebUI.THtmlArea($options)";
 -		$scripts->registerEndScript('prado:THtmlArea'.$this->ClientID,$script);
 -	}
 -
 -	/**
 -	 * @return string editor script URL.
 -	 */
 -	protected function getScriptUrl()
 -	{
 -		if($this->getEnableCompression())
 -			return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce_gzip.js';
 -		else
 -			return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce.js';
 -	}
 -
 -	/**
 -	 * Gets the editor script base URL by publishing the tarred source via TTarAssetManager.
 -	 * @return string URL base path to the published editor script
 -	 */
 -	protected function getScriptDeploymentPath()
 -	{
 -		$tarfile = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.tar');
 -		$md5sum = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.md5');
 -		if($tarfile===null || $md5sum===null)
 -			throw new TConfigurationException('htmlarea_tarfile_invalid');
 -		$url = $this->getApplication()->getAssetManager()->publishTarFile($tarfile, $md5sum);
 -		$this->copyCustomPlugins($url);
 -		return $url;
 -	}
 -
 -	protected function copyCustomPlugins($url)
 -	{
 -		if($plugins = $this->getCustomPluginPath())
 -		{
 -			$assets = $this->getApplication()->getAssetManager();
 -			$path = is_dir($plugins) ? $plugins : Prado::getPathOfNameSpace($plugins);
 -			$dest = $assets->getBasePath().'/'.basename($url).'/tiny_mce/plugins/';
 -			if(!is_dir($dest) || $this->getApplication()->getMode()!==TApplicationMode::Performance)
 -				$assets->copyDirectory($path, $dest);
 -		}
 -	}
 -
 -	/**
 -	 * Default editor options gives basic tool bar only.
 -	 * @return array editor initialization options.
 -	 */
 -	protected function getEditorOptions()
 -	{
 -		$options['mode'] = 'exact';
 -		$options['elements'] = $this->getClientID();
 -		$options['language'] = $this->getLanguageSuffix($this->getCulture());
 -		$options['theme'] = 'advanced';
 -
 -		//make it basic advanced to fit into 1 line of buttons.
 -		//$options['theme_advanced_buttons1'] = 'bold,italic,underline,strikethrough,separator,justifyleft,justifycenter,justifyright, justifyfull,separator,bullist,numlist,separator,undo,redo,separator,link,unlink,separator,charmap,separator,code,help';
 -		//$options['theme_advanced_buttons2'] = ' ';
 -		$options['theme_advanced_buttons1'] = 'formatselect,fontselect,fontsizeselect,separator,bold,italic,underline,strikethrough,sub,sup';
 -		$options['theme_advanced_buttons2'] = 'justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,outdent,indent,separator,forecolor,backcolor,separator,hr,link,unlink,image,charmap,separator,removeformat,code,help';
 -		$options['theme_advanced_buttons3'] = '';
 -
 -		$options['theme_advanced_toolbar_location'] = 'top';
 -		$options['theme_advanced_toolbar_align'] = 'left';
 -		$options['theme_advanced_path_location'] = 'bottom';
 -		$options['extended_valid_elements'] = 'a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]';
 -
 -		$options = array_merge($options, $this->parseEditorOptions($this->getOptions()));
 -		return $options;
 -	}
 -
 -	/**
 -	 * Parse additional options set in the Options property.
 -	 * @return array additional custom options
 -	 */
 -	protected function parseEditorOptions($string)
 -	{
 -		$options = array();
 -		$substrings = preg_split('/,\s*\n|\n/', trim($string));
 -		foreach($substrings as $bits)
 -		{
 -			$option = explode(":",$bits,2);
 -
 -			if(count($option) == 2)
 -			{
 -				$value=trim(trim($option[1]),"'\"");
 -				if (($s=strtolower($value))==='false') 
 -					$value=false;
 -				elseif ($s==='true')
 -					$value=true;
 -				$options[trim($option[0])] = $value;
 -			}
 -		}
 -		return $options;
 -	}
 -
 -	/**
 -	 * @return string localized editor interface language extension.
 -	 */
 -	protected function getLanguageSuffix($culture)
 -	{
 -		$app = $this->getApplication()->getGlobalization();
 -		if(empty($culture) && ($app!==null))
 -			$culture = $app->getCulture();
 -		$variants = array();
 -		if($app!==null)
 -			$variants = $app->getCultureVariants($culture);
 -
 -		foreach($variants as $variant)
 -		{
 -			if(isset(self::$_langs[$variant]))
 -				return self::$_langs[$variant];
 -		}
 -
 -		return 'en';
 -	}
 -
 -	/**
 -	 * Gets the name of the javascript class responsible for performing postback for this control.
 -	 * This method overrides the parent implementation.
 -	 * @return string the javascript class name
 -	 */
 -	protected function getClientClassName()
 -	{
 -		return 'Prado.WebUI.THtmlArea';
 -	}
 -}
 -
 +<?php +/** + * THtmlArea class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2011 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TTextBox class + */ +Prado::using('System.Web.UI.WebControls.TTextBox'); + +/** + * THtmlArea class + * + * THtmlArea wraps the visual editting functionalities provided by the + * TinyMCE project {@link http://tinymce.moxiecode.com/}. + * + * THtmlArea displays a WYSIWYG text area on the Web page for user input + * in the HTML format. The text displayed in the THtmlArea component is + * specified or determined by using the <b>Text</b> property. + * + * To enable the visual editting on the client side, set the property + * <b>EnableVisualEdit</b> to true (which is default value). + * To set the size of the editor when the visual editting is enabled, + * set the <b>Width</b> and <b>Height</b> properties instead of + * <b>Columns</b> and <b>Rows</b> because the latter has no meaning + * under the situation. + * + * The default editor gives only the basic tool bar. To change or add + * additional tool bars, use the {@link setOptions Options} property to add additional + * editor options with each options on a new line. + * See http://tinymce.moxiecode.com/tinymce/docs/index.html + * for a list of options. The options can be change/added as shown in the + * following example. + * <code> + * <com:THtmlArea> + *      <prop:Options> + *           plugins : "contextmenu,paste" + *           language : "zh_cn" + *      </prop:Options> + * </com:THtmlArea> + * </code> + * + * Compatibility + * The client-side visual editting capability is supported by + * Internet Explorer 5.0+ for Windows and Gecko-based browser. + * If the browser does not support the visual editting, + * a traditional textarea will be displayed. + * + * Browser support + * + * <code> + *                    Windows XP        MacOS X 10.4 + * ---------------------------------------------------- + * MSIE 6                  OK + * MSIE 5.5 SP2            OK + * MSIE 5.0                OK + * Mozilla 1.7.x           OK              OK + * Firefox 1.0.x           OK              OK + * Firefox 1.5b2           OK              OK + * Safari 2.0 (412)                        OK(1) + * Opera 9 Preview 1       OK(1)           OK(1) + * ---------------------------------------------------- + *    * (1) - Partialy working + * ---------------------------------------------------- + * </code> + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class THtmlArea extends TTextBox +{ +	/** +	 * @var array list of locale => language file pairs. +	 */ +	private static $_langs = array( +			'ar' => 'ar', +			'az' => 'az', +			'be' => 'be', +			'bg' => 'bg', +			'bn' => 'bn', +			'br' => 'br', +			'bs' => 'bs', +			'ca' => 'ca', +			'ch' => 'ch', +			'cn' => 'cn', +			'cs' => 'cs', +			'cy' => 'cy', +			'da' => 'da', +			'de' => 'de', +			'dv' => 'dv', +			'el' => 'el', +			'en' => 'en', +			'eo' => 'eo', +			'es' => 'es', +			'et' => 'et', +			'eu' => 'eu', +			'fa' => 'fa', +			'fi' => 'fi', +			'fr' => 'fr', +			'gl' => 'gl', +			'gu' => 'gu', +			'he' => 'he', +			'hi' => 'hi', +			'hr' => 'hr', +			'hu' => 'hu', +			'hy' => 'hy', +			'ia' => 'ia', +			'id' => 'id', +			'is' => 'is', +			'it' => 'it', +			'ja' => 'ja', +			'ka' => 'ka', +			'kl' => 'kl', +			'km' => 'km', +			'ko' => 'ko', +			'lb' => 'lb', +			'lt' => 'lt', +			'lv' => 'lv', +			'mk' => 'mk', +			'ml' => 'ml', +			'mn' => 'mn', +			'ms' => 'ms', +			'my' => 'my', +			'nb' => 'nb', +			'nl' => 'nl', +			'nn' => 'nn', +			'no' => 'no', +			'pl' => 'pl', +			'ps' => 'ps', +			'pt' => 'pt', +			'ro' => 'ro', +			'ru' => 'ru', +			'sc' => 'sc', +			'se' => 'se', +			'si' => 'si', +			'sk' => 'sk', +			'sl' => 'sl', +			'sq' => 'sq', +			'sr' => 'sr', +			'sv' => 'sv', +			'ta' => 'ta', +			'te' => 'te', +			'th' => 'th', +			'tn' => 'tn', +			'tr' => 'tr', +			'tt' => 'tt', +			'tw' => 'tw', +			'uk' => 'vi', +			'ur' => 'vi', +			'vi' => 'vi', +			'zh_CN' => 'zh-cn', +			'zh_TW' => 'zh-tw', +			'zh' => 'zh', +			'zu' => 'zu', +		); + +	/** +	 * @var array list of default plugins to load, override using getAvailablePlugins(); +	 */ +	private static $_plugins = array( +		'advhr', +		'advimage', +		'advlink', +		'advlist', +		'autolink', +		'autoresize', +		'autosave', +		'bbcode', +		'contextmenu', +		'directionality', +		'emotions', +		'example', +		'fullpage', +		'fullscreen', +		'iespell', +		'inlinepopups', +		'insertdatetime', +		'layer', +		'legacyoutput', +		'lists', +		'media', +		'nonbreaking', +		'noneditable', +		'pagebreak', +		'paste', +		'preview', +		'print', +		'save', +		'searchreplace', +		'spellchecker', +		'style', +		'tabfocus', +		'table', +		'template', +		'visualchars', +		'wordc', +		'wordcount', +		'xhtmlxtras' +	); + +	/** +	 * @var array default themes to load +	 */ +	private static $_themes = array( +		'simple', +		'advanced' +	); + +	/** +	 * Constructor. +	 * Sets default width and height. +	 */ +	public function __construct() +	{ +		$this->setWidth('470px'); +		$this->setHeight('250px'); +	} + +	/** +	 * Overrides the parent implementation. +	 * TextMode for THtmlArea control is always 'MultiLine' +	 * @return string the behavior mode of the THtmlArea component. +	 */ +	public function getTextMode() +	{ +		return 'MultiLine'; +	} + +	/** +	 * Overrides the parent implementation. +	 * TextMode for THtmlArea is always 'MultiLine' and cannot be changed to others. +	 * @param string the text mode +	 */ +	public function setTextMode($value) +	{ +		throw new TInvalidOperationException("htmlarea_textmode_readonly"); +	} + +	/** +	 * @return boolean whether change of the content should cause postback. Return false if EnableVisualEdit is true. +	 */ +	public function getAutoPostBack() +	{ +		return $this->getEnableVisualEdit() ? false : parent::getAutoPostBack(); +	} + +	/** +	 * @return boolean whether to show WYSIWYG text editor. Defaults to true. +	 */ +	public function getEnableVisualEdit() +	{ +		return $this->getViewState('EnableVisualEdit',true); +	} + +	/** +	 * Sets whether to show WYSIWYG text editor. +	 * @param boolean whether to show WYSIWYG text editor +	 */ +	public function setEnableVisualEdit($value) +	{ +		$this->setViewState('EnableVisualEdit',TPropertyValue::ensureBoolean($value),true); +	} + +	/** +	 * Gets the current culture. +	 * @return string current culture, e.g. en_AU. +	 */ +	public function getCulture() +	{ +		return $this->getViewState('Culture', ''); +	} + +	/** +	 * Sets the culture/language for the html area +	 * @param string a culture string, e.g. en_AU. +	 */ +	public function setCulture($value) +	{ +		$this->setViewState('Culture', $value, ''); +	} + +	/** +	 * Gets the list of options for the WYSIWYG (TinyMCE) editor +	 * @see http://tinymce.moxiecode.com/tinymce/docs/index.html +	 * @return string options +	 */ +	public function getOptions() +	{ +		return $this->getViewState('Options', ''); +	} + +	/** +	 * Sets the list of options for the WYSIWYG (TinyMCE) editor +	 * @see http://tinymce.moxiecode.com/tinymce/docs/index.html +	 * @param string options +	 */ +	public function setOptions($value) +	{ +		$this->setViewState('Options', $value, ''); +	} + +	/** +	 * @param string path to custom plugins to be copied. +	 */ +	public function setCustomPluginPath($value) +	{ +		$this->setViewState('CustomPluginPath', $value); +	} + +	/** +	 * @return string path to custom plugins to be copied. +	 */ +	public function getCustomPluginPath() +	{ +		return $this->getViewState('CustomPluginPath'); +	} + +	/** +	 * @return boolean enable compression of the javascript files, default is true. +	 */ +	public function getEnableCompression() +	{ +		return $this->getViewState('EnableCompression', true); +	} + +	/** +	 * @param boolean enable compression of the javascript files, default is true. +	 */ +	public function setEnableCompression($value) +	{ +		$this->setViewState('EnableCompression', TPropertyValue::ensureBoolean($value)); +	} + +	/** +	 * Adds attribute name-value pairs to renderer. +	 * This method overrides the parent implementation by registering +	 * additional javacript code. +	 * @param THtmlWriter the writer used for the rendering purpose +	 */ +	protected function addAttributesToRender($writer) +	{ +		if($this->getEnableVisualEdit() && $this->getEnabled(true)) +		{ +			$writer->addAttribute('id',$this->getClientID()); +			$this->registerEditorClientScript($writer); +		} + +		parent::addAttributesToRender($writer); +	} + +	/** +	 * Returns a list of plugins to be loaded. +	 * Override this method to customize. +	 * @return array list of plugins to be loaded +	 */ +	public function getAvailablePlugins() +	{ +		return self::$_plugins; +	} + +	/** +	 * @return array list of available themese +	 */ +	public function getAvailableThemes() +	{ +		return self::$_themes; +	} + +	protected function getCompressionOptions() +	{ +		return array( +			'plugins' => implode(',', $this->getAvailablePlugins()), +			'themes' => implode(',', $this->getAvailableThemes()), +			'languages' => $this->getLanguageSuffix($this->getCulture()), +			'disk_cache' => true, +			'debug' => false +		); +	} + +	protected function loadJavascriptLibrary() +	{ +		$scripts = $this->getPage()->getClientScript(); +		$scripts->registerPradoScript('htmlarea'); +		$scripts->registerScriptFile('prado:THtmlArea', $this->getScriptUrl()); +	} + +	/** +	 * Registers the editor javascript file and code to initialize the editor. +	 */ +	protected function registerEditorClientScript($writer) +	{ +		$this->loadJavascriptLibrary(); +		$scripts = $this->getPage()->getClientScript(); +		$options = array( +			'EditorOptions' => $this->getEditorOptions() +		); +		if($this->getEnableCompression()) +			$options['CompressionOptions'] = $this->getCompressionOptions(); + +		$options = TJavaScript::encode($options,true,true); +		$script = "new Prado.WebUI.THtmlArea($options)"; +		$scripts->registerEndScript('prado:THtmlArea'.$this->ClientID,$script); +	} + +	/** +	 * @return string editor script URL. +	 */ +	protected function getScriptUrl() +	{ +		if($this->getEnableCompression()) +			return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce_gzip.js'; +		else +			return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce.js'; +	} + +	/** +	 * Gets the editor script base URL by publishing the tarred source via TTarAssetManager. +	 * @return string URL base path to the published editor script +	 */ +	protected function getScriptDeploymentPath() +	{ +		$tarfile = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.tar'); +		$md5sum = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.md5'); +		if($tarfile===null || $md5sum===null) +			throw new TConfigurationException('htmlarea_tarfile_invalid'); +		$url = $this->getApplication()->getAssetManager()->publishTarFile($tarfile, $md5sum); +		$this->copyCustomPlugins($url); +		return $url; +	} + +	protected function copyCustomPlugins($url) +	{ +		if($plugins = $this->getCustomPluginPath()) +		{ +			$assets = $this->getApplication()->getAssetManager(); +			$path = is_dir($plugins) ? $plugins : Prado::getPathOfNameSpace($plugins); +			$dest = $assets->getBasePath().'/'.basename($url).'/tiny_mce/plugins/'; +			if(!is_dir($dest) || $this->getApplication()->getMode()!==TApplicationMode::Performance) +				$assets->copyDirectory($path, $dest); +		} +	} + +	/** +	 * Default editor options gives basic tool bar only. +	 * @return array editor initialization options. +	 */ +	protected function getEditorOptions() +	{ +		$options['mode'] = 'exact'; +		$options['elements'] = $this->getClientID(); +		$options['language'] = $this->getLanguageSuffix($this->getCulture()); +		$options['theme'] = 'advanced'; + +		//make it basic advanced to fit into 1 line of buttons. +		//$options['theme_advanced_buttons1'] = 'bold,italic,underline,strikethrough,separator,justifyleft,justifycenter,justifyright, justifyfull,separator,bullist,numlist,separator,undo,redo,separator,link,unlink,separator,charmap,separator,code,help'; +		//$options['theme_advanced_buttons2'] = ' '; +		$options['theme_advanced_buttons1'] = 'formatselect,fontselect,fontsizeselect,separator,bold,italic,underline,strikethrough,sub,sup'; +		$options['theme_advanced_buttons2'] = 'justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,outdent,indent,separator,forecolor,backcolor,separator,hr,link,unlink,image,charmap,separator,removeformat,code,help'; +		$options['theme_advanced_buttons3'] = ''; + +		$options['theme_advanced_toolbar_location'] = 'top'; +		$options['theme_advanced_toolbar_align'] = 'left'; +		$options['theme_advanced_path_location'] = 'bottom'; +		$options['extended_valid_elements'] = 'a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]'; + +		$options = array_merge($options, $this->parseEditorOptions($this->getOptions())); +		return $options; +	} + +	/** +	 * Parse additional options set in the Options property. +	 * @return array additional custom options +	 */ +	protected function parseEditorOptions($string) +	{ +		$options = array(); +		$substrings = preg_split('/,\s*\n|\n/', trim($string)); +		foreach($substrings as $bits) +		{ +			$option = explode(":",$bits,2); + +			if(count($option) == 2) +			{ +				$value=trim(trim($option[1]),"'\""); +				if (($s=strtolower($value))==='false')  +					$value=false; +				elseif ($s==='true') +					$value=true; +				$options[trim($option[0])] = $value; +			} +		} +		return $options; +	} + +	/** +	 * @return string localized editor interface language extension. +	 */ +	protected function getLanguageSuffix($culture) +	{ +		$app = $this->getApplication()->getGlobalization(); +		if(empty($culture) && ($app!==null)) +			$culture = $app->getCulture(); +		$variants = array(); +		if($app!==null) +			$variants = $app->getCultureVariants($culture); + +		foreach($variants as $variant) +		{ +			if(isset(self::$_langs[$variant])) +				return self::$_langs[$variant]; +		} + +		return 'en'; +	} + +	/** +	 * Gets the name of the javascript class responsible for performing postback for this control. +	 * This method overrides the parent implementation. +	 * @return string the javascript class name +	 */ +	protected function getClientClassName() +	{ +		return 'Prado.WebUI.THtmlArea'; +	} +} + diff --git a/framework/Web/UI/WebControls/TTabPanel.php b/framework/Web/UI/WebControls/TTabPanel.php index fd20b949..a79835ed 100644 --- a/framework/Web/UI/WebControls/TTabPanel.php +++ b/framework/Web/UI/WebControls/TTabPanel.php @@ -1,728 +1,731 @@ -<?php
 -/**
 - * TTabPanel class file.
 - *
 - * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
 - * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2011 PradoSoft
 - * @license http://www.pradosoft.com/license/
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.1.1
 - */
 -
 -/**
 - * Class TTabPanel.
 - *
 - * TTabPanel displays a tabbed panel. Users can click on the tab bar to switching among
 - * different tab views. Each tab view is an independent panel that can contain arbitrary content.
 - *
 - * If the {@link setAutoSwitch AutoSwitch} property is enabled, the user will be able to switch the active view
 - * to another one just hovering its corresponding tab caption.
 - *
 - * A TTabPanel control consists of one or several {@link TTabView} controls representing the possible
 - * tab views. At any time, only one tab view is visible (active), which is specified by any of
 - * the following properties:
 - * - {@link setActiveViewIndex ActiveViewIndex} - the zero-based integer index of the view in the view collection.
 - * - {@link setActiveViewID ActiveViewID} - the text ID of the visible view.
 - * - {@link setActiveView ActiveView} - the visible view instance.
 - * If both {@link setActiveViewIndex ActiveViewIndex} and {@link setActiveViewID ActiveViewID}
 - * are set, the latter takes precedence.
 - *
 - * TTabPanel uses CSS to specify the appearance of the tab bar and panel. By default,
 - * an embedded CSS file will be published which contains the default CSS for TTabPanel.
 - * You may also use your own CSS file by specifying the {@link setCssUrl CssUrl} property.
 - * The following properties specify the CSS classes used for elements in a TTabPanel:
 - * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'tab-panel');
 - * - {@link setTabCssClass TabCssClass} - the CSS class name for nonactive tab div elements (defaults to 'tab-normal');
 - * - {@link setActiveTabCssClass ActiveTabCssClass} - the CSS class name for the active tab div element (defaults to 'tab-active');
 - * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'tab-view');
 - *
 - * To use TTabPanel, write a template like following:
 - * <code>
 - * <com:TTabPanel>
 - *   <com:TTabView Caption="View 1">
 - *     content for view 1
 - *   </com:TTabView>
 - *   <com:TTabView Caption="View 2">
 - *     content for view 2
 - *   </com:TTabView>
 - *   <com:TTabView Caption="View 3">
 - *     content for view 3
 - *   </com:TTabView>
 - * </com:TTabPanel>
 - * </code>
 - *
 - * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.1.1
 - */
 -class TTabPanel extends TWebControl implements IPostBackDataHandler
 -{
 -	private $_dataChanged=false;
 -
 -	/**
 -	 * @return string tag name for the control
 -	 */
 -	protected function getTagName()
 -	{
 -		return 'div';
 -	}
 -
 -	/**
 -	 * Adds object parsed from template to the control.
 -	 * This method adds only {@link TTabView} objects into the {@link getViews Views} collection.
 -	 * All other objects are ignored.
 -	 * @param mixed object parsed from template
 -	 */
 -	public function addParsedObject($object)
 -	{
 -		if($object instanceof TTabView)
 -			$this->getControls()->add($object);
 -	}
 -
 -	/**
 -     * Returns the index of the active tab view.
 -     * Note, this property may not return the correct index.
 -     * To ensure the correctness, call {@link getActiveView()} first.
 -	 * @return integer the zero-based index of the active tab view. If -1, it means no active tab view. Default is 0 (the first view is active).
 -	 */
 -	public function getActiveViewIndex()
 -	{
 -		return $this->getViewState('ActiveViewIndex',0);
 -	}
 -
 -	/**
 -	 * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
 -	 * @throws TInvalidDataValueException if the view index is invalid
 -	 */
 -	public function setActiveViewIndex($value)
 -	{
 -		$this->setViewState('ActiveViewIndex',TPropertyValue::ensureInteger($value),0);
 -	}
 -
 -    /**
 -     * Returns the ID of the active tab view.
 -     * Note, this property may not return the correct ID.
 -     * To ensure the correctness, call {@link getActiveView()} first.
 -     * @return string The ID of the active tab view. Defaults to '', meaning not set.
 -     */
 -    public function getActiveViewID()
 -    {
 -		return $this->getViewState('ActiveViewID','');
 -    }
 -
 -    /**
 -     * @param string The ID of the active tab view.
 -     */
 -    public function setActiveViewID($value)
 -    {
 -		$this->setViewState('ActiveViewID',$value,'');
 -    }
 -
 -	/**
 -	 * Returns the currently active view.
 -	 * This method will examin the ActiveViewID, ActiveViewIndex and Views collection to
 -	 * determine which view is currently active. It will update ActiveViewID and ActiveViewIndex accordingly.
 -	 * @return TTabView the currently active view, null if no active view
 -	 * @throws TInvalidDataValueException if the active view ID or index set previously is invalid
 -	 */
 -	public function getActiveView()
 -	{
 -		$activeView=null;
 -		$views=$this->getViews();
 -		if(($id=$this->getActiveViewID())!=='')
 -		{
 -			if(($index=$views->findIndexByID($id))>=0)
 -				$activeView=$views->itemAt($index);
 -			else
 -				throw new TInvalidDataValueException('tabpanel_activeviewid_invalid',$id);
 -		}
 -		else if(($index=$this->getActiveViewIndex())>=0)
 -		{
 -			if($index<$views->getCount())
 -				$activeView=$views->itemAt($index);
 -			else
 -				throw new TInvalidDataValueException('tabpanel_activeviewindex_invalid',$index);
 -		}
 -		else
 -		{
 -			foreach($views as $index=>$view)
 -			{
 -				if($view->getActive())
 -				{
 -					$activeView=$view;
 -					break;
 -				}
 -			}
 -		}
 -		if($activeView!==null)
 -			$this->activateView($activeView);
 -		return $activeView;
 -	}
 -
 -	/**
 -	 * @param TTabView the view to be activated
 -	 * @throws TInvalidOperationException if the view is not in the view collection
 -	 */
 -	public function setActiveView($view)
 -	{
 -		if($this->getViews()->indexOf($view)>=0)
 -			$this->activateView($view);
 -		else
 -			throw new TInvalidOperationException('tabpanel_view_inexistent');
 -	}
 -
 -    /**
 -     * @return bool status of automatic tab switch on hover
 -     */
 -    public function getAutoSwitch()
 -    {
 -        return TPropertyValue::ensureBoolean($this->getViewState('AutoSwitch'));
 -    }
 -
 -    /**
 -     * @param bool whether to enable automatic tab switch on hover
 -     */
 -    public function setAutoSwitch($value)
 -    {
 -        $this->setViewState('AutoSwitch',TPropertyValue::ensureBoolean($value));
 -    }
 -
 -
 -    /**
 -     * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to ''.
 -     */
 -    public function getCssUrl()
 -    {
 -        return $this->getViewState('CssUrl','default');
 -    }
 -
 -    /**
 -     * @param string URL for the CSS file including all relevant CSS class definitions.
 -     */
 -    public function setCssUrl($value)
 -    {
 -        $this->setViewState('CssUrl',TPropertyValue::ensureString($value),'');
 -    }
 -
 -    /**
 -     * @return string CSS class for the whole tab control div. Defaults to 'tab-panel'.
 -     */
 -    public function getCssClass()
 -    {
 -    	$cssClass=parent::getCssClass();
 -    	return $cssClass===''?'tab-panel':$cssClass;
 -    }
 -
 -    /**
 -     * @return string CSS class for the currently displayed view div. Defaults to 'tab-view'.
 -     */
 -    public function getViewCssClass()
 -    {
 -        return $this->getViewStyle()->getCssClass();
 -    }
 -
 -    /**
 -     * @param string CSS class for the currently displayed view div.
 -     */
 -    public function setViewCssClass($value)
 -    {
 -        $this->getViewStyle()->setCssClass($value);
 -    }
 -
 -	/**
 -	 * @return TStyle the style for all the view div
 -	 */
 -	public function getViewStyle()
 -	{
 -		if(($style=$this->getViewState('ViewStyle',null))===null)
 -		{
 -			$style=new TStyle;
 -			$style->setCssClass('tab-view');
 -			$this->setViewState('ViewStyle',$style,null);
 -		}
 -		return $style;
 -	}
 -
 -    /**
 -     * @return string CSS class for non-active tabs. Defaults to 'tab-normal'.
 -     */
 -    public function getTabCssClass()
 -    {
 -        return $this->getTabStyle()->getCssClass();
 -    }
 -
 -    /**
 -     * @param string CSS class for non-active tabs.
 -     */
 -    public function setTabCssClass($value)
 -    {
 -        $this->getTabStyle()->setCssClass($value);
 -    }
 -
 -	/**
 -	 * @return TStyle the style for all the inactive tab div
 -	 */
 -	public function getTabStyle()
 -	{
 -		if(($style=$this->getViewState('TabStyle',null))===null)
 -		{
 -			$style=new TStyle;
 -			$style->setCssClass('tab-normal');
 -			$this->setViewState('TabStyle',$style,null);
 -		}
 -		return $style;
 -	}
 -
 -    /**
 -     * @return string CSS class for the active tab. Defaults to 'tab-active'.
 -     */
 -    public function getActiveTabCssClass()
 -    {
 -        return $this->getActiveTabStyle()->getCssClass();
 -    }
 -
 -    /**
 -     * @param string CSS class for the active tab.
 -     */
 -    public function setActiveTabCssClass($value)
 -    {
 -        $this->getActiveTabStyle()->setCssClass($value);
 -    }
 -
 -	/**
 -	 * @return TStyle the style for the active tab div
 -	 */
 -	public function getActiveTabStyle()
 -	{
 -		if(($style=$this->getViewState('ActiveTabStyle',null))===null)
 -		{
 -			$style=new TStyle;
 -			$style->setCssClass('tab-active');
 -			$this->setViewState('ActiveTabStyle',$style,null);
 -		}
 -		return $style;
 -	}
 -
 -	/**
 -	 * Activates the specified view.
 -	 * If there is any other view currently active, it will be deactivated.
 -	 * @param TTabView the view to be activated. If null, all views will be deactivated.
 -	 */
 -	protected function activateView($view)
 -	{
 -		$this->setActiveViewIndex(-1);
 -		$this->setActiveViewID('');
 -		foreach($this->getViews() as $index=>$v)
 -		{
 -			if($view===$v)
 -			{
 -				$this->setActiveViewIndex($index);
 -				$this->setActiveViewID($view->getID(false));
 -				$view->setActive(true);
 -			}
 -			else
 -				$v->setActive(false);
 -		}
 -	}
 -
 -	/**
 -	 * Loads user input data.
 -	 * This method is primarly used by framework developers.
 -	 * @param string the key that can be used to retrieve data from the input data collection
 -	 * @param array the input data collection
 -	 * @return boolean whether the data of the control has been changed
 -	 */
 -	public function loadPostData($key,$values)
 -	{
 -		if(($index=$values[$this->getClientID().'_1'])!==null)
 -		{
 -			$index=(int)$index;
 -			$currentIndex=$this->getActiveViewIndex();
 -			if($currentIndex!==$index)
 -			{
 -				$this->setActiveViewID(''); // clear up view ID
 -				$this->setActiveViewIndex($index);
 -				return $this->_dataChanged=true;
 -			}
 -		}
 -		return false;
 -	}
 -
 -	/**
 -	 * Raises postdata changed event.
 -	 * This method is required by {@link IPostBackDataHandler} interface.
 -	 * It is invoked by the framework when {@link getActiveViewIndex ActiveViewIndex} property
 -	 * is changed on postback.
 -	 * This method is primarly used by framework developers.
 -	 */
 -	public function raisePostDataChangedEvent()
 -	{
 -		// do nothing
 -	}
 -
 -	/**
 -	 * Returns a value indicating whether postback has caused the control data change.
 -	 * This method is required by the IPostBackDataHandler interface.
 -	 * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
 -	 */
 -	public function getDataChanged()
 -	{
 -		return $this->_dataChanged;
 -	}
 -
 -	/**
 -	 * Adds attributes to renderer.
 -	 * @param THtmlWriter the renderer
 -	 */
 -	protected function addAttributesToRender($writer)
 -	{
 -		$writer->addAttribute('id',$this->getClientID());
 -		$this->setCssClass($this->getCssClass());
 -		parent::addAttributesToRender($writer);
 -	}
 -
 -	/**
 -	 * Registers CSS and JS.
 -	 * This method is invoked right before the control rendering, if the control is visible.
 -	 * @param mixed event parameter
 -	 */
 -	public function onPreRender($param)
 -	{
 -		parent::onPreRender($param);
 -		$this->getActiveView();  // determine the active view
 -		$this->registerStyleSheet();
 -		$this->registerClientScript();
 -	}
 -
 -	/**
 -	 * Registers the CSS relevant to the TTabControl.
 -	 * It will register the CSS file specified by {@link getCssUrl CssUrl}.
 -	 * If that is not set, it will use the default CSS.
 -	 */
 -	protected function registerStyleSheet()
 -	{
 -		$url = $this->getCssUrl();
 -		
 -		if($url === '') {
 -			return;
 -		}
 -		
 -		if($url === 'default') {
 -			$url = $this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'tabpanel.css');
 -		}
 -		
 -		if($url !== '') {
 -			$this->getPage()->getClientScript()->registerStyleSheetFile($url, $url);
 -		}
 -	}
 -
 -	/**
 -	 * Registers the relevant JavaScript.
 -	 */
 -	protected function registerClientScript()
 -	{
 -		$id=$this->getClientID();
 -		$options=TJavaScript::encode($this->getClientOptions());
 -		$className=$this->getClientClassName();
 -		$page=$this->getPage();
 -		$cs=$page->getClientScript();
 -		$cs->registerPradoScript('tabpanel');
 -		$code="new $className($options);";
 -		$cs->registerEndScript("prado:$id", $code);
 -		// ensure an item is always active and visible
 -		$index = $this->getActiveViewIndex();
 -		if(!$this->getViews()->itemAt($index)->Visible)
 -			$index=0;
 -		$cs->registerHiddenField($id.'_1', $index);
 -		$page->registerRequiresPostData($this);
 -		$page->registerRequiresPostData($id."_1");
 -	}
 -
 -	/**
 -	 * Gets the name of the javascript class responsible for performing postback for this control.
 -	 * This method overrides the parent implementation.
 -	 * @return string the javascript class name
 -	 */
 -	protected function getClientClassName()
 -	{
 -		return 'Prado.WebUI.TTabPanel';
 -	}
 -
 -	/**
 -	 * @return array the options for JavaScript
 -	 */
 -	protected function getClientOptions()
 -	{
 -		$options['ID'] = $this->getClientID();
 -		$options['ActiveCssClass'] = $this->getActiveTabCssClass();
 -		$options['NormalCssClass'] = $this->getTabCssClass();
 -		$viewIDs = array();
 -		$viewVis = array();
 -		foreach($this->getViews() as $view)
 -		{
 -			$viewIDs[] = $view->getClientID();
 -			$viewVis[] = $view->getVisible();
 -		}
 -		$options['Views'] = $viewIDs;
 -		$options['ViewsVis'] = $viewVis;
 -		$options['AutoSwitch'] = $this->getAutoSwitch();
 -
 -		return $options;
 -	}
 -
 -	/**
 -	 * Creates a control collection object that is to be used to hold child controls
 -	 * @return TTabViewCollection control collection
 -	 */
 -	protected function createControlCollection()
 -	{
 -		return new TTabViewCollection($this);
 -	}
 -
 -	/**
 -	 * @return TTabViewCollection list of {@link TTabView} controls
 -	 */
 -	public function getViews()
 -	{
 -		return $this->getControls();
 -	}
 -
 -	/**
 -	 * Renders body contents of the tab control.
 -	 * @param THtmlWriter the writer used for the rendering purpose.
 -	 */
 -	public function renderContents($writer)
 -	{
 -		$views=$this->getViews();
 -		if($views->getCount()>0)
 -		{
 -			$writer->writeLine();
 -			// render tab bar
 -			foreach($views as $view)
 -			{
 -				$view->renderTab($writer);
 -				$writer->writeLine();
 -			}
 -			// render tab views
 -			foreach($views as $view)
 -			{
 -				$view->renderControl($writer);
 -				$writer->writeLine();
 -			}
 -		}
 -	}
 -}
 -
 -/**
 - * TTabView class.
 - *
 - * TTabView represents a view in a {@link TTabPanel} control.
 - *
 - * The content in a TTabView can be specified by the {@link setText Text} property
 - * or its child controls. In template syntax, the latter means enclosing the content
 - * within the TTabView component element. If both are set, {@link getText Text} takes precedence.
 - *
 - * Each TTabView is associated with a tab in the tab bar of the TTabPanel control.
 - * The tab caption is specified by {@link setCaption Caption}. If {@link setNavigateUrl NavigateUrl}
 - * is set, the tab will contain a hyperlink pointing to the specified URL. In this case,
 - * clicking on the tab will redirect the browser to the specified URL.
 - *
 - * TTabView may be toggled between visible (active) and invisible (inactive) by
 - * setting the {@link setActive Active} property.
 - *
 - * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.1.1
 - */
 -class TTabView extends TWebControl
 -{
 -	private $_active=false;
 -
 -	/**
 -	 * @return the tag name for the view element
 -	 */
 -	protected function getTagName()
 -	{
 -		return 'div';
 -	}
 -
 -	/**
 -	 * Adds attributes to renderer.
 -	 * @param THtmlWriter the renderer
 -	 */
 -	protected function addAttributesToRender($writer)
 -	{
 -		if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript())
 -			$this->getStyle()->setStyleField('display','none');
 -
 -		$this->getStyle()->mergeWith($this->getParent()->getViewStyle());
 -
 -		parent::addAttributesToRender($writer);
 -
 -		$writer->addAttribute('id',$this->getClientID());
 -	}
 -
 -	/**
 -	 * @return string the caption displayed on this tab. Defaults to ''.
 -	 */
 -	public function getCaption()
 -	{
 -		return $this->getViewState('Caption','');
 -	}
 -
 -	/**
 -	 * @param string the caption displayed on this tab
 -	 */
 -	public function setCaption($value)
 -	{
 -		$this->setViewState('Caption',TPropertyValue::ensureString($value),'');
 -	}
 -
 -	/**
 -	 * @return string the URL of the target page. Defaults to ''.
 -	 */
 -	public function getNavigateUrl()
 -	{
 -		return $this->getViewState('NavigateUrl','');
 -	}
 -
 -	/**
 -	 * Sets the URL of the target page.
 -	 * If not empty, clicking on this tab will redirect the browser to the specified URL.
 -	 * @param string the URL of the target page.
 -	 */
 -	public function setNavigateUrl($value)
 -	{
 -		$this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),'');
 -	}
 -
 -	/**
 -	 * @return string the text content displayed on this view. Defaults to ''.
 -	 */
 -	public function getText()
 -	{
 -		return $this->getViewState('Text','');
 -	}
 -
 -	/**
 -	 * Sets the text content to be displayed on this view.
 -	 * If this is not empty, the child content of the view will be ignored.
 -	 * @param string the text content displayed on this view
 -	 */
 -	public function setText($value)
 -	{
 -		$this->setViewState('Text',TPropertyValue::ensureString($value),'');
 -	}
 -
 -	/**
 -	 * @return boolean whether this tab view is active. Defaults to false.
 -	 */
 -	public function getActive()
 -	{
 -		return $this->_active;
 -	}
 -
 -	/**
 -	 * @param boolean whether this tab view is active.
 -	 */
 -	public function setActive($value)
 -	{
 -		$this->_active=TPropertyValue::ensureBoolean($value);
 -	}
 -
 -	/**
 -	 * Renders body contents of the tab view.
 -	 * @param THtmlWriter the writer used for the rendering purpose.
 -	 */
 -	public function renderContents($writer)
 -	{
 -		if(($text=$this->getText())!=='')
 -			$writer->write($text);
 -		else if($this->getHasControls())
 -			parent::renderContents($writer);
 -	}
 -
 -	/**
 -	 * Renders the tab associated with the tab view.
 -	 * @param THtmlWriter the writer for rendering purpose.
 -	 */
 -	public function renderTab($writer)
 -	{
 -		if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript())
 -		{
 -			$writer->addAttribute('id',$this->getClientID().'_0');
 -
 -			$style=$this->getActive()?$this->getParent()->getActiveTabStyle():$this->getParent()->getTabStyle();
 -			$style->addAttributesToRender($writer);
 -
 -			$writer->renderBeginTag($this->getTagName());
 -
 -			$this->renderTabContent($writer);
 -
 -			$writer->renderEndTag();
 -		}
 -	}
 -
 -	/**
 -	 * Renders the content in the tab.
 -	 * By default, a hyperlink is displayed.
 -	 * @param THtmlWriter the HTML writer
 -	 */
 -	protected function renderTabContent($writer)
 -	{
 -		if(($url=$this->getNavigateUrl())==='')
 -			$url='javascript://';
 -		if(($caption=$this->getCaption())==='')
 -			$caption=' ';
 -		$writer->write("<a href=\"{$url}\">{$caption}</a>");
 -	}
 -}
 -
 -/**
 - * TTabViewCollection class.
 - *
 - * TTabViewCollection is used to maintain a list of views belong to a {@link TTabPanel}.
 - *
 - * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.1.1
 - */
 -class TTabViewCollection extends TControlCollection
 -{
 -	/**
 -	 * Inserts an item at the specified position.
 -	 * This overrides the parent implementation by performing sanity check on the type of new item.
 -	 * @param integer the speicified position.
 -	 * @param mixed new item
 -	 * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TTabView} object.
 -	 */
 -	public function insertAt($index,$item)
 -	{
 -		if($item instanceof TTabView)
 -			parent::insertAt($index,$item);
 -		else
 -			throw new TInvalidDataTypeException('tabviewcollection_tabview_required');
 -	}
 -
 -	/**
 -	 * Finds the index of the tab view whose ID is the same as the one being looked for.
 -	 * @param string the explicit ID of the tab view to be looked for
 -	 * @return integer the index of the tab view found, -1 if not found.
 -	 */
 -	public function findIndexByID($id)
 -	{
 -		foreach($this as $index=>$view)
 -		{
 -			if($view->getID(false)===$id)
 -				return $index;
 -		}
 -		return -1;
 -	}
 -}
 -
 -?>
 +<?php +/** + * TTabPanel class file. + * + * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2011 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ + +/** + * Class TTabPanel. + * + * TTabPanel displays a tabbed panel. Users can click on the tab bar to switching among + * different tab views. Each tab view is an independent panel that can contain arbitrary content. + * + * If the {@link setAutoSwitch AutoSwitch} property is enabled, the user will be able to switch the active view + * to another one just hovering its corresponding tab caption. + * + * A TTabPanel control consists of one or several {@link TTabView} controls representing the possible + * tab views. At any time, only one tab view is visible (active), which is specified by any of + * the following properties: + * - {@link setActiveViewIndex ActiveViewIndex} - the zero-based integer index of the view in the view collection. + * - {@link setActiveViewID ActiveViewID} - the text ID of the visible view. + * - {@link setActiveView ActiveView} - the visible view instance. + * If both {@link setActiveViewIndex ActiveViewIndex} and {@link setActiveViewID ActiveViewID} + * are set, the latter takes precedence. + * + * TTabPanel uses CSS to specify the appearance of the tab bar and panel. By default, + * an embedded CSS file will be published which contains the default CSS for TTabPanel. + * You may also use your own CSS file by specifying the {@link setCssUrl CssUrl} property. + * The following properties specify the CSS classes used for elements in a TTabPanel: + * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'tab-panel'); + * - {@link setTabCssClass TabCssClass} - the CSS class name for nonactive tab div elements (defaults to 'tab-normal'); + * - {@link setActiveTabCssClass ActiveTabCssClass} - the CSS class name for the active tab div element (defaults to 'tab-active'); + * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'tab-view'); + * + * To use TTabPanel, write a template like following: + * <code> + * <com:TTabPanel> + *   <com:TTabView Caption="View 1"> + *     content for view 1 + *   </com:TTabView> + *   <com:TTabView Caption="View 2"> + *     content for view 2 + *   </com:TTabView> + *   <com:TTabView Caption="View 3"> + *     content for view 3 + *   </com:TTabView> + * </com:TTabPanel> + * </code> + * + * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TTabPanel extends TWebControl implements IPostBackDataHandler +{ +	private $_dataChanged=false; + +	/** +	 * @return string tag name for the control +	 */ +	protected function getTagName() +	{ +		return 'div'; +	} + +	/** +	 * Adds object parsed from template to the control. +	 * This method adds only {@link TTabView} objects into the {@link getViews Views} collection. +	 * All other objects are ignored. +	 * @param mixed object parsed from template +	 */ +	public function addParsedObject($object) +	{ +		if($object instanceof TTabView) +			$this->getControls()->add($object); +	} + +	/** +     * Returns the index of the active tab view. +     * Note, this property may not return the correct index. +     * To ensure the correctness, call {@link getActiveView()} first. +	 * @return integer the zero-based index of the active tab view. If -1, it means no active tab view. Default is 0 (the first view is active). +	 */ +	public function getActiveViewIndex() +	{ +		return $this->getViewState('ActiveViewIndex',0); +	} + +	/** +	 * @param integer the zero-based index of the current view in the view collection. -1 if no active view. +	 * @throws TInvalidDataValueException if the view index is invalid +	 */ +	public function setActiveViewIndex($value) +	{ +		$this->setViewState('ActiveViewIndex',TPropertyValue::ensureInteger($value),0); +	} + +    /** +     * Returns the ID of the active tab view. +     * Note, this property may not return the correct ID. +     * To ensure the correctness, call {@link getActiveView()} first. +     * @return string The ID of the active tab view. Defaults to '', meaning not set. +     */ +    public function getActiveViewID() +    { +		return $this->getViewState('ActiveViewID',''); +    } + +    /** +     * @param string The ID of the active tab view. +     */ +    public function setActiveViewID($value) +    { +		$this->setViewState('ActiveViewID',$value,''); +    } + +	/** +	 * Returns the currently active view. +	 * This method will examin the ActiveViewID, ActiveViewIndex and Views collection to +	 * determine which view is currently active. It will update ActiveViewID and ActiveViewIndex accordingly. +	 * @return TTabView the currently active view, null if no active view +	 * @throws TInvalidDataValueException if the active view ID or index set previously is invalid +	 */ +	public function getActiveView() +	{ +		$activeView=null; +		$views=$this->getViews(); +		if(($id=$this->getActiveViewID())!=='') +		{ +			if(($index=$views->findIndexByID($id))>=0) +				$activeView=$views->itemAt($index); +			else +				throw new TInvalidDataValueException('tabpanel_activeviewid_invalid',$id); +		} +		else if(($index=$this->getActiveViewIndex())>=0) +		{ +			if($index<$views->getCount()) +				$activeView=$views->itemAt($index); +			else +				throw new TInvalidDataValueException('tabpanel_activeviewindex_invalid',$index); +		} +		else +		{ +			foreach($views as $index=>$view) +			{ +				if($view->getActive()) +				{ +					$activeView=$view; +					break; +				} +			} +		} +		if($activeView!==null) +			$this->activateView($activeView); +		return $activeView; +	} + +	/** +	 * @param TTabView the view to be activated +	 * @throws TInvalidOperationException if the view is not in the view collection +	 */ +	public function setActiveView($view) +	{ +		if($this->getViews()->indexOf($view)>=0) +			$this->activateView($view); +		else +			throw new TInvalidOperationException('tabpanel_view_inexistent'); +	} + +    /** +     * @return bool status of automatic tab switch on hover +     */ +    public function getAutoSwitch() +    { +        return TPropertyValue::ensureBoolean($this->getViewState('AutoSwitch')); +    } + +    /** +     * @param bool whether to enable automatic tab switch on hover +     */ +    public function setAutoSwitch($value) +    { +        $this->setViewState('AutoSwitch',TPropertyValue::ensureBoolean($value)); +    } + + +    /** +     * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to ''. +     */ +    public function getCssUrl() +    { +        return $this->getViewState('CssUrl','default'); +    } + +    /** +     * @param string URL for the CSS file including all relevant CSS class definitions. +     */ +    public function setCssUrl($value) +    { +        $this->setViewState('CssUrl',TPropertyValue::ensureString($value),''); +    } + +    /** +     * @return string CSS class for the whole tab control div. Defaults to 'tab-panel'. +     */ +    public function getCssClass() +    { +    	$cssClass=parent::getCssClass(); +    	return $cssClass===''?'tab-panel':$cssClass; +    } + +    /** +     * @return string CSS class for the currently displayed view div. Defaults to 'tab-view'. +     */ +    public function getViewCssClass() +    { +        return $this->getViewStyle()->getCssClass(); +    } + +    /** +     * @param string CSS class for the currently displayed view div. +     */ +    public function setViewCssClass($value) +    { +        $this->getViewStyle()->setCssClass($value); +    } + +	/** +	 * @return TStyle the style for all the view div +	 */ +	public function getViewStyle() +	{ +		if(($style=$this->getViewState('ViewStyle',null))===null) +		{ +			$style=new TStyle; +			$style->setCssClass('tab-view'); +			$this->setViewState('ViewStyle',$style,null); +		} +		return $style; +	} + +    /** +     * @return string CSS class for non-active tabs. Defaults to 'tab-normal'. +     */ +    public function getTabCssClass() +    { +        return $this->getTabStyle()->getCssClass(); +    } + +    /** +     * @param string CSS class for non-active tabs. +     */ +    public function setTabCssClass($value) +    { +        $this->getTabStyle()->setCssClass($value); +    } + +	/** +	 * @return TStyle the style for all the inactive tab div +	 */ +	public function getTabStyle() +	{ +		if(($style=$this->getViewState('TabStyle',null))===null) +		{ +			$style=new TStyle; +			$style->setCssClass('tab-normal'); +			$this->setViewState('TabStyle',$style,null); +		} +		return $style; +	} + +    /** +     * @return string CSS class for the active tab. Defaults to 'tab-active'. +     */ +    public function getActiveTabCssClass() +    { +        return $this->getActiveTabStyle()->getCssClass(); +    } + +    /** +     * @param string CSS class for the active tab. +     */ +    public function setActiveTabCssClass($value) +    { +        $this->getActiveTabStyle()->setCssClass($value); +    } + +	/** +	 * @return TStyle the style for the active tab div +	 */ +	public function getActiveTabStyle() +	{ +		if(($style=$this->getViewState('ActiveTabStyle',null))===null) +		{ +			$style=new TStyle; +			$style->setCssClass('tab-active'); +			$this->setViewState('ActiveTabStyle',$style,null); +		} +		return $style; +	} + +	/** +	 * Activates the specified view. +	 * If there is any other view currently active, it will be deactivated. +	 * @param TTabView the view to be activated. If null, all views will be deactivated. +	 */ +	protected function activateView($view) +	{ +		$this->setActiveViewIndex(-1); +		$this->setActiveViewID(''); +		foreach($this->getViews() as $index=>$v) +		{ +			if($view===$v) +			{ +				$this->setActiveViewIndex($index); +				$this->setActiveViewID($view->getID(false)); +				$view->setActive(true); +			} +			else +				$v->setActive(false); +		} +	} + +	/** +	 * Loads user input data. +	 * This method is primarly used by framework developers. +	 * @param string the key that can be used to retrieve data from the input data collection +	 * @param array the input data collection +	 * @return boolean whether the data of the control has been changed +	 */ +	public function loadPostData($key,$values) +	{ +		if(($index=$values[$this->getClientID().'_1'])!==null) +		{ +			$index=(int)$index; +			$currentIndex=$this->getActiveViewIndex(); +			if($currentIndex!==$index) +			{ +				$this->setActiveViewID(''); // clear up view ID +				$this->setActiveViewIndex($index); +				return $this->_dataChanged=true; +			} +		} +		return false; +	} + +	/** +	 * Raises postdata changed event. +	 * This method is required by {@link IPostBackDataHandler} interface. +	 * It is invoked by the framework when {@link getActiveViewIndex ActiveViewIndex} property +	 * is changed on postback. +	 * This method is primarly used by framework developers. +	 */ +	public function raisePostDataChangedEvent() +	{ +		// do nothing +	} + +	/** +	 * Returns a value indicating whether postback has caused the control data change. +	 * This method is required by the IPostBackDataHandler interface. +	 * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. +	 */ +	public function getDataChanged() +	{ +		return $this->_dataChanged; +	} + +	/** +	 * Adds attributes to renderer. +	 * @param THtmlWriter the renderer +	 */ +	protected function addAttributesToRender($writer) +	{ +		$writer->addAttribute('id',$this->getClientID()); +		$this->setCssClass($this->getCssClass()); +		parent::addAttributesToRender($writer); +	} + +	/** +	 * Registers CSS and JS. +	 * This method is invoked right before the control rendering, if the control is visible. +	 * @param mixed event parameter +	 */ +	public function onPreRender($param) +	{ +		parent::onPreRender($param); +		$this->getActiveView();  // determine the active view +		$this->registerStyleSheet(); +	} + +	/** +	 * Registers the CSS relevant to the TTabControl. +	 * It will register the CSS file specified by {@link getCssUrl CssUrl}. +	 * If that is not set, it will use the default CSS. +	 */ +	protected function registerStyleSheet() +	{ +		$url = $this->getCssUrl(); +		 +		if($url === '') { +			return; +		} +		 +		if($url === 'default') { +			$url = $this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'tabpanel.css'); +		} +		 +		if($url !== '') { +			$this->getPage()->getClientScript()->registerStyleSheetFile($url, $url); +		} +	} + +	/** +	 * Registers the relevant JavaScript. +	 */ +	protected function registerClientScript() +	{ +		$id=$this->getClientID(); +		$options=TJavaScript::encode($this->getClientOptions()); +		$className=$this->getClientClassName(); +		$page=$this->getPage(); +		$cs=$page->getClientScript(); +		$cs->registerPradoScript('tabpanel'); +		$code="new $className($options);"; +		$cs->registerEndScript("prado:$id", $code); +		// ensure an item is always active and visible +		$index = $this->getActiveViewIndex(); +		if(!$this->getViews()->itemAt($index)->Visible) +			$index=0; +		$cs->registerHiddenField($id.'_1', $index); +		$page->registerRequiresPostData($this); +		$page->registerRequiresPostData($id."_1"); +	} + +	/** +	 * Gets the name of the javascript class responsible for performing postback for this control. +	 * This method overrides the parent implementation. +	 * @return string the javascript class name +	 */ +	protected function getClientClassName() +	{ +		return 'Prado.WebUI.TTabPanel'; +	} + +	/** +	 * @return array the options for JavaScript +	 */ +	protected function getClientOptions() +	{ +		$options['ID'] = $this->getClientID(); +		$options['ActiveCssClass'] = $this->getActiveTabCssClass(); +		$options['NormalCssClass'] = $this->getTabCssClass(); +		$viewIDs = array(); +		$viewVis = array(); +		foreach($this->getViews() as $view) +		{ +			$viewIDs[] = $view->getClientID(); +			$viewVis[] = $view->getVisible(); +		} +		$options['Views'] = $viewIDs; +		$options['ViewsVis'] = $viewVis; +		$options['AutoSwitch'] = $this->getAutoSwitch(); + +		return $options; +	} + +	/** +	 * Creates a control collection object that is to be used to hold child controls +	 * @return TTabViewCollection control collection +	 */ +	protected function createControlCollection() +	{ +		return new TTabViewCollection($this); +	} + +	/** +	 * @return TTabViewCollection list of {@link TTabView} controls +	 */ +	public function getViews() +	{ +		return $this->getControls(); +	} + +	public function render($writer) +	{ +		$this->registerClientScript(); +		parent::render($writer); +	} + +	/** +	 * Renders body contents of the tab control. +	 * @param THtmlWriter the writer used for the rendering purpose. +	 */ +	public function renderContents($writer) +	{ +		$views=$this->getViews(); +		if($views->getCount()>0) +		{ +			$writer->writeLine(); +			// render tab bar +			foreach($views as $view) +			{ +				$view->renderTab($writer); +				$writer->writeLine(); +			} +			// render tab views +			foreach($views as $view) +			{ +				$view->renderControl($writer); +				$writer->writeLine(); +			} +		} +	} +} + +/** + * TTabView class. + * + * TTabView represents a view in a {@link TTabPanel} control. + * + * The content in a TTabView can be specified by the {@link setText Text} property + * or its child controls. In template syntax, the latter means enclosing the content + * within the TTabView component element. If both are set, {@link getText Text} takes precedence. + * + * Each TTabView is associated with a tab in the tab bar of the TTabPanel control. + * The tab caption is specified by {@link setCaption Caption}. If {@link setNavigateUrl NavigateUrl} + * is set, the tab will contain a hyperlink pointing to the specified URL. In this case, + * clicking on the tab will redirect the browser to the specified URL. + * + * TTabView may be toggled between visible (active) and invisible (inactive) by + * setting the {@link setActive Active} property. + * + * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TTabView extends TWebControl +{ +	private $_active=false; + +	/** +	 * @return the tag name for the view element +	 */ +	protected function getTagName() +	{ +		return 'div'; +	} + +	/** +	 * Adds attributes to renderer. +	 * @param THtmlWriter the renderer +	 */ +	protected function addAttributesToRender($writer) +	{ +		if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript()) +			$this->getStyle()->setStyleField('display','none'); + +		$this->getStyle()->mergeWith($this->getParent()->getViewStyle()); + +		parent::addAttributesToRender($writer); + +		$writer->addAttribute('id',$this->getClientID()); +	} + +	/** +	 * @return string the caption displayed on this tab. Defaults to ''. +	 */ +	public function getCaption() +	{ +		return $this->getViewState('Caption',''); +	} + +	/** +	 * @param string the caption displayed on this tab +	 */ +	public function setCaption($value) +	{ +		$this->setViewState('Caption',TPropertyValue::ensureString($value),''); +	} + +	/** +	 * @return string the URL of the target page. Defaults to ''. +	 */ +	public function getNavigateUrl() +	{ +		return $this->getViewState('NavigateUrl',''); +	} + +	/** +	 * Sets the URL of the target page. +	 * If not empty, clicking on this tab will redirect the browser to the specified URL. +	 * @param string the URL of the target page. +	 */ +	public function setNavigateUrl($value) +	{ +		$this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),''); +	} + +	/** +	 * @return string the text content displayed on this view. Defaults to ''. +	 */ +	public function getText() +	{ +		return $this->getViewState('Text',''); +	} + +	/** +	 * Sets the text content to be displayed on this view. +	 * If this is not empty, the child content of the view will be ignored. +	 * @param string the text content displayed on this view +	 */ +	public function setText($value) +	{ +		$this->setViewState('Text',TPropertyValue::ensureString($value),''); +	} + +	/** +	 * @return boolean whether this tab view is active. Defaults to false. +	 */ +	public function getActive() +	{ +		return $this->_active; +	} + +	/** +	 * @param boolean whether this tab view is active. +	 */ +	public function setActive($value) +	{ +		$this->_active=TPropertyValue::ensureBoolean($value); +	} + +	/** +	 * Renders body contents of the tab view. +	 * @param THtmlWriter the writer used for the rendering purpose. +	 */ +	public function renderContents($writer) +	{ +		if(($text=$this->getText())!=='') +			$writer->write($text); +		else if($this->getHasControls()) +			parent::renderContents($writer); +	} + +	/** +	 * Renders the tab associated with the tab view. +	 * @param THtmlWriter the writer for rendering purpose. +	 */ +	public function renderTab($writer) +	{ +		if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript()) +		{ +			$writer->addAttribute('id',$this->getClientID().'_0'); + +			$style=$this->getActive()?$this->getParent()->getActiveTabStyle():$this->getParent()->getTabStyle(); +			$style->addAttributesToRender($writer); + +			$writer->renderBeginTag($this->getTagName()); + +			$this->renderTabContent($writer); + +			$writer->renderEndTag(); +		} +	} + +	/** +	 * Renders the content in the tab. +	 * By default, a hyperlink is displayed. +	 * @param THtmlWriter the HTML writer +	 */ +	protected function renderTabContent($writer) +	{ +		if(($url=$this->getNavigateUrl())==='') +			$url='javascript://'; +		if(($caption=$this->getCaption())==='') +			$caption=' '; +		$writer->write("<a href=\"{$url}\">{$caption}</a>"); +	} +} + +/** + * TTabViewCollection class. + * + * TTabViewCollection is used to maintain a list of views belong to a {@link TTabPanel}. + * + * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TTabViewCollection extends TControlCollection +{ +	/** +	 * Inserts an item at the specified position. +	 * This overrides the parent implementation by performing sanity check on the type of new item. +	 * @param integer the speicified position. +	 * @param mixed new item +	 * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TTabView} object. +	 */ +	public function insertAt($index,$item) +	{ +		if($item instanceof TTabView) +			parent::insertAt($index,$item); +		else +			throw new TInvalidDataTypeException('tabviewcollection_tabview_required'); +	} + +	/** +	 * Finds the index of the tab view whose ID is the same as the one being looked for. +	 * @param string the explicit ID of the tab view to be looked for +	 * @return integer the index of the tab view found, -1 if not found. +	 */ +	public function findIndexByID($id) +	{ +		foreach($this as $index=>$view) +		{ +			if($view->getID(false)===$id) +				return $index; +		} +		return -1; +	} +} diff --git a/framework/Web/UI/WebControls/TTextHighlighter.php b/framework/Web/UI/WebControls/TTextHighlighter.php index 48fb1d41..92b67846 100644 --- a/framework/Web/UI/WebControls/TTextHighlighter.php +++ b/framework/Web/UI/WebControls/TTextHighlighter.php @@ -1,206 +1,213 @@ -<?php
 -/**
 - * TTextHighlighter class file
 - *
 - * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
 - * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2011 PradoSoft
 - * @license http://www.pradosoft.com/license/
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - */
 -
 -Prado::using('System.3rdParty.TextHighlighter.Text.Highlighter',false);
 -Prado::using('System.3rdParty.TextHighlighter.Text.Highlighter.Renderer.Html',false);
 -Prado::using('System.Web.UI.WebControls.TTextProcessor');
 -
 -
 -/**
 - * TTextHighlighter class.
 - *
 - * TTextHighlighter does syntax highlighting its body content, including
 - * static text and rendering results of child controls.
 - * You can set {@link setLanguage Language} to specify what kind of syntax
 - * the body content is. Currently, TTextHighlighter supports the following
 - * languages: ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT, MYSQL, PERL,
 - * PHP, PYTHON, RUBY, SQL, XML and PRADO, where PRADO refers to PRADO template
 - * syntax. By setting {@link setShowLineNumbers ShowLineNumbers}
 - * to true, the highlighted result may be shown with line numbers.
 - *
 - * Note, TTextHighlighter requires {@link THead} to be placed on the page template
 - * because it needs to insert some CSS styles.
 - *
 - * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.0
 - */
 -class TTextHighlighter extends TTextProcessor
 -{
 -	private static $_lineNumberStyle=array(TTextHighlighterLineNumberStyle::Li => HL_NUMBERS_LI, TTextHighlighterLineNumberStyle::Table => HL_NUMBERS_TABLE);
 -
 -	/**
 -	 * @return string tag name of the panel
 -	 */
 -	protected function getTagName()
 -	{
 -		return 'div';
 -	}
 -
 -	/**
 -	 * @return string language whose syntax is to be used for highlighting. Defaults to 'php'.
 -	 */
 -	public function getLanguage()
 -	{
 -		return $this->getViewState('Language', 'php');
 -	}
 -
 -	/**
 -	 * @param string language (case-insensitive) whose syntax is to be used for highlighting.
 -	 * Valid values are those file names (without suffix) that are contained
 -	 * in '3rdParty/TextHighlighter/Text/Highlighter'. Currently, the following languages are supported:
 -	 * ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT,
 -	 * MYSQL, PERL, PHP, PRADO, PYTHON, RUBY, SQL, XML
 -	 * If a language is not supported, it will be displayed as plain text.
 -	 */
 -	public function setLanguage($value)
 -	{
 -		$this->setViewState('Language', $value, 'php');
 -	}
 -
 -	/**
 -	 * @return boolean whether to show line numbers in the highlighted result.
 -	 */
 -	public function getShowLineNumbers()
 -	{
 -		return $this->getViewState('ShowLineNumbers', false);
 -	}
 -
 -	/**
 -	 * @param boolean whether to show line numbers in the highlighted result.
 -	 */
 -	public function setShowLineNumbers($value)
 -	{
 -		$this->setViewState('ShowLineNumbers', TPropertyValue::ensureBoolean($value), false);
 -	}
 -
 -	/**
 -	 * @return boolean true will show "Copy Code" link. Defaults to false.
 -	 */
 -	public function getEnableCopyCode()
 -	{
 -		return $this->getViewState('CopyCode', false);
 -	}
 -
 -	/**
 -	 * @param boolean true to show the "Copy Code" link.
 -	 */
 -	public function setEnableCopyCode($value)
 -	{
 -		$this->setViewState('CopyCode', TPropertyValue::ensureBoolean($value), false);
 -	}
 -
 -	/**
 -	 * @return TTextHighlighterLineNumberStyle style of row number, Table by default
 -	 */
 -	public function getLineNumberStyle()
 -	{
 -		return $this->getViewState('LineNumberStyle', TTextHighlighterLineNumberStyle::Table);
 -	}
 -
 -	/**
 -	 * @param TTextHighlighterLineNumberStyle style of row number
 -	 */
 -	public function setLineNumberStyle($value)
 -	{
 -		$this->setViewState('LineNumberStyle', TPropertyValue::ensureEnum($value,'TTextHighlighterLineNumberStyle'));
 -	}
 -
 -	/**
 -	 * @return integer tab size. Defaults to 4.
 -	 */
 -	public function getTabSize()
 -	{
 -		return $this->getViewState('TabSize', 4);
 -	}
 -
 -	/**
 -	 * @param integer tab size
 -	 */
 -	public function setTabSize($value)
 -	{
 -		$this->setViewState('TabSize', TPropertyValue::ensureInteger($value));
 -	}
 -
 -	/**
 -	 * Registers css style for the highlighted result.
 -	 * This method overrides parent implementation.
 -	 * @param THtmlWriter writer
 -	 */
 -	public function onPreRender($writer)
 -	{
 -		parent::onPreRender($writer);
 -		$this->registerStyleSheet();
 -		$this->getPage()->getClientScript()->registerPradoScript('prado');
 -	}
 -
 -	/**
 -	 * Registers the stylesheet for presentation.
 -	 */
 -	protected function registerStyleSheet()
 -	{
 -		$cs=$this->getPage()->getClientScript();
 -		$cssFile=Prado::getPathOfNamespace('System.3rdParty.TextHighlighter.highlight','.css');
 -		$cssKey='prado:TTextHighlighter:'.$cssFile;
 -		if(!$cs->isStyleSheetFileRegistered($cssKey))
 -			$cs->registerStyleSheetFile($cssKey, $this->publishFilePath($cssFile));
 -	}
 -
 -	/**
 -	 * Processes a text string.
 -	 * This method is required by the parent class.
 -	 * @param string text string to be processed
 -	 * @return string the processed text result
 -	 */
 -	public function processText($text)
 -	{
 -		try
 -		{
 -			$highlighter=Text_Highlighter::factory($this->getLanguage());
 -		}
 -		catch(Exception $e)
 -		{
 -			$highlighter=false;
 -		}
 -		if($highlighter===false)
 -			return ('<pre>'.htmlentities(trim($text)).'</pre>');
 -
 -		$options["use_language"]=true;
 -		$options["tabsize"] = $this->getTabSize();
 -		if ($this->getShowLineNumbers())
 -			$options["numbers"] = self::$_lineNumberStyle[$this->getLineNumberStyle()];
 -		$highlighter->setRenderer(new Text_Highlighter_Renderer_Html($options));
 -		return $highlighter->highlight(trim($text));
 -	}
 -
 -	/**
 -	 * @return string header template with "Copy code" link.
 -	 */
 -	protected function getHeaderTemplate()
 -	{
 -		$id = $this->getClientID();
 -		return TJavaScript::renderScriptBlock("new Prado.WebUI.TTextHighlighter('{$id}');");
 -	}
 -}
 -
 -/**
 - * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
 - * @version $Id$
 - * @package System.Web.UI.WebControls
 - * @since 3.0
 - */
 -class TTextHighlighterLineNumberStyle extends TEnumerable
 -{
 -	const Li='Li';
 -	const Table='Table';
 -}
 +<?php +/** + * TTextHighlighter class file + * + * @author Wei Zhuo<weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2011 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.3rdParty.TextHighlighter.Text.Highlighter',false); +Prado::using('System.3rdParty.TextHighlighter.Text.Highlighter.Renderer.Html',false); +Prado::using('System.Web.UI.WebControls.TTextProcessor'); + + +/** + * TTextHighlighter class. + * + * TTextHighlighter does syntax highlighting its body content, including + * static text and rendering results of child controls. + * You can set {@link setLanguage Language} to specify what kind of syntax + * the body content is. Currently, TTextHighlighter supports the following + * languages: ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT, MYSQL, PERL, + * PHP, PYTHON, RUBY, SQL, XML and PRADO, where PRADO refers to PRADO template + * syntax. By setting {@link setShowLineNumbers ShowLineNumbers} + * to true, the highlighted result may be shown with line numbers. + * + * Note, TTextHighlighter requires {@link THead} to be placed on the page template + * because it needs to insert some CSS styles. + * + * @author Wei Zhuo<weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTextHighlighter extends TTextProcessor +{ +	private static $_lineNumberStyle=array(TTextHighlighterLineNumberStyle::Li => HL_NUMBERS_LI, TTextHighlighterLineNumberStyle::Table => HL_NUMBERS_TABLE); + +	/** +	 * @return string tag name of the panel +	 */ +	protected function getTagName() +	{ +		return 'div'; +	} + +	/** +	 * @return string language whose syntax is to be used for highlighting. Defaults to 'php'. +	 */ +	public function getLanguage() +	{ +		return $this->getViewState('Language', 'php'); +	} + +	/** +	 * @param string language (case-insensitive) whose syntax is to be used for highlighting. +	 * Valid values are those file names (without suffix) that are contained +	 * in '3rdParty/TextHighlighter/Text/Highlighter'. Currently, the following languages are supported: +	 * ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT, +	 * MYSQL, PERL, PHP, PRADO, PYTHON, RUBY, SQL, XML +	 * If a language is not supported, it will be displayed as plain text. +	 */ +	public function setLanguage($value) +	{ +		$this->setViewState('Language', $value, 'php'); +	} + +	/** +	 * @return boolean whether to show line numbers in the highlighted result. +	 */ +	public function getShowLineNumbers() +	{ +		return $this->getViewState('ShowLineNumbers', false); +	} + +	/** +	 * @param boolean whether to show line numbers in the highlighted result. +	 */ +	public function setShowLineNumbers($value) +	{ +		$this->setViewState('ShowLineNumbers', TPropertyValue::ensureBoolean($value), false); +	} + +	/** +	 * @return boolean true will show "Copy Code" link. Defaults to false. +	 */ +	public function getEnableCopyCode() +	{ +		return $this->getViewState('CopyCode', false); +	} + +	/** +	 * @param boolean true to show the "Copy Code" link. +	 */ +	public function setEnableCopyCode($value) +	{ +		$this->setViewState('CopyCode', TPropertyValue::ensureBoolean($value), false); +	} + +	/** +	 * @return TTextHighlighterLineNumberStyle style of row number, Table by default +	 */ +	public function getLineNumberStyle() +	{ +		return $this->getViewState('LineNumberStyle', TTextHighlighterLineNumberStyle::Table); +	} + +	/** +	 * @param TTextHighlighterLineNumberStyle style of row number +	 */ +	public function setLineNumberStyle($value) +	{ +		$this->setViewState('LineNumberStyle', TPropertyValue::ensureEnum($value,'TTextHighlighterLineNumberStyle')); +	} + +	/** +	 * @return integer tab size. Defaults to 4. +	 */ +	public function getTabSize() +	{ +		return $this->getViewState('TabSize', 4); +	} + +	/** +	 * @param integer tab size +	 */ +	public function setTabSize($value) +	{ +		$this->setViewState('TabSize', TPropertyValue::ensureInteger($value)); +	} + +	/** +	 * Registers css style for the highlighted result. +	 * This method overrides parent implementation. +	 * @param THtmlWriter writer +	 */ +	public function onPreRender($writer) +	{ +		parent::onPreRender($writer); +		$this->registerStyleSheet(); +	} + +	/** +	 * Registers the stylesheet for presentation. +	 */ +	protected function registerStyleSheet() +	{ +		$cs=$this->getPage()->getClientScript(); +		$cssFile=Prado::getPathOfNamespace('System.3rdParty.TextHighlighter.highlight','.css'); +		$cssKey='prado:TTextHighlighter:'.$cssFile; +		if(!$cs->isStyleSheetFileRegistered($cssKey)) +			$cs->registerStyleSheetFile($cssKey, $this->publishFilePath($cssFile)); +	} + +	/** +	 * Processes a text string. +	 * This method is required by the parent class. +	 * @param string text string to be processed +	 * @return string the processed text result +	 */ +	public function processText($text) +	{ +		try +		{ +			$highlighter=Text_Highlighter::factory($this->getLanguage()); +		} +		catch(Exception $e) +		{ +			$highlighter=false; +		} +		if($highlighter===false) +			return ('<pre>'.htmlentities(trim($text)).'</pre>'); + +		$options["use_language"]=true; +		$options["tabsize"] = $this->getTabSize(); +		if ($this->getShowLineNumbers()) +			$options["numbers"] = self::$_lineNumberStyle[$this->getLineNumberStyle()]; +		$highlighter->setRenderer(new Text_Highlighter_Renderer_Html($options)); +		return $highlighter->highlight(trim($text)); +	} + +	/** +	 * @return string header template with "Copy code" link. +	 */ +	protected function getHeaderTemplate() +	{ +		$id = $this->getClientID(); +		return TJavaScript::renderScriptBlock("new Prado.WebUI.TTextHighlighter('{$id}');"); +	} + +	public function render($writer) +	{ +		$this->getPage()->getClientScript()->registerPradoScript('prado'); +		parent::render($writer); +	} + + +} + +/** + * @author Wei Zhuo<weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTextHighlighterLineNumberStyle extends TEnumerable +{ +	const Li='Li'; +	const Table='Table'; +} | 
