diff options
Diffstat (limited to 'framework')
| -rw-r--r-- | framework/Web/UI/TPage.php | 2802 | 
1 files changed, 1401 insertions, 1401 deletions
| diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php index e46ee9f5..903711e4 100644 --- a/framework/Web/UI/TPage.php +++ b/framework/Web/UI/TPage.php @@ -1,1401 +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
 -         * @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;
 -	}
 -}
 +<?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; +	} +} | 
