From f6b22febb41b3f552e36d5d0190ce8672b4d6d6e Mon Sep 17 00:00:00 2001 From: Fabio Bas Date: Tue, 20 Jan 2015 22:54:21 +0100 Subject: one class per file: framework/Web/UI/*.php --- framework/Web/UI/IBroadcastEventReceiver.php | 33 + framework/Web/UI/IButtonControl.php | 96 +++ framework/Web/UI/INamingContainer.php | 22 + framework/Web/UI/IPageStatePersister.php | 42 + framework/Web/UI/IPostBackDataHandler.php | 42 + framework/Web/UI/IPostBackEventHandler.php | 30 + framework/Web/UI/ISurroundable.php | 27 + framework/Web/UI/ITemplate.php | 31 + framework/Web/UI/ITheme.php | 28 + framework/Web/UI/IValidatable.php | 36 + framework/Web/UI/IValidator.php | 47 ++ framework/Web/UI/TBroadcastEventParameter.php | 71 ++ framework/Web/UI/TClientScriptManager.php | 74 -- framework/Web/UI/TClientSideOptions.php | 84 ++ framework/Web/UI/TCommandEventParameter.php | 55 ++ framework/Web/UI/TCompositeLiteral.php | 108 +++ framework/Web/UI/TControl.php | 618 +------------- framework/Web/UI/TControlCollection.php | 95 +++ framework/Web/UI/TEmptyControlCollection.php | 44 + framework/Web/UI/TPage.php | 103 +-- framework/Web/UI/TPageStateFormatter.php | 79 ++ framework/Web/UI/TTemplate.php | 950 ++++++++++++++++++++++ framework/Web/UI/TTemplateManager.php | 1072 ------------------------- framework/Web/UI/TTheme.php | 339 ++++++++ framework/Web/UI/TThemeManager.php | 513 ------------ 25 files changed, 2261 insertions(+), 2378 deletions(-) create mode 100644 framework/Web/UI/IBroadcastEventReceiver.php create mode 100644 framework/Web/UI/IButtonControl.php create mode 100644 framework/Web/UI/INamingContainer.php create mode 100644 framework/Web/UI/IPageStatePersister.php create mode 100644 framework/Web/UI/IPostBackDataHandler.php create mode 100644 framework/Web/UI/IPostBackEventHandler.php create mode 100644 framework/Web/UI/ISurroundable.php create mode 100644 framework/Web/UI/ITemplate.php create mode 100644 framework/Web/UI/ITheme.php create mode 100644 framework/Web/UI/IValidatable.php create mode 100644 framework/Web/UI/IValidator.php create mode 100644 framework/Web/UI/TBroadcastEventParameter.php create mode 100644 framework/Web/UI/TClientSideOptions.php create mode 100644 framework/Web/UI/TCommandEventParameter.php create mode 100644 framework/Web/UI/TCompositeLiteral.php create mode 100644 framework/Web/UI/TControlCollection.php create mode 100644 framework/Web/UI/TEmptyControlCollection.php create mode 100644 framework/Web/UI/TPageStateFormatter.php create mode 100644 framework/Web/UI/TTemplate.php delete mode 100644 framework/Web/UI/TTemplateManager.php create mode 100644 framework/Web/UI/TTheme.php delete mode 100644 framework/Web/UI/TThemeManager.php (limited to 'framework/Web') diff --git a/framework/Web/UI/IBroadcastEventReceiver.php b/framework/Web/UI/IBroadcastEventReceiver.php new file mode 100644 index 00000000..d0d86e8e --- /dev/null +++ b/framework/Web/UI/IBroadcastEventReceiver.php @@ -0,0 +1,33 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * IBroadcastEventReceiver interface + * + * If a control wants to check broadcast event, it must implement this interface. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +interface IBroadcastEventReceiver +{ + /** + * Handles broadcast event. + * This method is invoked automatically when an event is broadcasted. + * Within this method, you may check the event name given in + * the event parameter to determine whether you should respond to + * this event. + * @param TControl sender of the event + * @param TBroadCastEventParameter event parameter + */ + public function broadcastEventReceived($sender,$param); +} \ No newline at end of file diff --git a/framework/Web/UI/IButtonControl.php b/framework/Web/UI/IButtonControl.php new file mode 100644 index 00000000..146ab1da --- /dev/null +++ b/framework/Web/UI/IButtonControl.php @@ -0,0 +1,96 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * IButtonControl interface + * + * IButtonControl specifies the common properties and events that must + * be implemented by a button control, such as {@link TButton}, {@link TLinkButton}, + * {@link TImageButton}. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +interface IButtonControl +{ + /** + * @return string caption of the button + */ + public function getText(); + + /** + * @param string caption of the button + */ + public function setText($value); + + /** + * @return boolean whether postback event trigger by this button will cause input validation + */ + public function getCausesValidation(); + + /** + * @param boolean whether postback event trigger by this button will cause input validation + */ + public function setCausesValidation($value); + + /** + * @return string the command name associated with the {@link onCommand OnCommand} event. + */ + public function getCommandName(); + + /** + * @param string the command name associated with the {@link onCommand OnCommand} event. + */ + public function setCommandName($value); + + /** + * @return string the parameter associated with the {@link onCommand OnCommand} event + */ + public function getCommandParameter(); + + /** + * @param string the parameter associated with the {@link onCommand OnCommand} event. + */ + public function setCommandParameter($value); + + /** + * @return string the group of validators which the button causes validation upon postback + */ + public function getValidationGroup(); + + /** + * @param string the group of validators which the button causes validation upon postback + */ + public function setValidationGroup($value); + + /** + * Raises OnClick event. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onClick($param); + + /** + * Raises OnCommand event. + * @param TCommandEventParameter event parameter to be passed to the event handlers + */ + public function onCommand($param); + + /** + * @param boolean set by a panel to register this button as the default button for the panel. + */ + public function setIsDefaultButton($value); + + /** + * @return boolean true if this button is registered as a default button for a panel. + */ + public function getIsDefaultButton(); +} \ No newline at end of file diff --git a/framework/Web/UI/INamingContainer.php b/framework/Web/UI/INamingContainer.php new file mode 100644 index 00000000..dd2634c0 --- /dev/null +++ b/framework/Web/UI/INamingContainer.php @@ -0,0 +1,22 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * INamingContainer interface. + * INamingContainer marks a control as a naming container. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +interface INamingContainer +{ +} \ No newline at end of file diff --git a/framework/Web/UI/IPageStatePersister.php b/framework/Web/UI/IPageStatePersister.php new file mode 100644 index 00000000..e1c4e8b1 --- /dev/null +++ b/framework/Web/UI/IPageStatePersister.php @@ -0,0 +1,42 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * IPageStatePersister interface. + * + * IPageStatePersister interface is required for all page state persister + * classes. + * + * @author Qiang Xue + * @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(); +} \ No newline at end of file diff --git a/framework/Web/UI/IPostBackDataHandler.php b/framework/Web/UI/IPostBackDataHandler.php new file mode 100644 index 00000000..77da5080 --- /dev/null +++ b/framework/Web/UI/IPostBackDataHandler.php @@ -0,0 +1,42 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * IPostBackDataHandler interface + * + * If a control wants to load post data, it must implement this interface. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +interface IPostBackDataHandler +{ + /** + * Loads user input data. + * The implementation of this function can use $values[$key] to get the user input + * data that are meant for the particular control. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the control has been changed + */ + public function loadPostData($key,$values); + /** + * Raises postdata changed event. + * The implementation of this function should raise appropriate event(s) (e.g. OnTextChanged) + * indicating the control data is changed. + */ + public function raisePostDataChangedEvent(); + /** + * @return boolean whether postback causes the data change. Defaults to false for non-postback state. + */ + public function getDataChanged(); +} \ No newline at end of file diff --git a/framework/Web/UI/IPostBackEventHandler.php b/framework/Web/UI/IPostBackEventHandler.php new file mode 100644 index 00000000..9ab2cb94 --- /dev/null +++ b/framework/Web/UI/IPostBackEventHandler.php @@ -0,0 +1,30 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * IPostBackEventHandler interface + * + * If a control wants to respond to postback event, it must implement this interface. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +interface IPostBackEventHandler +{ + /** + * Raises postback event. + * The implementation of this function should raise appropriate event(s) (e.g. OnClick, OnCommand) + * indicating the component is responsible for the postback event. + * @param string the parameter associated with the postback event + */ + public function raisePostBackEvent($param); +} \ No newline at end of file diff --git a/framework/Web/UI/ISurroundable.php b/framework/Web/UI/ISurroundable.php new file mode 100644 index 00000000..42be16bb --- /dev/null +++ b/framework/Web/UI/ISurroundable.php @@ -0,0 +1,27 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * ISurroundable interface + * + * Identifies controls that may create an additional surrounding tag. The id of the + * tag can be obtained with {@link getSurroundingTagID}. + * + * @package System.Web.UI + * @since 3.1.2 + */ +interface ISurroundable +{ + /** + * @return string the id of the embedding tag of the control or the control's clientID if not surrounded + */ + public function getSurroundingTagID(); +} \ No newline at end of file diff --git a/framework/Web/UI/ITemplate.php b/framework/Web/UI/ITemplate.php new file mode 100644 index 00000000..91701aab --- /dev/null +++ b/framework/Web/UI/ITemplate.php @@ -0,0 +1,31 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * ITemplate interface + * + * ITemplate specifies the interface for classes encapsulating + * parsed template structures. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +interface ITemplate +{ + /** + * Instantiates the template. + * Content in the template will be instantiated as components and text strings + * and passed to the specified parent control. + * @param TControl the parent control + */ + public function instantiateIn($parent); +} \ No newline at end of file diff --git a/framework/Web/UI/ITheme.php b/framework/Web/UI/ITheme.php new file mode 100644 index 00000000..af9452b1 --- /dev/null +++ b/framework/Web/UI/ITheme.php @@ -0,0 +1,28 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * ITheme interface. + * + * This interface must be implemented by theme. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +interface ITheme +{ + /** + * Applies this theme to the specified control. + * @param TControl the control to be applied with this theme + */ + public function applySkin($control); +} \ No newline at end of file diff --git a/framework/Web/UI/IValidatable.php b/framework/Web/UI/IValidatable.php new file mode 100644 index 00000000..5b8967e5 --- /dev/null +++ b/framework/Web/UI/IValidatable.php @@ -0,0 +1,36 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + + +/** + * IValidatable interface + * + * If a control wants to be validated by a validator, it must implement this interface. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +interface IValidatable +{ + /** + * @return mixed the value of the property to be validated. + */ + public function getValidationPropertyValue(); + /** + * @return boolean wether this control's validators validated successfully (must default to true) + */ + public function getIsValid(); + /** + * @return boolean wether this control's validators validated successfully + */ + public function setIsValid($value); +} \ No newline at end of file diff --git a/framework/Web/UI/IValidator.php b/framework/Web/UI/IValidator.php new file mode 100644 index 00000000..d6e43146 --- /dev/null +++ b/framework/Web/UI/IValidator.php @@ -0,0 +1,47 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + + +/** + * IValidator interface + * + * If a control wants to validate user input, it must implement this interface. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +interface IValidator +{ + /** + * Validates certain data. + * The implementation of this function should validate certain data + * (e.g. data entered into TTextBox control). + * @return boolean whether the data passes the validation + */ + public function validate(); + /** + * @return boolean whether the previous {@link validate()} is successful. + */ + public function getIsValid(); + /** + * @param boolean whether the validator validates successfully + */ + public function setIsValid($value); + /** + * @return string error message during last validate + */ + public function getErrorMessage(); + /** + * @param string error message for the validation + */ + public function setErrorMessage($value); +} \ No newline at end of file diff --git a/framework/Web/UI/TBroadcastEventParameter.php b/framework/Web/UI/TBroadcastEventParameter.php new file mode 100644 index 00000000..72cb4d82 --- /dev/null +++ b/framework/Web/UI/TBroadcastEventParameter.php @@ -0,0 +1,71 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * TBroadcastEventParameter class + * + * TBroadcastEventParameter encapsulates the parameter data for + * events that are broadcasted. The name of of the event is specified via + * {@link setName Name} property while the event parameter is via + * {@link setParameter Parameter} property. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +class TBroadcastEventParameter extends TEventParameter +{ + private $_name; + private $_param; + + /** + * Constructor. + * @param string name of the broadcast event + * @param mixed parameter of the broadcast event + */ + public function __construct($name='',$parameter=null) + { + $this->_name=$name; + $this->_param=$parameter; + } + + /** + * @return string name of the broadcast event + */ + public function getName() + { + return $this->_name; + } + + /** + * @param string name of the broadcast event + */ + public function setName($value) + { + $this->_name=$value; + } + + /** + * @return mixed parameter of the broadcast event + */ + public function getParameter() + { + return $this->_param; + } + + /** + * @param mixed parameter of the broadcast event + */ + public function setParameter($value) + { + $this->_param=$value; + } +} \ No newline at end of file diff --git a/framework/Web/UI/TClientScriptManager.php b/framework/Web/UI/TClientScriptManager.php index 937bd84e..0bd96ab9 100644 --- a/framework/Web/UI/TClientScriptManager.php +++ b/framework/Web/UI/TClientScriptManager.php @@ -773,77 +773,3 @@ class TClientScriptManager extends TApplicationComponent throw new Exception('Operation invalid when page is already rendering'); } } - -/** - * TClientSideOptions abstract class. - * - * TClientSideOptions manages client-side options for components that have - * common client-side javascript behaviours and client-side events such as - * between ActiveControls and validators. - * - * @author - * @package System.Web.UI - * @since 3.0 - */ -abstract class TClientSideOptions extends TComponent -{ - /** - * @var TMap list of client-side options. - */ - private $_options; - - /** - * Adds on client-side event handler by wrapping the code within a - * javascript function block. If the code begins with "javascript:", the - * code is assumed to be a javascript function block rather than arbiturary - * javascript statements. - * @param string option name - * @param string javascript statements. - */ - protected function setFunction($name, $code) - { - if(!TJavaScript::isJsLiteral($code)) - $code = TJavaScript::quoteJsLiteral($this->ensureFunction($code)); - $this->setOption($name, $code); - } - - /** - * @return string gets a particular option, null if not set. - */ - protected function getOption($name) - { - if ($this->_options) - return $this->_options->itemAt($name); - else - return null; - } - - /** - * @param string option name - * @param mixed option value. - */ - protected function setOption($name, $value) - { - $this->getOptions()->add($name, $value); - } - - /** - * @return TMap gets the list of options as TMap - */ - public function getOptions() - { - if (!$this->_options) - $this->_options = Prado::createComponent('System.Collections.TMap'); - return $this->_options; - } - - /** - * Ensure that the javascript statements are wrapped in a javascript - * function block as function(sender, parameter){ //code }. - */ - protected function ensureFunction($javascript) - { - return "function(sender, parameter){ {$javascript} }"; - } -} - diff --git a/framework/Web/UI/TClientSideOptions.php b/framework/Web/UI/TClientSideOptions.php new file mode 100644 index 00000000..180e1025 --- /dev/null +++ b/framework/Web/UI/TClientSideOptions.php @@ -0,0 +1,84 @@ + + * @author Gabor Berczi (lazyload additions & progressive rendering) + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * TClientSideOptions abstract class. + * + * TClientSideOptions manages client-side options for components that have + * common client-side javascript behaviours and client-side events such as + * between ActiveControls and validators. + * + * @author + * @package System.Web.UI + * @since 3.0 + */ +abstract class TClientSideOptions extends TComponent +{ + /** + * @var TMap list of client-side options. + */ + private $_options; + + /** + * Adds on client-side event handler by wrapping the code within a + * javascript function block. If the code begins with "javascript:", the + * code is assumed to be a javascript function block rather than arbiturary + * javascript statements. + * @param string option name + * @param string javascript statements. + */ + protected function setFunction($name, $code) + { + if(!TJavaScript::isJsLiteral($code)) + $code = TJavaScript::quoteJsLiteral($this->ensureFunction($code)); + $this->setOption($name, $code); + } + + /** + * @return string gets a particular option, null if not set. + */ + protected function getOption($name) + { + if ($this->_options) + return $this->_options->itemAt($name); + else + return null; + } + + /** + * @param string option name + * @param mixed option value. + */ + protected function setOption($name, $value) + { + $this->getOptions()->add($name, $value); + } + + /** + * @return TMap gets the list of options as TMap + */ + public function getOptions() + { + if (!$this->_options) + $this->_options = Prado::createComponent('System.Collections.TMap'); + return $this->_options; + } + + /** + * Ensure that the javascript statements are wrapped in a javascript + * function block as function(sender, parameter){ //code }. + */ + protected function ensureFunction($javascript) + { + return "function(sender, parameter){ {$javascript} }"; + } +} diff --git a/framework/Web/UI/TCommandEventParameter.php b/framework/Web/UI/TCommandEventParameter.php new file mode 100644 index 00000000..4357ce8e --- /dev/null +++ b/framework/Web/UI/TCommandEventParameter.php @@ -0,0 +1,55 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * TCommandEventParameter class + * + * TCommandEventParameter encapsulates the parameter data for Command + * event of button controls. You can access the name of the command via + * {@link getCommandName CommandName} property, and the parameter carried + * with the command via {@link getCommandParameter CommandParameter} property. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +class TCommandEventParameter extends TEventParameter +{ + private $_name; + private $_param; + + /** + * Constructor. + * @param string name of the command + * @param string parameter of the command + */ + public function __construct($name='',$parameter='') + { + $this->_name=$name; + $this->_param=$parameter; + } + + /** + * @return string name of the command + */ + public function getCommandName() + { + return $this->_name; + } + + /** + * @return string parameter of the command + */ + public function getCommandParameter() + { + return $this->_param; + } +} \ No newline at end of file diff --git a/framework/Web/UI/TCompositeLiteral.php b/framework/Web/UI/TCompositeLiteral.php new file mode 100644 index 00000000..d9af1174 --- /dev/null +++ b/framework/Web/UI/TCompositeLiteral.php @@ -0,0 +1,108 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + + +/** + * TCompositeLiteral class + * + * TCompositeLiteral is used internally by {@link TTemplate} for representing + * consecutive static strings, expressions and statements. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +class TCompositeLiteral extends TComponent implements IRenderable, IBindable +{ + const TYPE_EXPRESSION=0; + const TYPE_STATEMENTS=1; + const TYPE_DATABINDING=2; + private $_container=null; + private $_items=array(); + private $_expressions=array(); + private $_statements=array(); + private $_bindings=array(); + + /** + * Constructor. + * @param array list of items to be represented by TCompositeLiteral + */ + public function __construct($items) + { + $this->_items=array(); + $this->_expressions=array(); + $this->_statements=array(); + foreach($items as $id=>$item) + { + if(is_array($item)) + { + if($item[0]===self::TYPE_EXPRESSION) + $this->_expressions[$id]=$item[1]; + else if($item[0]===self::TYPE_STATEMENTS) + $this->_statements[$id]=$item[1]; + else if($item[0]===self::TYPE_DATABINDING) + $this->_bindings[$id]=$item[1]; + $this->_items[$id]=''; + } + else + $this->_items[$id]=$item; + } + } + + /** + * @return TComponent container of this component. It serves as the evaluation context of expressions and statements. + */ + public function getContainer() + { + return $this->_container; + } + + /** + * @param TComponent container of this component. It serves as the evaluation context of expressions and statements. + */ + public function setContainer(TComponent $value) + { + $this->_container=$value; + } + + /** + * Evaluates the expressions and/or statements in the component. + */ + public function evaluateDynamicContent() + { + $context=$this->_container===null?$this:$this->_container; + foreach($this->_expressions as $id=>$expression) + $this->_items[$id]=$context->evaluateExpression($expression); + foreach($this->_statements as $id=>$statement) + $this->_items[$id]=$context->evaluateStatements($statement); + } + + /** + * Performs databindings. + * This method is required by {@link IBindable} + */ + public function dataBind() + { + $context=$this->_container===null?$this:$this->_container; + foreach($this->_bindings as $id=>$binding) + $this->_items[$id]=$context->evaluateExpression($binding); + } + + /** + * Renders the content stored in this component. + * This method is required by {@link IRenderable} + * @param ITextWriter + */ + public function render($writer) + { + $writer->write(implode('',$this->_items)); + } +} \ No newline at end of file diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php index e5e6fa18..e32fb371 100644 --- a/framework/Web/UI/TControl.php +++ b/framework/Web/UI/TControl.php @@ -1749,620 +1749,4 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable } } } -} - - -/** - * TControlCollection class - * - * TControlCollection implements a collection that enables - * controls to maintain a list of their child controls. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -class TControlCollection extends TList -{ - /** - * the control that owns this collection. - * @var TControl - */ - private $_o; - - /** - * Constructor. - * @param TControl the control that owns this collection. - * @param boolean whether the list is read-only - */ - public function __construct(TControl $owner,$readOnly=false) - { - $this->_o=$owner; - parent::__construct(null,$readOnly); - } - - /** - * @return TControl the control that owns this collection. - */ - protected function getOwner() - { - return $this->_o; - } - - /** - * Inserts an item at the specified position. - * This overrides the parent implementation by performing additional - * operations for each newly added child control. - * @param integer the speicified position. - * @param mixed new item - * @throws TInvalidDataTypeException if the item to be inserted is neither a string nor a TControl. - */ - public function insertAt($index,$item) - { - if($item instanceof TControl) - { - parent::insertAt($index,$item); - $this->_o->addedControl($item); - } - else if(is_string($item) || ($item instanceof IRenderable)) - parent::insertAt($index,$item); - else - throw new TInvalidDataTypeException('controlcollection_control_required'); - } - - /** - * Removes an item at the specified position. - * This overrides the parent implementation by performing additional - * cleanup work when removing a child control. - * @param integer the index of the item to be removed. - * @return mixed the removed item. - */ - public function removeAt($index) - { - $item=parent::removeAt($index); - if($item instanceof TControl) - $this->_o->removedControl($item); - return $item; - } - - /** - * Overrides the parent implementation by invoking {@link TControl::clearNamingContainer} - */ - public function clear() - { - parent::clear(); - if($this->_o instanceof INamingContainer) - $this->_o->clearNamingContainer(); - } -} - -/** - * TEmptyControlCollection class - * - * TEmptyControlCollection implements an empty control list that prohibits adding - * controls to it. This is useful for controls that do not allow child controls. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -class TEmptyControlCollection extends TControlCollection -{ - /** - * Constructor. - * @param TControl the control that owns this collection. - */ - public function __construct(TControl $owner) - { - parent::__construct($owner,true); - } - - /** - * Inserts an item at the specified position. - * This overrides the parent implementation by ignoring new addition. - * @param integer the speicified position. - * @param mixed new item - */ - public function insertAt($index,$item) - { - if(!is_string($item)) // string is possible if property tag is used. we simply ignore it in this case - parent::insertAt($index,$item); // this will generate an exception in parent implementation - } -} - -/** - * INamingContainer interface. - * INamingContainer marks a control as a naming container. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -interface INamingContainer -{ -} - -/** - * IPostBackEventHandler interface - * - * If a control wants to respond to postback event, it must implement this interface. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -interface IPostBackEventHandler -{ - /** - * Raises postback event. - * The implementation of this function should raise appropriate event(s) (e.g. OnClick, OnCommand) - * indicating the component is responsible for the postback event. - * @param string the parameter associated with the postback event - */ - public function raisePostBackEvent($param); -} - -/** - * IPostBackDataHandler interface - * - * If a control wants to load post data, it must implement this interface. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -interface IPostBackDataHandler -{ - /** - * Loads user input data. - * The implementation of this function can use $values[$key] to get the user input - * data that are meant for the particular control. - * @param string the key that can be used to retrieve data from the input data collection - * @param array the input data collection - * @return boolean whether the data of the control has been changed - */ - public function loadPostData($key,$values); - /** - * Raises postdata changed event. - * The implementation of this function should raise appropriate event(s) (e.g. OnTextChanged) - * indicating the control data is changed. - */ - public function raisePostDataChangedEvent(); - /** - * @return boolean whether postback causes the data change. Defaults to false for non-postback state. - */ - public function getDataChanged(); -} - - -/** - * IValidator interface - * - * If a control wants to validate user input, it must implement this interface. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -interface IValidator -{ - /** - * Validates certain data. - * The implementation of this function should validate certain data - * (e.g. data entered into TTextBox control). - * @return boolean whether the data passes the validation - */ - public function validate(); - /** - * @return boolean whether the previous {@link validate()} is successful. - */ - public function getIsValid(); - /** - * @param boolean whether the validator validates successfully - */ - public function setIsValid($value); - /** - * @return string error message during last validate - */ - public function getErrorMessage(); - /** - * @param string error message for the validation - */ - public function setErrorMessage($value); -} - - -/** - * IValidatable interface - * - * If a control wants to be validated by a validator, it must implement this interface. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -interface IValidatable -{ - /** - * @return mixed the value of the property to be validated. - */ - public function getValidationPropertyValue(); - /** - * @return boolean wether this control's validators validated successfully (must default to true) - */ - public function getIsValid(); - /** - * @return boolean wether this control's validators validated successfully - */ - public function setIsValid($value); -} - -/** - * IBroadcastEventReceiver interface - * - * If a control wants to check broadcast event, it must implement this interface. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -interface IBroadcastEventReceiver -{ - /** - * Handles broadcast event. - * This method is invoked automatically when an event is broadcasted. - * Within this method, you may check the event name given in - * the event parameter to determine whether you should respond to - * this event. - * @param TControl sender of the event - * @param TBroadCastEventParameter event parameter - */ - public function broadcastEventReceived($sender,$param); -} - -/** - * ITheme interface. - * - * This interface must be implemented by theme. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -interface ITheme -{ - /** - * Applies this theme to the specified control. - * @param TControl the control to be applied with this theme - */ - public function applySkin($control); -} - -/** - * ITemplate interface - * - * ITemplate specifies the interface for classes encapsulating - * parsed template structures. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -interface ITemplate -{ - /** - * Instantiates the template. - * Content in the template will be instantiated as components and text strings - * and passed to the specified parent control. - * @param TControl the parent control - */ - public function instantiateIn($parent); -} - -/** - * IButtonControl interface - * - * IButtonControl specifies the common properties and events that must - * be implemented by a button control, such as {@link TButton}, {@link TLinkButton}, - * {@link TImageButton}. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -interface IButtonControl -{ - /** - * @return string caption of the button - */ - public function getText(); - - /** - * @param string caption of the button - */ - public function setText($value); - - /** - * @return boolean whether postback event trigger by this button will cause input validation - */ - public function getCausesValidation(); - - /** - * @param boolean whether postback event trigger by this button will cause input validation - */ - public function setCausesValidation($value); - - /** - * @return string the command name associated with the {@link onCommand OnCommand} event. - */ - public function getCommandName(); - - /** - * @param string the command name associated with the {@link onCommand OnCommand} event. - */ - public function setCommandName($value); - - /** - * @return string the parameter associated with the {@link onCommand OnCommand} event - */ - public function getCommandParameter(); - - /** - * @param string the parameter associated with the {@link onCommand OnCommand} event. - */ - public function setCommandParameter($value); - - /** - * @return string the group of validators which the button causes validation upon postback - */ - public function getValidationGroup(); - - /** - * @param string the group of validators which the button causes validation upon postback - */ - public function setValidationGroup($value); - - /** - * Raises OnClick event. - * @param TEventParameter event parameter to be passed to the event handlers - */ - public function onClick($param); - - /** - * Raises OnCommand event. - * @param TCommandEventParameter event parameter to be passed to the event handlers - */ - public function onCommand($param); - - /** - * @param boolean set by a panel to register this button as the default button for the panel. - */ - public function setIsDefaultButton($value); - - /** - * @return boolean true if this button is registered as a default button for a panel. - */ - public function getIsDefaultButton(); -} - -/** - * ISurroundable interface - * - * Identifies controls that may create an additional surrounding tag. The id of the - * tag can be obtained with {@link getSurroundingTagID}. - * - * @package System.Web.UI - * @since 3.1.2 - */ -interface ISurroundable -{ - /** - * @return string the id of the embedding tag of the control or the control's clientID if not surrounded - */ - public function getSurroundingTagID(); -} - -/** - * TBroadcastEventParameter class - * - * TBroadcastEventParameter encapsulates the parameter data for - * events that are broadcasted. The name of of the event is specified via - * {@link setName Name} property while the event parameter is via - * {@link setParameter Parameter} property. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -class TBroadcastEventParameter extends TEventParameter -{ - private $_name; - private $_param; - - /** - * Constructor. - * @param string name of the broadcast event - * @param mixed parameter of the broadcast event - */ - public function __construct($name='',$parameter=null) - { - $this->_name=$name; - $this->_param=$parameter; - } - - /** - * @return string name of the broadcast event - */ - public function getName() - { - return $this->_name; - } - - /** - * @param string name of the broadcast event - */ - public function setName($value) - { - $this->_name=$value; - } - - /** - * @return mixed parameter of the broadcast event - */ - public function getParameter() - { - return $this->_param; - } - - /** - * @param mixed parameter of the broadcast event - */ - public function setParameter($value) - { - $this->_param=$value; - } -} - -/** - * TCommandEventParameter class - * - * TCommandEventParameter encapsulates the parameter data for Command - * event of button controls. You can access the name of the command via - * {@link getCommandName CommandName} property, and the parameter carried - * with the command via {@link getCommandParameter CommandParameter} property. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -class TCommandEventParameter extends TEventParameter -{ - private $_name; - private $_param; - - /** - * Constructor. - * @param string name of the command - * @param string parameter of the command - */ - public function __construct($name='',$parameter='') - { - $this->_name=$name; - $this->_param=$parameter; - } - - /** - * @return string name of the command - */ - public function getCommandName() - { - return $this->_name; - } - - /** - * @return string parameter of the command - */ - public function getCommandParameter() - { - return $this->_param; - } -} - - -/** - * TCompositeLiteral class - * - * TCompositeLiteral is used internally by {@link TTemplate} for representing - * consecutive static strings, expressions and statements. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -class TCompositeLiteral extends TComponent implements IRenderable, IBindable -{ - const TYPE_EXPRESSION=0; - const TYPE_STATEMENTS=1; - const TYPE_DATABINDING=2; - private $_container=null; - private $_items=array(); - private $_expressions=array(); - private $_statements=array(); - private $_bindings=array(); - - /** - * Constructor. - * @param array list of items to be represented by TCompositeLiteral - */ - public function __construct($items) - { - $this->_items=array(); - $this->_expressions=array(); - $this->_statements=array(); - foreach($items as $id=>$item) - { - if(is_array($item)) - { - if($item[0]===self::TYPE_EXPRESSION) - $this->_expressions[$id]=$item[1]; - else if($item[0]===self::TYPE_STATEMENTS) - $this->_statements[$id]=$item[1]; - else if($item[0]===self::TYPE_DATABINDING) - $this->_bindings[$id]=$item[1]; - $this->_items[$id]=''; - } - else - $this->_items[$id]=$item; - } - } - - /** - * @return TComponent container of this component. It serves as the evaluation context of expressions and statements. - */ - public function getContainer() - { - return $this->_container; - } - - /** - * @param TComponent container of this component. It serves as the evaluation context of expressions and statements. - */ - public function setContainer(TComponent $value) - { - $this->_container=$value; - } - - /** - * Evaluates the expressions and/or statements in the component. - */ - public function evaluateDynamicContent() - { - $context=$this->_container===null?$this:$this->_container; - foreach($this->_expressions as $id=>$expression) - $this->_items[$id]=$context->evaluateExpression($expression); - foreach($this->_statements as $id=>$statement) - $this->_items[$id]=$context->evaluateStatements($statement); - } - - /** - * Performs databindings. - * This method is required by {@link IBindable} - */ - public function dataBind() - { - $context=$this->_container===null?$this:$this->_container; - foreach($this->_bindings as $id=>$binding) - $this->_items[$id]=$context->evaluateExpression($binding); - } - - /** - * Renders the content stored in this component. - * This method is required by {@link IRenderable} - * @param ITextWriter - */ - public function render($writer) - { - $writer->write(implode('',$this->_items)); - } -} - +} \ No newline at end of file diff --git a/framework/Web/UI/TControlCollection.php b/framework/Web/UI/TControlCollection.php new file mode 100644 index 00000000..9fc3cfad --- /dev/null +++ b/framework/Web/UI/TControlCollection.php @@ -0,0 +1,95 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + + +/** + * TControlCollection class + * + * TControlCollection implements a collection that enables + * controls to maintain a list of their child controls. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +class TControlCollection extends TList +{ + /** + * the control that owns this collection. + * @var TControl + */ + private $_o; + + /** + * Constructor. + * @param TControl the control that owns this collection. + * @param boolean whether the list is read-only + */ + public function __construct(TControl $owner,$readOnly=false) + { + $this->_o=$owner; + parent::__construct(null,$readOnly); + } + + /** + * @return TControl the control that owns this collection. + */ + protected function getOwner() + { + return $this->_o; + } + + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by performing additional + * operations for each newly added child control. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is neither a string nor a TControl. + */ + public function insertAt($index,$item) + { + if($item instanceof TControl) + { + parent::insertAt($index,$item); + $this->_o->addedControl($item); + } + else if(is_string($item) || ($item instanceof IRenderable)) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('controlcollection_control_required'); + } + + /** + * Removes an item at the specified position. + * This overrides the parent implementation by performing additional + * cleanup work when removing a child control. + * @param integer the index of the item to be removed. + * @return mixed the removed item. + */ + public function removeAt($index) + { + $item=parent::removeAt($index); + if($item instanceof TControl) + $this->_o->removedControl($item); + return $item; + } + + /** + * Overrides the parent implementation by invoking {@link TControl::clearNamingContainer} + */ + public function clear() + { + parent::clear(); + if($this->_o instanceof INamingContainer) + $this->_o->clearNamingContainer(); + } +} \ No newline at end of file diff --git a/framework/Web/UI/TEmptyControlCollection.php b/framework/Web/UI/TEmptyControlCollection.php new file mode 100644 index 00000000..22a2fff6 --- /dev/null +++ b/framework/Web/UI/TEmptyControlCollection.php @@ -0,0 +1,44 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * TEmptyControlCollection class + * + * TEmptyControlCollection implements an empty control list that prohibits adding + * controls to it. This is useful for controls that do not allow child controls. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +class TEmptyControlCollection extends TControlCollection +{ + /** + * Constructor. + * @param TControl the control that owns this collection. + */ + public function __construct(TControl $owner) + { + parent::__construct($owner,true); + } + + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by ignoring new addition. + * @param integer the speicified position. + * @param mixed new item + */ + public function insertAt($index,$item) + { + if(!is_string($item)) // string is possible if property tag is used. we simply ignore it in this case + parent::insertAt($index,$item); // this will generate an exception in parent implementation + } +} \ No newline at end of file diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php index 903711e4..2331d3fb 100644 --- a/framework/Web/UI/TPage.php +++ b/framework/Web/UI/TPage.php @@ -1297,105 +1297,4 @@ class TPage extends TTemplateControl } } -} - -/** - * IPageStatePersister interface. - * - * IPageStatePersister interface is required for all page state persister - * classes. - * - * @author Qiang Xue - * @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 - * @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; - } -} +} \ No newline at end of file diff --git a/framework/Web/UI/TPageStateFormatter.php b/framework/Web/UI/TPageStateFormatter.php new file mode 100644 index 00000000..77f3316d --- /dev/null +++ b/framework/Web/UI/TPageStateFormatter.php @@ -0,0 +1,79 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + + +/** + * 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 + * @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; + } +} \ No newline at end of file diff --git a/framework/Web/UI/TTemplate.php b/framework/Web/UI/TTemplate.php new file mode 100644 index 00000000..c90fab82 --- /dev/null +++ b/framework/Web/UI/TTemplate.php @@ -0,0 +1,950 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI + */ + +/** + * TTemplate implements PRADO template parsing logic. + * A TTemplate object represents a parsed PRADO control template. + * It can instantiate the template as child controls of a specified control. + * The template format is like HTML, with the following special tags introduced, + * - component tags: a component tag represents the configuration of a component. + * The tag name is in the format of com:ComponentType, where ComponentType is the component + * class name. Component tags must be well-formed. Attributes of the component tag + * are treated as either property initial values, event handler attachment, or regular + * tag attributes. + * - property tags: property tags are used to set large block of attribute values. + * The property tag name is in the format of where AttributeName + * can be a property name, an event name or a regular tag attribute name. + * - group subproperty tags: subproperties of a common property can be configured using + * + * - directive: directive specifies the property values for the template owner. + * It is in the format of <%@ property name-value pairs %>; + * - expressions: They are in the format of <%= PHP expression %> and <%% PHP statements %> + * - comments: There are two kinds of comments, regular HTML comments and special template comments. + * The former is in the format of , which will be treated as text strings. + * The latter is in the format of , which will be stripped out. + * + * Tags other than the above are not required to be well-formed. + * + * A TTemplate object represents a parsed PRADO template. To instantiate the template + * for a particular control, call {@link instantiateIn($control)}, which + * will create and intialize all components specified in the template and + * set their parent as $control. + * + * @author Qiang Xue + * @package System.Web.UI + * @since 3.0 + */ +class TTemplate extends TApplicationComponent implements ITemplate +{ + /** + * '' - template comments + * '' - HTML comments + * '<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>' - component tags + * '<\/?prop:([\w\.]+)\s*>' - property tags + * '<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>' - directives + * '<%[%#~\/\\$=\\[](.*?)%>' - expressions + * ')*)\s*\/>' - group subproperty tags + */ + const REGEX_RULES='/||<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|)*)\s*\/>/msS'; + + /** + * Different configurations of component property/event/attribute + */ + const CONFIG_DATABIND=0; + const CONFIG_EXPRESSION=1; + const CONFIG_ASSET=2; + const CONFIG_PARAMETER=3; + const CONFIG_LOCALIZATION=4; + const CONFIG_TEMPLATE=5; + + /** + * @var array list of component tags and strings + */ + private $_tpl=array(); + /** + * @var array list of directive settings + */ + private $_directive=array(); + /** + * @var string context path + */ + private $_contextPath; + /** + * @var string template file path (if available) + */ + private $_tplFile=null; + /** + * @var integer the line number that parsing starts from (internal use) + */ + private $_startingLine=0; + /** + * @var string template content to be parsed + */ + private $_content; + /** + * @var boolean whether this template is a source template + */ + private $_sourceTemplate=true; + /** + * @var string hash code of the template + */ + private $_hashCode=''; + private $_tplControl=null; + private $_includedFiles=array(); + private $_includeAtLine=array(); + private $_includeLines=array(); + + + /** + * Constructor. + * The template will be parsed after construction. + * @param string the template string + * @param string the template context directory + * @param string the template file, null if no file + * @param integer the line number that parsing starts from (internal use) + * @param boolean whether this template is a source template, i.e., this template is loaded from + * some external storage rather than from within another template. + */ + public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true) + { + $this->_sourceTemplate=$sourceTemplate; + $this->_contextPath=$contextPath; + $this->_tplFile=$tplFile; + $this->_startingLine=$startingLine; + $this->_content=$template; + $this->_hashCode=md5($template); + $this->parse($template); + $this->_content=null; // reset to save memory + } + + /** + * @return string template file path if available, null otherwise. + */ + public function getTemplateFile() + { + return $this->_tplFile; + } + + /** + * @return boolean whether this template is a source template, i.e., this template is loaded from + * some external storage rather than from within another template. + */ + public function getIsSourceTemplate() + { + return $this->_sourceTemplate; + } + + /** + * @return string context directory path + */ + public function getContextPath() + { + return $this->_contextPath; + } + + /** + * @return array name-value pairs declared in the directive + */ + public function getDirective() + { + return $this->_directive; + } + + /** + * @return string hash code that can be used to identify the template + */ + public function getHashCode() + { + return $this->_hashCode; + } + + /** + * @return array the parsed template + */ + public function &getItems() + { + return $this->_tpl; + } + + /** + * Instantiates the template. + * Content in the template will be instantiated as components and text strings + * and passed to the specified parent control. + * @param TControl the control who owns the template + * @param TControl the control who will become the root parent of the controls on the template. If null, it uses the template control. + */ + public function instantiateIn($tplControl,$parentControl=null) + { + $this->_tplControl=$tplControl; + if($parentControl===null) + $parentControl=$tplControl; + if(($page=$tplControl->getPage())===null) + $page=$this->getService()->getRequestedPage(); + $controls=array(); + $directChildren=array(); + foreach($this->_tpl as $key=>$object) + { + if($object[0]===-1) + $parent=$parentControl; + else if(isset($controls[$object[0]])) + $parent=$controls[$object[0]]; + else + continue; + if(isset($object[2])) // component + { + $component=Prado::createComponent($object[1]); + $properties=&$object[2]; + if($component instanceof TControl) + { + if($component instanceof TOutputCache) + $component->setCacheKeyPrefix($this->_hashCode.$key); + $component->setTemplateControl($tplControl); + if(isset($properties['id'])) + { + if(is_array($properties['id'])) + $properties['id']=$component->evaluateExpression($properties['id'][1]); + $tplControl->registerObject($properties['id'],$component); + } + if(isset($properties['skinid'])) + { + if(is_array($properties['skinid'])) + $component->setSkinID($component->evaluateExpression($properties['skinid'][1])); + else + $component->setSkinID($properties['skinid']); + unset($properties['skinid']); + } + + $component->trackViewState(false); + + $component->applyStyleSheetSkin($page); + foreach($properties as $name=>$value) + $this->configureControl($component,$name,$value); + + $component->trackViewState(true); + + if($parent===$parentControl) + $directChildren[]=$component; + else + $component->createdOnTemplate($parent); + if($component->getAllowChildControls()) + $controls[$key]=$component; + } + else if($component instanceof TComponent) + { + $controls[$key]=$component; + if(isset($properties['id'])) + { + if(is_array($properties['id'])) + $properties['id']=$component->evaluateExpression($properties['id'][1]); + $tplControl->registerObject($properties['id'],$component); + if(!$component->hasProperty('id')) + unset($properties['id']); + } + foreach($properties as $name=>$value) + $this->configureComponent($component,$name,$value); + if($parent===$parentControl) + $directChildren[]=$component; + else + $component->createdOnTemplate($parent); + } + } + else + { + if($object[1] instanceof TCompositeLiteral) + { + // need to clone a new object because the one in template is reused + $o=clone $object[1]; + $o->setContainer($tplControl); + if($parent===$parentControl) + $directChildren[]=$o; + else + $parent->addParsedObject($o); + } + else + { + if($parent===$parentControl) + $directChildren[]=$object[1]; + else + $parent->addParsedObject($object[1]); + } + } + } + // delay setting parent till now because the parent may cause + // the child to do lifecycle catchup which may cause problem + // if the child needs its own child controls. + foreach($directChildren as $control) + { + if($control instanceof TComponent) + $control->createdOnTemplate($parentControl); + else + $parentControl->addParsedObject($control); + } + } + + /** + * Configures a property/event of a control. + * @param TControl control to be configured + * @param string property name + * @param mixed property initial value + */ + protected function configureControl($control,$name,$value) + { + if(strncasecmp($name,'on',2)===0) // is an event + $this->configureEvent($control,$name,$value,$control); + else if(($pos=strrpos($name,'.'))===false) // is a simple property or custom attribute + $this->configureProperty($control,$name,$value); + else // is a subproperty + $this->configureSubProperty($control,$name,$value); + } + + /** + * Configures a property of a non-control component. + * @param TComponent component to be configured + * @param string property name + * @param mixed property initial value + */ + protected function configureComponent($component,$name,$value) + { + if(strpos($name,'.')===false) // is a simple property or custom attribute + $this->configureProperty($component,$name,$value); + else // is a subproperty + $this->configureSubProperty($component,$name,$value); + } + + /** + * Configures an event for a control. + * @param TControl control to be configured + * @param string event name + * @param string event handler + * @param TControl context control + */ + protected function configureEvent($control,$name,$value,$contextControl) + { + if(strpos($value,'.')===false) + $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value)); + else + $control->attachEventHandler($name,array($contextControl,$value)); + } + + /** + * Configures a simple property for a component. + * @param TComponent component to be configured + * @param string property name + * @param mixed property initial value + */ + protected function configureProperty($component,$name,$value) + { + if(is_array($value)) + { + switch($value[0]) + { + case self::CONFIG_DATABIND: + $component->bindProperty($name,$value[1]); + break; + case self::CONFIG_EXPRESSION: + if($component instanceof TControl) + $component->autoBindProperty($name,$value[1]); + else + { + $setter='set'.$name; + $component->$setter($this->_tplControl->evaluateExpression($value[1])); + } + break; + case self::CONFIG_TEMPLATE: + $setter='set'.$name; + $component->$setter($value[1]); + break; + case self::CONFIG_ASSET: // asset URL + $setter='set'.$name; + $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]); + $component->$setter($url); + break; + case self::CONFIG_PARAMETER: // application parameter + $setter='set'.$name; + $component->$setter($this->getApplication()->getParameters()->itemAt($value[1])); + break; + case self::CONFIG_LOCALIZATION: + $setter='set'.$name; + $component->$setter(Prado::localize($value[1])); + break; + default: // an error if reaching here + throw new TConfigurationException('template_tag_unexpected',$name,$value[1]); + break; + } + } + else + { + if (substr($name,0,2)=='js') + if ($value and !($value instanceof TJavaScriptLiteral)) + $value = new TJavaScriptLiteral($value); + $setter='set'.$name; + $component->$setter($value); + } + } + + /** + * Configures a subproperty for a component. + * @param TComponent component to be configured + * @param string subproperty name + * @param mixed subproperty initial value + */ + protected function configureSubProperty($component,$name,$value) + { + if(is_array($value)) + { + switch($value[0]) + { + case self::CONFIG_DATABIND: // databinding + $component->bindProperty($name,$value[1]); + break; + case self::CONFIG_EXPRESSION: // expression + if($component instanceof TControl) + $component->autoBindProperty($name,$value[1]); + else + $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1])); + break; + case self::CONFIG_TEMPLATE: + $component->setSubProperty($name,$value[1]); + break; + case self::CONFIG_ASSET: // asset URL + $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]); + $component->setSubProperty($name,$url); + break; + case self::CONFIG_PARAMETER: // application parameter + $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1])); + break; + case self::CONFIG_LOCALIZATION: + $component->setSubProperty($name,Prado::localize($value[1])); + break; + default: // an error if reaching here + throw new TConfigurationException('template_tag_unexpected',$name,$value[1]); + break; + } + } + else + $component->setSubProperty($name,$value); + } + + /** + * Parses a template string. + * + * This template parser recognizes five types of data: + * regular string, well-formed component tags, well-formed property tags, directives, and expressions. + * + * The parsing result is returned as an array. Each array element can be of three types: + * - a string, 0: container index; 1: string content; + * - a component tag, 0: container index; 1: component type; 2: attributes (name=>value pairs) + * If a directive is found in the template, it will be parsed and can be + * retrieved via {@link getDirective}, which returns an array consisting of + * name-value pairs in the directive. + * + * Note, attribute names are treated as case-insensitive and will be turned into lower cases. + * Component and directive types are case-sensitive. + * Container index is the index to the array element that stores the container object. + * If an object has no container, its container index is -1. + * + * @param string the template string + * @throws TConfigurationException if a parsing error is encountered + */ + protected function parse($input) + { + $input=$this->preprocess($input); + $tpl=&$this->_tpl; + $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE); + $expectPropEnd=false; + $textStart=0; + $stack=array(); + $container=-1; + $matchEnd=0; + $c=0; + $this->_directive=null; + try + { + for($i=0;$i<$n;++$i) + { + $match=&$matches[$i]; + $str=$match[0][0]; + $matchStart=$match[0][1]; + $matchEnd=$matchStart+strlen($str)-1; + if(strpos($str,'$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + $type=$match[1][0]; + $attributes=$this->parseAttributes($match[2][0],$match[2][1]); + $this->validateAttributes($type,$attributes); + $tpl[$c++]=array($container,$type,$attributes); + if($str[strlen($str)-2]!=='/') // open tag + { + $stack[] = $type; + $container=$c-1; + } + } + else if(strpos($str,'$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + $type=$match[1][0]; + + if(empty($stack)) + throw new TConfigurationException('template_closingtag_unexpected',""); + + $name=array_pop($stack); + if($name!==$type) + { + $tag=$name[0]==='@' ? '' : ""; + throw new TConfigurationException('template_closingtag_expected',$tag); + } + $container=$tpl[$container][0]; + } + else if(strpos($str,'<%@')===0) // directive + { + if($expectPropEnd) + continue; + if($matchStart>$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + if(isset($tpl[0]) || $this->_directive!==null) + throw new TConfigurationException('template_directive_nonunique'); + $this->_directive=$this->parseAttributes($match[4][0],$match[4][1]); + } + else if(strpos($str,'<%')===0) // expression + { + if($expectPropEnd) + continue; + if($matchStart>$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + $literal=trim($match[5][0]); + if($str[2]==='=') // expression + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal)); + else if($str[2]==='%') // statements + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal)); + else if($str[2]==='#') + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal)); + else if($str[2]==='$') + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')")); + else if($str[2]==='~') + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')")); + else if($str[2]==='/') + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'")); + else if($str[2]==='[') + { + $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\")); + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')")); + } + } + else if(strpos($str,'')===strlen($str)-2) //subproperties + { + if($expectPropEnd) + continue; + if($matchStart>$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + $prop=strtolower($match[6][0]); + $attrs=$this->parseAttributes($match[7][0],$match[7][1]); + $attributes=array(); + foreach($attrs as $name=>$value) + $attributes[$prop.'.'.$name]=$value; + $type=$tpl[$container][1]; + $this->validateAttributes($type,$attributes); + foreach($attributes as $name=>$value) + { + if(isset($tpl[$container][2][$name])) + throw new TConfigurationException('template_property_duplicated',$name); + $tpl[$container][2][$name]=$value; + } + } + else // regular property + { + $prop=strtolower($match[3][0]); + $stack[] = '@'.$prop; + if(!$expectPropEnd) + { + if($matchStart>$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + $expectPropEnd=true; + } + } + } + else if(strpos($str,'"); + $name=array_pop($stack); + if($name!=='@'.$prop) + { + $tag=$name[0]==='@' ? '' : ""; + throw new TConfigurationException('template_closingtag_expected',$tag); + } + if(($last=count($stack))<1 || $stack[$last-1][0]!=='@') + { + if($matchStart>$textStart) + { + $value=substr($input,$textStart,$matchStart-$textStart); + if(substr($prop,-8,8)==='template') + $value=$this->parseTemplateProperty($value,$textStart); + else + $value=$this->parseAttribute($value); + if($container>=0) + { + $type=$tpl[$container][1]; + $this->validateAttributes($type,array($prop=>$value)); + if(isset($tpl[$container][2][$prop])) + throw new TConfigurationException('template_property_duplicated',$prop); + $tpl[$container][2][$prop]=$value; + } + else // a property for the template control + $this->_directive[$prop]=$value; + $textStart=$matchEnd+1; + } + $expectPropEnd=false; + } + } + else if(strpos($str,', which will be treated as text strings. - * The latter is in the format of , which will be stripped out. - * - * Tags other than the above are not required to be well-formed. - * - * A TTemplate object represents a parsed PRADO template. To instantiate the template - * for a particular control, call {@link instantiateIn($control)}, which - * will create and intialize all components specified in the template and - * set their parent as $control. - * - * @author Qiang Xue - * @package System.Web.UI - * @since 3.0 - */ -class TTemplate extends TApplicationComponent implements ITemplate -{ - /** - * '' - template comments - * '' - HTML comments - * '<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>' - component tags - * '<\/?prop:([\w\.]+)\s*>' - property tags - * '<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>' - directives - * '<%[%#~\/\\$=\\[](.*?)%>' - expressions - * ')*)\s*\/>' - group subproperty tags - */ - const REGEX_RULES='/||<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|)*)\s*\/>/msS'; - - /** - * Different configurations of component property/event/attribute - */ - const CONFIG_DATABIND=0; - const CONFIG_EXPRESSION=1; - const CONFIG_ASSET=2; - const CONFIG_PARAMETER=3; - const CONFIG_LOCALIZATION=4; - const CONFIG_TEMPLATE=5; - - /** - * @var array list of component tags and strings - */ - private $_tpl=array(); - /** - * @var array list of directive settings - */ - private $_directive=array(); - /** - * @var string context path - */ - private $_contextPath; - /** - * @var string template file path (if available) - */ - private $_tplFile=null; - /** - * @var integer the line number that parsing starts from (internal use) - */ - private $_startingLine=0; - /** - * @var string template content to be parsed - */ - private $_content; - /** - * @var boolean whether this template is a source template - */ - private $_sourceTemplate=true; - /** - * @var string hash code of the template - */ - private $_hashCode=''; - private $_tplControl=null; - private $_includedFiles=array(); - private $_includeAtLine=array(); - private $_includeLines=array(); - - - /** - * Constructor. - * The template will be parsed after construction. - * @param string the template string - * @param string the template context directory - * @param string the template file, null if no file - * @param integer the line number that parsing starts from (internal use) - * @param boolean whether this template is a source template, i.e., this template is loaded from - * some external storage rather than from within another template. - */ - public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true) - { - $this->_sourceTemplate=$sourceTemplate; - $this->_contextPath=$contextPath; - $this->_tplFile=$tplFile; - $this->_startingLine=$startingLine; - $this->_content=$template; - $this->_hashCode=md5($template); - $this->parse($template); - $this->_content=null; // reset to save memory - } - - /** - * @return string template file path if available, null otherwise. - */ - public function getTemplateFile() - { - return $this->_tplFile; - } - - /** - * @return boolean whether this template is a source template, i.e., this template is loaded from - * some external storage rather than from within another template. - */ - public function getIsSourceTemplate() - { - return $this->_sourceTemplate; - } - - /** - * @return string context directory path - */ - public function getContextPath() - { - return $this->_contextPath; - } - - /** - * @return array name-value pairs declared in the directive - */ - public function getDirective() - { - return $this->_directive; - } - - /** - * @return string hash code that can be used to identify the template - */ - public function getHashCode() - { - return $this->_hashCode; - } - - /** - * @return array the parsed template - */ - public function &getItems() - { - return $this->_tpl; - } - - /** - * Instantiates the template. - * Content in the template will be instantiated as components and text strings - * and passed to the specified parent control. - * @param TControl the control who owns the template - * @param TControl the control who will become the root parent of the controls on the template. If null, it uses the template control. - */ - public function instantiateIn($tplControl,$parentControl=null) - { - $this->_tplControl=$tplControl; - if($parentControl===null) - $parentControl=$tplControl; - if(($page=$tplControl->getPage())===null) - $page=$this->getService()->getRequestedPage(); - $controls=array(); - $directChildren=array(); - foreach($this->_tpl as $key=>$object) - { - if($object[0]===-1) - $parent=$parentControl; - else if(isset($controls[$object[0]])) - $parent=$controls[$object[0]]; - else - continue; - if(isset($object[2])) // component - { - $component=Prado::createComponent($object[1]); - $properties=&$object[2]; - if($component instanceof TControl) - { - if($component instanceof TOutputCache) - $component->setCacheKeyPrefix($this->_hashCode.$key); - $component->setTemplateControl($tplControl); - if(isset($properties['id'])) - { - if(is_array($properties['id'])) - $properties['id']=$component->evaluateExpression($properties['id'][1]); - $tplControl->registerObject($properties['id'],$component); - } - if(isset($properties['skinid'])) - { - if(is_array($properties['skinid'])) - $component->setSkinID($component->evaluateExpression($properties['skinid'][1])); - else - $component->setSkinID($properties['skinid']); - unset($properties['skinid']); - } - - $component->trackViewState(false); - - $component->applyStyleSheetSkin($page); - foreach($properties as $name=>$value) - $this->configureControl($component,$name,$value); - - $component->trackViewState(true); - - if($parent===$parentControl) - $directChildren[]=$component; - else - $component->createdOnTemplate($parent); - if($component->getAllowChildControls()) - $controls[$key]=$component; - } - else if($component instanceof TComponent) - { - $controls[$key]=$component; - if(isset($properties['id'])) - { - if(is_array($properties['id'])) - $properties['id']=$component->evaluateExpression($properties['id'][1]); - $tplControl->registerObject($properties['id'],$component); - if(!$component->hasProperty('id')) - unset($properties['id']); - } - foreach($properties as $name=>$value) - $this->configureComponent($component,$name,$value); - if($parent===$parentControl) - $directChildren[]=$component; - else - $component->createdOnTemplate($parent); - } - } - else - { - if($object[1] instanceof TCompositeLiteral) - { - // need to clone a new object because the one in template is reused - $o=clone $object[1]; - $o->setContainer($tplControl); - if($parent===$parentControl) - $directChildren[]=$o; - else - $parent->addParsedObject($o); - } - else - { - if($parent===$parentControl) - $directChildren[]=$object[1]; - else - $parent->addParsedObject($object[1]); - } - } - } - // delay setting parent till now because the parent may cause - // the child to do lifecycle catchup which may cause problem - // if the child needs its own child controls. - foreach($directChildren as $control) - { - if($control instanceof TComponent) - $control->createdOnTemplate($parentControl); - else - $parentControl->addParsedObject($control); - } - } - - /** - * Configures a property/event of a control. - * @param TControl control to be configured - * @param string property name - * @param mixed property initial value - */ - protected function configureControl($control,$name,$value) - { - if(strncasecmp($name,'on',2)===0) // is an event - $this->configureEvent($control,$name,$value,$control); - else if(($pos=strrpos($name,'.'))===false) // is a simple property or custom attribute - $this->configureProperty($control,$name,$value); - else // is a subproperty - $this->configureSubProperty($control,$name,$value); - } - - /** - * Configures a property of a non-control component. - * @param TComponent component to be configured - * @param string property name - * @param mixed property initial value - */ - protected function configureComponent($component,$name,$value) - { - if(strpos($name,'.')===false) // is a simple property or custom attribute - $this->configureProperty($component,$name,$value); - else // is a subproperty - $this->configureSubProperty($component,$name,$value); - } - - /** - * Configures an event for a control. - * @param TControl control to be configured - * @param string event name - * @param string event handler - * @param TControl context control - */ - protected function configureEvent($control,$name,$value,$contextControl) - { - if(strpos($value,'.')===false) - $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value)); - else - $control->attachEventHandler($name,array($contextControl,$value)); - } - - /** - * Configures a simple property for a component. - * @param TComponent component to be configured - * @param string property name - * @param mixed property initial value - */ - protected function configureProperty($component,$name,$value) - { - if(is_array($value)) - { - switch($value[0]) - { - case self::CONFIG_DATABIND: - $component->bindProperty($name,$value[1]); - break; - case self::CONFIG_EXPRESSION: - if($component instanceof TControl) - $component->autoBindProperty($name,$value[1]); - else - { - $setter='set'.$name; - $component->$setter($this->_tplControl->evaluateExpression($value[1])); - } - break; - case self::CONFIG_TEMPLATE: - $setter='set'.$name; - $component->$setter($value[1]); - break; - case self::CONFIG_ASSET: // asset URL - $setter='set'.$name; - $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]); - $component->$setter($url); - break; - case self::CONFIG_PARAMETER: // application parameter - $setter='set'.$name; - $component->$setter($this->getApplication()->getParameters()->itemAt($value[1])); - break; - case self::CONFIG_LOCALIZATION: - $setter='set'.$name; - $component->$setter(Prado::localize($value[1])); - break; - default: // an error if reaching here - throw new TConfigurationException('template_tag_unexpected',$name,$value[1]); - break; - } - } - else - { - if (substr($name,0,2)=='js') - if ($value and !($value instanceof TJavaScriptLiteral)) - $value = new TJavaScriptLiteral($value); - $setter='set'.$name; - $component->$setter($value); - } - } - - /** - * Configures a subproperty for a component. - * @param TComponent component to be configured - * @param string subproperty name - * @param mixed subproperty initial value - */ - protected function configureSubProperty($component,$name,$value) - { - if(is_array($value)) - { - switch($value[0]) - { - case self::CONFIG_DATABIND: // databinding - $component->bindProperty($name,$value[1]); - break; - case self::CONFIG_EXPRESSION: // expression - if($component instanceof TControl) - $component->autoBindProperty($name,$value[1]); - else - $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1])); - break; - case self::CONFIG_TEMPLATE: - $component->setSubProperty($name,$value[1]); - break; - case self::CONFIG_ASSET: // asset URL - $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]); - $component->setSubProperty($name,$url); - break; - case self::CONFIG_PARAMETER: // application parameter - $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1])); - break; - case self::CONFIG_LOCALIZATION: - $component->setSubProperty($name,Prado::localize($value[1])); - break; - default: // an error if reaching here - throw new TConfigurationException('template_tag_unexpected',$name,$value[1]); - break; - } - } - else - $component->setSubProperty($name,$value); - } - - /** - * Parses a template string. - * - * This template parser recognizes five types of data: - * regular string, well-formed component tags, well-formed property tags, directives, and expressions. - * - * The parsing result is returned as an array. Each array element can be of three types: - * - a string, 0: container index; 1: string content; - * - a component tag, 0: container index; 1: component type; 2: attributes (name=>value pairs) - * If a directive is found in the template, it will be parsed and can be - * retrieved via {@link getDirective}, which returns an array consisting of - * name-value pairs in the directive. - * - * Note, attribute names are treated as case-insensitive and will be turned into lower cases. - * Component and directive types are case-sensitive. - * Container index is the index to the array element that stores the container object. - * If an object has no container, its container index is -1. - * - * @param string the template string - * @throws TConfigurationException if a parsing error is encountered - */ - protected function parse($input) - { - $input=$this->preprocess($input); - $tpl=&$this->_tpl; - $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE); - $expectPropEnd=false; - $textStart=0; - $stack=array(); - $container=-1; - $matchEnd=0; - $c=0; - $this->_directive=null; - try - { - for($i=0;$i<$n;++$i) - { - $match=&$matches[$i]; - $str=$match[0][0]; - $matchStart=$match[0][1]; - $matchEnd=$matchStart+strlen($str)-1; - if(strpos($str,'$textStart) - $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); - $textStart=$matchEnd+1; - $type=$match[1][0]; - $attributes=$this->parseAttributes($match[2][0],$match[2][1]); - $this->validateAttributes($type,$attributes); - $tpl[$c++]=array($container,$type,$attributes); - if($str[strlen($str)-2]!=='/') // open tag - { - $stack[] = $type; - $container=$c-1; - } - } - else if(strpos($str,'$textStart) - $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); - $textStart=$matchEnd+1; - $type=$match[1][0]; - - if(empty($stack)) - throw new TConfigurationException('template_closingtag_unexpected',""); - - $name=array_pop($stack); - if($name!==$type) - { - $tag=$name[0]==='@' ? '' : ""; - throw new TConfigurationException('template_closingtag_expected',$tag); - } - $container=$tpl[$container][0]; - } - else if(strpos($str,'<%@')===0) // directive - { - if($expectPropEnd) - continue; - if($matchStart>$textStart) - $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); - $textStart=$matchEnd+1; - if(isset($tpl[0]) || $this->_directive!==null) - throw new TConfigurationException('template_directive_nonunique'); - $this->_directive=$this->parseAttributes($match[4][0],$match[4][1]); - } - else if(strpos($str,'<%')===0) // expression - { - if($expectPropEnd) - continue; - if($matchStart>$textStart) - $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); - $textStart=$matchEnd+1; - $literal=trim($match[5][0]); - if($str[2]==='=') // expression - $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal)); - else if($str[2]==='%') // statements - $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal)); - else if($str[2]==='#') - $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal)); - else if($str[2]==='$') - $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')")); - else if($str[2]==='~') - $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')")); - else if($str[2]==='/') - $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'")); - else if($str[2]==='[') - { - $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\")); - $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')")); - } - } - else if(strpos($str,'')===strlen($str)-2) //subproperties - { - if($expectPropEnd) - continue; - if($matchStart>$textStart) - $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); - $textStart=$matchEnd+1; - $prop=strtolower($match[6][0]); - $attrs=$this->parseAttributes($match[7][0],$match[7][1]); - $attributes=array(); - foreach($attrs as $name=>$value) - $attributes[$prop.'.'.$name]=$value; - $type=$tpl[$container][1]; - $this->validateAttributes($type,$attributes); - foreach($attributes as $name=>$value) - { - if(isset($tpl[$container][2][$name])) - throw new TConfigurationException('template_property_duplicated',$name); - $tpl[$container][2][$name]=$value; - } - } - else // regular property - { - $prop=strtolower($match[3][0]); - $stack[] = '@'.$prop; - if(!$expectPropEnd) - { - if($matchStart>$textStart) - $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); - $textStart=$matchEnd+1; - $expectPropEnd=true; - } - } - } - else if(strpos($str,'"); - $name=array_pop($stack); - if($name!=='@'.$prop) - { - $tag=$name[0]==='@' ? '' : ""; - throw new TConfigurationException('template_closingtag_expected',$tag); - } - if(($last=count($stack))<1 || $stack[$last-1][0]!=='@') - { - if($matchStart>$textStart) - { - $value=substr($input,$textStart,$matchStart-$textStart); - if(substr($prop,-8,8)==='template') - $value=$this->parseTemplateProperty($value,$textStart); - else - $value=$this->parseAttribute($value); - if($container>=0) - { - $type=$tpl[$container][1]; - $this->validateAttributes($type,array($prop=>$value)); - if(isset($tpl[$container][2][$prop])) - throw new TConfigurationException('template_property_duplicated',$prop); - $tpl[$container][2][$prop]=$value; - } - else // a property for the template control - $this->_directive[$prop]=$value; - $textStart=$matchEnd+1; - } - $expectPropEnd=false; - } - } - else if(strpos($str,'