diff options
Diffstat (limited to 'framework/Web/UI')
| -rw-r--r-- | framework/Web/UI/TPage.php | 2817 | 
1 files changed, 1401 insertions, 1416 deletions
| diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php index c633a3be..e46ee9f5 100644 --- a/framework/Web/UI/TPage.php +++ b/framework/Web/UI/TPage.php @@ -1,1416 +1,1401 @@ -<?php -/** - * TPage class file - * - * @author Qiang Xue <qiang.xue@gmail.com> - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2014 PradoSoft - * @license http://www.pradosoft.com/license/ - * @package System.Web.UI - */ - -Prado::using('System.Web.UI.WebControls.*'); -Prado::using('System.Web.UI.TControl'); -Prado::using('System.Web.UI.WebControls.TWebControl'); -Prado::using('System.Web.UI.TCompositeControl'); -Prado::using('System.Web.UI.TTemplateControl'); -Prado::using('System.Web.UI.TForm'); -Prado::using('System.Web.UI.TClientScriptManager'); - -/** - * TPage class - * - * @author Qiang Xue <qiang.xue@gmail.com> - * @package System.Web.UI - * @since 3.0 - */ -class TPage extends TTemplateControl -{ -	/** -	 * system post fields -	 */ -	const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET'; -	const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER'; -	const FIELD_LASTFOCUS='PRADO_LASTFOCUS'; -	const FIELD_PAGESTATE='PRADO_PAGESTATE'; -	const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET'; -	const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER'; - -	/** -	 * @var array system post fields -	 */ -	private static $_systemPostFields=array( -		'PRADO_POSTBACK_TARGET'=>true, -		'PRADO_POSTBACK_PARAMETER'=>true, -		'PRADO_LASTFOCUS'=>true, -		'PRADO_PAGESTATE'=>true, -		'PRADO_CALLBACK_TARGET'=>true, -		'PRADO_CALLBACK_PARAMETER'=>true -	); -	/** -	 * @var TForm form instance -	 */ -	private $_form; -	/** -	 * @var THead head instance -	 */ -	private $_head; -	/** -	 * @var array list of registered validators -	 */ -	private $_validators=array(); -	/** -	 * @var boolean if validation has been performed -	 */ -	private $_validated=false; -	/** -	 * @var TTheme page theme -	 */ -	private $_theme; -	/** -	 * @var string page title set when Head is not in page yet -	 */ -	private $_title; -	/** -	 * @var TTheme page stylesheet theme -	 */ -	private $_styleSheet; -	/** -	 * @var TClientScriptManager client script manager -	 */ -	private $_clientScript; -	/** -	 * @var TMap data post back by user -	 */ -	protected $_postData; -	/** -	 * @var TMap postback data that is not handled during first invocation of LoadPostData. -	 */ -	protected $_restPostData; -	/** -	 * @var array list of controls whose data have been changed due to the postback -	 */ -	protected $_controlsPostDataChanged=array(); -	/** -	 * @var array list of controls that need to load post data in the current request -	 */ -	protected $_controlsRequiringPostData=array(); -	/** -	 * @var array list of controls that need to load post data in the next postback -	 */ -	protected $_controlsRegisteredForPostData=array(); -	/** -	 * @var TControl control that needs to raise postback event -	 */ -	private $_postBackEventTarget; -	/** -	 * @var string postback event parameter -	 */ -	private $_postBackEventParameter; -	/** -	 * @var boolean whether the form has been rendered -	 */ -	protected $_formRendered=false; -	/** -	 * @var boolean whether the current rendering is within a form -	 */ -	protected $_inFormRender=false; -	/** -	 * @var TControl|string the control or the ID of the element on the page to be focused when the page is sent back to user -	 */ -	private $_focus; -	/** -	 * @var string page path to this page -	 */ -	private $_pagePath=''; -	/** -	 * @var boolean whether page state should be HMAC validated -	 */ -	private $_enableStateValidation=true; -	/** -	 * @var boolean whether page state should be encrypted -	 */ -	private $_enableStateEncryption=false; -	/** -	 * @var boolean whether page state should be compressed -	 * @since 3.1.6 -	 */ -	private $_enableStateCompression=true; -	/** -	 * @var string page state persister class name -	 */ -	private $_statePersisterClass='System.Web.UI.TPageStatePersister'; -	/** -	 * @var mixed page state persister -	 */ -	private $_statePersister; -	/** -	 * @var TStack stack used to store currently active caching controls -	 */ -	private $_cachingStack; -	/** -	 * @var string state string to be stored on the client side -	 */ -	private $_clientState=''; -	/** -	 * @var boolean true if loading post data. -	 */ -	protected $_isLoadingPostData=false; -	/** -	 * @var boolean whether client supports javascript -	 */ -	private $_enableJavaScript=true; -	/** -	 * @var THtmlWriter current html render writer -	 */ -	private $_writer; - -	/** -	 * Constructor. -	 * Sets the page object to itself. -	 * Derived classes must call parent implementation. -	 */ -	public function __construct() -	{ -		$this->setPage($this); -	} - -	/** -	 * Runs through the page lifecycles. -	 * @param THtmlTextWriter the HTML writer -	 */ -	public function run($writer) -	{ -		Prado::trace("Running page life cycles",'System.Web.UI.TPage'); -		$this->_writer = $writer; - -		$this->determinePostBackMode(); - -		if($this->getIsPostBack()) -		{ -			if($this->getIsCallback()) -				$this->processCallbackRequest($writer); -			else -				$this->processPostBackRequest($writer); -		} -		else -			$this->processNormalRequest($writer); - -		$this->_writer = null; -	} - -	protected function processNormalRequest($writer) -	{ -		Prado::trace("Page onPreInit()",'System.Web.UI.TPage'); -		$this->onPreInit(null); - -		Prado::trace("Page initRecursive()",'System.Web.UI.TPage'); -		$this->initRecursive(); - -		Prado::trace("Page onInitComplete()",'System.Web.UI.TPage'); -		$this->onInitComplete(null); - -		Prado::trace("Page onPreLoad()",'System.Web.UI.TPage'); -		$this->onPreLoad(null); -		Prado::trace("Page loadRecursive()",'System.Web.UI.TPage'); -		$this->loadRecursive(); -		Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage'); -		$this->onLoadComplete(null); - -		Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage'); -		$this->preRenderRecursive(); -		Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage'); -		$this->onPreRenderComplete(null); - -		Prado::trace("Page savePageState()",'System.Web.UI.TPage'); -		$this->savePageState(); -		Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage'); -		$this->onSaveStateComplete(null); - -		Prado::trace("Page renderControl()",'System.Web.UI.TPage'); -		$this->renderControl($writer); -		Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage'); -		$this->unloadRecursive(); -	} - -	protected function processPostBackRequest($writer) -	{ -		Prado::trace("Page onPreInit()",'System.Web.UI.TPage'); -		$this->onPreInit(null); - -		Prado::trace("Page initRecursive()",'System.Web.UI.TPage'); -		$this->initRecursive(); - -		Prado::trace("Page onInitComplete()",'System.Web.UI.TPage'); -		$this->onInitComplete(null); - -		$this->_restPostData=new TMap; -		Prado::trace("Page loadPageState()",'System.Web.UI.TPage'); -		$this->loadPageState(); -		Prado::trace("Page processPostData()",'System.Web.UI.TPage'); -		$this->processPostData($this->_postData,true); -		Prado::trace("Page onPreLoad()",'System.Web.UI.TPage'); -		$this->onPreLoad(null); -		Prado::trace("Page loadRecursive()",'System.Web.UI.TPage'); -		$this->loadRecursive(); -		Prado::trace("Page processPostData()",'System.Web.UI.TPage'); -		$this->processPostData($this->_restPostData,false); -		Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage'); -		$this->raiseChangedEvents(); -		Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage'); -		$this->raisePostBackEvent(); -		Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage'); -		$this->onLoadComplete(null); - -		Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage'); -		$this->preRenderRecursive(); -		Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage'); -		$this->onPreRenderComplete(null); - -		Prado::trace("Page savePageState()",'System.Web.UI.TPage'); -		$this->savePageState(); -		Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage'); -		$this->onSaveStateComplete(null); - -		Prado::trace("Page renderControl()",'System.Web.UI.TPage'); -		$this->renderControl($writer); -		Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage'); -		$this->unloadRecursive(); -	} - -	protected static function decodeUTF8($data, $enc) -	{ -		if(is_array($data)) -		{ -			foreach($data as $k=>$v) -				$data[$k]=self::decodeUTF8($v, $enc); -			return $data; -		} elseif(is_string($data)) { -			return iconv('UTF-8',$enc.'//IGNORE',$data); -		} else { -			return $data; -		} -	} - -	/** -	 * Sets Adapter to TActivePageAdapter and calls apter to process the -	 * callback request. -	 */ -	protected function processCallbackRequest($writer) -	{ -		Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter'); - -		$this->setAdapter(new TActivePageAdapter($this)); - -        $callbackEventParameter = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER); -        if(strlen($callbackEventParameter) > 0) -            $this->_postData[TPage::FIELD_CALLBACK_PARAMETER]=TJavaScript::jsonDecode((string)$callbackEventParameter); - -        // Decode Callback postData from UTF-8 to current Charset -        if (($g=$this->getApplication()->getGlobalization(false))!==null && -            strtoupper($enc=$g->getCharset())!='UTF-8') -                foreach ($this->_postData as $k=>$v) -                	$this->_postData[$k]=self::decodeUTF8($v, $enc); - -		Prado::trace("Page onPreInit()",'System.Web.UI.TPage'); -		$this->onPreInit(null); - -		Prado::trace("Page initRecursive()",'System.Web.UI.TPage'); -		$this->initRecursive(); - -		Prado::trace("Page onInitComplete()",'System.Web.UI.TPage'); -		$this->onInitComplete(null); - -		$this->_restPostData=new TMap; -		Prado::trace("Page loadPageState()",'System.Web.UI.TPage'); -		$this->loadPageState(); -		Prado::trace("Page processPostData()",'System.Web.UI.TPage'); -		$this->processPostData($this->_postData,true); -		Prado::trace("Page onPreLoad()",'System.Web.UI.TPage'); -		$this->onPreLoad(null); -		Prado::trace("Page loadRecursive()",'System.Web.UI.TPage'); -		$this->loadRecursive(); - -		Prado::trace("Page processPostData()",'System.Web.UI.TPage'); -		$this->processPostData($this->_restPostData,false); - -		Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage'); -		$this->raiseChangedEvents(); - - -		$this->getAdapter()->processCallbackEvent($writer); - -/* -		Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage'); -		$this->raisePostBackEvent(); -*/ -		Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage'); -		$this->onLoadComplete(null); - -		Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage'); -		$this->preRenderRecursive(); -		Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage'); -		$this->onPreRenderComplete(null); - -		Prado::trace("Page savePageState()",'System.Web.UI.TPage'); -		$this->savePageState(); -		Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage'); -		$this->onSaveStateComplete(null); - -/* -		Prado::trace("Page renderControl()",'System.Web.UI.TPage'); -		$this->renderControl($writer); -*/ -		$this->getAdapter()->renderCallbackResponse($writer); - -		Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage'); -		$this->unloadRecursive(); -	} - -	/** -	 * Gets the callback client script handler that allows javascript functions -	 * to be executed during the callback response. -	 * @return TCallbackClientScript interface to client-side javascript code. -	 */ -	public function getCallbackClient() -	{ -		if($this->getAdapter() !== null) -			return $this->getAdapter()->getCallbackClientHandler(); -		else -			return new TCallbackClientScript(); -	} - -	/** -	 * Set a new callback client handler. -	 * @param TCallbackClientScript new callback client script handler. -	 */ -	public function setCallbackClient($client) -	{ -		$this->getAdapter()->setCallbackClientHandler($client); -	} - -	/** -	 * @return TControl the control responsible for the current callback event, -	 * null if nonexistent -	 */ -	public function getCallbackEventTarget() -	{ -		return $this->getAdapter()->getCallbackEventTarget(); -	} - -	/** -	 * Registers a control to raise callback event in the current request. -	 * @param TControl control registered to raise callback event. -	 */ -	public function setCallbackEventTarget(TControl $control) -	{ -		$this->getAdapter()->setCallbackEventTarget($control); -	} - -	/** -	 * Callback parameter is decoded assuming JSON encoding. -	 * @return string callback event parameter -	 */ -	public function getCallbackEventParameter() -	{ -		return $this->getAdapter()->getCallbackEventParameter(); -	} - -	/** -	 * @param mixed callback event parameter -	 */ -	public function setCallbackEventParameter($value) -	{ -		$this->getAdapter()->setCallbackEventParameter($value); -	} - -	/** -	 * @return TForm the form on the page -	 */ -	public function getForm() -	{ -		return $this->_form; -	} - -	/** -	 * Registers a TForm instance to the page. -	 * Note, a page can contain at most one TForm instance. -	 * @param TForm the form on the page -	 * @throws TInvalidOperationException if this method is invoked twice or more. -	 */ -	public function setForm(TForm $form) -	{ -		if($this->_form===null) -			$this->_form=$form; -		else -			throw new TInvalidOperationException('page_form_duplicated'); -	} - -	/** -	 * Returns a list of registered validators. -	 * If validation group is specified, only the validators in that group will be returned. -	 * @param string validation group -	 * @return TList registered validators in the requested group. If the group is null, all validators will be returned. -	 */ -	public function getValidators($validationGroup=null) -	{ -		if(!$this->_validators) -			$this->_validators=new TList; -		if(empty($validationGroup) === true) -			return $this->_validators; -		else -		{ -			$list=new TList; -			foreach($this->_validators as $validator) -				if($validator->getValidationGroup()===$validationGroup) -					$list->add($validator); -			return $list; -		} -	} - -	/** -	 * Performs input validation. -	 * This method will invoke the registered validators to perform the actual validation. -	 * If validation group is specified, only the validators in that group will be invoked. -	 * @param string validation group. If null, all validators will perform validation. -	 */ -	public function validate($validationGroup=null) -	{ -		Prado::trace("Page validate()",'System.Web.UI.TPage'); -		$this->_validated=true; -		if($this->_validators && $this->_validators->getCount()) -		{ -			if($validationGroup===null) -			{ -				foreach($this->_validators as $validator) -					$validator->validate(); -			} -			else -			{ -				foreach($this->_validators as $validator) -				{ -					if($validator->getValidationGroup()===$validationGroup) -						$validator->validate(); -				} -			} -		} -	} - -	/** -	 * Returns whether user input is valid or not. -	 * This method must be invoked after {@link validate} is called. -	 * @return boolean whether the user input is valid or not. -	 * @throws TInvalidOperationException if {@link validate} is not invoked yet. -	 */ -	public function getIsValid() -	{ -		if($this->_validated) -		{ -			if($this->_validators && $this->_validators->getCount()) -			{ -				foreach($this->_validators as $validator) -					if(!$validator->getIsValid()) -						return false; -			} -			return true; -		} -		else -			throw new TInvalidOperationException('page_isvalid_unknown'); -	} - -	/** -	 * @return TTheme the theme used for the page. Defaults to null. -	 */ -	public function getTheme() -	{ -		if(is_string($this->_theme)) -			$this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme); -		return $this->_theme; -	} - -	/** -	 * Sets the theme to be used for the page. -	 * @param string|TTheme the theme name or the theme object to be used for the page. -	 */ -	public function setTheme($value) -	{ -		$this->_theme=empty($value)?null:$value; -	} - - -	/** -	 * @return TTheme the stylesheet theme used for the page. Defaults to null. -	 */ -	public function getStyleSheetTheme() -	{ -		if(is_string($this->_styleSheet)) -			$this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet); -		return $this->_styleSheet; -	} - -	/** -	 * Sets the stylesheet theme to be used for the page. -	 * @param string|TTheme the stylesheet theme name or the stylesheet theme object to be used for the page. -	 */ -	public function setStyleSheetTheme($value) -	{ -		$this->_styleSheet=empty($value)?null:$value; -	} - -	/** -	 * Applies a skin in the current theme to a control. -	 * This method should only be used by framework developers. -	 * @param TControl a control to be applied skin with -	 */ -	public function applyControlSkin($control) -	{ -		if(($theme=$this->getTheme())!==null) -			$theme->applySkin($control); -	} - -	/** -	 * Applies a stylesheet skin in the current theme to a control. -	 * This method should only be used by framework developers. -	 * @param TControl a control to be applied stylesheet skin with -	 */ -	public function applyControlStyleSheet($control) -	{ -		if(($theme=$this->getStyleSheetTheme())!==null) -			$theme->applySkin($control); -	} - -	/** -	 * @return TClientScriptManager client script manager -	 */ -	public function getClientScript() -	{ -		if(!$this->_clientScript) { -			$className = $classPath = $this->getService()->getClientScriptManagerClass(); -			Prado::using($className); -			if(($pos=strrpos($className,'.'))!==false) -				$className=substr($className,$pos+1); - - 			if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager'))) -				throw new THttpException(404,'page_csmanagerclass_invalid',$classPath); - -			$this->_clientScript=new $className($this); -		} -		return $this->_clientScript; -	} - -	/** -	 * Raises OnPreInit event. -	 * This method is invoked right before {@link onInit OnInit} stage. -	 * You may override this method to provide additional initialization that -	 * should be done before {@link onInit OnInit} (e.g. setting {@link setTheme Theme} or -	 * {@link setStyleSheetTheme StyleSheetTheme}). -	 * Remember to call the parent implementation to ensure OnPreInit event is raised. -	 * @param mixed event parameter -	 */ -	public function onPreInit($param) -	{ -		$this->raiseEvent('OnPreInit',$this,$param); -	} - -	/** -	 * Raises OnInitComplete event. -	 * This method is invoked right after {@link onInit OnInit} stage and before {@link onLoad OnLoad} stage. -	 * You may override this method to provide additional initialization that -	 * should be done after {@link onInit OnInit}. -	 * Remember to call the parent implementation to ensure OnInitComplete event is raised. -	 * @param mixed event parameter -	 */ -	public function onInitComplete($param) -	{ -		$this->raiseEvent('OnInitComplete',$this,$param); -	} - -	/** -	 * Raises OnPreLoad event. -	 * This method is invoked right before {@link onLoad OnLoad} stage. -	 * You may override this method to provide additional page loading logic that -	 * should be done before {@link onLoad OnLoad}. -	 * Remember to call the parent implementation to ensure OnPreLoad event is raised. -	 * @param mixed event parameter -	 */ -	public function onPreLoad($param) -	{ -		$this->raiseEvent('OnPreLoad',$this,$param); -	} - -	/** -	 * Raises OnLoadComplete event. -	 * This method is invoked right after {@link onLoad OnLoad} stage. -	 * You may override this method to provide additional page loading logic that -	 * should be done after {@link onLoad OnLoad}. -	 * Remember to call the parent implementation to ensure OnLoadComplete event is raised. -	 * @param mixed event parameter -	 */ -	public function onLoadComplete($param) -	{ -		$this->raiseEvent('OnLoadComplete',$this,$param); -	} - -	/** -	 * Raises OnPreRenderComplete event. -	 * This method is invoked right after {@link onPreRender OnPreRender} stage. -	 * You may override this method to provide additional preparation for page rendering -	 * that should be done after {@link onPreRender OnPreRender}. -	 * Remember to call the parent implementation to ensure OnPreRenderComplete event is raised. -	 * @param mixed event parameter -	 */ -	public function onPreRenderComplete($param) -	{ -		$this->raiseEvent('OnPreRenderComplete',$this,$param); -		$cs=$this->getClientScript(); -		$theme=$this->getTheme(); -		if($theme instanceof ITheme) -		{ -			foreach($theme->getStyleSheetFiles() as $url) -				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url)); -			foreach($theme->getJavaScriptFiles() as $url) -				$cs->registerHeadScriptFile($url,$url); -		} -		$styleSheet=$this->getStyleSheetTheme(); -		if($styleSheet instanceof ITheme) -		{ -			foreach($styleSheet->getStyleSheetFiles() as $url) -				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url)); -			foreach($styleSheet->getJavaScriptFiles() as $url) -				$cs->registerHeadScriptFile($url,$url); -		} - -		if($cs->getRequiresHead() && $this->getHead()===null) -			throw new TConfigurationException('page_head_required'); -	} - -	/** -	 * Determines the media type of the CSS file. -	 * The media type is determined according to the following file name pattern: -	 *        xxx.media-type.extension -	 * For example, 'mystyle.print.css' means its media type is 'print'. -	 * @param string CSS URL -	 * @return string media type of the CSS file -	 */ -	private function getCssMediaType($url) -	{ -		$segs=explode('.',basename($url)); -		if(isset($segs[2])) -			return $segs[count($segs)-2]; -		else -			return ''; -	} - -	/** -	 * Raises OnSaveStateComplete event. -	 * This method is invoked right after {@link onSaveState OnSaveState} stage. -	 * You may override this method to provide additional logic after page state is saved. -	 * Remember to call the parent implementation to ensure OnSaveStateComplete event is raised. -	 * @param mixed event parameter -	 */ -	public function onSaveStateComplete($param) -	{ -		$this->raiseEvent('OnSaveStateComplete',$this,$param); -	} - -	/** -	 * Determines whether the current page request is a postback. -	 * Call {@link getIsPostBack} to get the result. -	 */ -	private function determinePostBackMode() -	{ -		$postData=$this->getRequest(); -		if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET)) -			$this->_postData=$postData; -	} - -	/** -	 * @return boolean whether the current page request is a postback -	 */ -	public function getIsPostBack() -	{ -		return $this->_postData!==null; -	} - -	/** -	 * @return boolean whether this is a callback request -	 */ -	public function getIsCallback() -	{ -		return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET); -	} - -	/** -	 * This method is invoked when control state is to be saved. -	 * You can override this method to do last step state saving. -	 * Parent implementation must be invoked. -	 */ -	public function saveState() -	{ -		parent::saveState(); -		$this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array()); -	} - -	/** -	 * This method is invoked right after the control has loaded its state. -	 * You can override this method to initialize data from the control state. -	 * Parent implementation must be invoked. -	 */ -	public function loadState() -	{ -		parent::loadState(); -		$this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array()); -	} - -	/** -	 * Loads page state from persistent storage. -	 */ -	protected function loadPageState() -	{ -		Prado::trace("Loading state",'System.Web.UI.TPage'); -		$state=$this->getStatePersister()->load(); -		$this->loadStateRecursive($state,$this->getEnableViewState()); -	} - -	/** -	 * Saves page state from persistent storage. -	 */ -	protected function savePageState() -	{ -		Prado::trace("Saving state",'System.Web.UI.TPage'); -		$state=&$this->saveStateRecursive($this->getEnableViewState()); -		$this->getStatePersister()->save($state); -	} - -	/** -	 * @param string the field name -	 * @return boolean whether the specified field is a system field in postback data -	 */ -	protected function isSystemPostField($field) -	{ -		return isset(self::$_systemPostFields[$field]); -	} - -	/** -	 * Registers a control for loading post data in the next postback. -	 * This method needs to be invoked if the control to load post data -	 * may not have a post variable in some cases. For example, a checkbox, -	 * if not checked, will not have a post value. -	 * @param TControl control registered for loading post data -	 */ -	public function registerRequiresPostData($control) -	{ -		$id=is_string($control)?$control:$control->getUniqueID(); -		$this->_controlsRegisteredForPostData[$id]=true; -		$params=func_get_args(); -		foreach($this->getCachingStack() as $item) -			$item->registerAction('Page','registerRequiresPostData',array($id)); -	} - -	/** -	 * @return TControl the control responsible for the current postback event, null if nonexistent -	 */ -	public function getPostBackEventTarget() -	{ -		if($this->_postBackEventTarget===null && $this->_postData!==null) -		{ -			$eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET); -			if(!empty($eventTarget)) -				$this->_postBackEventTarget=$this->findControl($eventTarget); -		} -		return $this->_postBackEventTarget; -	} - -	/** -	 * Registers a control to raise postback event in the current request. -	 * @param TControl control registered to raise postback event. -	 */ -	public function setPostBackEventTarget(TControl $control) -	{ -		$this->_postBackEventTarget=$control; -	} - -	/** -	 * @return string postback event parameter -	 */ -	public function getPostBackEventParameter() -	{ -		if($this->_postBackEventParameter===null && $this->_postData!==null) -		{ -			if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null) -				$this->_postBackEventParameter=''; -		} -		return $this->_postBackEventParameter; -	} - -	/** -	 * @param string postback event parameter -	 */ -	public function setPostBackEventParameter($value) -	{ -		$this->_postBackEventParameter=$value; -	} - -	/** -	 * Processes post data. -	 * @param TMap post data to be processed -	 * @param boolean whether this method is invoked before {@link onLoad OnLoad}. -	 */ -	protected function processPostData($postData,$beforeLoad) -	{ -		$this->_isLoadingPostData=true; -		if($beforeLoad) -			$this->_restPostData=new TMap; -		foreach($postData as $key=>$value) -		{ -			if($this->isSystemPostField($key)) -				continue; -			else if($control=$this->findControl($key)) -			{ -				if($control instanceof IPostBackDataHandler) -				{ -					if($control->loadPostData($key,$postData)) -						$this->_controlsPostDataChanged[]=$control; -				} -				else if($control instanceof IPostBackEventHandler && -					empty($this->_postData[self::FIELD_POSTBACK_TARGET])) -				{ -					$this->_postData->add(self::FIELD_POSTBACK_TARGET,$key);  // not calling setPostBackEventTarget() because the control may be removed later -				} -				unset($this->_controlsRequiringPostData[$key]); -			} -			else if($beforeLoad) -				$this->_restPostData->add($key,$value); -		} - -		foreach($this->_controlsRequiringPostData as $key=>$value) -		{ -			if($control=$this->findControl($key)) -			{ -				if($control instanceof IPostBackDataHandler) -				{ -					if($control->loadPostData($key,$this->_postData)) -						$this->_controlsPostDataChanged[]=$control; -				} -				else -					throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key); -				unset($this->_controlsRequiringPostData[$key]); -			} -		} -		$this->_isLoadingPostData=false; -	} - -	/** -	 * @return boolean true if loading post data. -	 */ -	public function getIsLoadingPostData() -	{ -		return $this->_isLoadingPostData; -	} - -	/** -	 * Raises OnPostDataChangedEvent for controls whose data have been changed due to the postback. -	 */ -	protected function raiseChangedEvents() -	{ -		foreach($this->_controlsPostDataChanged as $control) -			$control->raisePostDataChangedEvent(); -	} - -	/** -	 * Raises PostBack event. -	 */ -	protected function raisePostBackEvent() -	{ -		if(($postBackHandler=$this->getPostBackEventTarget())===null) -			$this->validate(); -		else if($postBackHandler instanceof IPostBackEventHandler) -			$postBackHandler->raisePostBackEvent($this->getPostBackEventParameter()); -	} - -	/** -	 * @return boolean Whether form rendering is in progress -	 */ -	public function getInFormRender() -	{ -		return $this->_inFormRender; -	} - -	/** -	 * Ensures the control is rendered within a form. -	 * @param TControl the control to be rendered -	 * @throws TConfigurationException if the control is outside of the form -	 */ -	public function ensureRenderInForm($control) -	{ -		if(!$this->getIsCallback() && !$this->_inFormRender) -			throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null); -	} - -	/** -	 * @internal This method is invoked by TForm at the beginning of its rendering -	 */ -	public function beginFormRender($writer) -	{ -		if($this->_formRendered) -			throw new TConfigurationException('page_form_duplicated'); -		$this->_formRendered=true; -		$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState()); -		$this->_inFormRender=true; -	} - -	/** -	 * @internal This method is invoked by TForm  at the end of its rendering -	 */ -	public function endFormRender($writer) -	{ -		if($this->_focus) -		{ -			if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true)) -				$focus=$this->_focus->getClientID(); -			else -				$focus=$this->_focus; -			$this->getClientScript()->registerFocusControl($focus); -		} -		else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null) -			$this->getClientScript()->registerFocusControl($lastFocus); -		$this->_inFormRender=false; -	} - -	/** -	 * Sets input focus on a control after the page is rendered to users. -	 * @param TControl|string control to receive focus, or the ID of the element on the page to receive focus -	 */ -	public function setFocus($value) -	{ -		$this->_focus=$value; -	} - -	/** -	 * @return boolean whether client supports javascript. Defaults to true. -	 */ -	public function getClientSupportsJavaScript() -	{ -		return $this->_enableJavaScript; -	} - -	/** -	 * @param boolean whether client supports javascript. If false, javascript will not be generated for controls. -	 */ -	public function setClientSupportsJavaScript($value) -	{ -		$this->_enableJavaScript=TPropertyValue::ensureBoolean($value); -	} - -	/** -	 * @return THead page head, null if not available -	 */ -	public function getHead() -	{ -		return $this->_head; -	} - -	/** -	 * @param THead page head -	 * @throws TInvalidOperationException if a head already exists -	 */ -	public function setHead(THead $value) -	{ -		if($this->_head) -			throw new TInvalidOperationException('page_head_duplicated'); -		$this->_head=$value; -		if($this->_title!==null) -		{ -			$this->_head->setTitle($this->_title); -			$this->_title=null; -		} -	} - -	/** -	 * @return string page title. -	 */ -	public function getTitle() -	{ -		if($this->_head) -			return $this->_head->getTitle(); -		else -			return $this->_title===null ? '' : $this->_title; -	} - -	/** -	 * Sets the page title. -	 * Note, a {@link THead} control needs to place on the page -	 * in order that this title be rendered. -	 * @param string page title. This will override the title set in {@link getHead Head}. -	 */ -	public function setTitle($value) -	{ -		if($this->_head) -			$this->_head->setTitle($value); -		else -			$this->_title=$value; -	} - -	/** -	 * Returns the state to be stored on the client side. -	 * This method should only be used by framework and control developers. -	 * @return string the state to be stored on the client side -	 */ -	public function getClientState() -	{ -		return $this->_clientState; -	} - -	/** -	 * Sets the state to be stored on the client side. -	 * This method should only be used by framework and control developers. -	 * @param string the state to be stored on the client side -	 */ -	public function setClientState($state) -	{ -		$this->_clientState=$state; -	} - -	/** -	 * @return string the state postback from client side -	 */ -	public function getRequestClientState() -	{ -		return $this->getRequest()->itemAt(self::FIELD_PAGESTATE); -	} - -	/** -	 * @return string class name of the page state persister. Defaults to TPageStatePersister. -	 */ -	public function getStatePersisterClass() -	{ -		return $this->_statePersisterClass; -	} - -	/** -	 * @param string class name of the page state persister. -	 */ -	public function setStatePersisterClass($value) -	{ -		$this->_statePersisterClass=$value; -	} - -	/** -	 * @return IPageStatePersister page state persister -	 */ -	public function getStatePersister() -	{ -		if($this->_statePersister===null) -		{ -			$this->_statePersister=Prado::createComponent($this->_statePersisterClass); -			if(!($this->_statePersister instanceof IPageStatePersister)) -				throw new TInvalidDataTypeException('page_statepersister_invalid'); -			$this->_statePersister->setPage($this); -		} -		return $this->_statePersister; -	} - -	/** -	 * @return boolean whether page state should be HMAC validated. Defaults to true. -	 */ -	public function getEnableStateValidation() -	{ -		return $this->_enableStateValidation; -	} - -	/** -	 * @param boolean whether page state should be HMAC validated. -	 */ -	public function setEnableStateValidation($value) -	{ -		$this->_enableStateValidation=TPropertyValue::ensureBoolean($value); -	} - -	/** -	 * @return boolean whether page state should be encrypted. Defaults to false. -	 */ -	public function getEnableStateEncryption() -	{ -		return $this->_enableStateEncryption; -	} - -	/** -	 * @param boolean whether page state should be encrypted. -	 */ -	public function setEnableStateEncryption($value) -	{ -		$this->_enableStateEncryption=TPropertyValue::ensureBoolean($value); -	} - -	/** -	 * @return boolean whether page state should be compressed. Defaults to true. -	 * @since 3.1.6 -	 */ -	public function getEnableStateCompression() -	{ -		return $this->_enableStateCompression; -	} - -	/** -	 * @param boolean whether page state should be compressed. -	 * @since 3.1.6 -	 */ -	public function setEnableStateCompression($value) -	{ -		$this->_enableStateCompression=TPropertyValue::ensureBoolean($value); -	} - -	/** -	 * @return string the requested page path for this page -	 */ -	public function getPagePath() -	{ -		return $this->_pagePath; -	} - -	/** -	 * @param string the requested page path for this page -	 */ -	public function setPagePath($value) -	{ -		$this->_pagePath=$value; -	} - -	/** -	 * Registers an action associated with the content being cached. -	 * The registered action will be replayed if the content stored -	 * in the cache is served to end-users. -	 * @param string context of the action method. This is a property-path -	 * referring to the context object (e.g. Page, Page.ClientScript). -	 * @param string method name of the context object -	 * @param array list of parameters to be passed to the action method -	 */ -	public function registerCachingAction($context,$funcName,$funcParams) -	{ -		if($this->_cachingStack) -		{ -			foreach($this->_cachingStack as $cache) -				$cache->registerAction($context,$funcName,$funcParams); -		} -	} - -	/** -	 * @return TStack stack of {@link TOutputCache} objects -	 */ -	public function getCachingStack() -	{ -		if(!$this->_cachingStack) -			$this->_cachingStack=new TStack; -		return $this->_cachingStack; -	} - -	/** -	 * Flushes output -	 */ -	public function flushWriter() -	{ -		if ($this->_writer) -			$this->Response->write($this->_writer->flush()); -	} -         -        /** -         * Function to update view controls with data in a given AR object. -         * View controls and AR object need to have the same name in IDs and Attrs respectively. -         * @param TActiveRecord $arObj -         * @author Daniel Sampedro <darthdaniel85@gmail.com> -         */ -        public function tryToUpdateView($arObj, $throwExceptions = false) -        { -                $objAttrs = get_class_vars(get_class($arObj)); -                foreach (array_keys($objAttrs) as $key) -                { -                        try -                        { -                                if ($key != "RELATIONS") -                                { -                                        $control = $this->{$key}; -                                        switch (get_class($control)) -                                        { -                                                default: -                                                case "TTextBox": -                                                        $control->Text = $arObj->{$key}; -                                                        break; -                                                case "TCheckBox": -                                                        $control->Checked = (boolean) $arObj->{$key}; -                                                        break; -                                                case "TDatePicker": -                                                        $control->Date = $arObj->{$key}; -                                                        break; -                                        } -                                } else -                                { -                                        foreach ($objAttrs["RELATIONS"] as $relKey => $relValues) -                                        { -                                                $relControl = $this->{$relKey}; -                                                switch ($relValues[0]) -                                                { -                                                        case TActiveRecord::BELONGS_TO: -                                                        case TActiveRecord::HAS_ONE: -                                                                $relControl->Text = $arObj->{$relKey}; -                                                                break; -                                                        case TActiveRecord::HAS_MANY: -                                                                if($relControl instanceof TListControl){ -                                                                        $relControl->DataSource = $arObj->{$relKey}; -                                                                        $relControl->dataBind(); -                                                                } -                                                                break; -                                                } -                                        } -                                        break; -                                } -                        } catch (Exception $ex) -                        { -                                if ($throwExceptions) -                                { -                                        throw $ex; -                                } -                        } -                } -        } -         -        /** -         * Function to try to update an AR object with data in view controls. -         * @param TActiveRecord $arObj -         * @author Daniel Sampedro <darthdaniel85@gmail.com> -         */ -        public function tryToUpdateAR($arObj, $throwExceptions = false) -        { -                $objAttrs = get_class_vars(get_class($arObj)); -                foreach (array_keys($objAttrs) as $key) -                { -                        try -                        { -                                if ($key == "RELATIONS") -                                { -                                       break; -                                }  -                                $control = $this->{$key}; -                                switch (get_class($control)) -                                { -                                        default: -                                        case "TTextBox": -                                                 $arObj->{$key} = $control->Text; -                                                break; -                                        case "TCheckBox": -                                                $arObj->{$key} = $control->Checked; -                                                break; -                                        case "TDatePicker": -                                                $arObj->{$key} = $control->Date; -                                                break; -                                } -                        } catch (Exception $ex) -                        { -                                if ($throwExceptions) -                                { -                                        throw $ex; -                                } -                        } -                } -        } -} - -/** - * IPageStatePersister interface. - * - * IPageStatePersister interface is required for all page state persister - * classes. - * - * @author Qiang Xue <qiang.xue@gmail.com> - * @package System.Web.UI - * @since 3.1 - */ -interface IPageStatePersister -{ -	/** -	 * @param TPage the page that this persister works for -	 */ -	public function getPage(); -	/** -	 * @param TPage the page that this persister works for -	 */ -	public function setPage(TPage $page); -	/** -	 * Saves state to persistent storage. -	 * @param mixed state to be stored -	 */ -	public function save($state); -	/** -	 * Loads page state from persistent storage -	 * @return mixed the restored state -	 */ -	public function load(); -} - - -/** - * TPageStateFormatter class. - * - * TPageStateFormatter is a utility class to transform the page state - * into and from a string that can be properly saved in persistent storage. - * - * Depending on the {@link TPage::getEnableStateValidation() EnableStateValidation} - * and {@link TPage::getEnableStateEncryption() EnableStateEncryption}, - * TPageStateFormatter may do HMAC validation and encryption to prevent - * the state data from being tampered or viewed. - * The private keys and hashing/encryption methods are determined by - * {@link TApplication::getSecurityManager() SecurityManager}. - * - * @author Qiang Xue <qiang.xue@gmail.com> - * @version $Revision: $  $Date: $ - * @package System.Web.UI - * @since 3.1 - */ -class TPageStateFormatter -{ -	/** -	 * @param TPage -	 * @param mixed state data -	 * @return string serialized data -	 */ -	public static function serialize($page,$data) -	{ -		$sm=$page->getApplication()->getSecurityManager(); -		if($page->getEnableStateValidation()) -			$str=$sm->hashData(serialize($data)); -		else -			$str=serialize($data); -		if($page->getEnableStateCompression() && extension_loaded('zlib')) -			$str=gzcompress($str); -		if($page->getEnableStateEncryption()) -			$str=$sm->encrypt($str); -		return base64_encode($str); -	} - -	/** -	 * @param TPage -	 * @param string serialized data -	 * @return mixed unserialized state data, null if data is corrupted -	 */ -	public static function unserialize($page,$data) -	{ -		$str=base64_decode($data); -		if($str==='') -			return null; -		if($str!==false) -		{ -			$sm=$page->getApplication()->getSecurityManager(); -			if($page->getEnableStateEncryption()) -				$str=$sm->decrypt($str); -			if($page->getEnableStateCompression() && extension_loaded('zlib')) -				$str=@gzuncompress($str); -			if($page->getEnableStateValidation()) -			{ -				if(($str=$sm->validateData($str))!==false) -					return unserialize($str); -			} -			else -				return unserialize($str); -		} -		return null; -	} -} +<?php
 +/**
 + * TPage class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2005-2014 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @package System.Web.UI
 + */
 +
 +Prado::using('System.Web.UI.WebControls.*');
 +Prado::using('System.Web.UI.TControl');
 +Prado::using('System.Web.UI.WebControls.TWebControl');
 +Prado::using('System.Web.UI.TCompositeControl');
 +Prado::using('System.Web.UI.TTemplateControl');
 +Prado::using('System.Web.UI.TForm');
 +Prado::using('System.Web.UI.TClientScriptManager');
 +
 +/**
 + * TPage class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @package System.Web.UI
 + * @since 3.0
 + */
 +class TPage extends TTemplateControl
 +{
 +	/**
 +	 * system post fields
 +	 */
 +	const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
 +	const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
 +	const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
 +	const FIELD_PAGESTATE='PRADO_PAGESTATE';
 +	const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
 +	const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
 +
 +	/**
 +	 * @var array system post fields
 +	 */
 +	private static $_systemPostFields=array(
 +		'PRADO_POSTBACK_TARGET'=>true,
 +		'PRADO_POSTBACK_PARAMETER'=>true,
 +		'PRADO_LASTFOCUS'=>true,
 +		'PRADO_PAGESTATE'=>true,
 +		'PRADO_CALLBACK_TARGET'=>true,
 +		'PRADO_CALLBACK_PARAMETER'=>true
 +	);
 +	/**
 +	 * @var TForm form instance
 +	 */
 +	private $_form;
 +	/**
 +	 * @var THead head instance
 +	 */
 +	private $_head;
 +	/**
 +	 * @var array list of registered validators
 +	 */
 +	private $_validators=array();
 +	/**
 +	 * @var boolean if validation has been performed
 +	 */
 +	private $_validated=false;
 +	/**
 +	 * @var TTheme page theme
 +	 */
 +	private $_theme;
 +	/**
 +	 * @var string page title set when Head is not in page yet
 +	 */
 +	private $_title;
 +	/**
 +	 * @var TTheme page stylesheet theme
 +	 */
 +	private $_styleSheet;
 +	/**
 +	 * @var TClientScriptManager client script manager
 +	 */
 +	private $_clientScript;
 +	/**
 +	 * @var TMap data post back by user
 +	 */
 +	protected $_postData;
 +	/**
 +	 * @var TMap postback data that is not handled during first invocation of LoadPostData.
 +	 */
 +	protected $_restPostData;
 +	/**
 +	 * @var array list of controls whose data have been changed due to the postback
 +	 */
 +	protected $_controlsPostDataChanged=array();
 +	/**
 +	 * @var array list of controls that need to load post data in the current request
 +	 */
 +	protected $_controlsRequiringPostData=array();
 +	/**
 +	 * @var array list of controls that need to load post data in the next postback
 +	 */
 +	protected $_controlsRegisteredForPostData=array();
 +	/**
 +	 * @var TControl control that needs to raise postback event
 +	 */
 +	private $_postBackEventTarget;
 +	/**
 +	 * @var string postback event parameter
 +	 */
 +	private $_postBackEventParameter;
 +	/**
 +	 * @var boolean whether the form has been rendered
 +	 */
 +	protected $_formRendered=false;
 +	/**
 +	 * @var boolean whether the current rendering is within a form
 +	 */
 +	protected $_inFormRender=false;
 +	/**
 +	 * @var TControl|string the control or the ID of the element on the page to be focused when the page is sent back to user
 +	 */
 +	private $_focus;
 +	/**
 +	 * @var string page path to this page
 +	 */
 +	private $_pagePath='';
 +	/**
 +	 * @var boolean whether page state should be HMAC validated
 +	 */
 +	private $_enableStateValidation=true;
 +	/**
 +	 * @var boolean whether page state should be encrypted
 +	 */
 +	private $_enableStateEncryption=false;
 +	/**
 +	 * @var boolean whether page state should be compressed
 +	 * @since 3.1.6
 +	 */
 +	private $_enableStateCompression=true;
 +	/**
 +	 * @var string page state persister class name
 +	 */
 +	private $_statePersisterClass='System.Web.UI.TPageStatePersister';
 +	/**
 +	 * @var mixed page state persister
 +	 */
 +	private $_statePersister;
 +	/**
 +	 * @var TStack stack used to store currently active caching controls
 +	 */
 +	private $_cachingStack;
 +	/**
 +	 * @var string state string to be stored on the client side
 +	 */
 +	private $_clientState='';
 +	/**
 +	 * @var boolean true if loading post data.
 +	 */
 +	protected $_isLoadingPostData=false;
 +	/**
 +	 * @var boolean whether client supports javascript
 +	 */
 +	private $_enableJavaScript=true;
 +	/**
 +	 * @var THtmlWriter current html render writer
 +	 */
 +	private $_writer;
 +
 +	/**
 +	 * Constructor.
 +	 * Sets the page object to itself.
 +	 * Derived classes must call parent implementation.
 +	 */
 +	public function __construct()
 +	{
 +		$this->setPage($this);
 +	}
 +
 +	/**
 +	 * Runs through the page lifecycles.
 +	 * @param THtmlTextWriter the HTML writer
 +	 */
 +	public function run($writer)
 +	{
 +		Prado::trace("Running page life cycles",'System.Web.UI.TPage');
 +		$this->_writer = $writer;
 +
 +		$this->determinePostBackMode();
 +
 +		if($this->getIsPostBack())
 +		{
 +			if($this->getIsCallback())
 +				$this->processCallbackRequest($writer);
 +			else
 +				$this->processPostBackRequest($writer);
 +		}
 +		else
 +			$this->processNormalRequest($writer);
 +
 +		$this->_writer = null;
 +	}
 +
 +	protected function processNormalRequest($writer)
 +	{
 +		Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
 +		$this->onPreInit(null);
 +
 +		Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
 +		$this->initRecursive();
 +
 +		Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
 +		$this->onInitComplete(null);
 +
 +		Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
 +		$this->onPreLoad(null);
 +		Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
 +		$this->loadRecursive();
 +		Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
 +		$this->onLoadComplete(null);
 +
 +		Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
 +		$this->preRenderRecursive();
 +		Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
 +		$this->onPreRenderComplete(null);
 +
 +		Prado::trace("Page savePageState()",'System.Web.UI.TPage');
 +		$this->savePageState();
 +		Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
 +		$this->onSaveStateComplete(null);
 +
 +		Prado::trace("Page renderControl()",'System.Web.UI.TPage');
 +		$this->renderControl($writer);
 +		Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
 +		$this->unloadRecursive();
 +	}
 +
 +	protected function processPostBackRequest($writer)
 +	{
 +		Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
 +		$this->onPreInit(null);
 +
 +		Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
 +		$this->initRecursive();
 +
 +		Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
 +		$this->onInitComplete(null);
 +
 +		$this->_restPostData=new TMap;
 +		Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
 +		$this->loadPageState();
 +		Prado::trace("Page processPostData()",'System.Web.UI.TPage');
 +		$this->processPostData($this->_postData,true);
 +		Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
 +		$this->onPreLoad(null);
 +		Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
 +		$this->loadRecursive();
 +		Prado::trace("Page processPostData()",'System.Web.UI.TPage');
 +		$this->processPostData($this->_restPostData,false);
 +		Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
 +		$this->raiseChangedEvents();
 +		Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
 +		$this->raisePostBackEvent();
 +		Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
 +		$this->onLoadComplete(null);
 +
 +		Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
 +		$this->preRenderRecursive();
 +		Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
 +		$this->onPreRenderComplete(null);
 +
 +		Prado::trace("Page savePageState()",'System.Web.UI.TPage');
 +		$this->savePageState();
 +		Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
 +		$this->onSaveStateComplete(null);
 +
 +		Prado::trace("Page renderControl()",'System.Web.UI.TPage');
 +		$this->renderControl($writer);
 +		Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
 +		$this->unloadRecursive();
 +	}
 +
 +	protected static function decodeUTF8($data, $enc)
 +	{
 +		if(is_array($data))
 +		{
 +			foreach($data as $k=>$v)
 +				$data[$k]=self::decodeUTF8($v, $enc);
 +			return $data;
 +		} elseif(is_string($data)) {
 +			return iconv('UTF-8',$enc.'//IGNORE',$data);
 +		} else {
 +			return $data;
 +		}
 +	}
 +
 +	/**
 +	 * Sets Adapter to TActivePageAdapter and calls apter to process the
 +	 * callback request.
 +	 */
 +	protected function processCallbackRequest($writer)
 +	{
 +		Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
 +
 +		$this->setAdapter(new TActivePageAdapter($this));
 +
 +        $callbackEventParameter = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
 +        if(strlen($callbackEventParameter) > 0)
 +            $this->_postData[TPage::FIELD_CALLBACK_PARAMETER]=TJavaScript::jsonDecode((string)$callbackEventParameter);
 +
 +        // Decode Callback postData from UTF-8 to current Charset
 +        if (($g=$this->getApplication()->getGlobalization(false))!==null &&
 +            strtoupper($enc=$g->getCharset())!='UTF-8')
 +                foreach ($this->_postData as $k=>$v)
 +                	$this->_postData[$k]=self::decodeUTF8($v, $enc);
 +
 +		Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
 +		$this->onPreInit(null);
 +
 +		Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
 +		$this->initRecursive();
 +
 +		Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
 +		$this->onInitComplete(null);
 +
 +		$this->_restPostData=new TMap;
 +		Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
 +		$this->loadPageState();
 +		Prado::trace("Page processPostData()",'System.Web.UI.TPage');
 +		$this->processPostData($this->_postData,true);
 +		Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
 +		$this->onPreLoad(null);
 +		Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
 +		$this->loadRecursive();
 +
 +		Prado::trace("Page processPostData()",'System.Web.UI.TPage');
 +		$this->processPostData($this->_restPostData,false);
 +
 +		Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
 +		$this->raiseChangedEvents();
 +
 +
 +		$this->getAdapter()->processCallbackEvent($writer);
 +
 +/*
 +		Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
 +		$this->raisePostBackEvent();
 +*/
 +		Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
 +		$this->onLoadComplete(null);
 +
 +		Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
 +		$this->preRenderRecursive();
 +		Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
 +		$this->onPreRenderComplete(null);
 +
 +		Prado::trace("Page savePageState()",'System.Web.UI.TPage');
 +		$this->savePageState();
 +		Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
 +		$this->onSaveStateComplete(null);
 +
 +/*
 +		Prado::trace("Page renderControl()",'System.Web.UI.TPage');
 +		$this->renderControl($writer);
 +*/
 +		$this->getAdapter()->renderCallbackResponse($writer);
 +
 +		Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
 +		$this->unloadRecursive();
 +	}
 +
 +	/**
 +	 * Gets the callback client script handler that allows javascript functions
 +	 * to be executed during the callback response.
 +	 * @return TCallbackClientScript interface to client-side javascript code.
 +	 */
 +	public function getCallbackClient()
 +	{
 +		if($this->getAdapter() !== null)
 +			return $this->getAdapter()->getCallbackClientHandler();
 +		else
 +			return new TCallbackClientScript();
 +	}
 +
 +	/**
 +	 * Set a new callback client handler.
 +	 * @param TCallbackClientScript new callback client script handler.
 +	 */
 +	public function setCallbackClient($client)
 +	{
 +		$this->getAdapter()->setCallbackClientHandler($client);
 +	}
 +
 +	/**
 +	 * @return TControl the control responsible for the current callback event,
 +	 * null if nonexistent
 +	 */
 +	public function getCallbackEventTarget()
 +	{
 +		return $this->getAdapter()->getCallbackEventTarget();
 +	}
 +
 +	/**
 +	 * Registers a control to raise callback event in the current request.
 +	 * @param TControl control registered to raise callback event.
 +	 */
 +	public function setCallbackEventTarget(TControl $control)
 +	{
 +		$this->getAdapter()->setCallbackEventTarget($control);
 +	}
 +
 +	/**
 +	 * Callback parameter is decoded assuming JSON encoding.
 +	 * @return string callback event parameter
 +	 */
 +	public function getCallbackEventParameter()
 +	{
 +		return $this->getAdapter()->getCallbackEventParameter();
 +	}
 +
 +	/**
 +	 * @param mixed callback event parameter
 +	 */
 +	public function setCallbackEventParameter($value)
 +	{
 +		$this->getAdapter()->setCallbackEventParameter($value);
 +	}
 +
 +	/**
 +	 * @return TForm the form on the page
 +	 */
 +	public function getForm()
 +	{
 +		return $this->_form;
 +	}
 +
 +	/**
 +	 * Registers a TForm instance to the page.
 +	 * Note, a page can contain at most one TForm instance.
 +	 * @param TForm the form on the page
 +	 * @throws TInvalidOperationException if this method is invoked twice or more.
 +	 */
 +	public function setForm(TForm $form)
 +	{
 +		if($this->_form===null)
 +			$this->_form=$form;
 +		else
 +			throw new TInvalidOperationException('page_form_duplicated');
 +	}
 +
 +	/**
 +	 * Returns a list of registered validators.
 +	 * If validation group is specified, only the validators in that group will be returned.
 +	 * @param string validation group
 +	 * @return TList registered validators in the requested group. If the group is null, all validators will be returned.
 +	 */
 +	public function getValidators($validationGroup=null)
 +	{
 +		if(!$this->_validators)
 +			$this->_validators=new TList;
 +		if(empty($validationGroup) === true)
 +			return $this->_validators;
 +		else
 +		{
 +			$list=new TList;
 +			foreach($this->_validators as $validator)
 +				if($validator->getValidationGroup()===$validationGroup)
 +					$list->add($validator);
 +			return $list;
 +		}
 +	}
 +
 +	/**
 +	 * Performs input validation.
 +	 * This method will invoke the registered validators to perform the actual validation.
 +	 * If validation group is specified, only the validators in that group will be invoked.
 +	 * @param string validation group. If null, all validators will perform validation.
 +	 */
 +	public function validate($validationGroup=null)
 +	{
 +		Prado::trace("Page validate()",'System.Web.UI.TPage');
 +		$this->_validated=true;
 +		if($this->_validators && $this->_validators->getCount())
 +		{
 +			if($validationGroup===null)
 +			{
 +				foreach($this->_validators as $validator)
 +					$validator->validate();
 +			}
 +			else
 +			{
 +				foreach($this->_validators as $validator)
 +				{
 +					if($validator->getValidationGroup()===$validationGroup)
 +						$validator->validate();
 +				}
 +			}
 +		}
 +	}
 +
 +	/**
 +	 * Returns whether user input is valid or not.
 +	 * This method must be invoked after {@link validate} is called.
 +	 * @return boolean whether the user input is valid or not.
 +	 * @throws TInvalidOperationException if {@link validate} is not invoked yet.
 +	 */
 +	public function getIsValid()
 +	{
 +		if($this->_validated)
 +		{
 +			if($this->_validators && $this->_validators->getCount())
 +			{
 +				foreach($this->_validators as $validator)
 +					if(!$validator->getIsValid())
 +						return false;
 +			}
 +			return true;
 +		}
 +		else
 +			throw new TInvalidOperationException('page_isvalid_unknown');
 +	}
 +
 +	/**
 +	 * @return TTheme the theme used for the page. Defaults to null.
 +	 */
 +	public function getTheme()
 +	{
 +		if(is_string($this->_theme))
 +			$this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
 +		return $this->_theme;
 +	}
 +
 +	/**
 +	 * Sets the theme to be used for the page.
 +	 * @param string|TTheme the theme name or the theme object to be used for the page.
 +	 */
 +	public function setTheme($value)
 +	{
 +		$this->_theme=empty($value)?null:$value;
 +	}
 +
 +
 +	/**
 +	 * @return TTheme the stylesheet theme used for the page. Defaults to null.
 +	 */
 +	public function getStyleSheetTheme()
 +	{
 +		if(is_string($this->_styleSheet))
 +			$this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
 +		return $this->_styleSheet;
 +	}
 +
 +	/**
 +	 * Sets the stylesheet theme to be used for the page.
 +	 * @param string|TTheme the stylesheet theme name or the stylesheet theme object to be used for the page.
 +	 */
 +	public function setStyleSheetTheme($value)
 +	{
 +		$this->_styleSheet=empty($value)?null:$value;
 +	}
 +
 +	/**
 +	 * Applies a skin in the current theme to a control.
 +	 * This method should only be used by framework developers.
 +	 * @param TControl a control to be applied skin with
 +	 */
 +	public function applyControlSkin($control)
 +	{
 +		if(($theme=$this->getTheme())!==null)
 +			$theme->applySkin($control);
 +	}
 +
 +	/**
 +	 * Applies a stylesheet skin in the current theme to a control.
 +	 * This method should only be used by framework developers.
 +	 * @param TControl a control to be applied stylesheet skin with
 +	 */
 +	public function applyControlStyleSheet($control)
 +	{
 +		if(($theme=$this->getStyleSheetTheme())!==null)
 +			$theme->applySkin($control);
 +	}
 +
 +	/**
 +	 * @return TClientScriptManager client script manager
 +	 */
 +	public function getClientScript()
 +	{
 +		if(!$this->_clientScript) {
 +			$className = $classPath = $this->getService()->getClientScriptManagerClass();
 +			Prado::using($className);
 +			if(($pos=strrpos($className,'.'))!==false)
 +				$className=substr($className,$pos+1);
 +
 + 			if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
 +				throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
 +
 +			$this->_clientScript=new $className($this);
 +		}
 +		return $this->_clientScript;
 +	}
 +
 +	/**
 +	 * Raises OnPreInit event.
 +	 * This method is invoked right before {@link onInit OnInit} stage.
 +	 * You may override this method to provide additional initialization that
 +	 * should be done before {@link onInit OnInit} (e.g. setting {@link setTheme Theme} or
 +	 * {@link setStyleSheetTheme StyleSheetTheme}).
 +	 * Remember to call the parent implementation to ensure OnPreInit event is raised.
 +	 * @param mixed event parameter
 +	 */
 +	public function onPreInit($param)
 +	{
 +		$this->raiseEvent('OnPreInit',$this,$param);
 +	}
 +
 +	/**
 +	 * Raises OnInitComplete event.
 +	 * This method is invoked right after {@link onInit OnInit} stage and before {@link onLoad OnLoad} stage.
 +	 * You may override this method to provide additional initialization that
 +	 * should be done after {@link onInit OnInit}.
 +	 * Remember to call the parent implementation to ensure OnInitComplete event is raised.
 +	 * @param mixed event parameter
 +	 */
 +	public function onInitComplete($param)
 +	{
 +		$this->raiseEvent('OnInitComplete',$this,$param);
 +	}
 +
 +	/**
 +	 * Raises OnPreLoad event.
 +	 * This method is invoked right before {@link onLoad OnLoad} stage.
 +	 * You may override this method to provide additional page loading logic that
 +	 * should be done before {@link onLoad OnLoad}.
 +	 * Remember to call the parent implementation to ensure OnPreLoad event is raised.
 +	 * @param mixed event parameter
 +	 */
 +	public function onPreLoad($param)
 +	{
 +		$this->raiseEvent('OnPreLoad',$this,$param);
 +	}
 +
 +	/**
 +	 * Raises OnLoadComplete event.
 +	 * This method is invoked right after {@link onLoad OnLoad} stage.
 +	 * You may override this method to provide additional page loading logic that
 +	 * should be done after {@link onLoad OnLoad}.
 +	 * Remember to call the parent implementation to ensure OnLoadComplete event is raised.
 +	 * @param mixed event parameter
 +	 */
 +	public function onLoadComplete($param)
 +	{
 +		$this->raiseEvent('OnLoadComplete',$this,$param);
 +	}
 +
 +	/**
 +	 * Raises OnPreRenderComplete event.
 +	 * This method is invoked right after {@link onPreRender OnPreRender} stage.
 +	 * You may override this method to provide additional preparation for page rendering
 +	 * that should be done after {@link onPreRender OnPreRender}.
 +	 * Remember to call the parent implementation to ensure OnPreRenderComplete event is raised.
 +	 * @param mixed event parameter
 +	 */
 +	public function onPreRenderComplete($param)
 +	{
 +		$this->raiseEvent('OnPreRenderComplete',$this,$param);
 +		$cs=$this->getClientScript();
 +		$theme=$this->getTheme();
 +		if($theme instanceof ITheme)
 +		{
 +			foreach($theme->getStyleSheetFiles() as $url)
 +				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
 +			foreach($theme->getJavaScriptFiles() as $url)
 +				$cs->registerHeadScriptFile($url,$url);
 +		}
 +		$styleSheet=$this->getStyleSheetTheme();
 +		if($styleSheet instanceof ITheme)
 +		{
 +			foreach($styleSheet->getStyleSheetFiles() as $url)
 +				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
 +			foreach($styleSheet->getJavaScriptFiles() as $url)
 +				$cs->registerHeadScriptFile($url,$url);
 +		}
 +
 +		if($cs->getRequiresHead() && $this->getHead()===null)
 +			throw new TConfigurationException('page_head_required');
 +	}
 +
 +	/**
 +	 * Determines the media type of the CSS file.
 +	 * The media type is determined according to the following file name pattern:
 +	 *        xxx.media-type.extension
 +	 * For example, 'mystyle.print.css' means its media type is 'print'.
 +	 * @param string CSS URL
 +	 * @return string media type of the CSS file
 +	 */
 +	private function getCssMediaType($url)
 +	{
 +		$segs=explode('.',basename($url));
 +		if(isset($segs[2]))
 +			return $segs[count($segs)-2];
 +		else
 +			return '';
 +	}
 +
 +	/**
 +	 * Raises OnSaveStateComplete event.
 +	 * This method is invoked right after {@link onSaveState OnSaveState} stage.
 +	 * You may override this method to provide additional logic after page state is saved.
 +	 * Remember to call the parent implementation to ensure OnSaveStateComplete event is raised.
 +	 * @param mixed event parameter
 +	 */
 +	public function onSaveStateComplete($param)
 +	{
 +		$this->raiseEvent('OnSaveStateComplete',$this,$param);
 +	}
 +
 +	/**
 +	 * Determines whether the current page request is a postback.
 +	 * Call {@link getIsPostBack} to get the result.
 +	 */
 +	private function determinePostBackMode()
 +	{
 +		$postData=$this->getRequest();
 +		if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
 +			$this->_postData=$postData;
 +	}
 +
 +	/**
 +	 * @return boolean whether the current page request is a postback
 +	 */
 +	public function getIsPostBack()
 +	{
 +		return $this->_postData!==null;
 +	}
 +
 +	/**
 +	 * @return boolean whether this is a callback request
 +	 */
 +	public function getIsCallback()
 +	{
 +		return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
 +	}
 +
 +	/**
 +	 * This method is invoked when control state is to be saved.
 +	 * You can override this method to do last step state saving.
 +	 * Parent implementation must be invoked.
 +	 */
 +	public function saveState()
 +	{
 +		parent::saveState();
 +		$this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
 +	}
 +
 +	/**
 +	 * This method is invoked right after the control has loaded its state.
 +	 * You can override this method to initialize data from the control state.
 +	 * Parent implementation must be invoked.
 +	 */
 +	public function loadState()
 +	{
 +		parent::loadState();
 +		$this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
 +	}
 +
 +	/**
 +	 * Loads page state from persistent storage.
 +	 */
 +	protected function loadPageState()
 +	{
 +		Prado::trace("Loading state",'System.Web.UI.TPage');
 +		$state=$this->getStatePersister()->load();
 +		$this->loadStateRecursive($state,$this->getEnableViewState());
 +	}
 +
 +	/**
 +	 * Saves page state from persistent storage.
 +	 */
 +	protected function savePageState()
 +	{
 +		Prado::trace("Saving state",'System.Web.UI.TPage');
 +		$state=&$this->saveStateRecursive($this->getEnableViewState());
 +		$this->getStatePersister()->save($state);
 +	}
 +
 +	/**
 +	 * @param string the field name
 +	 * @return boolean whether the specified field is a system field in postback data
 +	 */
 +	protected function isSystemPostField($field)
 +	{
 +		return isset(self::$_systemPostFields[$field]);
 +	}
 +
 +	/**
 +	 * Registers a control for loading post data in the next postback.
 +	 * This method needs to be invoked if the control to load post data
 +	 * may not have a post variable in some cases. For example, a checkbox,
 +	 * if not checked, will not have a post value.
 +	 * @param TControl control registered for loading post data
 +	 */
 +	public function registerRequiresPostData($control)
 +	{
 +		$id=is_string($control)?$control:$control->getUniqueID();
 +		$this->_controlsRegisteredForPostData[$id]=true;
 +		$params=func_get_args();
 +		foreach($this->getCachingStack() as $item)
 +			$item->registerAction('Page','registerRequiresPostData',array($id));
 +	}
 +
 +	/**
 +	 * @return TControl the control responsible for the current postback event, null if nonexistent
 +	 */
 +	public function getPostBackEventTarget()
 +	{
 +		if($this->_postBackEventTarget===null && $this->_postData!==null)
 +		{
 +			$eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
 +			if(!empty($eventTarget))
 +				$this->_postBackEventTarget=$this->findControl($eventTarget);
 +		}
 +		return $this->_postBackEventTarget;
 +	}
 +
 +	/**
 +	 * Registers a control to raise postback event in the current request.
 +	 * @param TControl control registered to raise postback event.
 +	 */
 +	public function setPostBackEventTarget(TControl $control)
 +	{
 +		$this->_postBackEventTarget=$control;
 +	}
 +
 +	/**
 +	 * @return string postback event parameter
 +	 */
 +	public function getPostBackEventParameter()
 +	{
 +		if($this->_postBackEventParameter===null && $this->_postData!==null)
 +		{
 +			if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
 +				$this->_postBackEventParameter='';
 +		}
 +		return $this->_postBackEventParameter;
 +	}
 +
 +	/**
 +	 * @param string postback event parameter
 +	 */
 +	public function setPostBackEventParameter($value)
 +	{
 +		$this->_postBackEventParameter=$value;
 +	}
 +
 +	/**
 +	 * Processes post data.
 +	 * @param TMap post data to be processed
 +	 * @param boolean whether this method is invoked before {@link onLoad OnLoad}.
 +	 */
 +	protected function processPostData($postData,$beforeLoad)
 +	{
 +		$this->_isLoadingPostData=true;
 +		if($beforeLoad)
 +			$this->_restPostData=new TMap;
 +		foreach($postData as $key=>$value)
 +		{
 +			if($this->isSystemPostField($key))
 +				continue;
 +			else if($control=$this->findControl($key))
 +			{
 +				if($control instanceof IPostBackDataHandler)
 +				{
 +					if($control->loadPostData($key,$postData))
 +						$this->_controlsPostDataChanged[]=$control;
 +				}
 +				else if($control instanceof IPostBackEventHandler &&
 +					empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
 +				{
 +					$this->_postData->add(self::FIELD_POSTBACK_TARGET,$key);  // not calling setPostBackEventTarget() because the control may be removed later
 +				}
 +				unset($this->_controlsRequiringPostData[$key]);
 +			}
 +			else if($beforeLoad)
 +				$this->_restPostData->add($key,$value);
 +		}
 +
 +		foreach($this->_controlsRequiringPostData as $key=>$value)
 +		{
 +			if($control=$this->findControl($key))
 +			{
 +				if($control instanceof IPostBackDataHandler)
 +				{
 +					if($control->loadPostData($key,$this->_postData))
 +						$this->_controlsPostDataChanged[]=$control;
 +				}
 +				else
 +					throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
 +				unset($this->_controlsRequiringPostData[$key]);
 +			}
 +		}
 +		$this->_isLoadingPostData=false;
 +	}
 +
 +	/**
 +	 * @return boolean true if loading post data.
 +	 */
 +	public function getIsLoadingPostData()
 +	{
 +		return $this->_isLoadingPostData;
 +	}
 +
 +	/**
 +	 * Raises OnPostDataChangedEvent for controls whose data have been changed due to the postback.
 +	 */
 +	protected function raiseChangedEvents()
 +	{
 +		foreach($this->_controlsPostDataChanged as $control)
 +			$control->raisePostDataChangedEvent();
 +	}
 +
 +	/**
 +	 * Raises PostBack event.
 +	 */
 +	protected function raisePostBackEvent()
 +	{
 +		if(($postBackHandler=$this->getPostBackEventTarget())===null)
 +			$this->validate();
 +		else if($postBackHandler instanceof IPostBackEventHandler)
 +			$postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
 +	}
 +
 +	/**
 +	 * @return boolean Whether form rendering is in progress
 +	 */
 +	public function getInFormRender()
 +	{
 +		return $this->_inFormRender;
 +	}
 +
 +	/**
 +	 * Ensures the control is rendered within a form.
 +	 * @param TControl the control to be rendered
 +	 * @throws TConfigurationException if the control is outside of the form
 +	 */
 +	public function ensureRenderInForm($control)
 +	{
 +		if(!$this->getIsCallback() && !$this->_inFormRender)
 +			throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
 +	}
 +
 +	/**
 +	 * @internal This method is invoked by TForm at the beginning of its rendering
 +	 */
 +	public function beginFormRender($writer)
 +	{
 +		if($this->_formRendered)
 +			throw new TConfigurationException('page_form_duplicated');
 +		$this->_formRendered=true;
 +		$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
 +		$this->_inFormRender=true;
 +	}
 +
 +	/**
 +	 * @internal This method is invoked by TForm  at the end of its rendering
 +	 */
 +	public function endFormRender($writer)
 +	{
 +		if($this->_focus)
 +		{
 +			if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
 +				$focus=$this->_focus->getClientID();
 +			else
 +				$focus=$this->_focus;
 +			$this->getClientScript()->registerFocusControl($focus);
 +		}
 +		else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
 +			$this->getClientScript()->registerFocusControl($lastFocus);
 +		$this->_inFormRender=false;
 +	}
 +
 +	/**
 +	 * Sets input focus on a control after the page is rendered to users.
 +	 * @param TControl|string control to receive focus, or the ID of the element on the page to receive focus
 +	 */
 +	public function setFocus($value)
 +	{
 +		$this->_focus=$value;
 +	}
 +
 +	/**
 +	 * @return boolean whether client supports javascript. Defaults to true.
 +	 */
 +	public function getClientSupportsJavaScript()
 +	{
 +		return $this->_enableJavaScript;
 +	}
 +
 +	/**
 +	 * @param boolean whether client supports javascript. If false, javascript will not be generated for controls.
 +	 */
 +	public function setClientSupportsJavaScript($value)
 +	{
 +		$this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
 +	}
 +
 +	/**
 +	 * @return THead page head, null if not available
 +	 */
 +	public function getHead()
 +	{
 +		return $this->_head;
 +	}
 +
 +	/**
 +	 * @param THead page head
 +	 * @throws TInvalidOperationException if a head already exists
 +	 */
 +	public function setHead(THead $value)
 +	{
 +		if($this->_head)
 +			throw new TInvalidOperationException('page_head_duplicated');
 +		$this->_head=$value;
 +		if($this->_title!==null)
 +		{
 +			$this->_head->setTitle($this->_title);
 +			$this->_title=null;
 +		}
 +	}
 +
 +	/**
 +	 * @return string page title.
 +	 */
 +	public function getTitle()
 +	{
 +		if($this->_head)
 +			return $this->_head->getTitle();
 +		else
 +			return $this->_title===null ? '' : $this->_title;
 +	}
 +
 +	/**
 +	 * Sets the page title.
 +	 * Note, a {@link THead} control needs to place on the page
 +	 * in order that this title be rendered.
 +	 * @param string page title. This will override the title set in {@link getHead Head}.
 +	 */
 +	public function setTitle($value)
 +	{
 +		if($this->_head)
 +			$this->_head->setTitle($value);
 +		else
 +			$this->_title=$value;
 +	}
 +
 +	/**
 +	 * Returns the state to be stored on the client side.
 +	 * This method should only be used by framework and control developers.
 +	 * @return string the state to be stored on the client side
 +	 */
 +	public function getClientState()
 +	{
 +		return $this->_clientState;
 +	}
 +
 +	/**
 +	 * Sets the state to be stored on the client side.
 +	 * This method should only be used by framework and control developers.
 +	 * @param string the state to be stored on the client side
 +	 */
 +	public function setClientState($state)
 +	{
 +		$this->_clientState=$state;
 +	}
 +
 +	/**
 +	 * @return string the state postback from client side
 +	 */
 +	public function getRequestClientState()
 +	{
 +		return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
 +	}
 +
 +	/**
 +	 * @return string class name of the page state persister. Defaults to TPageStatePersister.
 +	 */
 +	public function getStatePersisterClass()
 +	{
 +		return $this->_statePersisterClass;
 +	}
 +
 +	/**
 +	 * @param string class name of the page state persister.
 +	 */
 +	public function setStatePersisterClass($value)
 +	{
 +		$this->_statePersisterClass=$value;
 +	}
 +
 +	/**
 +	 * @return IPageStatePersister page state persister
 +	 */
 +	public function getStatePersister()
 +	{
 +		if($this->_statePersister===null)
 +		{
 +			$this->_statePersister=Prado::createComponent($this->_statePersisterClass);
 +			if(!($this->_statePersister instanceof IPageStatePersister))
 +				throw new TInvalidDataTypeException('page_statepersister_invalid');
 +			$this->_statePersister->setPage($this);
 +		}
 +		return $this->_statePersister;
 +	}
 +
 +	/**
 +	 * @return boolean whether page state should be HMAC validated. Defaults to true.
 +	 */
 +	public function getEnableStateValidation()
 +	{
 +		return $this->_enableStateValidation;
 +	}
 +
 +	/**
 +	 * @param boolean whether page state should be HMAC validated.
 +	 */
 +	public function setEnableStateValidation($value)
 +	{
 +		$this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
 +	}
 +
 +	/**
 +	 * @return boolean whether page state should be encrypted. Defaults to false.
 +	 */
 +	public function getEnableStateEncryption()
 +	{
 +		return $this->_enableStateEncryption;
 +	}
 +
 +	/**
 +	 * @param boolean whether page state should be encrypted.
 +	 */
 +	public function setEnableStateEncryption($value)
 +	{
 +		$this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
 +	}
 +
 +	/**
 +	 * @return boolean whether page state should be compressed. Defaults to true.
 +	 * @since 3.1.6
 +	 */
 +	public function getEnableStateCompression()
 +	{
 +		return $this->_enableStateCompression;
 +	}
 +
 +	/**
 +	 * @param boolean whether page state should be compressed.
 +	 * @since 3.1.6
 +	 */
 +	public function setEnableStateCompression($value)
 +	{
 +		$this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
 +	}
 +
 +	/**
 +	 * @return string the requested page path for this page
 +	 */
 +	public function getPagePath()
 +	{
 +		return $this->_pagePath;
 +	}
 +
 +	/**
 +	 * @param string the requested page path for this page
 +	 */
 +	public function setPagePath($value)
 +	{
 +		$this->_pagePath=$value;
 +	}
 +
 +	/**
 +	 * Registers an action associated with the content being cached.
 +	 * The registered action will be replayed if the content stored
 +	 * in the cache is served to end-users.
 +	 * @param string context of the action method. This is a property-path
 +	 * referring to the context object (e.g. Page, Page.ClientScript).
 +	 * @param string method name of the context object
 +	 * @param array list of parameters to be passed to the action method
 +	 */
 +	public function registerCachingAction($context,$funcName,$funcParams)
 +	{
 +		if($this->_cachingStack)
 +		{
 +			foreach($this->_cachingStack as $cache)
 +				$cache->registerAction($context,$funcName,$funcParams);
 +		}
 +	}
 +
 +	/**
 +	 * @return TStack stack of {@link TOutputCache} objects
 +	 */
 +	public function getCachingStack()
 +	{
 +		if(!$this->_cachingStack)
 +			$this->_cachingStack=new TStack;
 +		return $this->_cachingStack;
 +	}
 +
 +	/**
 +	 * Flushes output
 +	 */
 +	public function flushWriter()
 +	{
 +		if ($this->_writer)
 +			$this->Response->write($this->_writer->flush());
 +	}
 +        
 +        /**
 +         * Function to update view controls with data in a given AR object.
 +         * View controls and AR object need to have the same name in IDs and Attrs respectively.
 +         * @param TActiveRecord $arObj
 +         * @param Boolean $throwExceptions Wheter or not to throw exceptions
 +         * @author Daniel Sampedro <darthdaniel85@gmail.com>
 +         */
 +        public function tryToUpdateView($arObj, $throwExceptions = false)
 +        {
 +                $objAttrs = get_class_vars(get_class($arObj));
 +                foreach (array_keys($objAttrs) as $key)
 +                {
 +                        try
 +                        {
 +                                if ($key != "RELATIONS")
 +                                {
 +                                        $control = $this->{$key};
 +                                        if ($control instanceof TTextBox)
 +                                                $control->Text = $arObj->{$key};
 +                                        elseif ($control instanceof TCheckBox)
 +                                                $control->Checked = (boolean) $arObj->{$key};
 +                                        elseif ($control instanceof TDatePicker)
 +                                                $control->Date = $arObj->{$key};
 +                                }
 +                                else
 +                                {
 +                                        foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
 +                                        {
 +                                                $relControl = $this->{$relKey};
 +                                                switch ($relValues[0])
 +                                                {
 +                                                        case TActiveRecord::BELONGS_TO:
 +                                                        case TActiveRecord::HAS_ONE:
 +                                                                $relControl->Text = $arObj->{$relKey};
 +                                                                break;
 +                                                        case TActiveRecord::HAS_MANY:
 +                                                                if ($relControl instanceof TListControl)
 +                                                                {
 +                                                                        $relControl->DataSource = $arObj->{$relKey};
 +                                                                        $relControl->dataBind();
 +                                                                }
 +                                                                break;
 +                                                }
 +                                        }
 +                                        break;
 +                                }
 +                        } catch (Exception $ex)
 +                        {
 +                                if ($throwExceptions)
 +                                        throw $ex;
 +                        }
 +                }
 +        }
 +
 +        /**
 +         * Function to try to update an AR object with data in view controls.
 +         * @param TActiveRecord $arObj
 +         * @param Boolean $throwExceptions Wheter or not to throw exceptions
 +         * @author Daniel Sampedro <darthdaniel85@gmail.com>
 +         */
 +        public function tryToUpdateAR($arObj, $throwExceptions = false)
 +        {
 +                $objAttrs = get_class_vars(get_class($arObj));
 +                foreach (array_keys($objAttrs) as $key)
 +                {
 +                        try
 +                        {
 +                                if ($key == "RELATIONS")
 +                                        break;
 +                                $control = $this->{$key};
 +                                if ($control instanceof TTextBox)
 +                                        $arObj->{$key} = $control->Text;
 +                                elseif ($control instanceof TCheckBox)
 +                                        $arObj->{$key} = $control->Checked;
 +                                elseif ($control instanceof TDatePicker)
 +                                        $arObj->{$key} = $control->Date;
 +                        } catch (Exception $ex)
 +                        {
 +                                if ($throwExceptions)
 +                                        throw $ex;
 +                        }
 +                }
 +        }
 +
 +}
 +
 +/**
 + * IPageStatePersister interface.
 + *
 + * IPageStatePersister interface is required for all page state persister
 + * classes.
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @package System.Web.UI
 + * @since 3.1
 + */
 +interface IPageStatePersister
 +{
 +	/**
 +	 * @param TPage the page that this persister works for
 +	 */
 +	public function getPage();
 +	/**
 +	 * @param TPage the page that this persister works for
 +	 */
 +	public function setPage(TPage $page);
 +	/**
 +	 * Saves state to persistent storage.
 +	 * @param mixed state to be stored
 +	 */
 +	public function save($state);
 +	/**
 +	 * Loads page state from persistent storage
 +	 * @return mixed the restored state
 +	 */
 +	public function load();
 +}
 +
 +
 +/**
 + * TPageStateFormatter class.
 + *
 + * TPageStateFormatter is a utility class to transform the page state
 + * into and from a string that can be properly saved in persistent storage.
 + *
 + * Depending on the {@link TPage::getEnableStateValidation() EnableStateValidation}
 + * and {@link TPage::getEnableStateEncryption() EnableStateEncryption},
 + * TPageStateFormatter may do HMAC validation and encryption to prevent
 + * the state data from being tampered or viewed.
 + * The private keys and hashing/encryption methods are determined by
 + * {@link TApplication::getSecurityManager() SecurityManager}.
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @version $Revision: $  $Date: $
 + * @package System.Web.UI
 + * @since 3.1
 + */
 +class TPageStateFormatter
 +{
 +	/**
 +	 * @param TPage
 +	 * @param mixed state data
 +	 * @return string serialized data
 +	 */
 +	public static function serialize($page,$data)
 +	{
 +		$sm=$page->getApplication()->getSecurityManager();
 +		if($page->getEnableStateValidation())
 +			$str=$sm->hashData(serialize($data));
 +		else
 +			$str=serialize($data);
 +		if($page->getEnableStateCompression() && extension_loaded('zlib'))
 +			$str=gzcompress($str);
 +		if($page->getEnableStateEncryption())
 +			$str=$sm->encrypt($str);
 +		return base64_encode($str);
 +	}
 +
 +	/**
 +	 * @param TPage
 +	 * @param string serialized data
 +	 * @return mixed unserialized state data, null if data is corrupted
 +	 */
 +	public static function unserialize($page,$data)
 +	{
 +		$str=base64_decode($data);
 +		if($str==='')
 +			return null;
 +		if($str!==false)
 +		{
 +			$sm=$page->getApplication()->getSecurityManager();
 +			if($page->getEnableStateEncryption())
 +				$str=$sm->decrypt($str);
 +			if($page->getEnableStateCompression() && extension_loaded('zlib'))
 +				$str=@gzuncompress($str);
 +			if($page->getEnableStateValidation())
 +			{
 +				if(($str=$sm->validateData($str))!==false)
 +					return unserialize($str);
 +			}
 +			else
 +				return unserialize($str);
 +		}
 +		return null;
 +	}
 +}
 | 
